Statistics
| Branch: | Revision:

root / ui / vnc-enc-tight.c @ 48ff7a62

History | View | Annotate | Download (66.5 kB)

1 380282b0 Corentin Chary
/*
2 380282b0 Corentin Chary
 * QEMU VNC display driver: tight encoding
3 380282b0 Corentin Chary
 *
4 380282b0 Corentin Chary
 * From libvncserver/libvncserver/tight.c
5 380282b0 Corentin Chary
 * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
6 380282b0 Corentin Chary
 * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
7 380282b0 Corentin Chary
 *
8 380282b0 Corentin Chary
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
9 380282b0 Corentin Chary
 *
10 380282b0 Corentin Chary
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 380282b0 Corentin Chary
 * of this software and associated documentation files (the "Software"), to deal
12 380282b0 Corentin Chary
 * in the Software without restriction, including without limitation the rights
13 380282b0 Corentin Chary
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 380282b0 Corentin Chary
 * copies of the Software, and to permit persons to whom the Software is
15 380282b0 Corentin Chary
 * furnished to do so, subject to the following conditions:
16 380282b0 Corentin Chary
 *
17 380282b0 Corentin Chary
 * The above copyright notice and this permission notice shall be included in
18 380282b0 Corentin Chary
 * all copies or substantial portions of the Software.
19 380282b0 Corentin Chary
 *
20 380282b0 Corentin Chary
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 380282b0 Corentin Chary
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 380282b0 Corentin Chary
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 380282b0 Corentin Chary
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 380282b0 Corentin Chary
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 380282b0 Corentin Chary
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 380282b0 Corentin Chary
 * THE SOFTWARE.
27 380282b0 Corentin Chary
 */
28 380282b0 Corentin Chary
29 efe556ad Corentin Chary
#include "config-host.h"
30 2f6f5c7a Corentin Chary
31 f26e428d Roy Tam
/* This needs to be before jpeglib.h line because of conflict with
32 f26e428d Roy Tam
   INT32 definitions between jmorecfg.h (included by jpeglib.h) and
33 f26e428d Roy Tam
   Win32 basetsd.h (included by windows.h). */
34 f26e428d Roy Tam
#include "qemu-common.h"
35 f26e428d Roy Tam
36 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
37 2fb0c09f Stefan Weil
/* The following define is needed by pngconf.h. Otherwise it won't compile,
38 2fb0c09f Stefan Weil
   because setjmp.h was already included by qemu-common.h. */
39 2fb0c09f Stefan Weil
#define PNG_SKIP_SETJMP_CHECK
40 efe556ad Corentin Chary
#include <png.h>
41 efe556ad Corentin Chary
#endif
42 2f6f5c7a Corentin Chary
#ifdef CONFIG_VNC_JPEG
43 2f6f5c7a Corentin Chary
#include <stdio.h>
44 2f6f5c7a Corentin Chary
#include <jpeglib.h>
45 2f6f5c7a Corentin Chary
#endif
46 2f6f5c7a Corentin Chary
47 2f6f5c7a Corentin Chary
#include "bswap.h"
48 aa7d73fd Corentin Chary
#include "qint.h"
49 380282b0 Corentin Chary
#include "vnc.h"
50 245f7b51 Corentin Chary
#include "vnc-enc-tight.h"
51 5136a052 Corentin Chary
#include "vnc-palette.h"
52 380282b0 Corentin Chary
53 380282b0 Corentin Chary
/* Compression level stuff. The following array contains various
54 380282b0 Corentin Chary
   encoder parameters for each of 10 compression levels (0..9).
55 380282b0 Corentin Chary
   Last three parameters correspond to JPEG quality levels (0..9). */
56 380282b0 Corentin Chary
57 380282b0 Corentin Chary
static const struct {
58 380282b0 Corentin Chary
    int max_rect_size, max_rect_width;
59 380282b0 Corentin Chary
    int mono_min_rect_size, gradient_min_rect_size;
60 380282b0 Corentin Chary
    int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level;
61 380282b0 Corentin Chary
    int gradient_threshold, gradient_threshold24;
62 380282b0 Corentin Chary
    int idx_max_colors_divisor;
63 380282b0 Corentin Chary
    int jpeg_quality, jpeg_threshold, jpeg_threshold24;
64 380282b0 Corentin Chary
} tight_conf[] = {
65 380282b0 Corentin Chary
    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
66 380282b0 Corentin Chary
    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
67 380282b0 Corentin Chary
    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
68 380282b0 Corentin Chary
    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
69 380282b0 Corentin Chary
    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
70 380282b0 Corentin Chary
    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
71 380282b0 Corentin Chary
    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
72 380282b0 Corentin Chary
    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
73 380282b0 Corentin Chary
    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
74 380282b0 Corentin Chary
    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
75 380282b0 Corentin Chary
};
76 380282b0 Corentin Chary
77 efe556ad Corentin Chary
78 efe556ad Corentin Chary
static int tight_send_framebuffer_update(VncState *vs, int x, int y,
79 efe556ad Corentin Chary
                                         int w, int h);
80 efe556ad Corentin Chary
81 ce702e93 Corentin Chary
#ifdef CONFIG_VNC_JPEG
82 ce702e93 Corentin Chary
static const struct {
83 ce702e93 Corentin Chary
    double jpeg_freq_min;       /* Don't send JPEG if the freq is bellow */
84 ce702e93 Corentin Chary
    double jpeg_freq_threshold; /* Always send JPEG if the freq is above */
85 ce702e93 Corentin Chary
    int jpeg_idx;               /* Allow indexed JPEG */
86 ce702e93 Corentin Chary
    int jpeg_full;              /* Allow full color JPEG */
87 ce702e93 Corentin Chary
} tight_jpeg_conf[] = {
88 8cb4a6b7 Corentin Chary
    { 0,   8,  1, 1 },
89 8cb4a6b7 Corentin Chary
    { 0,   8,  1, 1 },
90 8cb4a6b7 Corentin Chary
    { 0,   8,  1, 1 },
91 8cb4a6b7 Corentin Chary
    { 0,   8,  1, 1 },
92 8cb4a6b7 Corentin Chary
    { 0,   10, 1, 1 },
93 8cb4a6b7 Corentin Chary
    { 0.1, 10, 1, 1 },
94 8cb4a6b7 Corentin Chary
    { 0.2, 10, 1, 1 },
95 8cb4a6b7 Corentin Chary
    { 0.3, 12, 0, 0 },
96 8cb4a6b7 Corentin Chary
    { 0.4, 14, 0, 0 },
97 8cb4a6b7 Corentin Chary
    { 0.5, 16, 0, 0 },
98 ce702e93 Corentin Chary
};
99 ce702e93 Corentin Chary
#endif
100 ce702e93 Corentin Chary
101 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
102 3941bf6f Corentin Chary
static const struct {
103 3941bf6f Corentin Chary
    int png_zlib_level, png_filters;
104 3941bf6f Corentin Chary
} tight_png_conf[] = {
105 3941bf6f Corentin Chary
    { 0, PNG_NO_FILTERS },
106 3941bf6f Corentin Chary
    { 1, PNG_NO_FILTERS },
107 3941bf6f Corentin Chary
    { 2, PNG_NO_FILTERS },
108 3941bf6f Corentin Chary
    { 3, PNG_NO_FILTERS },
109 3941bf6f Corentin Chary
    { 4, PNG_NO_FILTERS },
110 3941bf6f Corentin Chary
    { 5, PNG_ALL_FILTERS },
111 3941bf6f Corentin Chary
    { 6, PNG_ALL_FILTERS },
112 3941bf6f Corentin Chary
    { 7, PNG_ALL_FILTERS },
113 3941bf6f Corentin Chary
    { 8, PNG_ALL_FILTERS },
114 3941bf6f Corentin Chary
    { 9, PNG_ALL_FILTERS },
115 3941bf6f Corentin Chary
};
116 3941bf6f Corentin Chary
117 efe556ad Corentin Chary
static int send_png_rect(VncState *vs, int x, int y, int w, int h,
118 5136a052 Corentin Chary
                         VncPalette *palette);
119 efe556ad Corentin Chary
120 efe556ad Corentin Chary
static bool tight_can_send_png_rect(VncState *vs, int w, int h)
121 efe556ad Corentin Chary
{
122 d1af0e05 Corentin Chary
    if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
123 efe556ad Corentin Chary
        return false;
124 efe556ad Corentin Chary
    }
125 efe556ad Corentin Chary
126 efe556ad Corentin Chary
    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
127 efe556ad Corentin Chary
        vs->clientds.pf.bytes_per_pixel == 1) {
128 efe556ad Corentin Chary
        return false;
129 efe556ad Corentin Chary
    }
130 efe556ad Corentin Chary
131 efe556ad Corentin Chary
    return true;
132 efe556ad Corentin Chary
}
133 efe556ad Corentin Chary
#endif
134 efe556ad Corentin Chary
135 b4bea3f2 Corentin Chary
/*
136 2f6f5c7a Corentin Chary
 * Code to guess if given rectangle is suitable for smooth image
137 2f6f5c7a Corentin Chary
 * compression (by applying "gradient" filter or JPEG coder).
138 2f6f5c7a Corentin Chary
 */
139 2f6f5c7a Corentin Chary
140 249cdb42 Blue Swirl
static unsigned int
141 2f6f5c7a Corentin Chary
tight_detect_smooth_image24(VncState *vs, int w, int h)
142 2f6f5c7a Corentin Chary
{
143 2f6f5c7a Corentin Chary
    int off;
144 2f6f5c7a Corentin Chary
    int x, y, d, dx;
145 249cdb42 Blue Swirl
    unsigned int c;
146 249cdb42 Blue Swirl
    unsigned int stats[256];
147 2f6f5c7a Corentin Chary
    int pixels = 0;
148 2f6f5c7a Corentin Chary
    int pix, left[3];
149 249cdb42 Blue Swirl
    unsigned int errors;
150 d1af0e05 Corentin Chary
    unsigned char *buf = vs->tight.tight.buffer;
151 2f6f5c7a Corentin Chary
152 2f6f5c7a Corentin Chary
    /*
153 2f6f5c7a Corentin Chary
     * If client is big-endian, color samples begin from the second
154 2f6f5c7a Corentin Chary
     * byte (offset 1) of a 32-bit pixel value.
155 2f6f5c7a Corentin Chary
     */
156 2f6f5c7a Corentin Chary
    off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
157 2f6f5c7a Corentin Chary
158 2f6f5c7a Corentin Chary
    memset(stats, 0, sizeof (stats));
159 2f6f5c7a Corentin Chary
160 2f6f5c7a Corentin Chary
    for (y = 0, x = 0; y < h && x < w;) {
161 2f6f5c7a Corentin Chary
        for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH;
162 2f6f5c7a Corentin Chary
             d++) {
163 2f6f5c7a Corentin Chary
            for (c = 0; c < 3; c++) {
164 2f6f5c7a Corentin Chary
                left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF;
165 2f6f5c7a Corentin Chary
            }
166 2f6f5c7a Corentin Chary
            for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) {
167 2f6f5c7a Corentin Chary
                for (c = 0; c < 3; c++) {
168 2f6f5c7a Corentin Chary
                    pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
169 2f6f5c7a Corentin Chary
                    stats[abs(pix - left[c])]++;
170 2f6f5c7a Corentin Chary
                    left[c] = pix;
171 2f6f5c7a Corentin Chary
                }
172 2f6f5c7a Corentin Chary
                pixels++;
173 2f6f5c7a Corentin Chary
            }
174 2f6f5c7a Corentin Chary
        }
175 2f6f5c7a Corentin Chary
        if (w > h) {
176 2f6f5c7a Corentin Chary
            x += h;
177 2f6f5c7a Corentin Chary
            y = 0;
178 2f6f5c7a Corentin Chary
        } else {
179 2f6f5c7a Corentin Chary
            x = 0;
180 2f6f5c7a Corentin Chary
            y += w;
181 2f6f5c7a Corentin Chary
        }
182 2f6f5c7a Corentin Chary
    }
183 2f6f5c7a Corentin Chary
184 2f6f5c7a Corentin Chary
    /* 95% smooth or more ... */
185 2f6f5c7a Corentin Chary
    if (stats[0] * 33 / pixels >= 95) {
186 2f6f5c7a Corentin Chary
        return 0;
187 2f6f5c7a Corentin Chary
    }
188 2f6f5c7a Corentin Chary
189 2f6f5c7a Corentin Chary
    errors = 0;
190 2f6f5c7a Corentin Chary
    for (c = 1; c < 8; c++) {
191 2f6f5c7a Corentin Chary
        errors += stats[c] * (c * c);
192 2f6f5c7a Corentin Chary
        if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
193 2f6f5c7a Corentin Chary
            return 0;
194 2f6f5c7a Corentin Chary
        }
195 2f6f5c7a Corentin Chary
    }
196 2f6f5c7a Corentin Chary
    for (; c < 256; c++) {
197 2f6f5c7a Corentin Chary
        errors += stats[c] * (c * c);
198 2f6f5c7a Corentin Chary
    }
199 2f6f5c7a Corentin Chary
    errors /= (pixels * 3 - stats[0]);
200 2f6f5c7a Corentin Chary
201 2f6f5c7a Corentin Chary
    return errors;
202 2f6f5c7a Corentin Chary
}
203 2f6f5c7a Corentin Chary
204 2f6f5c7a Corentin Chary
#define DEFINE_DETECT_FUNCTION(bpp)                                     \
205 2f6f5c7a Corentin Chary
                                                                        \
206 249cdb42 Blue Swirl
    static unsigned int                                                 \
207 2f6f5c7a Corentin Chary
    tight_detect_smooth_image##bpp(VncState *vs, int w, int h) {        \
208 2f6f5c7a Corentin Chary
        bool endian;                                                    \
209 2f6f5c7a Corentin Chary
        uint##bpp##_t pix;                                              \
210 2f6f5c7a Corentin Chary
        int max[3], shift[3];                                           \
211 2f6f5c7a Corentin Chary
        int x, y, d, dx;                                                \
212 249cdb42 Blue Swirl
        unsigned int c;                                                 \
213 249cdb42 Blue Swirl
        unsigned int stats[256];                                        \
214 2f6f5c7a Corentin Chary
        int pixels = 0;                                                 \
215 2f6f5c7a Corentin Chary
        int sample, sum, left[3];                                       \
216 249cdb42 Blue Swirl
        unsigned int errors;                                            \
217 d1af0e05 Corentin Chary
        unsigned char *buf = vs->tight.tight.buffer;                    \
218 2f6f5c7a Corentin Chary
                                                                        \
219 2f6f5c7a Corentin Chary
        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
220 2f6f5c7a Corentin Chary
                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
221 2f6f5c7a Corentin Chary
                                                                        \
222 2f6f5c7a Corentin Chary
                                                                        \
223 2f6f5c7a Corentin Chary
        max[0] = vs->clientds.pf.rmax;                                  \
224 2f6f5c7a Corentin Chary
        max[1] = vs->clientds.pf.gmax;                                  \
225 2f6f5c7a Corentin Chary
        max[2] = vs->clientds.pf.bmax;                                  \
226 2f6f5c7a Corentin Chary
        shift[0] = vs->clientds.pf.rshift;                              \
227 2f6f5c7a Corentin Chary
        shift[1] = vs->clientds.pf.gshift;                              \
228 2f6f5c7a Corentin Chary
        shift[2] = vs->clientds.pf.bshift;                              \
229 2f6f5c7a Corentin Chary
                                                                        \
230 2f6f5c7a Corentin Chary
        memset(stats, 0, sizeof(stats));                                \
231 2f6f5c7a Corentin Chary
                                                                        \
232 2f6f5c7a Corentin Chary
        y = 0, x = 0;                                                   \
233 2f6f5c7a Corentin Chary
        while (y < h && x < w) {                                        \
234 2f6f5c7a Corentin Chary
            for (d = 0; d < h - y &&                                    \
235 2f6f5c7a Corentin Chary
                     d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) {  \
236 2f6f5c7a Corentin Chary
                pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d];              \
237 2f6f5c7a Corentin Chary
                if (endian) {                                           \
238 ba5e7f82 Izumi Tsutsui
                    pix = bswap##bpp(pix);                              \
239 2f6f5c7a Corentin Chary
                }                                                       \
240 2f6f5c7a Corentin Chary
                for (c = 0; c < 3; c++) {                               \
241 2f6f5c7a Corentin Chary
                    left[c] = (int)(pix >> shift[c] & max[c]);          \
242 2f6f5c7a Corentin Chary
                }                                                       \
243 2f6f5c7a Corentin Chary
                for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH;       \
244 2f6f5c7a Corentin Chary
                     dx++) {                                            \
245 2f6f5c7a Corentin Chary
                    pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx];       \
246 2f6f5c7a Corentin Chary
                    if (endian) {                                       \
247 ba5e7f82 Izumi Tsutsui
                        pix = bswap##bpp(pix);                          \
248 2f6f5c7a Corentin Chary
                    }                                                   \
249 2f6f5c7a Corentin Chary
                    sum = 0;                                            \
250 2f6f5c7a Corentin Chary
                    for (c = 0; c < 3; c++) {                           \
251 2f6f5c7a Corentin Chary
                        sample = (int)(pix >> shift[c] & max[c]);       \
252 2f6f5c7a Corentin Chary
                        sum += abs(sample - left[c]);                   \
253 2f6f5c7a Corentin Chary
                        left[c] = sample;                               \
254 2f6f5c7a Corentin Chary
                    }                                                   \
255 2f6f5c7a Corentin Chary
                    if (sum > 255) {                                    \
256 2f6f5c7a Corentin Chary
                        sum = 255;                                      \
257 2f6f5c7a Corentin Chary
                    }                                                   \
258 2f6f5c7a Corentin Chary
                    stats[sum]++;                                       \
259 2f6f5c7a Corentin Chary
                    pixels++;                                           \
260 2f6f5c7a Corentin Chary
                }                                                       \
261 2f6f5c7a Corentin Chary
            }                                                           \
262 2f6f5c7a Corentin Chary
            if (w > h) {                                                \
263 2f6f5c7a Corentin Chary
                x += h;                                                 \
264 2f6f5c7a Corentin Chary
                y = 0;                                                  \
265 2f6f5c7a Corentin Chary
            } else {                                                    \
266 2f6f5c7a Corentin Chary
                x = 0;                                                  \
267 2f6f5c7a Corentin Chary
                y += w;                                                 \
268 2f6f5c7a Corentin Chary
            }                                                           \
269 2f6f5c7a Corentin Chary
        }                                                               \
270 2f6f5c7a Corentin Chary
                                                                        \
271 2f6f5c7a Corentin Chary
        if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
272 2f6f5c7a Corentin Chary
            return 0;                                                   \
273 2f6f5c7a Corentin Chary
        }                                                               \
274 2f6f5c7a Corentin Chary
                                                                        \
275 2f6f5c7a Corentin Chary
        errors = 0;                                                     \
276 2f6f5c7a Corentin Chary
        for (c = 1; c < 8; c++) {                                       \
277 2f6f5c7a Corentin Chary
            errors += stats[c] * (c * c);                               \
278 2f6f5c7a Corentin Chary
            if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {           \
279 2f6f5c7a Corentin Chary
                return 0;                                               \
280 2f6f5c7a Corentin Chary
            }                                                           \
281 2f6f5c7a Corentin Chary
        }                                                               \
282 2f6f5c7a Corentin Chary
        for (; c < 256; c++) {                                          \
283 2f6f5c7a Corentin Chary
            errors += stats[c] * (c * c);                               \
284 2f6f5c7a Corentin Chary
        }                                                               \
285 2f6f5c7a Corentin Chary
        errors /= (pixels - stats[0]);                                  \
286 2f6f5c7a Corentin Chary
                                                                        \
287 2f6f5c7a Corentin Chary
        return errors;                                                  \
288 2f6f5c7a Corentin Chary
    }
289 2f6f5c7a Corentin Chary
290 2f6f5c7a Corentin Chary
DEFINE_DETECT_FUNCTION(16)
291 2f6f5c7a Corentin Chary
DEFINE_DETECT_FUNCTION(32)
292 2f6f5c7a Corentin Chary
293 2f6f5c7a Corentin Chary
static int
294 2f6f5c7a Corentin Chary
tight_detect_smooth_image(VncState *vs, int w, int h)
295 2f6f5c7a Corentin Chary
{
296 249cdb42 Blue Swirl
    unsigned int errors;
297 d1af0e05 Corentin Chary
    int compression = vs->tight.compression;
298 d1af0e05 Corentin Chary
    int quality = vs->tight.quality;
299 2f6f5c7a Corentin Chary
300 6f9c78c1 Corentin Chary
    if (!vs->vd->lossy) {
301 6f9c78c1 Corentin Chary
        return 0;
302 6f9c78c1 Corentin Chary
    }
303 6f9c78c1 Corentin Chary
304 2f6f5c7a Corentin Chary
    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
305 2f6f5c7a Corentin Chary
        vs->clientds.pf.bytes_per_pixel == 1 ||
306 2f6f5c7a Corentin Chary
        w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
307 2f6f5c7a Corentin Chary
        return 0;
308 2f6f5c7a Corentin Chary
    }
309 2f6f5c7a Corentin Chary
310 7bccf573 Blue Swirl
    if (vs->tight.quality != (uint8_t)-1) {
311 2f6f5c7a Corentin Chary
        if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
312 2f6f5c7a Corentin Chary
            return 0;
313 2f6f5c7a Corentin Chary
        }
314 2f6f5c7a Corentin Chary
    } else {
315 2f6f5c7a Corentin Chary
        if (w * h < tight_conf[compression].gradient_min_rect_size) {
316 2f6f5c7a Corentin Chary
            return 0;
317 2f6f5c7a Corentin Chary
        }
318 2f6f5c7a Corentin Chary
    }
319 2f6f5c7a Corentin Chary
320 2f6f5c7a Corentin Chary
    if (vs->clientds.pf.bytes_per_pixel == 4) {
321 d1af0e05 Corentin Chary
        if (vs->tight.pixel24) {
322 2f6f5c7a Corentin Chary
            errors = tight_detect_smooth_image24(vs, w, h);
323 7bccf573 Blue Swirl
            if (vs->tight.quality != (uint8_t)-1) {
324 2f6f5c7a Corentin Chary
                return (errors < tight_conf[quality].jpeg_threshold24);
325 2f6f5c7a Corentin Chary
            }
326 2f6f5c7a Corentin Chary
            return (errors < tight_conf[compression].gradient_threshold24);
327 2f6f5c7a Corentin Chary
        } else {
328 2f6f5c7a Corentin Chary
            errors = tight_detect_smooth_image32(vs, w, h);
329 2f6f5c7a Corentin Chary
        }
330 2f6f5c7a Corentin Chary
    } else {
331 2f6f5c7a Corentin Chary
        errors = tight_detect_smooth_image16(vs, w, h);
332 2f6f5c7a Corentin Chary
    }
333 2f6f5c7a Corentin Chary
    if (quality != -1) {
334 2f6f5c7a Corentin Chary
        return (errors < tight_conf[quality].jpeg_threshold);
335 2f6f5c7a Corentin Chary
    }
336 2f6f5c7a Corentin Chary
    return (errors < tight_conf[compression].gradient_threshold);
337 2f6f5c7a Corentin Chary
}
338 2f6f5c7a Corentin Chary
339 2f6f5c7a Corentin Chary
/*
340 aa7d73fd Corentin Chary
 * Code to determine how many different colors used in rectangle.
341 aa7d73fd Corentin Chary
 */
342 aa7d73fd Corentin Chary
#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
343 aa7d73fd Corentin Chary
                                                                        \
344 aa7d73fd Corentin Chary
    static int                                                          \
345 aa7d73fd Corentin Chary
    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
346 aa7d73fd Corentin Chary
                            int max, size_t count,                      \
347 aa7d73fd Corentin Chary
                            uint32_t *bg, uint32_t *fg,                 \
348 5136a052 Corentin Chary
                            VncPalette **palette) {                     \
349 aa7d73fd Corentin Chary
        uint##bpp##_t *data;                                            \
350 aa7d73fd Corentin Chary
        uint##bpp##_t c0, c1, ci;                                       \
351 aa7d73fd Corentin Chary
        int i, n0, n1;                                                  \
352 aa7d73fd Corentin Chary
                                                                        \
353 d1af0e05 Corentin Chary
        data = (uint##bpp##_t *)vs->tight.tight.buffer;                 \
354 aa7d73fd Corentin Chary
                                                                        \
355 aa7d73fd Corentin Chary
        c0 = data[0];                                                   \
356 aa7d73fd Corentin Chary
        i = 1;                                                          \
357 aa7d73fd Corentin Chary
        while (i < count && data[i] == c0)                              \
358 aa7d73fd Corentin Chary
            i++;                                                        \
359 aa7d73fd Corentin Chary
        if (i >= count) {                                               \
360 aa7d73fd Corentin Chary
            *bg = *fg = c0;                                             \
361 aa7d73fd Corentin Chary
            return 1;                                                   \
362 aa7d73fd Corentin Chary
        }                                                               \
363 aa7d73fd Corentin Chary
                                                                        \
364 aa7d73fd Corentin Chary
        if (max < 2) {                                                  \
365 aa7d73fd Corentin Chary
            return 0;                                                   \
366 aa7d73fd Corentin Chary
        }                                                               \
367 aa7d73fd Corentin Chary
                                                                        \
368 aa7d73fd Corentin Chary
        n0 = i;                                                         \
369 aa7d73fd Corentin Chary
        c1 = data[i];                                                   \
370 aa7d73fd Corentin Chary
        n1 = 0;                                                         \
371 aa7d73fd Corentin Chary
        for (i++; i < count; i++) {                                     \
372 aa7d73fd Corentin Chary
            ci = data[i];                                               \
373 aa7d73fd Corentin Chary
            if (ci == c0) {                                             \
374 aa7d73fd Corentin Chary
                n0++;                                                   \
375 aa7d73fd Corentin Chary
            } else if (ci == c1) {                                      \
376 aa7d73fd Corentin Chary
                n1++;                                                   \
377 aa7d73fd Corentin Chary
            } else                                                      \
378 aa7d73fd Corentin Chary
                break;                                                  \
379 aa7d73fd Corentin Chary
        }                                                               \
380 aa7d73fd Corentin Chary
        if (i >= count) {                                               \
381 aa7d73fd Corentin Chary
            if (n0 > n1) {                                              \
382 aa7d73fd Corentin Chary
                *bg = (uint32_t)c0;                                     \
383 aa7d73fd Corentin Chary
                *fg = (uint32_t)c1;                                     \
384 aa7d73fd Corentin Chary
            } else {                                                    \
385 aa7d73fd Corentin Chary
                *bg = (uint32_t)c1;                                     \
386 aa7d73fd Corentin Chary
                *fg = (uint32_t)c0;                                     \
387 aa7d73fd Corentin Chary
            }                                                           \
388 aa7d73fd Corentin Chary
            return 2;                                                   \
389 aa7d73fd Corentin Chary
        }                                                               \
390 aa7d73fd Corentin Chary
                                                                        \
391 aa7d73fd Corentin Chary
        if (max == 2) {                                                 \
392 aa7d73fd Corentin Chary
            return 0;                                                   \
393 aa7d73fd Corentin Chary
        }                                                               \
394 aa7d73fd Corentin Chary
                                                                        \
395 5136a052 Corentin Chary
        *palette = palette_new(max, bpp);                               \
396 5136a052 Corentin Chary
        palette_put(*palette, c0);                                      \
397 5136a052 Corentin Chary
        palette_put(*palette, c1);                                      \
398 5136a052 Corentin Chary
        palette_put(*palette, ci);                                      \
399 aa7d73fd Corentin Chary
                                                                        \
400 aa7d73fd Corentin Chary
        for (i++; i < count; i++) {                                     \
401 aa7d73fd Corentin Chary
            if (data[i] == ci) {                                        \
402 aa7d73fd Corentin Chary
                continue;                                               \
403 aa7d73fd Corentin Chary
            } else {                                                    \
404 5d8efe39 Corentin Chary
                ci = data[i];                                           \
405 5136a052 Corentin Chary
                if (!palette_put(*palette, (uint32_t)ci)) {             \
406 aa7d73fd Corentin Chary
                    return 0;                                           \
407 aa7d73fd Corentin Chary
                }                                                       \
408 aa7d73fd Corentin Chary
            }                                                           \
409 aa7d73fd Corentin Chary
        }                                                               \
410 aa7d73fd Corentin Chary
                                                                        \
411 5136a052 Corentin Chary
        return palette_size(*palette);                                  \
412 aa7d73fd Corentin Chary
    }
413 aa7d73fd Corentin Chary
414 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(8)
415 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(16)
416 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(32)
417 aa7d73fd Corentin Chary
418 aa7d73fd Corentin Chary
static int tight_fill_palette(VncState *vs, int x, int y,
419 aa7d73fd Corentin Chary
                              size_t count, uint32_t *bg, uint32_t *fg,
420 5136a052 Corentin Chary
                              VncPalette **palette)
421 aa7d73fd Corentin Chary
{
422 aa7d73fd Corentin Chary
    int max;
423 aa7d73fd Corentin Chary
424 d1af0e05 Corentin Chary
    max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
425 aa7d73fd Corentin Chary
    if (max < 2 &&
426 d1af0e05 Corentin Chary
        count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
427 aa7d73fd Corentin Chary
        max = 2;
428 aa7d73fd Corentin Chary
    }
429 aa7d73fd Corentin Chary
    if (max >= 256) {
430 aa7d73fd Corentin Chary
        max = 256;
431 aa7d73fd Corentin Chary
    }
432 aa7d73fd Corentin Chary
433 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
434 aa7d73fd Corentin Chary
    case 4:
435 aa7d73fd Corentin Chary
        return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
436 aa7d73fd Corentin Chary
    case 2:
437 aa7d73fd Corentin Chary
        return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
438 aa7d73fd Corentin Chary
    default:
439 aa7d73fd Corentin Chary
        max = 2;
440 aa7d73fd Corentin Chary
        return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
441 aa7d73fd Corentin Chary
    }
442 aa7d73fd Corentin Chary
    return 0;
443 aa7d73fd Corentin Chary
}
444 aa7d73fd Corentin Chary
445 aa7d73fd Corentin Chary
/*
446 aa7d73fd Corentin Chary
 * Converting truecolor samples into palette indices.
447 aa7d73fd Corentin Chary
 */
448 aa7d73fd Corentin Chary
#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
449 aa7d73fd Corentin Chary
                                                                        \
450 aa7d73fd Corentin Chary
    static void                                                         \
451 aa7d73fd Corentin Chary
    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
452 5136a052 Corentin Chary
                                   VncPalette *palette) {               \
453 aa7d73fd Corentin Chary
        uint##bpp##_t *src;                                             \
454 aa7d73fd Corentin Chary
        uint##bpp##_t rgb;                                              \
455 54d43eac Corentin Chary
        int i, rep;                                                     \
456 aa7d73fd Corentin Chary
        uint8_t idx;                                                    \
457 aa7d73fd Corentin Chary
                                                                        \
458 aa7d73fd Corentin Chary
        src = (uint##bpp##_t *) buf;                                    \
459 aa7d73fd Corentin Chary
                                                                        \
460 54d43eac Corentin Chary
        for (i = 0; i < count; i++) {                                   \
461 efe556ad Corentin Chary
                                                                        \
462 aa7d73fd Corentin Chary
            rgb = *src++;                                               \
463 aa7d73fd Corentin Chary
            rep = 0;                                                    \
464 54d43eac Corentin Chary
            while (i < count && *src == rgb) {                          \
465 54d43eac Corentin Chary
                rep++, src++, i++;                                      \
466 aa7d73fd Corentin Chary
            }                                                           \
467 5136a052 Corentin Chary
            idx = palette_idx(palette, rgb);                            \
468 5136a052 Corentin Chary
            /*                                                          \
469 5136a052 Corentin Chary
             * Should never happen, but don't break everything          \
470 5136a052 Corentin Chary
             * if it does, use the first color instead                  \
471 5136a052 Corentin Chary
             */                                                         \
472 7bccf573 Blue Swirl
            if (idx == (uint8_t)-1) {                                   \
473 aa7d73fd Corentin Chary
                idx = 0;                                                \
474 aa7d73fd Corentin Chary
            }                                                           \
475 aa7d73fd Corentin Chary
            while (rep >= 0) {                                          \
476 aa7d73fd Corentin Chary
                *buf++ = idx;                                           \
477 aa7d73fd Corentin Chary
                rep--;                                                  \
478 aa7d73fd Corentin Chary
            }                                                           \
479 aa7d73fd Corentin Chary
        }                                                               \
480 aa7d73fd Corentin Chary
    }
481 aa7d73fd Corentin Chary
482 aa7d73fd Corentin Chary
DEFINE_IDX_ENCODE_FUNCTION(16)
483 aa7d73fd Corentin Chary
DEFINE_IDX_ENCODE_FUNCTION(32)
484 aa7d73fd Corentin Chary
485 aa7d73fd Corentin Chary
#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
486 aa7d73fd Corentin Chary
                                                                        \
487 aa7d73fd Corentin Chary
    static void                                                         \
488 aa7d73fd Corentin Chary
    tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h,             \
489 aa7d73fd Corentin Chary
                                uint##bpp##_t bg, uint##bpp##_t fg) {   \
490 aa7d73fd Corentin Chary
        uint##bpp##_t *ptr;                                             \
491 aa7d73fd Corentin Chary
        unsigned int value, mask;                                       \
492 aa7d73fd Corentin Chary
        int aligned_width;                                              \
493 aa7d73fd Corentin Chary
        int x, y, bg_bits;                                              \
494 aa7d73fd Corentin Chary
                                                                        \
495 aa7d73fd Corentin Chary
        ptr = (uint##bpp##_t *) buf;                                    \
496 aa7d73fd Corentin Chary
        aligned_width = w - w % 8;                                      \
497 aa7d73fd Corentin Chary
                                                                        \
498 aa7d73fd Corentin Chary
        for (y = 0; y < h; y++) {                                       \
499 aa7d73fd Corentin Chary
            for (x = 0; x < aligned_width; x += 8) {                    \
500 aa7d73fd Corentin Chary
                for (bg_bits = 0; bg_bits < 8; bg_bits++) {             \
501 aa7d73fd Corentin Chary
                    if (*ptr++ != bg) {                                 \
502 aa7d73fd Corentin Chary
                        break;                                          \
503 aa7d73fd Corentin Chary
                    }                                                   \
504 aa7d73fd Corentin Chary
                }                                                       \
505 aa7d73fd Corentin Chary
                if (bg_bits == 8) {                                     \
506 aa7d73fd Corentin Chary
                    *buf++ = 0;                                         \
507 aa7d73fd Corentin Chary
                    continue;                                           \
508 aa7d73fd Corentin Chary
                }                                                       \
509 aa7d73fd Corentin Chary
                mask = 0x80 >> bg_bits;                                 \
510 aa7d73fd Corentin Chary
                value = mask;                                           \
511 aa7d73fd Corentin Chary
                for (bg_bits++; bg_bits < 8; bg_bits++) {               \
512 aa7d73fd Corentin Chary
                    mask >>= 1;                                         \
513 aa7d73fd Corentin Chary
                    if (*ptr++ != bg) {                                 \
514 aa7d73fd Corentin Chary
                        value |= mask;                                  \
515 aa7d73fd Corentin Chary
                    }                                                   \
516 aa7d73fd Corentin Chary
                }                                                       \
517 aa7d73fd Corentin Chary
                *buf++ = (uint8_t)value;                                \
518 aa7d73fd Corentin Chary
            }                                                           \
519 aa7d73fd Corentin Chary
                                                                        \
520 aa7d73fd Corentin Chary
            mask = 0x80;                                                \
521 aa7d73fd Corentin Chary
            value = 0;                                                  \
522 aa7d73fd Corentin Chary
            if (x >= w) {                                               \
523 aa7d73fd Corentin Chary
                continue;                                               \
524 aa7d73fd Corentin Chary
            }                                                           \
525 aa7d73fd Corentin Chary
                                                                        \
526 aa7d73fd Corentin Chary
            for (; x < w; x++) {                                        \
527 aa7d73fd Corentin Chary
                if (*ptr++ != bg) {                                     \
528 aa7d73fd Corentin Chary
                    value |= mask;                                      \
529 aa7d73fd Corentin Chary
                }                                                       \
530 aa7d73fd Corentin Chary
                mask >>= 1;                                             \
531 aa7d73fd Corentin Chary
            }                                                           \
532 aa7d73fd Corentin Chary
            *buf++ = (uint8_t)value;                                    \
533 aa7d73fd Corentin Chary
        }                                                               \
534 aa7d73fd Corentin Chary
    }
535 aa7d73fd Corentin Chary
536 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(8)
537 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(16)
538 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(32)
539 aa7d73fd Corentin Chary
540 aa7d73fd Corentin Chary
/*
541 2f6f5c7a Corentin Chary
 * ``Gradient'' filter for 24-bit color samples.
542 2f6f5c7a Corentin Chary
 * Should be called only when redMax, greenMax and blueMax are 255.
543 2f6f5c7a Corentin Chary
 * Color components assumed to be byte-aligned.
544 2f6f5c7a Corentin Chary
 */
545 2f6f5c7a Corentin Chary
546 2f6f5c7a Corentin Chary
static void
547 2f6f5c7a Corentin Chary
tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
548 2f6f5c7a Corentin Chary
{
549 2f6f5c7a Corentin Chary
    uint32_t *buf32;
550 2f6f5c7a Corentin Chary
    uint32_t pix32;
551 2f6f5c7a Corentin Chary
    int shift[3];
552 2f6f5c7a Corentin Chary
    int *prev;
553 2f6f5c7a Corentin Chary
    int here[3], upper[3], left[3], upperleft[3];
554 2f6f5c7a Corentin Chary
    int prediction;
555 2f6f5c7a Corentin Chary
    int x, y, c;
556 2f6f5c7a Corentin Chary
557 2f6f5c7a Corentin Chary
    buf32 = (uint32_t *)buf;
558 d1af0e05 Corentin Chary
    memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
559 2f6f5c7a Corentin Chary
560 2f6f5c7a Corentin Chary
    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
561 2f6f5c7a Corentin Chary
        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
562 2f6f5c7a Corentin Chary
        shift[0] = vs->clientds.pf.rshift;
563 2f6f5c7a Corentin Chary
        shift[1] = vs->clientds.pf.gshift;
564 2f6f5c7a Corentin Chary
        shift[2] = vs->clientds.pf.bshift;
565 2f6f5c7a Corentin Chary
    } else {
566 2f6f5c7a Corentin Chary
        shift[0] = 24 - vs->clientds.pf.rshift;
567 2f6f5c7a Corentin Chary
        shift[1] = 24 - vs->clientds.pf.gshift;
568 2f6f5c7a Corentin Chary
        shift[2] = 24 - vs->clientds.pf.bshift;
569 2f6f5c7a Corentin Chary
    }
570 2f6f5c7a Corentin Chary
571 2f6f5c7a Corentin Chary
    for (y = 0; y < h; y++) {
572 2f6f5c7a Corentin Chary
        for (c = 0; c < 3; c++) {
573 2f6f5c7a Corentin Chary
            upper[c] = 0;
574 2f6f5c7a Corentin Chary
            here[c] = 0;
575 2f6f5c7a Corentin Chary
        }
576 d1af0e05 Corentin Chary
        prev = (int *)vs->tight.gradient.buffer;
577 2f6f5c7a Corentin Chary
        for (x = 0; x < w; x++) {
578 2f6f5c7a Corentin Chary
            pix32 = *buf32++;
579 2f6f5c7a Corentin Chary
            for (c = 0; c < 3; c++) {
580 2f6f5c7a Corentin Chary
                upperleft[c] = upper[c];
581 2f6f5c7a Corentin Chary
                left[c] = here[c];
582 2f6f5c7a Corentin Chary
                upper[c] = *prev;
583 2f6f5c7a Corentin Chary
                here[c] = (int)(pix32 >> shift[c] & 0xFF);
584 2f6f5c7a Corentin Chary
                *prev++ = here[c];
585 2f6f5c7a Corentin Chary
586 2f6f5c7a Corentin Chary
                prediction = left[c] + upper[c] - upperleft[c];
587 2f6f5c7a Corentin Chary
                if (prediction < 0) {
588 2f6f5c7a Corentin Chary
                    prediction = 0;
589 2f6f5c7a Corentin Chary
                } else if (prediction > 0xFF) {
590 2f6f5c7a Corentin Chary
                    prediction = 0xFF;
591 2f6f5c7a Corentin Chary
                }
592 2f6f5c7a Corentin Chary
                *buf++ = (char)(here[c] - prediction);
593 2f6f5c7a Corentin Chary
            }
594 2f6f5c7a Corentin Chary
        }
595 2f6f5c7a Corentin Chary
    }
596 2f6f5c7a Corentin Chary
}
597 2f6f5c7a Corentin Chary
598 2f6f5c7a Corentin Chary
599 2f6f5c7a Corentin Chary
/*
600 2f6f5c7a Corentin Chary
 * ``Gradient'' filter for other color depths.
601 2f6f5c7a Corentin Chary
 */
602 2f6f5c7a Corentin Chary
603 2f6f5c7a Corentin Chary
#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                            \
604 2f6f5c7a Corentin Chary
                                                                        \
605 2f6f5c7a Corentin Chary
    static void                                                         \
606 2f6f5c7a Corentin Chary
    tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf,        \
607 2f6f5c7a Corentin Chary
                               int w, int h) {                          \
608 2f6f5c7a Corentin Chary
        uint##bpp##_t pix, diff;                                        \
609 2f6f5c7a Corentin Chary
        bool endian;                                                    \
610 2f6f5c7a Corentin Chary
        int *prev;                                                      \
611 2f6f5c7a Corentin Chary
        int max[3], shift[3];                                           \
612 2f6f5c7a Corentin Chary
        int here[3], upper[3], left[3], upperleft[3];                   \
613 2f6f5c7a Corentin Chary
        int prediction;                                                 \
614 2f6f5c7a Corentin Chary
        int x, y, c;                                                    \
615 2f6f5c7a Corentin Chary
                                                                        \
616 d1af0e05 Corentin Chary
        memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));     \
617 2f6f5c7a Corentin Chary
                                                                        \
618 2f6f5c7a Corentin Chary
        endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
619 2f6f5c7a Corentin Chary
                  (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
620 2f6f5c7a Corentin Chary
                                                                        \
621 2f6f5c7a Corentin Chary
        max[0] = vs->clientds.pf.rmax;                                  \
622 2f6f5c7a Corentin Chary
        max[1] = vs->clientds.pf.gmax;                                  \
623 2f6f5c7a Corentin Chary
        max[2] = vs->clientds.pf.bmax;                                  \
624 2f6f5c7a Corentin Chary
        shift[0] = vs->clientds.pf.rshift;                              \
625 2f6f5c7a Corentin Chary
        shift[1] = vs->clientds.pf.gshift;                              \
626 2f6f5c7a Corentin Chary
        shift[2] = vs->clientds.pf.bshift;                              \
627 2f6f5c7a Corentin Chary
                                                                        \
628 2f6f5c7a Corentin Chary
        for (y = 0; y < h; y++) {                                       \
629 2f6f5c7a Corentin Chary
            for (c = 0; c < 3; c++) {                                   \
630 2f6f5c7a Corentin Chary
                upper[c] = 0;                                           \
631 2f6f5c7a Corentin Chary
                here[c] = 0;                                            \
632 2f6f5c7a Corentin Chary
            }                                                           \
633 d1af0e05 Corentin Chary
            prev = (int *)vs->tight.gradient.buffer;                    \
634 2f6f5c7a Corentin Chary
            for (x = 0; x < w; x++) {                                   \
635 2f6f5c7a Corentin Chary
                pix = *buf;                                             \
636 2f6f5c7a Corentin Chary
                if (endian) {                                           \
637 ba5e7f82 Izumi Tsutsui
                    pix = bswap##bpp(pix);                              \
638 2f6f5c7a Corentin Chary
                }                                                       \
639 2f6f5c7a Corentin Chary
                diff = 0;                                               \
640 2f6f5c7a Corentin Chary
                for (c = 0; c < 3; c++) {                               \
641 2f6f5c7a Corentin Chary
                    upperleft[c] = upper[c];                            \
642 2f6f5c7a Corentin Chary
                    left[c] = here[c];                                  \
643 2f6f5c7a Corentin Chary
                    upper[c] = *prev;                                   \
644 2f6f5c7a Corentin Chary
                    here[c] = (int)(pix >> shift[c] & max[c]);          \
645 2f6f5c7a Corentin Chary
                    *prev++ = here[c];                                  \
646 2f6f5c7a Corentin Chary
                                                                        \
647 2f6f5c7a Corentin Chary
                    prediction = left[c] + upper[c] - upperleft[c];     \
648 2f6f5c7a Corentin Chary
                    if (prediction < 0) {                               \
649 2f6f5c7a Corentin Chary
                        prediction = 0;                                 \
650 2f6f5c7a Corentin Chary
                    } else if (prediction > max[c]) {                   \
651 2f6f5c7a Corentin Chary
                        prediction = max[c];                            \
652 2f6f5c7a Corentin Chary
                    }                                                   \
653 2f6f5c7a Corentin Chary
                    diff |= ((here[c] - prediction) & max[c])           \
654 2f6f5c7a Corentin Chary
                        << shift[c];                                    \
655 2f6f5c7a Corentin Chary
                }                                                       \
656 2f6f5c7a Corentin Chary
                if (endian) {                                           \
657 ba5e7f82 Izumi Tsutsui
                    diff = bswap##bpp(diff);                            \
658 2f6f5c7a Corentin Chary
                }                                                       \
659 2f6f5c7a Corentin Chary
                *buf++ = diff;                                          \
660 2f6f5c7a Corentin Chary
            }                                                           \
661 2f6f5c7a Corentin Chary
        }                                                               \
662 2f6f5c7a Corentin Chary
    }
663 2f6f5c7a Corentin Chary
664 2f6f5c7a Corentin Chary
DEFINE_GRADIENT_FILTER_FUNCTION(16)
665 2f6f5c7a Corentin Chary
DEFINE_GRADIENT_FILTER_FUNCTION(32)
666 2f6f5c7a Corentin Chary
667 2f6f5c7a Corentin Chary
/*
668 b4bea3f2 Corentin Chary
 * Check if a rectangle is all of the same color. If needSameColor is
669 b4bea3f2 Corentin Chary
 * set to non-zero, then also check that its color equals to the
670 b0cd712c Stefan Weil
 * *colorPtr value. The result is 1 if the test is successful, and in
671 b4bea3f2 Corentin Chary
 * that case new color will be stored in *colorPtr.
672 b4bea3f2 Corentin Chary
 */
673 b4bea3f2 Corentin Chary
674 b4bea3f2 Corentin Chary
#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                \
675 b4bea3f2 Corentin Chary
                                                                        \
676 b4bea3f2 Corentin Chary
    static bool                                                         \
677 b4bea3f2 Corentin Chary
    check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h,     \
678 b4bea3f2 Corentin Chary
                          uint32_t* color, bool samecolor)              \
679 b4bea3f2 Corentin Chary
    {                                                                   \
680 b4bea3f2 Corentin Chary
        VncDisplay *vd = vs->vd;                                        \
681 b4bea3f2 Corentin Chary
        uint##bpp##_t *fbptr;                                           \
682 b4bea3f2 Corentin Chary
        uint##bpp##_t c;                                                \
683 b4bea3f2 Corentin Chary
        int dx, dy;                                                     \
684 b4bea3f2 Corentin Chary
                                                                        \
685 b4bea3f2 Corentin Chary
        fbptr = (uint##bpp##_t *)                                       \
686 b4bea3f2 Corentin Chary
            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
687 b4bea3f2 Corentin Chary
             x * ds_get_bytes_per_pixel(vs->ds));                       \
688 b4bea3f2 Corentin Chary
                                                                        \
689 b4bea3f2 Corentin Chary
        c = *fbptr;                                                     \
690 b4bea3f2 Corentin Chary
        if (samecolor && (uint32_t)c != *color) {                       \
691 b4bea3f2 Corentin Chary
            return false;                                               \
692 b4bea3f2 Corentin Chary
        }                                                               \
693 b4bea3f2 Corentin Chary
                                                                        \
694 b4bea3f2 Corentin Chary
        for (dy = 0; dy < h; dy++) {                                    \
695 b4bea3f2 Corentin Chary
            for (dx = 0; dx < w; dx++) {                                \
696 b4bea3f2 Corentin Chary
                if (c != fbptr[dx]) {                                   \
697 b4bea3f2 Corentin Chary
                    return false;                                       \
698 b4bea3f2 Corentin Chary
                }                                                       \
699 b4bea3f2 Corentin Chary
            }                                                           \
700 b4bea3f2 Corentin Chary
            fbptr = (uint##bpp##_t *)                                   \
701 b4bea3f2 Corentin Chary
                ((uint8_t *)fbptr + ds_get_linesize(vs->ds));           \
702 b4bea3f2 Corentin Chary
        }                                                               \
703 b4bea3f2 Corentin Chary
                                                                        \
704 b4bea3f2 Corentin Chary
        *color = (uint32_t)c;                                           \
705 b4bea3f2 Corentin Chary
        return true;                                                    \
706 b4bea3f2 Corentin Chary
    }
707 b4bea3f2 Corentin Chary
708 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(32)
709 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(16)
710 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(8)
711 b4bea3f2 Corentin Chary
712 b4bea3f2 Corentin Chary
static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
713 b4bea3f2 Corentin Chary
                             uint32_t* color, bool samecolor)
714 b4bea3f2 Corentin Chary
{
715 b4bea3f2 Corentin Chary
    VncDisplay *vd = vs->vd;
716 b4bea3f2 Corentin Chary
717 b4bea3f2 Corentin Chary
    switch(vd->server->pf.bytes_per_pixel) {
718 b4bea3f2 Corentin Chary
    case 4:
719 b4bea3f2 Corentin Chary
        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
720 b4bea3f2 Corentin Chary
    case 2:
721 b4bea3f2 Corentin Chary
        return check_solid_tile16(vs, x, y, w, h, color, samecolor);
722 b4bea3f2 Corentin Chary
    default:
723 b4bea3f2 Corentin Chary
        return check_solid_tile8(vs, x, y, w, h, color, samecolor);
724 b4bea3f2 Corentin Chary
    }
725 b4bea3f2 Corentin Chary
}
726 b4bea3f2 Corentin Chary
727 b4bea3f2 Corentin Chary
static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
728 b4bea3f2 Corentin Chary
                                 uint32_t color, int *w_ptr, int *h_ptr)
729 b4bea3f2 Corentin Chary
{
730 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
731 b4bea3f2 Corentin Chary
    int w_prev;
732 b4bea3f2 Corentin Chary
    int w_best = 0, h_best = 0;
733 b4bea3f2 Corentin Chary
734 b4bea3f2 Corentin Chary
    w_prev = w;
735 b4bea3f2 Corentin Chary
736 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
737 b4bea3f2 Corentin Chary
738 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
739 b4bea3f2 Corentin Chary
        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
740 b4bea3f2 Corentin Chary
741 b4bea3f2 Corentin Chary
        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
742 b4bea3f2 Corentin Chary
            break;
743 b4bea3f2 Corentin Chary
        }
744 b4bea3f2 Corentin Chary
745 b4bea3f2 Corentin Chary
        for (dx = x + dw; dx < x + w_prev;) {
746 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
747 b4bea3f2 Corentin Chary
748 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
749 b4bea3f2 Corentin Chary
                break;
750 b4bea3f2 Corentin Chary
            }
751 b4bea3f2 Corentin Chary
            dx += dw;
752 b4bea3f2 Corentin Chary
        }
753 b4bea3f2 Corentin Chary
754 b4bea3f2 Corentin Chary
        w_prev = dx - x;
755 b4bea3f2 Corentin Chary
        if (w_prev * (dy + dh - y) > w_best * h_best) {
756 b4bea3f2 Corentin Chary
            w_best = w_prev;
757 b4bea3f2 Corentin Chary
            h_best = dy + dh - y;
758 b4bea3f2 Corentin Chary
        }
759 b4bea3f2 Corentin Chary
    }
760 b4bea3f2 Corentin Chary
761 b4bea3f2 Corentin Chary
    *w_ptr = w_best;
762 b4bea3f2 Corentin Chary
    *h_ptr = h_best;
763 b4bea3f2 Corentin Chary
}
764 b4bea3f2 Corentin Chary
765 b4bea3f2 Corentin Chary
static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
766 b4bea3f2 Corentin Chary
                              uint32_t color, int *x_ptr, int *y_ptr,
767 b4bea3f2 Corentin Chary
                              int *w_ptr, int *h_ptr)
768 b4bea3f2 Corentin Chary
{
769 b4bea3f2 Corentin Chary
    int cx, cy;
770 b4bea3f2 Corentin Chary
771 b4bea3f2 Corentin Chary
    /* Try to extend the area upwards. */
772 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr - 1;
773 b4bea3f2 Corentin Chary
          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
774 b4bea3f2 Corentin Chary
          cy-- );
775 b4bea3f2 Corentin Chary
    *h_ptr += *y_ptr - (cy + 1);
776 b4bea3f2 Corentin Chary
    *y_ptr = cy + 1;
777 b4bea3f2 Corentin Chary
778 b4bea3f2 Corentin Chary
    /* ... downwards. */
779 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr + *h_ptr;
780 b4bea3f2 Corentin Chary
          cy < y + h &&
781 b4bea3f2 Corentin Chary
              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
782 b4bea3f2 Corentin Chary
          cy++ );
783 b4bea3f2 Corentin Chary
    *h_ptr += cy - (*y_ptr + *h_ptr);
784 b4bea3f2 Corentin Chary
785 b4bea3f2 Corentin Chary
    /* ... to the left. */
786 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr - 1;
787 b4bea3f2 Corentin Chary
          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
788 b4bea3f2 Corentin Chary
          cx-- );
789 b4bea3f2 Corentin Chary
    *w_ptr += *x_ptr - (cx + 1);
790 b4bea3f2 Corentin Chary
    *x_ptr = cx + 1;
791 b4bea3f2 Corentin Chary
792 b4bea3f2 Corentin Chary
    /* ... to the right. */
793 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr + *w_ptr;
794 b4bea3f2 Corentin Chary
          cx < x + w &&
795 b4bea3f2 Corentin Chary
              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
796 b4bea3f2 Corentin Chary
          cx++ );
797 b4bea3f2 Corentin Chary
    *w_ptr += cx - (*x_ptr + *w_ptr);
798 b4bea3f2 Corentin Chary
}
799 b4bea3f2 Corentin Chary
800 380282b0 Corentin Chary
static int tight_init_stream(VncState *vs, int stream_id,
801 380282b0 Corentin Chary
                             int level, int strategy)
802 380282b0 Corentin Chary
{
803 d1af0e05 Corentin Chary
    z_streamp zstream = &vs->tight.stream[stream_id];
804 380282b0 Corentin Chary
805 380282b0 Corentin Chary
    if (zstream->opaque == NULL) {
806 380282b0 Corentin Chary
        int err;
807 380282b0 Corentin Chary
808 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
809 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
810 380282b0 Corentin Chary
        zstream->zalloc = vnc_zlib_zalloc;
811 380282b0 Corentin Chary
        zstream->zfree = vnc_zlib_zfree;
812 380282b0 Corentin Chary
813 380282b0 Corentin Chary
        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
814 380282b0 Corentin Chary
                           MAX_MEM_LEVEL, strategy);
815 380282b0 Corentin Chary
816 380282b0 Corentin Chary
        if (err != Z_OK) {
817 380282b0 Corentin Chary
            fprintf(stderr, "VNC: error initializing zlib\n");
818 380282b0 Corentin Chary
            return -1;
819 380282b0 Corentin Chary
        }
820 380282b0 Corentin Chary
821 d1af0e05 Corentin Chary
        vs->tight.levels[stream_id] = level;
822 380282b0 Corentin Chary
        zstream->opaque = vs;
823 380282b0 Corentin Chary
    }
824 380282b0 Corentin Chary
825 d1af0e05 Corentin Chary
    if (vs->tight.levels[stream_id] != level) {
826 380282b0 Corentin Chary
        if (deflateParams(zstream, level, strategy) != Z_OK) {
827 380282b0 Corentin Chary
            return -1;
828 380282b0 Corentin Chary
        }
829 d1af0e05 Corentin Chary
        vs->tight.levels[stream_id] = level;
830 380282b0 Corentin Chary
    }
831 380282b0 Corentin Chary
    return 0;
832 380282b0 Corentin Chary
}
833 380282b0 Corentin Chary
834 380282b0 Corentin Chary
static void tight_send_compact_size(VncState *vs, size_t len)
835 380282b0 Corentin Chary
{
836 380282b0 Corentin Chary
    int lpc = 0;
837 380282b0 Corentin Chary
    int bytes = 0;
838 380282b0 Corentin Chary
    char buf[3] = {0, 0, 0};
839 380282b0 Corentin Chary
840 380282b0 Corentin Chary
    buf[bytes++] = len & 0x7F;
841 380282b0 Corentin Chary
    if (len > 0x7F) {
842 380282b0 Corentin Chary
        buf[bytes-1] |= 0x80;
843 380282b0 Corentin Chary
        buf[bytes++] = (len >> 7) & 0x7F;
844 380282b0 Corentin Chary
        if (len > 0x3FFF) {
845 380282b0 Corentin Chary
            buf[bytes-1] |= 0x80;
846 380282b0 Corentin Chary
            buf[bytes++] = (len >> 14) & 0xFF;
847 380282b0 Corentin Chary
        }
848 380282b0 Corentin Chary
    }
849 b4bea3f2 Corentin Chary
    for (lpc = 0; lpc < bytes; lpc++) {
850 380282b0 Corentin Chary
        vnc_write_u8(vs, buf[lpc]);
851 380282b0 Corentin Chary
    }
852 380282b0 Corentin Chary
}
853 380282b0 Corentin Chary
854 380282b0 Corentin Chary
static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
855 380282b0 Corentin Chary
                               int level, int strategy)
856 380282b0 Corentin Chary
{
857 d1af0e05 Corentin Chary
    z_streamp zstream = &vs->tight.stream[stream_id];
858 380282b0 Corentin Chary
    int previous_out;
859 380282b0 Corentin Chary
860 380282b0 Corentin Chary
    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
861 d1af0e05 Corentin Chary
        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
862 380282b0 Corentin Chary
        return bytes;
863 380282b0 Corentin Chary
    }
864 380282b0 Corentin Chary
865 380282b0 Corentin Chary
    if (tight_init_stream(vs, stream_id, level, strategy)) {
866 380282b0 Corentin Chary
        return -1;
867 380282b0 Corentin Chary
    }
868 380282b0 Corentin Chary
869 380282b0 Corentin Chary
    /* reserve memory in output buffer */
870 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.zlib, bytes + 64);
871 380282b0 Corentin Chary
872 380282b0 Corentin Chary
    /* set pointers */
873 d1af0e05 Corentin Chary
    zstream->next_in = vs->tight.tight.buffer;
874 d1af0e05 Corentin Chary
    zstream->avail_in = vs->tight.tight.offset;
875 d1af0e05 Corentin Chary
    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
876 d1af0e05 Corentin Chary
    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
877 2caa9e9d Michael Tokarev
    previous_out = zstream->avail_out;
878 380282b0 Corentin Chary
    zstream->data_type = Z_BINARY;
879 380282b0 Corentin Chary
880 380282b0 Corentin Chary
    /* start encoding */
881 380282b0 Corentin Chary
    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
882 380282b0 Corentin Chary
        fprintf(stderr, "VNC: error during tight compression\n");
883 380282b0 Corentin Chary
        return -1;
884 380282b0 Corentin Chary
    }
885 380282b0 Corentin Chary
886 d1af0e05 Corentin Chary
    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
887 2caa9e9d Michael Tokarev
    /* ...how much data has actually been produced by deflate() */
888 2caa9e9d Michael Tokarev
    bytes = previous_out - zstream->avail_out;
889 380282b0 Corentin Chary
890 380282b0 Corentin Chary
    tight_send_compact_size(vs, bytes);
891 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.zlib.buffer, bytes);
892 380282b0 Corentin Chary
893 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.zlib);
894 380282b0 Corentin Chary
895 380282b0 Corentin Chary
    return bytes;
896 380282b0 Corentin Chary
}
897 380282b0 Corentin Chary
898 380282b0 Corentin Chary
/*
899 380282b0 Corentin Chary
 * Subencoding implementations.
900 380282b0 Corentin Chary
 */
901 aa7d73fd Corentin Chary
static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
902 380282b0 Corentin Chary
{
903 380282b0 Corentin Chary
    uint32_t *buf32;
904 380282b0 Corentin Chary
    uint32_t pix;
905 380282b0 Corentin Chary
    int rshift, gshift, bshift;
906 380282b0 Corentin Chary
907 380282b0 Corentin Chary
    buf32 = (uint32_t *)buf;
908 380282b0 Corentin Chary
909 380282b0 Corentin Chary
    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
910 380282b0 Corentin Chary
        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
911 380282b0 Corentin Chary
        rshift = vs->clientds.pf.rshift;
912 380282b0 Corentin Chary
        gshift = vs->clientds.pf.gshift;
913 380282b0 Corentin Chary
        bshift = vs->clientds.pf.bshift;
914 380282b0 Corentin Chary
    } else {
915 380282b0 Corentin Chary
        rshift = 24 - vs->clientds.pf.rshift;
916 380282b0 Corentin Chary
        gshift = 24 - vs->clientds.pf.gshift;
917 380282b0 Corentin Chary
        bshift = 24 - vs->clientds.pf.bshift;
918 380282b0 Corentin Chary
    }
919 380282b0 Corentin Chary
920 aa7d73fd Corentin Chary
    if (ret) {
921 aa7d73fd Corentin Chary
        *ret = count * 3;
922 aa7d73fd Corentin Chary
    }
923 380282b0 Corentin Chary
924 380282b0 Corentin Chary
    while (count--) {
925 380282b0 Corentin Chary
        pix = *buf32++;
926 380282b0 Corentin Chary
        *buf++ = (char)(pix >> rshift);
927 380282b0 Corentin Chary
        *buf++ = (char)(pix >> gshift);
928 380282b0 Corentin Chary
        *buf++ = (char)(pix >> bshift);
929 380282b0 Corentin Chary
    }
930 380282b0 Corentin Chary
}
931 380282b0 Corentin Chary
932 efe556ad Corentin Chary
static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
933 380282b0 Corentin Chary
{
934 380282b0 Corentin Chary
    int stream = 0;
935 2116eff9 Jes Sorensen
    ssize_t bytes;
936 380282b0 Corentin Chary
937 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
938 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
939 efe556ad Corentin Chary
        return send_png_rect(vs, x, y, w, h, NULL);
940 efe556ad Corentin Chary
    }
941 efe556ad Corentin Chary
#endif
942 efe556ad Corentin Chary
943 380282b0 Corentin Chary
    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
944 380282b0 Corentin Chary
945 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
946 d1af0e05 Corentin Chary
        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
947 380282b0 Corentin Chary
        bytes = 3;
948 380282b0 Corentin Chary
    } else {
949 380282b0 Corentin Chary
        bytes = vs->clientds.pf.bytes_per_pixel;
950 380282b0 Corentin Chary
    }
951 380282b0 Corentin Chary
952 380282b0 Corentin Chary
    bytes = tight_compress_data(vs, stream, w * h * bytes,
953 d1af0e05 Corentin Chary
                                tight_conf[vs->tight.compression].raw_zlib_level,
954 380282b0 Corentin Chary
                                Z_DEFAULT_STRATEGY);
955 380282b0 Corentin Chary
956 380282b0 Corentin Chary
    return (bytes >= 0);
957 380282b0 Corentin Chary
}
958 380282b0 Corentin Chary
959 b4bea3f2 Corentin Chary
static int send_solid_rect(VncState *vs)
960 b4bea3f2 Corentin Chary
{
961 b4bea3f2 Corentin Chary
    size_t bytes;
962 b4bea3f2 Corentin Chary
963 b4bea3f2 Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
964 b4bea3f2 Corentin Chary
965 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
966 d1af0e05 Corentin Chary
        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
967 b4bea3f2 Corentin Chary
        bytes = 3;
968 b4bea3f2 Corentin Chary
    } else {
969 b4bea3f2 Corentin Chary
        bytes = vs->clientds.pf.bytes_per_pixel;
970 b4bea3f2 Corentin Chary
    }
971 b4bea3f2 Corentin Chary
972 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.tight.buffer, bytes);
973 b4bea3f2 Corentin Chary
    return 1;
974 b4bea3f2 Corentin Chary
}
975 b4bea3f2 Corentin Chary
976 efe556ad Corentin Chary
static int send_mono_rect(VncState *vs, int x, int y,
977 efe556ad Corentin Chary
                          int w, int h, uint32_t bg, uint32_t fg)
978 aa7d73fd Corentin Chary
{
979 2116eff9 Jes Sorensen
    ssize_t bytes;
980 aa7d73fd Corentin Chary
    int stream = 1;
981 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].mono_zlib_level;
982 aa7d73fd Corentin Chary
983 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
984 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
985 efe556ad Corentin Chary
        int ret;
986 efe556ad Corentin Chary
        int bpp = vs->clientds.pf.bytes_per_pixel * 8;
987 5136a052 Corentin Chary
        VncPalette *palette = palette_new(2, bpp);
988 efe556ad Corentin Chary
989 5136a052 Corentin Chary
        palette_put(palette, bg);
990 5136a052 Corentin Chary
        palette_put(palette, fg);
991 efe556ad Corentin Chary
        ret = send_png_rect(vs, x, y, w, h, palette);
992 5136a052 Corentin Chary
        palette_destroy(palette);
993 efe556ad Corentin Chary
        return ret;
994 efe556ad Corentin Chary
    }
995 efe556ad Corentin Chary
#endif
996 efe556ad Corentin Chary
997 aa7d73fd Corentin Chary
    bytes = ((w + 7) / 8) * h;
998 aa7d73fd Corentin Chary
999 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1000 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
1001 aa7d73fd Corentin Chary
    vnc_write_u8(vs, 1);
1002 aa7d73fd Corentin Chary
1003 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
1004 aa7d73fd Corentin Chary
    case 4:
1005 aa7d73fd Corentin Chary
    {
1006 aa7d73fd Corentin Chary
        uint32_t buf[2] = {bg, fg};
1007 aa7d73fd Corentin Chary
        size_t ret = sizeof (buf);
1008 aa7d73fd Corentin Chary
1009 d1af0e05 Corentin Chary
        if (vs->tight.pixel24) {
1010 aa7d73fd Corentin Chary
            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
1011 aa7d73fd Corentin Chary
        }
1012 aa7d73fd Corentin Chary
        vnc_write(vs, buf, ret);
1013 aa7d73fd Corentin Chary
1014 d1af0e05 Corentin Chary
        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
1015 aa7d73fd Corentin Chary
        break;
1016 aa7d73fd Corentin Chary
    }
1017 aa7d73fd Corentin Chary
    case 2:
1018 aa7d73fd Corentin Chary
        vnc_write(vs, &bg, 2);
1019 aa7d73fd Corentin Chary
        vnc_write(vs, &fg, 2);
1020 d1af0e05 Corentin Chary
        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
1021 aa7d73fd Corentin Chary
        break;
1022 aa7d73fd Corentin Chary
    default:
1023 aa7d73fd Corentin Chary
        vnc_write_u8(vs, bg);
1024 aa7d73fd Corentin Chary
        vnc_write_u8(vs, fg);
1025 d1af0e05 Corentin Chary
        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
1026 aa7d73fd Corentin Chary
        break;
1027 aa7d73fd Corentin Chary
    }
1028 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1029 aa7d73fd Corentin Chary
1030 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
1031 aa7d73fd Corentin Chary
    return (bytes >= 0);
1032 aa7d73fd Corentin Chary
}
1033 aa7d73fd Corentin Chary
1034 aa7d73fd Corentin Chary
struct palette_cb_priv {
1035 aa7d73fd Corentin Chary
    VncState *vs;
1036 aa7d73fd Corentin Chary
    uint8_t *header;
1037 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1038 efe556ad Corentin Chary
    png_colorp png_palette;
1039 efe556ad Corentin Chary
#endif
1040 aa7d73fd Corentin Chary
};
1041 aa7d73fd Corentin Chary
1042 5136a052 Corentin Chary
static void write_palette(int idx, uint32_t color, void *opaque)
1043 aa7d73fd Corentin Chary
{
1044 aa7d73fd Corentin Chary
    struct palette_cb_priv *priv = opaque;
1045 aa7d73fd Corentin Chary
    VncState *vs = priv->vs;
1046 aa7d73fd Corentin Chary
    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
1047 aa7d73fd Corentin Chary
1048 aa7d73fd Corentin Chary
    if (bytes == 4) {
1049 aa7d73fd Corentin Chary
        ((uint32_t*)priv->header)[idx] = color;
1050 aa7d73fd Corentin Chary
    } else {
1051 aa7d73fd Corentin Chary
        ((uint16_t*)priv->header)[idx] = color;
1052 aa7d73fd Corentin Chary
    }
1053 aa7d73fd Corentin Chary
}
1054 aa7d73fd Corentin Chary
1055 efe556ad Corentin Chary
static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
1056 2f6f5c7a Corentin Chary
{
1057 2f6f5c7a Corentin Chary
    int stream = 3;
1058 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
1059 2116eff9 Jes Sorensen
    ssize_t bytes;
1060 2f6f5c7a Corentin Chary
1061 2f6f5c7a Corentin Chary
    if (vs->clientds.pf.bytes_per_pixel == 1)
1062 efe556ad Corentin Chary
        return send_full_color_rect(vs, x, y, w, h);
1063 2f6f5c7a Corentin Chary
1064 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1065 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
1066 2f6f5c7a Corentin Chary
1067 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
1068 2f6f5c7a Corentin Chary
1069 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
1070 d1af0e05 Corentin Chary
        tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
1071 2f6f5c7a Corentin Chary
        bytes = 3;
1072 2f6f5c7a Corentin Chary
    } else if (vs->clientds.pf.bytes_per_pixel == 4) {
1073 d1af0e05 Corentin Chary
        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
1074 2f6f5c7a Corentin Chary
        bytes = 4;
1075 2f6f5c7a Corentin Chary
    } else {
1076 d1af0e05 Corentin Chary
        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
1077 2f6f5c7a Corentin Chary
        bytes = 2;
1078 2f6f5c7a Corentin Chary
    }
1079 2f6f5c7a Corentin Chary
1080 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.gradient);
1081 2f6f5c7a Corentin Chary
1082 2f6f5c7a Corentin Chary
    bytes = w * h * bytes;
1083 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1084 2f6f5c7a Corentin Chary
1085 2f6f5c7a Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes,
1086 2f6f5c7a Corentin Chary
                                level, Z_FILTERED);
1087 2f6f5c7a Corentin Chary
    return (bytes >= 0);
1088 2f6f5c7a Corentin Chary
}
1089 2f6f5c7a Corentin Chary
1090 efe556ad Corentin Chary
static int send_palette_rect(VncState *vs, int x, int y,
1091 5136a052 Corentin Chary
                             int w, int h, VncPalette *palette)
1092 aa7d73fd Corentin Chary
{
1093 aa7d73fd Corentin Chary
    int stream = 2;
1094 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].idx_zlib_level;
1095 aa7d73fd Corentin Chary
    int colors;
1096 2116eff9 Jes Sorensen
    ssize_t bytes;
1097 aa7d73fd Corentin Chary
1098 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1099 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
1100 efe556ad Corentin Chary
        return send_png_rect(vs, x, y, w, h, palette);
1101 efe556ad Corentin Chary
    }
1102 efe556ad Corentin Chary
#endif
1103 efe556ad Corentin Chary
1104 5136a052 Corentin Chary
    colors = palette_size(palette);
1105 aa7d73fd Corentin Chary
1106 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1107 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
1108 aa7d73fd Corentin Chary
    vnc_write_u8(vs, colors - 1);
1109 aa7d73fd Corentin Chary
1110 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
1111 aa7d73fd Corentin Chary
    case 4:
1112 aa7d73fd Corentin Chary
    {
1113 aa7d73fd Corentin Chary
        size_t old_offset, offset;
1114 5136a052 Corentin Chary
        uint32_t header[palette_size(palette)];
1115 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1116 aa7d73fd Corentin Chary
1117 aa7d73fd Corentin Chary
        old_offset = vs->output.offset;
1118 5136a052 Corentin Chary
        palette_iter(palette, write_palette, &priv);
1119 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
1120 aa7d73fd Corentin Chary
1121 d1af0e05 Corentin Chary
        if (vs->tight.pixel24) {
1122 aa7d73fd Corentin Chary
            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
1123 aa7d73fd Corentin Chary
            vs->output.offset = old_offset + offset;
1124 aa7d73fd Corentin Chary
        }
1125 aa7d73fd Corentin Chary
1126 d1af0e05 Corentin Chary
        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
1127 aa7d73fd Corentin Chary
        break;
1128 aa7d73fd Corentin Chary
    }
1129 aa7d73fd Corentin Chary
    case 2:
1130 aa7d73fd Corentin Chary
    {
1131 5136a052 Corentin Chary
        uint16_t header[palette_size(palette)];
1132 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1133 aa7d73fd Corentin Chary
1134 5136a052 Corentin Chary
        palette_iter(palette, write_palette, &priv);
1135 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
1136 d1af0e05 Corentin Chary
        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
1137 aa7d73fd Corentin Chary
        break;
1138 aa7d73fd Corentin Chary
    }
1139 aa7d73fd Corentin Chary
    default:
1140 aa7d73fd Corentin Chary
        return -1; /* No palette for 8bits colors */
1141 aa7d73fd Corentin Chary
        break;
1142 aa7d73fd Corentin Chary
    }
1143 aa7d73fd Corentin Chary
    bytes = w * h;
1144 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1145 aa7d73fd Corentin Chary
1146 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes,
1147 aa7d73fd Corentin Chary
                                level, Z_DEFAULT_STRATEGY);
1148 aa7d73fd Corentin Chary
    return (bytes >= 0);
1149 aa7d73fd Corentin Chary
}
1150 aa7d73fd Corentin Chary
1151 efe556ad Corentin Chary
#if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG)
1152 efe556ad Corentin Chary
static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
1153 efe556ad Corentin Chary
                              int count)
1154 2f6f5c7a Corentin Chary
{
1155 2f6f5c7a Corentin Chary
    VncDisplay *vd = vs->vd;
1156 2f6f5c7a Corentin Chary
    uint32_t *fbptr;
1157 2f6f5c7a Corentin Chary
    uint32_t pix;
1158 2f6f5c7a Corentin Chary
1159 2f6f5c7a Corentin Chary
    fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) +
1160 2f6f5c7a Corentin Chary
                         x * ds_get_bytes_per_pixel(vs->ds));
1161 2f6f5c7a Corentin Chary
1162 2f6f5c7a Corentin Chary
    while (count--) {
1163 2f6f5c7a Corentin Chary
        pix = *fbptr++;
1164 2f6f5c7a Corentin Chary
        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift);
1165 2f6f5c7a Corentin Chary
        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift);
1166 2f6f5c7a Corentin Chary
        *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift);
1167 2f6f5c7a Corentin Chary
    }
1168 2f6f5c7a Corentin Chary
}
1169 2f6f5c7a Corentin Chary
1170 efe556ad Corentin Chary
#define DEFINE_RGB_GET_ROW_FUNCTION(bpp)                                \
1171 2f6f5c7a Corentin Chary
                                                                        \
1172 2f6f5c7a Corentin Chary
    static void                                                         \
1173 efe556ad Corentin Chary
    rgb_prepare_row##bpp(VncState *vs, uint8_t *dst,                    \
1174 efe556ad Corentin Chary
                         int x, int y, int count)                       \
1175 2f6f5c7a Corentin Chary
    {                                                                   \
1176 2f6f5c7a Corentin Chary
        VncDisplay *vd = vs->vd;                                        \
1177 2f6f5c7a Corentin Chary
        uint##bpp##_t *fbptr;                                           \
1178 2f6f5c7a Corentin Chary
        uint##bpp##_t pix;                                              \
1179 2f6f5c7a Corentin Chary
        int r, g, b;                                                    \
1180 2f6f5c7a Corentin Chary
                                                                        \
1181 2f6f5c7a Corentin Chary
        fbptr = (uint##bpp##_t *)                                       \
1182 2f6f5c7a Corentin Chary
            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
1183 2f6f5c7a Corentin Chary
             x * ds_get_bytes_per_pixel(vs->ds));                       \
1184 2f6f5c7a Corentin Chary
                                                                        \
1185 2f6f5c7a Corentin Chary
        while (count--) {                                               \
1186 2f6f5c7a Corentin Chary
            pix = *fbptr++;                                             \
1187 2f6f5c7a Corentin Chary
                                                                        \
1188 2f6f5c7a Corentin Chary
            r = (int)((pix >> vs->ds->surface->pf.rshift)               \
1189 2f6f5c7a Corentin Chary
                      & vs->ds->surface->pf.rmax);                      \
1190 2f6f5c7a Corentin Chary
            g = (int)((pix >> vs->ds->surface->pf.gshift)               \
1191 2f6f5c7a Corentin Chary
                      & vs->ds->surface->pf.gmax);                      \
1192 2f6f5c7a Corentin Chary
            b = (int)((pix >> vs->ds->surface->pf.bshift)               \
1193 2f6f5c7a Corentin Chary
                      & vs->ds->surface->pf.bmax);                      \
1194 2f6f5c7a Corentin Chary
                                                                        \
1195 2f6f5c7a Corentin Chary
            *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \
1196 2f6f5c7a Corentin Chary
                               / vs->ds->surface->pf.rmax);             \
1197 2f6f5c7a Corentin Chary
            *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \
1198 2f6f5c7a Corentin Chary
                               / vs->ds->surface->pf.gmax);             \
1199 2f6f5c7a Corentin Chary
            *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \
1200 2f6f5c7a Corentin Chary
                               / vs->ds->surface->pf.bmax);             \
1201 2f6f5c7a Corentin Chary
        }                                                               \
1202 2f6f5c7a Corentin Chary
    }
1203 2f6f5c7a Corentin Chary
1204 efe556ad Corentin Chary
DEFINE_RGB_GET_ROW_FUNCTION(16)
1205 efe556ad Corentin Chary
DEFINE_RGB_GET_ROW_FUNCTION(32)
1206 2f6f5c7a Corentin Chary
1207 efe556ad Corentin Chary
static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
1208 efe556ad Corentin Chary
                            int count)
1209 2f6f5c7a Corentin Chary
{
1210 4043a013 Corentin Chary
    if (ds_get_bytes_per_pixel(vs->ds) == 4) {
1211 4043a013 Corentin Chary
        if (vs->ds->surface->pf.rmax == 0xFF &&
1212 4043a013 Corentin Chary
            vs->ds->surface->pf.gmax == 0xFF &&
1213 4043a013 Corentin Chary
            vs->ds->surface->pf.bmax == 0xFF) {
1214 4043a013 Corentin Chary
            rgb_prepare_row24(vs, dst, x, y, count);
1215 4043a013 Corentin Chary
        } else {
1216 4043a013 Corentin Chary
            rgb_prepare_row32(vs, dst, x, y, count);
1217 4043a013 Corentin Chary
        }
1218 4043a013 Corentin Chary
    } else {
1219 efe556ad Corentin Chary
        rgb_prepare_row16(vs, dst, x, y, count);
1220 4043a013 Corentin Chary
    }
1221 2f6f5c7a Corentin Chary
}
1222 efe556ad Corentin Chary
#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */
1223 2f6f5c7a Corentin Chary
1224 2f6f5c7a Corentin Chary
/*
1225 efe556ad Corentin Chary
 * JPEG compression stuff.
1226 efe556ad Corentin Chary
 */
1227 efe556ad Corentin Chary
#ifdef CONFIG_VNC_JPEG
1228 efe556ad Corentin Chary
/*
1229 2f6f5c7a Corentin Chary
 * Destination manager implementation for JPEG library.
1230 2f6f5c7a Corentin Chary
 */
1231 2f6f5c7a Corentin Chary
1232 2f6f5c7a Corentin Chary
/* This is called once per encoding */
1233 2f6f5c7a Corentin Chary
static void jpeg_init_destination(j_compress_ptr cinfo)
1234 2f6f5c7a Corentin Chary
{
1235 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1236 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1237 2f6f5c7a Corentin Chary
1238 2f6f5c7a Corentin Chary
    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
1239 2f6f5c7a Corentin Chary
    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
1240 2f6f5c7a Corentin Chary
}
1241 2f6f5c7a Corentin Chary
1242 2f6f5c7a Corentin Chary
/* This is called when we ran out of buffer (shouldn't happen!) */
1243 2f6f5c7a Corentin Chary
static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
1244 2f6f5c7a Corentin Chary
{
1245 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1246 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1247 2f6f5c7a Corentin Chary
1248 2f6f5c7a Corentin Chary
    buffer->offset = buffer->capacity;
1249 2f6f5c7a Corentin Chary
    buffer_reserve(buffer, 2048);
1250 2f6f5c7a Corentin Chary
    jpeg_init_destination(cinfo);
1251 2f6f5c7a Corentin Chary
    return TRUE;
1252 2f6f5c7a Corentin Chary
}
1253 2f6f5c7a Corentin Chary
1254 2f6f5c7a Corentin Chary
/* This is called when we are done processing data */
1255 2f6f5c7a Corentin Chary
static void jpeg_term_destination(j_compress_ptr cinfo)
1256 2f6f5c7a Corentin Chary
{
1257 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1258 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1259 2f6f5c7a Corentin Chary
1260 2f6f5c7a Corentin Chary
    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
1261 2f6f5c7a Corentin Chary
}
1262 2f6f5c7a Corentin Chary
1263 2f6f5c7a Corentin Chary
static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
1264 2f6f5c7a Corentin Chary
{
1265 2f6f5c7a Corentin Chary
    struct jpeg_compress_struct cinfo;
1266 2f6f5c7a Corentin Chary
    struct jpeg_error_mgr jerr;
1267 2f6f5c7a Corentin Chary
    struct jpeg_destination_mgr manager;
1268 2f6f5c7a Corentin Chary
    JSAMPROW row[1];
1269 2f6f5c7a Corentin Chary
    uint8_t *buf;
1270 2f6f5c7a Corentin Chary
    int dy;
1271 2f6f5c7a Corentin Chary
1272 2f6f5c7a Corentin Chary
    if (ds_get_bytes_per_pixel(vs->ds) == 1)
1273 efe556ad Corentin Chary
        return send_full_color_rect(vs, x, y, w, h);
1274 2f6f5c7a Corentin Chary
1275 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.jpeg, 2048);
1276 2f6f5c7a Corentin Chary
1277 2f6f5c7a Corentin Chary
    cinfo.err = jpeg_std_error(&jerr);
1278 2f6f5c7a Corentin Chary
    jpeg_create_compress(&cinfo);
1279 2f6f5c7a Corentin Chary
1280 2f6f5c7a Corentin Chary
    cinfo.client_data = vs;
1281 2f6f5c7a Corentin Chary
    cinfo.image_width = w;
1282 2f6f5c7a Corentin Chary
    cinfo.image_height = h;
1283 2f6f5c7a Corentin Chary
    cinfo.input_components = 3;
1284 2f6f5c7a Corentin Chary
    cinfo.in_color_space = JCS_RGB;
1285 2f6f5c7a Corentin Chary
1286 2f6f5c7a Corentin Chary
    jpeg_set_defaults(&cinfo);
1287 2f6f5c7a Corentin Chary
    jpeg_set_quality(&cinfo, quality, true);
1288 2f6f5c7a Corentin Chary
1289 2f6f5c7a Corentin Chary
    manager.init_destination = jpeg_init_destination;
1290 2f6f5c7a Corentin Chary
    manager.empty_output_buffer = jpeg_empty_output_buffer;
1291 2f6f5c7a Corentin Chary
    manager.term_destination = jpeg_term_destination;
1292 2f6f5c7a Corentin Chary
    cinfo.dest = &manager;
1293 2f6f5c7a Corentin Chary
1294 2f6f5c7a Corentin Chary
    jpeg_start_compress(&cinfo, true);
1295 2f6f5c7a Corentin Chary
1296 d9c18c24 Corentin Chary
    buf = qemu_malloc(w * 3);
1297 d9c18c24 Corentin Chary
    row[0] = buf;
1298 2f6f5c7a Corentin Chary
    for (dy = 0; dy < h; dy++) {
1299 efe556ad Corentin Chary
        rgb_prepare_row(vs, buf, x, y + dy, w);
1300 2f6f5c7a Corentin Chary
        jpeg_write_scanlines(&cinfo, row, 1);
1301 2f6f5c7a Corentin Chary
    }
1302 d9c18c24 Corentin Chary
    qemu_free(buf);
1303 2f6f5c7a Corentin Chary
1304 2f6f5c7a Corentin Chary
    jpeg_finish_compress(&cinfo);
1305 2f6f5c7a Corentin Chary
    jpeg_destroy_compress(&cinfo);
1306 2f6f5c7a Corentin Chary
1307 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
1308 2f6f5c7a Corentin Chary
1309 d1af0e05 Corentin Chary
    tight_send_compact_size(vs, vs->tight.jpeg.offset);
1310 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
1311 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.jpeg);
1312 2f6f5c7a Corentin Chary
1313 2f6f5c7a Corentin Chary
    return 1;
1314 2f6f5c7a Corentin Chary
}
1315 2f6f5c7a Corentin Chary
#endif /* CONFIG_VNC_JPEG */
1316 2f6f5c7a Corentin Chary
1317 efe556ad Corentin Chary
/*
1318 efe556ad Corentin Chary
 * PNG compression stuff.
1319 efe556ad Corentin Chary
 */
1320 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1321 5136a052 Corentin Chary
static void write_png_palette(int idx, uint32_t pix, void *opaque)
1322 efe556ad Corentin Chary
{
1323 efe556ad Corentin Chary
    struct palette_cb_priv *priv = opaque;
1324 efe556ad Corentin Chary
    VncState *vs = priv->vs;
1325 efe556ad Corentin Chary
    png_colorp color = &priv->png_palette[idx];
1326 efe556ad Corentin Chary
1327 d1af0e05 Corentin Chary
    if (vs->tight.pixel24)
1328 efe556ad Corentin Chary
    {
1329 efe556ad Corentin Chary
        color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
1330 efe556ad Corentin Chary
        color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
1331 efe556ad Corentin Chary
        color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
1332 efe556ad Corentin Chary
    }
1333 efe556ad Corentin Chary
    else
1334 efe556ad Corentin Chary
    {
1335 efe556ad Corentin Chary
        int red, green, blue;
1336 efe556ad Corentin Chary
1337 efe556ad Corentin Chary
        red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
1338 efe556ad Corentin Chary
        green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
1339 efe556ad Corentin Chary
        blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
1340 efe556ad Corentin Chary
        color->red = ((red * 255 + vs->clientds.pf.rmax / 2) /
1341 efe556ad Corentin Chary
                      vs->clientds.pf.rmax);
1342 efe556ad Corentin Chary
        color->green = ((green * 255 + vs->clientds.pf.gmax / 2) /
1343 efe556ad Corentin Chary
                        vs->clientds.pf.gmax);
1344 efe556ad Corentin Chary
        color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) /
1345 efe556ad Corentin Chary
                       vs->clientds.pf.bmax);
1346 efe556ad Corentin Chary
    }
1347 efe556ad Corentin Chary
}
1348 efe556ad Corentin Chary
1349 efe556ad Corentin Chary
static void png_write_data(png_structp png_ptr, png_bytep data,
1350 efe556ad Corentin Chary
                           png_size_t length)
1351 efe556ad Corentin Chary
{
1352 efe556ad Corentin Chary
    VncState *vs = png_get_io_ptr(png_ptr);
1353 efe556ad Corentin Chary
1354 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
1355 d1af0e05 Corentin Chary
    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
1356 efe556ad Corentin Chary
1357 d1af0e05 Corentin Chary
    vs->tight.png.offset += length;
1358 efe556ad Corentin Chary
}
1359 efe556ad Corentin Chary
1360 efe556ad Corentin Chary
static void png_flush_data(png_structp png_ptr)
1361 efe556ad Corentin Chary
{
1362 efe556ad Corentin Chary
}
1363 efe556ad Corentin Chary
1364 efe556ad Corentin Chary
static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
1365 efe556ad Corentin Chary
{
1366 efe556ad Corentin Chary
    return qemu_malloc(size);
1367 efe556ad Corentin Chary
}
1368 efe556ad Corentin Chary
1369 efe556ad Corentin Chary
static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
1370 efe556ad Corentin Chary
{
1371 efe556ad Corentin Chary
    qemu_free(ptr);
1372 efe556ad Corentin Chary
}
1373 efe556ad Corentin Chary
1374 efe556ad Corentin Chary
static int send_png_rect(VncState *vs, int x, int y, int w, int h,
1375 5136a052 Corentin Chary
                         VncPalette *palette)
1376 efe556ad Corentin Chary
{
1377 efe556ad Corentin Chary
    png_byte color_type;
1378 efe556ad Corentin Chary
    png_structp png_ptr;
1379 efe556ad Corentin Chary
    png_infop info_ptr;
1380 efe556ad Corentin Chary
    png_colorp png_palette = NULL;
1381 d1af0e05 Corentin Chary
    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
1382 d1af0e05 Corentin Chary
    int filters = tight_png_conf[vs->tight.compression].png_filters;
1383 efe556ad Corentin Chary
    uint8_t *buf;
1384 efe556ad Corentin Chary
    int dy;
1385 efe556ad Corentin Chary
1386 efe556ad Corentin Chary
    png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
1387 efe556ad Corentin Chary
                                        NULL, vnc_png_malloc, vnc_png_free);
1388 efe556ad Corentin Chary
1389 efe556ad Corentin Chary
    if (png_ptr == NULL)
1390 efe556ad Corentin Chary
        return -1;
1391 efe556ad Corentin Chary
1392 efe556ad Corentin Chary
    info_ptr = png_create_info_struct(png_ptr);
1393 efe556ad Corentin Chary
1394 efe556ad Corentin Chary
    if (info_ptr == NULL) {
1395 efe556ad Corentin Chary
        png_destroy_write_struct(&png_ptr, NULL);
1396 efe556ad Corentin Chary
        return -1;
1397 efe556ad Corentin Chary
    }
1398 efe556ad Corentin Chary
1399 efe556ad Corentin Chary
    png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
1400 efe556ad Corentin Chary
    png_set_compression_level(png_ptr, level);
1401 3941bf6f Corentin Chary
    png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
1402 efe556ad Corentin Chary
1403 efe556ad Corentin Chary
    if (palette) {
1404 efe556ad Corentin Chary
        color_type = PNG_COLOR_TYPE_PALETTE;
1405 efe556ad Corentin Chary
    } else {
1406 efe556ad Corentin Chary
        color_type = PNG_COLOR_TYPE_RGB;
1407 efe556ad Corentin Chary
    }
1408 efe556ad Corentin Chary
1409 efe556ad Corentin Chary
    png_set_IHDR(png_ptr, info_ptr, w, h,
1410 efe556ad Corentin Chary
                 8, color_type, PNG_INTERLACE_NONE,
1411 efe556ad Corentin Chary
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1412 efe556ad Corentin Chary
1413 efe556ad Corentin Chary
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
1414 efe556ad Corentin Chary
        struct palette_cb_priv priv;
1415 efe556ad Corentin Chary
1416 efe556ad Corentin Chary
        png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
1417 5136a052 Corentin Chary
                                 palette_size(palette));
1418 efe556ad Corentin Chary
1419 efe556ad Corentin Chary
        priv.vs = vs;
1420 efe556ad Corentin Chary
        priv.png_palette = png_palette;
1421 5136a052 Corentin Chary
        palette_iter(palette, write_png_palette, &priv);
1422 efe556ad Corentin Chary
1423 5136a052 Corentin Chary
        png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
1424 efe556ad Corentin Chary
1425 efe556ad Corentin Chary
        if (vs->clientds.pf.bytes_per_pixel == 4) {
1426 d1af0e05 Corentin Chary
            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
1427 efe556ad Corentin Chary
        } else {
1428 d1af0e05 Corentin Chary
            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
1429 efe556ad Corentin Chary
        }
1430 efe556ad Corentin Chary
    }
1431 efe556ad Corentin Chary
1432 efe556ad Corentin Chary
    png_write_info(png_ptr, info_ptr);
1433 efe556ad Corentin Chary
1434 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.png, 2048);
1435 efe556ad Corentin Chary
    buf = qemu_malloc(w * 3);
1436 efe556ad Corentin Chary
    for (dy = 0; dy < h; dy++)
1437 efe556ad Corentin Chary
    {
1438 efe556ad Corentin Chary
        if (color_type == PNG_COLOR_TYPE_PALETTE) {
1439 d1af0e05 Corentin Chary
            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
1440 efe556ad Corentin Chary
        } else {
1441 efe556ad Corentin Chary
            rgb_prepare_row(vs, buf, x, y + dy, w);
1442 efe556ad Corentin Chary
        }
1443 efe556ad Corentin Chary
        png_write_row(png_ptr, buf);
1444 efe556ad Corentin Chary
    }
1445 efe556ad Corentin Chary
    qemu_free(buf);
1446 efe556ad Corentin Chary
1447 efe556ad Corentin Chary
    png_write_end(png_ptr, NULL);
1448 efe556ad Corentin Chary
1449 efe556ad Corentin Chary
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
1450 efe556ad Corentin Chary
        png_free(png_ptr, png_palette);
1451 efe556ad Corentin Chary
    }
1452 efe556ad Corentin Chary
1453 efe556ad Corentin Chary
    png_destroy_write_struct(&png_ptr, &info_ptr);
1454 efe556ad Corentin Chary
1455 efe556ad Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
1456 efe556ad Corentin Chary
1457 d1af0e05 Corentin Chary
    tight_send_compact_size(vs, vs->tight.png.offset);
1458 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
1459 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.png);
1460 efe556ad Corentin Chary
    return 1;
1461 efe556ad Corentin Chary
}
1462 efe556ad Corentin Chary
#endif /* CONFIG_VNC_PNG */
1463 efe556ad Corentin Chary
1464 380282b0 Corentin Chary
static void vnc_tight_start(VncState *vs)
1465 380282b0 Corentin Chary
{
1466 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.tight);
1467 380282b0 Corentin Chary
1468 380282b0 Corentin Chary
    // make the output buffer be the zlib buffer, so we can compress it later
1469 d1af0e05 Corentin Chary
    vs->tight.tmp = vs->output;
1470 d1af0e05 Corentin Chary
    vs->output = vs->tight.tight;
1471 380282b0 Corentin Chary
}
1472 380282b0 Corentin Chary
1473 380282b0 Corentin Chary
static void vnc_tight_stop(VncState *vs)
1474 380282b0 Corentin Chary
{
1475 380282b0 Corentin Chary
    // switch back to normal output/zlib buffers
1476 d1af0e05 Corentin Chary
    vs->tight.tight = vs->output;
1477 d1af0e05 Corentin Chary
    vs->output = vs->tight.tmp;
1478 380282b0 Corentin Chary
}
1479 380282b0 Corentin Chary
1480 03817eb8 Corentin Chary
static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
1481 03817eb8 Corentin Chary
                                int bg, int fg, int colors, VncPalette *palette)
1482 380282b0 Corentin Chary
{
1483 03817eb8 Corentin Chary
    int ret;
1484 380282b0 Corentin Chary
1485 03817eb8 Corentin Chary
    if (colors == 0) {
1486 03817eb8 Corentin Chary
        if (tight_detect_smooth_image(vs, w, h)) {
1487 03817eb8 Corentin Chary
            ret = send_gradient_rect(vs, x, y, w, h);
1488 03817eb8 Corentin Chary
        } else {
1489 03817eb8 Corentin Chary
            ret = send_full_color_rect(vs, x, y, w, h);
1490 03817eb8 Corentin Chary
        }
1491 03817eb8 Corentin Chary
    } else if (colors == 1) {
1492 03817eb8 Corentin Chary
        ret = send_solid_rect(vs);
1493 03817eb8 Corentin Chary
    } else if (colors == 2) {
1494 03817eb8 Corentin Chary
        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
1495 03817eb8 Corentin Chary
    } else if (colors <= 256) {
1496 03817eb8 Corentin Chary
        ret = send_palette_rect(vs, x, y, w, h, palette);
1497 d167f9bc Blue Swirl
    } else {
1498 d167f9bc Blue Swirl
        ret = 0;
1499 03817eb8 Corentin Chary
    }
1500 03817eb8 Corentin Chary
    return ret;
1501 03817eb8 Corentin Chary
}
1502 380282b0 Corentin Chary
1503 03817eb8 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1504 03817eb8 Corentin Chary
static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
1505 03817eb8 Corentin Chary
                              int bg, int fg, int colors,
1506 ce702e93 Corentin Chary
                              VncPalette *palette, bool force)
1507 03817eb8 Corentin Chary
{
1508 03817eb8 Corentin Chary
    int ret;
1509 aa7d73fd Corentin Chary
1510 aa7d73fd Corentin Chary
    if (colors == 0) {
1511 ce702e93 Corentin Chary
        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
1512 ce702e93 Corentin Chary
                      tight_detect_smooth_image(vs, w, h))) {
1513 03817eb8 Corentin Chary
            int quality = tight_conf[vs->tight.quality].jpeg_quality;
1514 2f6f5c7a Corentin Chary
1515 03817eb8 Corentin Chary
            ret = send_jpeg_rect(vs, x, y, w, h, quality);
1516 2f6f5c7a Corentin Chary
        } else {
1517 efe556ad Corentin Chary
            ret = send_full_color_rect(vs, x, y, w, h);
1518 2f6f5c7a Corentin Chary
        }
1519 aa7d73fd Corentin Chary
    } else if (colors == 1) {
1520 aa7d73fd Corentin Chary
        ret = send_solid_rect(vs);
1521 aa7d73fd Corentin Chary
    } else if (colors == 2) {
1522 efe556ad Corentin Chary
        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
1523 aa7d73fd Corentin Chary
    } else if (colors <= 256) {
1524 ce702e93 Corentin Chary
        if (force || (colors > 96 &&
1525 ce702e93 Corentin Chary
                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
1526 ce702e93 Corentin Chary
                      tight_detect_smooth_image(vs, w, h))) {
1527 d1af0e05 Corentin Chary
            int quality = tight_conf[vs->tight.quality].jpeg_quality;
1528 2f6f5c7a Corentin Chary
1529 2f6f5c7a Corentin Chary
            ret = send_jpeg_rect(vs, x, y, w, h, quality);
1530 2f6f5c7a Corentin Chary
        } else {
1531 efe556ad Corentin Chary
            ret = send_palette_rect(vs, x, y, w, h, palette);
1532 2f6f5c7a Corentin Chary
        }
1533 ad7ee4ad Blue Swirl
    } else {
1534 ad7ee4ad Blue Swirl
        ret = 0;
1535 03817eb8 Corentin Chary
    }
1536 03817eb8 Corentin Chary
    return ret;
1537 03817eb8 Corentin Chary
}
1538 2f6f5c7a Corentin Chary
#endif
1539 03817eb8 Corentin Chary
1540 03817eb8 Corentin Chary
static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
1541 03817eb8 Corentin Chary
{
1542 03817eb8 Corentin Chary
    VncPalette *palette = NULL;
1543 03817eb8 Corentin Chary
    uint32_t bg = 0, fg = 0;
1544 03817eb8 Corentin Chary
    int colors;
1545 03817eb8 Corentin Chary
    int ret = 0;
1546 cf76a1ce Peter Maydell
#ifdef CONFIG_VNC_JPEG
1547 ce702e93 Corentin Chary
    bool force_jpeg = false;
1548 ce702e93 Corentin Chary
    bool allow_jpeg = true;
1549 cf76a1ce Peter Maydell
#endif
1550 03817eb8 Corentin Chary
1551 03817eb8 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
1552 03817eb8 Corentin Chary
1553 03817eb8 Corentin Chary
    vnc_tight_start(vs);
1554 03817eb8 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
1555 03817eb8 Corentin Chary
    vnc_tight_stop(vs);
1556 03817eb8 Corentin Chary
1557 ce702e93 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1558 80e0c8c3 Corentin Chary
    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
1559 ce702e93 Corentin Chary
        double freq = vnc_update_freq(vs, x, y, w, h);
1560 ce702e93 Corentin Chary
1561 ce702e93 Corentin Chary
        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
1562 ce702e93 Corentin Chary
            allow_jpeg = false;
1563 ce702e93 Corentin Chary
        }
1564 ce702e93 Corentin Chary
        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
1565 ce702e93 Corentin Chary
            force_jpeg = true;
1566 ce702e93 Corentin Chary
            vnc_sent_lossy_rect(vs, x, y, w, h);
1567 ce702e93 Corentin Chary
        }
1568 ce702e93 Corentin Chary
    }
1569 ce702e93 Corentin Chary
#endif
1570 ce702e93 Corentin Chary
1571 03817eb8 Corentin Chary
    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
1572 03817eb8 Corentin Chary
1573 03817eb8 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1574 ce702e93 Corentin Chary
    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
1575 ce702e93 Corentin Chary
        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette,
1576 ce702e93 Corentin Chary
                                 force_jpeg);
1577 03817eb8 Corentin Chary
    } else {
1578 03817eb8 Corentin Chary
        ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
1579 aa7d73fd Corentin Chary
    }
1580 03817eb8 Corentin Chary
#else
1581 03817eb8 Corentin Chary
    ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
1582 03817eb8 Corentin Chary
#endif
1583 03817eb8 Corentin Chary
1584 5136a052 Corentin Chary
    palette_destroy(palette);
1585 aa7d73fd Corentin Chary
    return ret;
1586 380282b0 Corentin Chary
}
1587 380282b0 Corentin Chary
1588 b4bea3f2 Corentin Chary
static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
1589 b4bea3f2 Corentin Chary
{
1590 d1af0e05 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
1591 b4bea3f2 Corentin Chary
1592 b4bea3f2 Corentin Chary
    vnc_tight_start(vs);
1593 b4bea3f2 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
1594 b4bea3f2 Corentin Chary
    vnc_tight_stop(vs);
1595 b4bea3f2 Corentin Chary
1596 b4bea3f2 Corentin Chary
    return send_solid_rect(vs);
1597 b4bea3f2 Corentin Chary
}
1598 b4bea3f2 Corentin Chary
1599 ce702e93 Corentin Chary
static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
1600 ce702e93 Corentin Chary
                            bool split)
1601 380282b0 Corentin Chary
{
1602 380282b0 Corentin Chary
    int max_size, max_width;
1603 380282b0 Corentin Chary
    int max_sub_width, max_sub_height;
1604 380282b0 Corentin Chary
    int dx, dy;
1605 380282b0 Corentin Chary
    int rw, rh;
1606 380282b0 Corentin Chary
    int n = 0;
1607 380282b0 Corentin Chary
1608 d1af0e05 Corentin Chary
    max_size = tight_conf[vs->tight.compression].max_rect_size;
1609 d1af0e05 Corentin Chary
    max_width = tight_conf[vs->tight.compression].max_rect_width;
1610 380282b0 Corentin Chary
1611 ce702e93 Corentin Chary
    if (split && (w > max_width || w * h > max_size)) {
1612 380282b0 Corentin Chary
        max_sub_width = (w > max_width) ? max_width : w;
1613 380282b0 Corentin Chary
        max_sub_height = max_size / max_sub_width;
1614 380282b0 Corentin Chary
1615 380282b0 Corentin Chary
        for (dy = 0; dy < h; dy += max_sub_height) {
1616 380282b0 Corentin Chary
            for (dx = 0; dx < w; dx += max_width) {
1617 380282b0 Corentin Chary
                rw = MIN(max_sub_width, w - dx);
1618 380282b0 Corentin Chary
                rh = MIN(max_sub_height, h - dy);
1619 380282b0 Corentin Chary
                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
1620 380282b0 Corentin Chary
            }
1621 380282b0 Corentin Chary
        }
1622 380282b0 Corentin Chary
    } else {
1623 380282b0 Corentin Chary
        n += send_sub_rect(vs, x, y, w, h);
1624 380282b0 Corentin Chary
    }
1625 380282b0 Corentin Chary
1626 380282b0 Corentin Chary
    return n;
1627 380282b0 Corentin Chary
}
1628 380282b0 Corentin Chary
1629 b4bea3f2 Corentin Chary
static int find_large_solid_color_rect(VncState *vs, int x, int y,
1630 b4bea3f2 Corentin Chary
                                       int w, int h, int max_rows)
1631 b4bea3f2 Corentin Chary
{
1632 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
1633 b4bea3f2 Corentin Chary
    int n = 0;
1634 b4bea3f2 Corentin Chary
1635 b4bea3f2 Corentin Chary
    /* Try to find large solid-color areas and send them separately. */
1636 b4bea3f2 Corentin Chary
1637 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
1638 b4bea3f2 Corentin Chary
1639 b4bea3f2 Corentin Chary
        /* If a rectangle becomes too large, send its upper part now. */
1640 b4bea3f2 Corentin Chary
1641 b4bea3f2 Corentin Chary
        if (dy - y >= max_rows) {
1642 ce702e93 Corentin Chary
            n += send_rect_simple(vs, x, y, w, max_rows, true);
1643 b4bea3f2 Corentin Chary
            y += max_rows;
1644 b4bea3f2 Corentin Chary
            h -= max_rows;
1645 b4bea3f2 Corentin Chary
        }
1646 b4bea3f2 Corentin Chary
1647 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
1648 b4bea3f2 Corentin Chary
1649 b4bea3f2 Corentin Chary
        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
1650 b4bea3f2 Corentin Chary
            uint32_t color_value;
1651 b4bea3f2 Corentin Chary
            int x_best, y_best, w_best, h_best;
1652 b4bea3f2 Corentin Chary
1653 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
1654 b4bea3f2 Corentin Chary
1655 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
1656 b4bea3f2 Corentin Chary
                continue ;
1657 b4bea3f2 Corentin Chary
            }
1658 b4bea3f2 Corentin Chary
1659 b4bea3f2 Corentin Chary
            /* Get dimensions of solid-color area. */
1660 b4bea3f2 Corentin Chary
1661 b4bea3f2 Corentin Chary
            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
1662 b4bea3f2 Corentin Chary
                                 color_value, &w_best, &h_best);
1663 b4bea3f2 Corentin Chary
1664 b4bea3f2 Corentin Chary
            /* Make sure a solid rectangle is large enough
1665 b4bea3f2 Corentin Chary
               (or the whole rectangle is of the same color). */
1666 b4bea3f2 Corentin Chary
1667 b4bea3f2 Corentin Chary
            if (w_best * h_best != w * h &&
1668 b4bea3f2 Corentin Chary
                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
1669 b4bea3f2 Corentin Chary
                continue;
1670 b4bea3f2 Corentin Chary
            }
1671 b4bea3f2 Corentin Chary
1672 b4bea3f2 Corentin Chary
            /* Try to extend solid rectangle to maximum size. */
1673 b4bea3f2 Corentin Chary
1674 b4bea3f2 Corentin Chary
            x_best = dx; y_best = dy;
1675 b4bea3f2 Corentin Chary
            extend_solid_area(vs, x, y, w, h, color_value,
1676 b4bea3f2 Corentin Chary
                              &x_best, &y_best, &w_best, &h_best);
1677 b4bea3f2 Corentin Chary
1678 b4bea3f2 Corentin Chary
            /* Send rectangles at top and left to solid-color area. */
1679 b4bea3f2 Corentin Chary
1680 b4bea3f2 Corentin Chary
            if (y_best != y) {
1681 ce702e93 Corentin Chary
                n += send_rect_simple(vs, x, y, w, y_best-y, true);
1682 b4bea3f2 Corentin Chary
            }
1683 b4bea3f2 Corentin Chary
            if (x_best != x) {
1684 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x, y_best,
1685 efe556ad Corentin Chary
                                                   x_best-x, h_best);
1686 b4bea3f2 Corentin Chary
            }
1687 b4bea3f2 Corentin Chary
1688 b4bea3f2 Corentin Chary
            /* Send solid-color rectangle. */
1689 b4bea3f2 Corentin Chary
            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
1690 b4bea3f2 Corentin Chary
1691 b4bea3f2 Corentin Chary
            /* Send remaining rectangles (at right and bottom). */
1692 b4bea3f2 Corentin Chary
1693 b4bea3f2 Corentin Chary
            if (x_best + w_best != x + w) {
1694 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x_best+w_best,
1695 efe556ad Corentin Chary
                                                   y_best,
1696 efe556ad Corentin Chary
                                                   w-(x_best-x)-w_best,
1697 efe556ad Corentin Chary
                                                   h_best);
1698 b4bea3f2 Corentin Chary
            }
1699 b4bea3f2 Corentin Chary
            if (y_best + h_best != y + h) {
1700 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x, y_best+h_best,
1701 efe556ad Corentin Chary
                                                   w, h-(y_best-y)-h_best);
1702 b4bea3f2 Corentin Chary
            }
1703 b4bea3f2 Corentin Chary
1704 b4bea3f2 Corentin Chary
            /* Return after all recursive calls are done. */
1705 b4bea3f2 Corentin Chary
            return n;
1706 b4bea3f2 Corentin Chary
        }
1707 b4bea3f2 Corentin Chary
    }
1708 ce702e93 Corentin Chary
    return n + send_rect_simple(vs, x, y, w, h, true);
1709 b4bea3f2 Corentin Chary
}
1710 b4bea3f2 Corentin Chary
1711 efe556ad Corentin Chary
static int tight_send_framebuffer_update(VncState *vs, int x, int y,
1712 efe556ad Corentin Chary
                                         int w, int h)
1713 380282b0 Corentin Chary
{
1714 b4bea3f2 Corentin Chary
    int max_rows;
1715 b4bea3f2 Corentin Chary
1716 380282b0 Corentin Chary
    if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
1717 380282b0 Corentin Chary
        vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
1718 d1af0e05 Corentin Chary
        vs->tight.pixel24 = true;
1719 380282b0 Corentin Chary
    } else {
1720 d1af0e05 Corentin Chary
        vs->tight.pixel24 = false;
1721 380282b0 Corentin Chary
    }
1722 380282b0 Corentin Chary
1723 cf76a1ce Peter Maydell
#ifdef CONFIG_VNC_JPEG
1724 368d2588 Corentin Chary
    if (vs->tight.quality != (uint8_t)-1) {
1725 ce702e93 Corentin Chary
        double freq = vnc_update_freq(vs, x, y, w, h);
1726 ce702e93 Corentin Chary
1727 ce702e93 Corentin Chary
        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
1728 ce702e93 Corentin Chary
            return send_rect_simple(vs, x, y, w, h, false);
1729 ce702e93 Corentin Chary
        }
1730 ce702e93 Corentin Chary
    }
1731 cf76a1ce Peter Maydell
#endif
1732 ce702e93 Corentin Chary
1733 ce702e93 Corentin Chary
    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) {
1734 ce702e93 Corentin Chary
        return send_rect_simple(vs, x, y, w, h, true);
1735 ce702e93 Corentin Chary
    }
1736 b4bea3f2 Corentin Chary
1737 b4bea3f2 Corentin Chary
    /* Calculate maximum number of rows in one non-solid rectangle. */
1738 b4bea3f2 Corentin Chary
1739 d1af0e05 Corentin Chary
    max_rows = tight_conf[vs->tight.compression].max_rect_size;
1740 d1af0e05 Corentin Chary
    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
1741 b4bea3f2 Corentin Chary
1742 b4bea3f2 Corentin Chary
    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
1743 380282b0 Corentin Chary
}
1744 380282b0 Corentin Chary
1745 efe556ad Corentin Chary
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
1746 efe556ad Corentin Chary
                                      int w, int h)
1747 efe556ad Corentin Chary
{
1748 d1af0e05 Corentin Chary
    vs->tight.type = VNC_ENCODING_TIGHT;
1749 efe556ad Corentin Chary
    return tight_send_framebuffer_update(vs, x, y, w, h);
1750 efe556ad Corentin Chary
}
1751 efe556ad Corentin Chary
1752 efe556ad Corentin Chary
int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
1753 efe556ad Corentin Chary
                                          int w, int h)
1754 efe556ad Corentin Chary
{
1755 d1af0e05 Corentin Chary
    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
1756 efe556ad Corentin Chary
    return tight_send_framebuffer_update(vs, x, y, w, h);
1757 efe556ad Corentin Chary
}
1758 efe556ad Corentin Chary
1759 380282b0 Corentin Chary
void vnc_tight_clear(VncState *vs)
1760 380282b0 Corentin Chary
{
1761 380282b0 Corentin Chary
    int i;
1762 d1af0e05 Corentin Chary
    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
1763 d1af0e05 Corentin Chary
        if (vs->tight.stream[i].opaque) {
1764 d1af0e05 Corentin Chary
            deflateEnd(&vs->tight.stream[i]);
1765 380282b0 Corentin Chary
        }
1766 380282b0 Corentin Chary
    }
1767 380282b0 Corentin Chary
1768 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.tight);
1769 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.zlib);
1770 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.gradient);
1771 2f6f5c7a Corentin Chary
#ifdef CONFIG_VNC_JPEG
1772 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.jpeg);
1773 2f6f5c7a Corentin Chary
#endif
1774 b5469b11 Corentin Chary
#ifdef CONFIG_VNC_PNG
1775 b5469b11 Corentin Chary
    buffer_free(&vs->tight.png);
1776 b5469b11 Corentin Chary
#endif
1777 380282b0 Corentin Chary
}