Statistics
| Branch: | Revision:

root / ui / vnc-enc-tight.c @ 396d2cfc

History | View | Annotate | Download (61.2 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 1de7afc9 Paolo Bonzini
#include "qemu/bswap.h"
48 7b1b5d19 Paolo Bonzini
#include "qapi/qmp/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 9f64916d Gerd Hoffmann
        vs->client_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 9f64916d Gerd Hoffmann
    off = vs->client_be;
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 9f64916d Gerd Hoffmann
        endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
220 9f64916d Gerd Hoffmann
                      (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
221 2f6f5c7a Corentin Chary
                                                                        \
222 2f6f5c7a Corentin Chary
                                                                        \
223 9f64916d Gerd Hoffmann
        max[0] = vs->client_pf.rmax;                                  \
224 9f64916d Gerd Hoffmann
        max[1] = vs->client_pf.gmax;                                  \
225 9f64916d Gerd Hoffmann
        max[2] = vs->client_pf.bmax;                                  \
226 9f64916d Gerd Hoffmann
        shift[0] = vs->client_pf.rshift;                              \
227 9f64916d Gerd Hoffmann
        shift[1] = vs->client_pf.gshift;                              \
228 9f64916d Gerd Hoffmann
        shift[2] = vs->client_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 9f64916d Gerd Hoffmann
        vs->client_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 9f64916d Gerd Hoffmann
    if (vs->client_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 9f64916d Gerd Hoffmann
    switch (vs->client_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 9f64916d Gerd Hoffmann
    if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
561 9f64916d Gerd Hoffmann
             (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
562 9f64916d Gerd Hoffmann
        shift[0] = vs->client_pf.rshift;
563 9f64916d Gerd Hoffmann
        shift[1] = vs->client_pf.gshift;
564 9f64916d Gerd Hoffmann
        shift[2] = vs->client_pf.bshift;
565 2f6f5c7a Corentin Chary
    } else {
566 9f64916d Gerd Hoffmann
        shift[0] = 24 - vs->client_pf.rshift;
567 9f64916d Gerd Hoffmann
        shift[1] = 24 - vs->client_pf.gshift;
568 9f64916d Gerd Hoffmann
        shift[2] = 24 - vs->client_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 9f64916d Gerd Hoffmann
        endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
619 9f64916d Gerd Hoffmann
                       (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
620 2f6f5c7a Corentin Chary
                                                                        \
621 9f64916d Gerd Hoffmann
        max[0] = vs->client_pf.rmax;                                    \
622 9f64916d Gerd Hoffmann
        max[1] = vs->client_pf.gmax;                                    \
623 9f64916d Gerd Hoffmann
        max[2] = vs->client_pf.bmax;                                    \
624 9f64916d Gerd Hoffmann
        shift[0] = vs->client_pf.rshift;                                \
625 9f64916d Gerd Hoffmann
        shift[1] = vs->client_pf.gshift;                                \
626 9f64916d Gerd Hoffmann
        shift[2] = vs->client_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 94362682 Gerd Hoffmann
static bool
675 94362682 Gerd Hoffmann
check_solid_tile32(VncState *vs, int x, int y, int w, int h,
676 94362682 Gerd Hoffmann
                   uint32_t *color, bool samecolor)
677 94362682 Gerd Hoffmann
{
678 94362682 Gerd Hoffmann
    VncDisplay *vd = vs->vd;
679 94362682 Gerd Hoffmann
    uint32_t *fbptr;
680 94362682 Gerd Hoffmann
    uint32_t c;
681 94362682 Gerd Hoffmann
    int dx, dy;
682 94362682 Gerd Hoffmann
683 94362682 Gerd Hoffmann
    fbptr = vnc_server_fb_ptr(vd, x, y);
684 94362682 Gerd Hoffmann
685 94362682 Gerd Hoffmann
    c = *fbptr;
686 94362682 Gerd Hoffmann
    if (samecolor && (uint32_t)c != *color) {
687 94362682 Gerd Hoffmann
        return false;
688 b4bea3f2 Corentin Chary
    }
689 b4bea3f2 Corentin Chary
690 94362682 Gerd Hoffmann
    for (dy = 0; dy < h; dy++) {
691 94362682 Gerd Hoffmann
        for (dx = 0; dx < w; dx++) {
692 94362682 Gerd Hoffmann
            if (c != fbptr[dx]) {
693 94362682 Gerd Hoffmann
                return false;
694 94362682 Gerd Hoffmann
            }
695 94362682 Gerd Hoffmann
        }
696 94362682 Gerd Hoffmann
        fbptr = (uint32_t *)
697 94362682 Gerd Hoffmann
            ((uint8_t *)fbptr + vnc_server_fb_stride(vd));
698 94362682 Gerd Hoffmann
    }
699 94362682 Gerd Hoffmann
700 94362682 Gerd Hoffmann
    *color = (uint32_t)c;
701 94362682 Gerd Hoffmann
    return true;
702 94362682 Gerd Hoffmann
}
703 b4bea3f2 Corentin Chary
704 b4bea3f2 Corentin Chary
static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
705 b4bea3f2 Corentin Chary
                             uint32_t* color, bool samecolor)
706 b4bea3f2 Corentin Chary
{
707 9f64916d Gerd Hoffmann
    switch (VNC_SERVER_FB_BYTES) {
708 b4bea3f2 Corentin Chary
    case 4:
709 b4bea3f2 Corentin Chary
        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
710 b4bea3f2 Corentin Chary
    }
711 b4bea3f2 Corentin Chary
}
712 b4bea3f2 Corentin Chary
713 b4bea3f2 Corentin Chary
static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
714 b4bea3f2 Corentin Chary
                                 uint32_t color, int *w_ptr, int *h_ptr)
715 b4bea3f2 Corentin Chary
{
716 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
717 b4bea3f2 Corentin Chary
    int w_prev;
718 b4bea3f2 Corentin Chary
    int w_best = 0, h_best = 0;
719 b4bea3f2 Corentin Chary
720 b4bea3f2 Corentin Chary
    w_prev = w;
721 b4bea3f2 Corentin Chary
722 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
723 b4bea3f2 Corentin Chary
724 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
725 b4bea3f2 Corentin Chary
        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
726 b4bea3f2 Corentin Chary
727 b4bea3f2 Corentin Chary
        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
728 b4bea3f2 Corentin Chary
            break;
729 b4bea3f2 Corentin Chary
        }
730 b4bea3f2 Corentin Chary
731 b4bea3f2 Corentin Chary
        for (dx = x + dw; dx < x + w_prev;) {
732 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
733 b4bea3f2 Corentin Chary
734 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
735 b4bea3f2 Corentin Chary
                break;
736 b4bea3f2 Corentin Chary
            }
737 b4bea3f2 Corentin Chary
            dx += dw;
738 b4bea3f2 Corentin Chary
        }
739 b4bea3f2 Corentin Chary
740 b4bea3f2 Corentin Chary
        w_prev = dx - x;
741 b4bea3f2 Corentin Chary
        if (w_prev * (dy + dh - y) > w_best * h_best) {
742 b4bea3f2 Corentin Chary
            w_best = w_prev;
743 b4bea3f2 Corentin Chary
            h_best = dy + dh - y;
744 b4bea3f2 Corentin Chary
        }
745 b4bea3f2 Corentin Chary
    }
746 b4bea3f2 Corentin Chary
747 b4bea3f2 Corentin Chary
    *w_ptr = w_best;
748 b4bea3f2 Corentin Chary
    *h_ptr = h_best;
749 b4bea3f2 Corentin Chary
}
750 b4bea3f2 Corentin Chary
751 b4bea3f2 Corentin Chary
static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
752 b4bea3f2 Corentin Chary
                              uint32_t color, int *x_ptr, int *y_ptr,
753 b4bea3f2 Corentin Chary
                              int *w_ptr, int *h_ptr)
754 b4bea3f2 Corentin Chary
{
755 b4bea3f2 Corentin Chary
    int cx, cy;
756 b4bea3f2 Corentin Chary
757 b4bea3f2 Corentin Chary
    /* Try to extend the area upwards. */
758 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr - 1;
759 b4bea3f2 Corentin Chary
          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
760 b4bea3f2 Corentin Chary
          cy-- );
761 b4bea3f2 Corentin Chary
    *h_ptr += *y_ptr - (cy + 1);
762 b4bea3f2 Corentin Chary
    *y_ptr = cy + 1;
763 b4bea3f2 Corentin Chary
764 b4bea3f2 Corentin Chary
    /* ... downwards. */
765 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr + *h_ptr;
766 b4bea3f2 Corentin Chary
          cy < y + h &&
767 b4bea3f2 Corentin Chary
              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
768 b4bea3f2 Corentin Chary
          cy++ );
769 b4bea3f2 Corentin Chary
    *h_ptr += cy - (*y_ptr + *h_ptr);
770 b4bea3f2 Corentin Chary
771 b4bea3f2 Corentin Chary
    /* ... to the left. */
772 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr - 1;
773 b4bea3f2 Corentin Chary
          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
774 b4bea3f2 Corentin Chary
          cx-- );
775 b4bea3f2 Corentin Chary
    *w_ptr += *x_ptr - (cx + 1);
776 b4bea3f2 Corentin Chary
    *x_ptr = cx + 1;
777 b4bea3f2 Corentin Chary
778 b4bea3f2 Corentin Chary
    /* ... to the right. */
779 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr + *w_ptr;
780 b4bea3f2 Corentin Chary
          cx < x + w &&
781 b4bea3f2 Corentin Chary
              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
782 b4bea3f2 Corentin Chary
          cx++ );
783 b4bea3f2 Corentin Chary
    *w_ptr += cx - (*x_ptr + *w_ptr);
784 b4bea3f2 Corentin Chary
}
785 b4bea3f2 Corentin Chary
786 380282b0 Corentin Chary
static int tight_init_stream(VncState *vs, int stream_id,
787 380282b0 Corentin Chary
                             int level, int strategy)
788 380282b0 Corentin Chary
{
789 d1af0e05 Corentin Chary
    z_streamp zstream = &vs->tight.stream[stream_id];
790 380282b0 Corentin Chary
791 380282b0 Corentin Chary
    if (zstream->opaque == NULL) {
792 380282b0 Corentin Chary
        int err;
793 380282b0 Corentin Chary
794 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
795 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
796 380282b0 Corentin Chary
        zstream->zalloc = vnc_zlib_zalloc;
797 380282b0 Corentin Chary
        zstream->zfree = vnc_zlib_zfree;
798 380282b0 Corentin Chary
799 380282b0 Corentin Chary
        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
800 380282b0 Corentin Chary
                           MAX_MEM_LEVEL, strategy);
801 380282b0 Corentin Chary
802 380282b0 Corentin Chary
        if (err != Z_OK) {
803 380282b0 Corentin Chary
            fprintf(stderr, "VNC: error initializing zlib\n");
804 380282b0 Corentin Chary
            return -1;
805 380282b0 Corentin Chary
        }
806 380282b0 Corentin Chary
807 d1af0e05 Corentin Chary
        vs->tight.levels[stream_id] = level;
808 380282b0 Corentin Chary
        zstream->opaque = vs;
809 380282b0 Corentin Chary
    }
810 380282b0 Corentin Chary
811 d1af0e05 Corentin Chary
    if (vs->tight.levels[stream_id] != level) {
812 380282b0 Corentin Chary
        if (deflateParams(zstream, level, strategy) != Z_OK) {
813 380282b0 Corentin Chary
            return -1;
814 380282b0 Corentin Chary
        }
815 d1af0e05 Corentin Chary
        vs->tight.levels[stream_id] = level;
816 380282b0 Corentin Chary
    }
817 380282b0 Corentin Chary
    return 0;
818 380282b0 Corentin Chary
}
819 380282b0 Corentin Chary
820 380282b0 Corentin Chary
static void tight_send_compact_size(VncState *vs, size_t len)
821 380282b0 Corentin Chary
{
822 380282b0 Corentin Chary
    int lpc = 0;
823 380282b0 Corentin Chary
    int bytes = 0;
824 380282b0 Corentin Chary
    char buf[3] = {0, 0, 0};
825 380282b0 Corentin Chary
826 380282b0 Corentin Chary
    buf[bytes++] = len & 0x7F;
827 380282b0 Corentin Chary
    if (len > 0x7F) {
828 380282b0 Corentin Chary
        buf[bytes-1] |= 0x80;
829 380282b0 Corentin Chary
        buf[bytes++] = (len >> 7) & 0x7F;
830 380282b0 Corentin Chary
        if (len > 0x3FFF) {
831 380282b0 Corentin Chary
            buf[bytes-1] |= 0x80;
832 380282b0 Corentin Chary
            buf[bytes++] = (len >> 14) & 0xFF;
833 380282b0 Corentin Chary
        }
834 380282b0 Corentin Chary
    }
835 b4bea3f2 Corentin Chary
    for (lpc = 0; lpc < bytes; lpc++) {
836 380282b0 Corentin Chary
        vnc_write_u8(vs, buf[lpc]);
837 380282b0 Corentin Chary
    }
838 380282b0 Corentin Chary
}
839 380282b0 Corentin Chary
840 380282b0 Corentin Chary
static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
841 380282b0 Corentin Chary
                               int level, int strategy)
842 380282b0 Corentin Chary
{
843 d1af0e05 Corentin Chary
    z_streamp zstream = &vs->tight.stream[stream_id];
844 380282b0 Corentin Chary
    int previous_out;
845 380282b0 Corentin Chary
846 380282b0 Corentin Chary
    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
847 d1af0e05 Corentin Chary
        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
848 380282b0 Corentin Chary
        return bytes;
849 380282b0 Corentin Chary
    }
850 380282b0 Corentin Chary
851 380282b0 Corentin Chary
    if (tight_init_stream(vs, stream_id, level, strategy)) {
852 380282b0 Corentin Chary
        return -1;
853 380282b0 Corentin Chary
    }
854 380282b0 Corentin Chary
855 380282b0 Corentin Chary
    /* reserve memory in output buffer */
856 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.zlib, bytes + 64);
857 380282b0 Corentin Chary
858 380282b0 Corentin Chary
    /* set pointers */
859 d1af0e05 Corentin Chary
    zstream->next_in = vs->tight.tight.buffer;
860 d1af0e05 Corentin Chary
    zstream->avail_in = vs->tight.tight.offset;
861 d1af0e05 Corentin Chary
    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
862 d1af0e05 Corentin Chary
    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
863 2caa9e9d Michael Tokarev
    previous_out = zstream->avail_out;
864 380282b0 Corentin Chary
    zstream->data_type = Z_BINARY;
865 380282b0 Corentin Chary
866 380282b0 Corentin Chary
    /* start encoding */
867 380282b0 Corentin Chary
    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
868 380282b0 Corentin Chary
        fprintf(stderr, "VNC: error during tight compression\n");
869 380282b0 Corentin Chary
        return -1;
870 380282b0 Corentin Chary
    }
871 380282b0 Corentin Chary
872 d1af0e05 Corentin Chary
    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
873 2caa9e9d Michael Tokarev
    /* ...how much data has actually been produced by deflate() */
874 2caa9e9d Michael Tokarev
    bytes = previous_out - zstream->avail_out;
875 380282b0 Corentin Chary
876 380282b0 Corentin Chary
    tight_send_compact_size(vs, bytes);
877 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.zlib.buffer, bytes);
878 380282b0 Corentin Chary
879 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.zlib);
880 380282b0 Corentin Chary
881 380282b0 Corentin Chary
    return bytes;
882 380282b0 Corentin Chary
}
883 380282b0 Corentin Chary
884 380282b0 Corentin Chary
/*
885 380282b0 Corentin Chary
 * Subencoding implementations.
886 380282b0 Corentin Chary
 */
887 aa7d73fd Corentin Chary
static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
888 380282b0 Corentin Chary
{
889 380282b0 Corentin Chary
    uint32_t *buf32;
890 380282b0 Corentin Chary
    uint32_t pix;
891 380282b0 Corentin Chary
    int rshift, gshift, bshift;
892 380282b0 Corentin Chary
893 380282b0 Corentin Chary
    buf32 = (uint32_t *)buf;
894 380282b0 Corentin Chary
895 9f64916d Gerd Hoffmann
    if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
896 9f64916d Gerd Hoffmann
             (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
897 9f64916d Gerd Hoffmann
        rshift = vs->client_pf.rshift;
898 9f64916d Gerd Hoffmann
        gshift = vs->client_pf.gshift;
899 9f64916d Gerd Hoffmann
        bshift = vs->client_pf.bshift;
900 380282b0 Corentin Chary
    } else {
901 9f64916d Gerd Hoffmann
        rshift = 24 - vs->client_pf.rshift;
902 9f64916d Gerd Hoffmann
        gshift = 24 - vs->client_pf.gshift;
903 9f64916d Gerd Hoffmann
        bshift = 24 - vs->client_pf.bshift;
904 380282b0 Corentin Chary
    }
905 380282b0 Corentin Chary
906 aa7d73fd Corentin Chary
    if (ret) {
907 aa7d73fd Corentin Chary
        *ret = count * 3;
908 aa7d73fd Corentin Chary
    }
909 380282b0 Corentin Chary
910 380282b0 Corentin Chary
    while (count--) {
911 380282b0 Corentin Chary
        pix = *buf32++;
912 380282b0 Corentin Chary
        *buf++ = (char)(pix >> rshift);
913 380282b0 Corentin Chary
        *buf++ = (char)(pix >> gshift);
914 380282b0 Corentin Chary
        *buf++ = (char)(pix >> bshift);
915 380282b0 Corentin Chary
    }
916 380282b0 Corentin Chary
}
917 380282b0 Corentin Chary
918 efe556ad Corentin Chary
static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
919 380282b0 Corentin Chary
{
920 380282b0 Corentin Chary
    int stream = 0;
921 2116eff9 Jes Sorensen
    ssize_t bytes;
922 380282b0 Corentin Chary
923 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
924 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
925 efe556ad Corentin Chary
        return send_png_rect(vs, x, y, w, h, NULL);
926 efe556ad Corentin Chary
    }
927 efe556ad Corentin Chary
#endif
928 efe556ad Corentin Chary
929 380282b0 Corentin Chary
    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
930 380282b0 Corentin Chary
931 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
932 d1af0e05 Corentin Chary
        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
933 380282b0 Corentin Chary
        bytes = 3;
934 380282b0 Corentin Chary
    } else {
935 9f64916d Gerd Hoffmann
        bytes = vs->client_pf.bytes_per_pixel;
936 380282b0 Corentin Chary
    }
937 380282b0 Corentin Chary
938 380282b0 Corentin Chary
    bytes = tight_compress_data(vs, stream, w * h * bytes,
939 d1af0e05 Corentin Chary
                                tight_conf[vs->tight.compression].raw_zlib_level,
940 380282b0 Corentin Chary
                                Z_DEFAULT_STRATEGY);
941 380282b0 Corentin Chary
942 380282b0 Corentin Chary
    return (bytes >= 0);
943 380282b0 Corentin Chary
}
944 380282b0 Corentin Chary
945 b4bea3f2 Corentin Chary
static int send_solid_rect(VncState *vs)
946 b4bea3f2 Corentin Chary
{
947 b4bea3f2 Corentin Chary
    size_t bytes;
948 b4bea3f2 Corentin Chary
949 b4bea3f2 Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
950 b4bea3f2 Corentin Chary
951 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
952 d1af0e05 Corentin Chary
        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
953 b4bea3f2 Corentin Chary
        bytes = 3;
954 b4bea3f2 Corentin Chary
    } else {
955 9f64916d Gerd Hoffmann
        bytes = vs->client_pf.bytes_per_pixel;
956 b4bea3f2 Corentin Chary
    }
957 b4bea3f2 Corentin Chary
958 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.tight.buffer, bytes);
959 b4bea3f2 Corentin Chary
    return 1;
960 b4bea3f2 Corentin Chary
}
961 b4bea3f2 Corentin Chary
962 efe556ad Corentin Chary
static int send_mono_rect(VncState *vs, int x, int y,
963 efe556ad Corentin Chary
                          int w, int h, uint32_t bg, uint32_t fg)
964 aa7d73fd Corentin Chary
{
965 2116eff9 Jes Sorensen
    ssize_t bytes;
966 aa7d73fd Corentin Chary
    int stream = 1;
967 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].mono_zlib_level;
968 aa7d73fd Corentin Chary
969 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
970 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
971 efe556ad Corentin Chary
        int ret;
972 9f64916d Gerd Hoffmann
        int bpp = vs->client_pf.bytes_per_pixel * 8;
973 5136a052 Corentin Chary
        VncPalette *palette = palette_new(2, bpp);
974 efe556ad Corentin Chary
975 5136a052 Corentin Chary
        palette_put(palette, bg);
976 5136a052 Corentin Chary
        palette_put(palette, fg);
977 efe556ad Corentin Chary
        ret = send_png_rect(vs, x, y, w, h, palette);
978 5136a052 Corentin Chary
        palette_destroy(palette);
979 efe556ad Corentin Chary
        return ret;
980 efe556ad Corentin Chary
    }
981 efe556ad Corentin Chary
#endif
982 efe556ad Corentin Chary
983 aa7d73fd Corentin Chary
    bytes = ((w + 7) / 8) * h;
984 aa7d73fd Corentin Chary
985 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
986 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
987 aa7d73fd Corentin Chary
    vnc_write_u8(vs, 1);
988 aa7d73fd Corentin Chary
989 9f64916d Gerd Hoffmann
    switch (vs->client_pf.bytes_per_pixel) {
990 aa7d73fd Corentin Chary
    case 4:
991 aa7d73fd Corentin Chary
    {
992 aa7d73fd Corentin Chary
        uint32_t buf[2] = {bg, fg};
993 aa7d73fd Corentin Chary
        size_t ret = sizeof (buf);
994 aa7d73fd Corentin Chary
995 d1af0e05 Corentin Chary
        if (vs->tight.pixel24) {
996 aa7d73fd Corentin Chary
            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
997 aa7d73fd Corentin Chary
        }
998 aa7d73fd Corentin Chary
        vnc_write(vs, buf, ret);
999 aa7d73fd Corentin Chary
1000 d1af0e05 Corentin Chary
        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
1001 aa7d73fd Corentin Chary
        break;
1002 aa7d73fd Corentin Chary
    }
1003 aa7d73fd Corentin Chary
    case 2:
1004 aa7d73fd Corentin Chary
        vnc_write(vs, &bg, 2);
1005 aa7d73fd Corentin Chary
        vnc_write(vs, &fg, 2);
1006 d1af0e05 Corentin Chary
        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
1007 aa7d73fd Corentin Chary
        break;
1008 aa7d73fd Corentin Chary
    default:
1009 aa7d73fd Corentin Chary
        vnc_write_u8(vs, bg);
1010 aa7d73fd Corentin Chary
        vnc_write_u8(vs, fg);
1011 d1af0e05 Corentin Chary
        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
1012 aa7d73fd Corentin Chary
        break;
1013 aa7d73fd Corentin Chary
    }
1014 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1015 aa7d73fd Corentin Chary
1016 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
1017 aa7d73fd Corentin Chary
    return (bytes >= 0);
1018 aa7d73fd Corentin Chary
}
1019 aa7d73fd Corentin Chary
1020 aa7d73fd Corentin Chary
struct palette_cb_priv {
1021 aa7d73fd Corentin Chary
    VncState *vs;
1022 aa7d73fd Corentin Chary
    uint8_t *header;
1023 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1024 efe556ad Corentin Chary
    png_colorp png_palette;
1025 efe556ad Corentin Chary
#endif
1026 aa7d73fd Corentin Chary
};
1027 aa7d73fd Corentin Chary
1028 5136a052 Corentin Chary
static void write_palette(int idx, uint32_t color, void *opaque)
1029 aa7d73fd Corentin Chary
{
1030 aa7d73fd Corentin Chary
    struct palette_cb_priv *priv = opaque;
1031 aa7d73fd Corentin Chary
    VncState *vs = priv->vs;
1032 9f64916d Gerd Hoffmann
    uint32_t bytes = vs->client_pf.bytes_per_pixel;
1033 aa7d73fd Corentin Chary
1034 aa7d73fd Corentin Chary
    if (bytes == 4) {
1035 aa7d73fd Corentin Chary
        ((uint32_t*)priv->header)[idx] = color;
1036 aa7d73fd Corentin Chary
    } else {
1037 aa7d73fd Corentin Chary
        ((uint16_t*)priv->header)[idx] = color;
1038 aa7d73fd Corentin Chary
    }
1039 aa7d73fd Corentin Chary
}
1040 aa7d73fd Corentin Chary
1041 efe556ad Corentin Chary
static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
1042 2f6f5c7a Corentin Chary
{
1043 2f6f5c7a Corentin Chary
    int stream = 3;
1044 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
1045 2116eff9 Jes Sorensen
    ssize_t bytes;
1046 2f6f5c7a Corentin Chary
1047 9f64916d Gerd Hoffmann
    if (vs->client_pf.bytes_per_pixel == 1) {
1048 efe556ad Corentin Chary
        return send_full_color_rect(vs, x, y, w, h);
1049 9f64916d Gerd Hoffmann
    }
1050 2f6f5c7a Corentin Chary
1051 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1052 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
1053 2f6f5c7a Corentin Chary
1054 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
1055 2f6f5c7a Corentin Chary
1056 d1af0e05 Corentin Chary
    if (vs->tight.pixel24) {
1057 d1af0e05 Corentin Chary
        tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
1058 2f6f5c7a Corentin Chary
        bytes = 3;
1059 9f64916d Gerd Hoffmann
    } else if (vs->client_pf.bytes_per_pixel == 4) {
1060 d1af0e05 Corentin Chary
        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
1061 2f6f5c7a Corentin Chary
        bytes = 4;
1062 2f6f5c7a Corentin Chary
    } else {
1063 d1af0e05 Corentin Chary
        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
1064 2f6f5c7a Corentin Chary
        bytes = 2;
1065 2f6f5c7a Corentin Chary
    }
1066 2f6f5c7a Corentin Chary
1067 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.gradient);
1068 2f6f5c7a Corentin Chary
1069 2f6f5c7a Corentin Chary
    bytes = w * h * bytes;
1070 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1071 2f6f5c7a Corentin Chary
1072 2f6f5c7a Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes,
1073 2f6f5c7a Corentin Chary
                                level, Z_FILTERED);
1074 2f6f5c7a Corentin Chary
    return (bytes >= 0);
1075 2f6f5c7a Corentin Chary
}
1076 2f6f5c7a Corentin Chary
1077 efe556ad Corentin Chary
static int send_palette_rect(VncState *vs, int x, int y,
1078 5136a052 Corentin Chary
                             int w, int h, VncPalette *palette)
1079 aa7d73fd Corentin Chary
{
1080 aa7d73fd Corentin Chary
    int stream = 2;
1081 d1af0e05 Corentin Chary
    int level = tight_conf[vs->tight.compression].idx_zlib_level;
1082 aa7d73fd Corentin Chary
    int colors;
1083 2116eff9 Jes Sorensen
    ssize_t bytes;
1084 aa7d73fd Corentin Chary
1085 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1086 efe556ad Corentin Chary
    if (tight_can_send_png_rect(vs, w, h)) {
1087 efe556ad Corentin Chary
        return send_png_rect(vs, x, y, w, h, palette);
1088 efe556ad Corentin Chary
    }
1089 efe556ad Corentin Chary
#endif
1090 efe556ad Corentin Chary
1091 5136a052 Corentin Chary
    colors = palette_size(palette);
1092 aa7d73fd Corentin Chary
1093 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1094 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
1095 aa7d73fd Corentin Chary
    vnc_write_u8(vs, colors - 1);
1096 aa7d73fd Corentin Chary
1097 9f64916d Gerd Hoffmann
    switch (vs->client_pf.bytes_per_pixel) {
1098 aa7d73fd Corentin Chary
    case 4:
1099 aa7d73fd Corentin Chary
    {
1100 aa7d73fd Corentin Chary
        size_t old_offset, offset;
1101 5136a052 Corentin Chary
        uint32_t header[palette_size(palette)];
1102 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1103 aa7d73fd Corentin Chary
1104 aa7d73fd Corentin Chary
        old_offset = vs->output.offset;
1105 5136a052 Corentin Chary
        palette_iter(palette, write_palette, &priv);
1106 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
1107 aa7d73fd Corentin Chary
1108 d1af0e05 Corentin Chary
        if (vs->tight.pixel24) {
1109 aa7d73fd Corentin Chary
            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
1110 aa7d73fd Corentin Chary
            vs->output.offset = old_offset + offset;
1111 aa7d73fd Corentin Chary
        }
1112 aa7d73fd Corentin Chary
1113 d1af0e05 Corentin Chary
        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
1114 aa7d73fd Corentin Chary
        break;
1115 aa7d73fd Corentin Chary
    }
1116 aa7d73fd Corentin Chary
    case 2:
1117 aa7d73fd Corentin Chary
    {
1118 5136a052 Corentin Chary
        uint16_t header[palette_size(palette)];
1119 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1120 aa7d73fd Corentin Chary
1121 5136a052 Corentin Chary
        palette_iter(palette, write_palette, &priv);
1122 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
1123 d1af0e05 Corentin Chary
        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
1124 aa7d73fd Corentin Chary
        break;
1125 aa7d73fd Corentin Chary
    }
1126 aa7d73fd Corentin Chary
    default:
1127 aa7d73fd Corentin Chary
        return -1; /* No palette for 8bits colors */
1128 aa7d73fd Corentin Chary
        break;
1129 aa7d73fd Corentin Chary
    }
1130 aa7d73fd Corentin Chary
    bytes = w * h;
1131 d1af0e05 Corentin Chary
    vs->tight.tight.offset = bytes;
1132 aa7d73fd Corentin Chary
1133 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes,
1134 aa7d73fd Corentin Chary
                                level, Z_DEFAULT_STRATEGY);
1135 aa7d73fd Corentin Chary
    return (bytes >= 0);
1136 aa7d73fd Corentin Chary
}
1137 aa7d73fd Corentin Chary
1138 2f6f5c7a Corentin Chary
/*
1139 efe556ad Corentin Chary
 * JPEG compression stuff.
1140 efe556ad Corentin Chary
 */
1141 efe556ad Corentin Chary
#ifdef CONFIG_VNC_JPEG
1142 efe556ad Corentin Chary
/*
1143 2f6f5c7a Corentin Chary
 * Destination manager implementation for JPEG library.
1144 2f6f5c7a Corentin Chary
 */
1145 2f6f5c7a Corentin Chary
1146 2f6f5c7a Corentin Chary
/* This is called once per encoding */
1147 2f6f5c7a Corentin Chary
static void jpeg_init_destination(j_compress_ptr cinfo)
1148 2f6f5c7a Corentin Chary
{
1149 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1150 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1151 2f6f5c7a Corentin Chary
1152 2f6f5c7a Corentin Chary
    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
1153 2f6f5c7a Corentin Chary
    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
1154 2f6f5c7a Corentin Chary
}
1155 2f6f5c7a Corentin Chary
1156 2f6f5c7a Corentin Chary
/* This is called when we ran out of buffer (shouldn't happen!) */
1157 2f6f5c7a Corentin Chary
static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
1158 2f6f5c7a Corentin Chary
{
1159 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1160 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1161 2f6f5c7a Corentin Chary
1162 2f6f5c7a Corentin Chary
    buffer->offset = buffer->capacity;
1163 2f6f5c7a Corentin Chary
    buffer_reserve(buffer, 2048);
1164 2f6f5c7a Corentin Chary
    jpeg_init_destination(cinfo);
1165 2f6f5c7a Corentin Chary
    return TRUE;
1166 2f6f5c7a Corentin Chary
}
1167 2f6f5c7a Corentin Chary
1168 2f6f5c7a Corentin Chary
/* This is called when we are done processing data */
1169 2f6f5c7a Corentin Chary
static void jpeg_term_destination(j_compress_ptr cinfo)
1170 2f6f5c7a Corentin Chary
{
1171 2f6f5c7a Corentin Chary
    VncState *vs = cinfo->client_data;
1172 d1af0e05 Corentin Chary
    Buffer *buffer = &vs->tight.jpeg;
1173 2f6f5c7a Corentin Chary
1174 2f6f5c7a Corentin Chary
    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
1175 2f6f5c7a Corentin Chary
}
1176 2f6f5c7a Corentin Chary
1177 2f6f5c7a Corentin Chary
static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
1178 2f6f5c7a Corentin Chary
{
1179 2f6f5c7a Corentin Chary
    struct jpeg_compress_struct cinfo;
1180 2f6f5c7a Corentin Chary
    struct jpeg_error_mgr jerr;
1181 2f6f5c7a Corentin Chary
    struct jpeg_destination_mgr manager;
1182 47683d66 Gerd Hoffmann
    pixman_image_t *linebuf;
1183 2f6f5c7a Corentin Chary
    JSAMPROW row[1];
1184 2f6f5c7a Corentin Chary
    uint8_t *buf;
1185 2f6f5c7a Corentin Chary
    int dy;
1186 2f6f5c7a Corentin Chary
1187 2f6f5c7a Corentin Chary
    if (ds_get_bytes_per_pixel(vs->ds) == 1)
1188 efe556ad Corentin Chary
        return send_full_color_rect(vs, x, y, w, h);
1189 2f6f5c7a Corentin Chary
1190 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.jpeg, 2048);
1191 2f6f5c7a Corentin Chary
1192 2f6f5c7a Corentin Chary
    cinfo.err = jpeg_std_error(&jerr);
1193 2f6f5c7a Corentin Chary
    jpeg_create_compress(&cinfo);
1194 2f6f5c7a Corentin Chary
1195 2f6f5c7a Corentin Chary
    cinfo.client_data = vs;
1196 2f6f5c7a Corentin Chary
    cinfo.image_width = w;
1197 2f6f5c7a Corentin Chary
    cinfo.image_height = h;
1198 2f6f5c7a Corentin Chary
    cinfo.input_components = 3;
1199 2f6f5c7a Corentin Chary
    cinfo.in_color_space = JCS_RGB;
1200 2f6f5c7a Corentin Chary
1201 2f6f5c7a Corentin Chary
    jpeg_set_defaults(&cinfo);
1202 2f6f5c7a Corentin Chary
    jpeg_set_quality(&cinfo, quality, true);
1203 2f6f5c7a Corentin Chary
1204 2f6f5c7a Corentin Chary
    manager.init_destination = jpeg_init_destination;
1205 2f6f5c7a Corentin Chary
    manager.empty_output_buffer = jpeg_empty_output_buffer;
1206 2f6f5c7a Corentin Chary
    manager.term_destination = jpeg_term_destination;
1207 2f6f5c7a Corentin Chary
    cinfo.dest = &manager;
1208 2f6f5c7a Corentin Chary
1209 2f6f5c7a Corentin Chary
    jpeg_start_compress(&cinfo, true);
1210 2f6f5c7a Corentin Chary
1211 47683d66 Gerd Hoffmann
    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
1212 47683d66 Gerd Hoffmann
    buf = (uint8_t *)pixman_image_get_data(linebuf);
1213 d9c18c24 Corentin Chary
    row[0] = buf;
1214 2f6f5c7a Corentin Chary
    for (dy = 0; dy < h; dy++) {
1215 bc210eb1 Gerd Hoffmann
        qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
1216 2f6f5c7a Corentin Chary
        jpeg_write_scanlines(&cinfo, row, 1);
1217 2f6f5c7a Corentin Chary
    }
1218 47683d66 Gerd Hoffmann
    qemu_pixman_image_unref(linebuf);
1219 2f6f5c7a Corentin Chary
1220 2f6f5c7a Corentin Chary
    jpeg_finish_compress(&cinfo);
1221 2f6f5c7a Corentin Chary
    jpeg_destroy_compress(&cinfo);
1222 2f6f5c7a Corentin Chary
1223 2f6f5c7a Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
1224 2f6f5c7a Corentin Chary
1225 d1af0e05 Corentin Chary
    tight_send_compact_size(vs, vs->tight.jpeg.offset);
1226 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
1227 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.jpeg);
1228 2f6f5c7a Corentin Chary
1229 2f6f5c7a Corentin Chary
    return 1;
1230 2f6f5c7a Corentin Chary
}
1231 2f6f5c7a Corentin Chary
#endif /* CONFIG_VNC_JPEG */
1232 2f6f5c7a Corentin Chary
1233 efe556ad Corentin Chary
/*
1234 efe556ad Corentin Chary
 * PNG compression stuff.
1235 efe556ad Corentin Chary
 */
1236 efe556ad Corentin Chary
#ifdef CONFIG_VNC_PNG
1237 5136a052 Corentin Chary
static void write_png_palette(int idx, uint32_t pix, void *opaque)
1238 efe556ad Corentin Chary
{
1239 efe556ad Corentin Chary
    struct palette_cb_priv *priv = opaque;
1240 efe556ad Corentin Chary
    VncState *vs = priv->vs;
1241 efe556ad Corentin Chary
    png_colorp color = &priv->png_palette[idx];
1242 efe556ad Corentin Chary
1243 d1af0e05 Corentin Chary
    if (vs->tight.pixel24)
1244 efe556ad Corentin Chary
    {
1245 9f64916d Gerd Hoffmann
        color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
1246 9f64916d Gerd Hoffmann
        color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
1247 9f64916d Gerd Hoffmann
        color->blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax;
1248 efe556ad Corentin Chary
    }
1249 efe556ad Corentin Chary
    else
1250 efe556ad Corentin Chary
    {
1251 efe556ad Corentin Chary
        int red, green, blue;
1252 efe556ad Corentin Chary
1253 9f64916d Gerd Hoffmann
        red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
1254 9f64916d Gerd Hoffmann
        green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
1255 9f64916d Gerd Hoffmann
        blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax;
1256 9f64916d Gerd Hoffmann
        color->red = ((red * 255 + vs->client_pf.rmax / 2) /
1257 9f64916d Gerd Hoffmann
                      vs->client_pf.rmax);
1258 9f64916d Gerd Hoffmann
        color->green = ((green * 255 + vs->client_pf.gmax / 2) /
1259 9f64916d Gerd Hoffmann
                        vs->client_pf.gmax);
1260 9f64916d Gerd Hoffmann
        color->blue = ((blue * 255 + vs->client_pf.bmax / 2) /
1261 9f64916d Gerd Hoffmann
                       vs->client_pf.bmax);
1262 efe556ad Corentin Chary
    }
1263 efe556ad Corentin Chary
}
1264 efe556ad Corentin Chary
1265 efe556ad Corentin Chary
static void png_write_data(png_structp png_ptr, png_bytep data,
1266 efe556ad Corentin Chary
                           png_size_t length)
1267 efe556ad Corentin Chary
{
1268 efe556ad Corentin Chary
    VncState *vs = png_get_io_ptr(png_ptr);
1269 efe556ad Corentin Chary
1270 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
1271 d1af0e05 Corentin Chary
    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
1272 efe556ad Corentin Chary
1273 d1af0e05 Corentin Chary
    vs->tight.png.offset += length;
1274 efe556ad Corentin Chary
}
1275 efe556ad Corentin Chary
1276 efe556ad Corentin Chary
static void png_flush_data(png_structp png_ptr)
1277 efe556ad Corentin Chary
{
1278 efe556ad Corentin Chary
}
1279 efe556ad Corentin Chary
1280 efe556ad Corentin Chary
static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
1281 efe556ad Corentin Chary
{
1282 7267c094 Anthony Liguori
    return g_malloc(size);
1283 efe556ad Corentin Chary
}
1284 efe556ad Corentin Chary
1285 efe556ad Corentin Chary
static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
1286 efe556ad Corentin Chary
{
1287 7267c094 Anthony Liguori
    g_free(ptr);
1288 efe556ad Corentin Chary
}
1289 efe556ad Corentin Chary
1290 efe556ad Corentin Chary
static int send_png_rect(VncState *vs, int x, int y, int w, int h,
1291 5136a052 Corentin Chary
                         VncPalette *palette)
1292 efe556ad Corentin Chary
{
1293 efe556ad Corentin Chary
    png_byte color_type;
1294 efe556ad Corentin Chary
    png_structp png_ptr;
1295 efe556ad Corentin Chary
    png_infop info_ptr;
1296 efe556ad Corentin Chary
    png_colorp png_palette = NULL;
1297 47683d66 Gerd Hoffmann
    pixman_image_t *linebuf;
1298 d1af0e05 Corentin Chary
    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
1299 d1af0e05 Corentin Chary
    int filters = tight_png_conf[vs->tight.compression].png_filters;
1300 efe556ad Corentin Chary
    uint8_t *buf;
1301 efe556ad Corentin Chary
    int dy;
1302 efe556ad Corentin Chary
1303 efe556ad Corentin Chary
    png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
1304 efe556ad Corentin Chary
                                        NULL, vnc_png_malloc, vnc_png_free);
1305 efe556ad Corentin Chary
1306 efe556ad Corentin Chary
    if (png_ptr == NULL)
1307 efe556ad Corentin Chary
        return -1;
1308 efe556ad Corentin Chary
1309 efe556ad Corentin Chary
    info_ptr = png_create_info_struct(png_ptr);
1310 efe556ad Corentin Chary
1311 efe556ad Corentin Chary
    if (info_ptr == NULL) {
1312 efe556ad Corentin Chary
        png_destroy_write_struct(&png_ptr, NULL);
1313 efe556ad Corentin Chary
        return -1;
1314 efe556ad Corentin Chary
    }
1315 efe556ad Corentin Chary
1316 efe556ad Corentin Chary
    png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
1317 efe556ad Corentin Chary
    png_set_compression_level(png_ptr, level);
1318 3941bf6f Corentin Chary
    png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
1319 efe556ad Corentin Chary
1320 efe556ad Corentin Chary
    if (palette) {
1321 efe556ad Corentin Chary
        color_type = PNG_COLOR_TYPE_PALETTE;
1322 efe556ad Corentin Chary
    } else {
1323 efe556ad Corentin Chary
        color_type = PNG_COLOR_TYPE_RGB;
1324 efe556ad Corentin Chary
    }
1325 efe556ad Corentin Chary
1326 efe556ad Corentin Chary
    png_set_IHDR(png_ptr, info_ptr, w, h,
1327 efe556ad Corentin Chary
                 8, color_type, PNG_INTERLACE_NONE,
1328 efe556ad Corentin Chary
                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1329 efe556ad Corentin Chary
1330 efe556ad Corentin Chary
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
1331 efe556ad Corentin Chary
        struct palette_cb_priv priv;
1332 efe556ad Corentin Chary
1333 efe556ad Corentin Chary
        png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
1334 5136a052 Corentin Chary
                                 palette_size(palette));
1335 efe556ad Corentin Chary
1336 efe556ad Corentin Chary
        priv.vs = vs;
1337 efe556ad Corentin Chary
        priv.png_palette = png_palette;
1338 5136a052 Corentin Chary
        palette_iter(palette, write_png_palette, &priv);
1339 efe556ad Corentin Chary
1340 5136a052 Corentin Chary
        png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
1341 efe556ad Corentin Chary
1342 9f64916d Gerd Hoffmann
        if (vs->client_pf.bytes_per_pixel == 4) {
1343 d1af0e05 Corentin Chary
            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
1344 efe556ad Corentin Chary
        } else {
1345 d1af0e05 Corentin Chary
            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
1346 efe556ad Corentin Chary
        }
1347 efe556ad Corentin Chary
    }
1348 efe556ad Corentin Chary
1349 efe556ad Corentin Chary
    png_write_info(png_ptr, info_ptr);
1350 efe556ad Corentin Chary
1351 d1af0e05 Corentin Chary
    buffer_reserve(&vs->tight.png, 2048);
1352 47683d66 Gerd Hoffmann
    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
1353 47683d66 Gerd Hoffmann
    buf = (uint8_t *)pixman_image_get_data(linebuf);
1354 efe556ad Corentin Chary
    for (dy = 0; dy < h; dy++)
1355 efe556ad Corentin Chary
    {
1356 efe556ad Corentin Chary
        if (color_type == PNG_COLOR_TYPE_PALETTE) {
1357 d1af0e05 Corentin Chary
            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
1358 efe556ad Corentin Chary
        } else {
1359 bc210eb1 Gerd Hoffmann
            qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, x, y + dy);
1360 efe556ad Corentin Chary
        }
1361 efe556ad Corentin Chary
        png_write_row(png_ptr, buf);
1362 efe556ad Corentin Chary
    }
1363 47683d66 Gerd Hoffmann
    qemu_pixman_image_unref(linebuf);
1364 efe556ad Corentin Chary
1365 efe556ad Corentin Chary
    png_write_end(png_ptr, NULL);
1366 efe556ad Corentin Chary
1367 efe556ad Corentin Chary
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
1368 efe556ad Corentin Chary
        png_free(png_ptr, png_palette);
1369 efe556ad Corentin Chary
    }
1370 efe556ad Corentin Chary
1371 efe556ad Corentin Chary
    png_destroy_write_struct(&png_ptr, &info_ptr);
1372 efe556ad Corentin Chary
1373 efe556ad Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
1374 efe556ad Corentin Chary
1375 d1af0e05 Corentin Chary
    tight_send_compact_size(vs, vs->tight.png.offset);
1376 d1af0e05 Corentin Chary
    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
1377 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.png);
1378 efe556ad Corentin Chary
    return 1;
1379 efe556ad Corentin Chary
}
1380 efe556ad Corentin Chary
#endif /* CONFIG_VNC_PNG */
1381 efe556ad Corentin Chary
1382 380282b0 Corentin Chary
static void vnc_tight_start(VncState *vs)
1383 380282b0 Corentin Chary
{
1384 d1af0e05 Corentin Chary
    buffer_reset(&vs->tight.tight);
1385 380282b0 Corentin Chary
1386 380282b0 Corentin Chary
    // make the output buffer be the zlib buffer, so we can compress it later
1387 d1af0e05 Corentin Chary
    vs->tight.tmp = vs->output;
1388 d1af0e05 Corentin Chary
    vs->output = vs->tight.tight;
1389 380282b0 Corentin Chary
}
1390 380282b0 Corentin Chary
1391 380282b0 Corentin Chary
static void vnc_tight_stop(VncState *vs)
1392 380282b0 Corentin Chary
{
1393 380282b0 Corentin Chary
    // switch back to normal output/zlib buffers
1394 d1af0e05 Corentin Chary
    vs->tight.tight = vs->output;
1395 d1af0e05 Corentin Chary
    vs->output = vs->tight.tmp;
1396 380282b0 Corentin Chary
}
1397 380282b0 Corentin Chary
1398 03817eb8 Corentin Chary
static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
1399 03817eb8 Corentin Chary
                                int bg, int fg, int colors, VncPalette *palette)
1400 380282b0 Corentin Chary
{
1401 03817eb8 Corentin Chary
    int ret;
1402 380282b0 Corentin Chary
1403 03817eb8 Corentin Chary
    if (colors == 0) {
1404 03817eb8 Corentin Chary
        if (tight_detect_smooth_image(vs, w, h)) {
1405 03817eb8 Corentin Chary
            ret = send_gradient_rect(vs, x, y, w, h);
1406 03817eb8 Corentin Chary
        } else {
1407 03817eb8 Corentin Chary
            ret = send_full_color_rect(vs, x, y, w, h);
1408 03817eb8 Corentin Chary
        }
1409 03817eb8 Corentin Chary
    } else if (colors == 1) {
1410 03817eb8 Corentin Chary
        ret = send_solid_rect(vs);
1411 03817eb8 Corentin Chary
    } else if (colors == 2) {
1412 03817eb8 Corentin Chary
        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
1413 03817eb8 Corentin Chary
    } else if (colors <= 256) {
1414 03817eb8 Corentin Chary
        ret = send_palette_rect(vs, x, y, w, h, palette);
1415 d167f9bc Blue Swirl
    } else {
1416 d167f9bc Blue Swirl
        ret = 0;
1417 03817eb8 Corentin Chary
    }
1418 03817eb8 Corentin Chary
    return ret;
1419 03817eb8 Corentin Chary
}
1420 380282b0 Corentin Chary
1421 03817eb8 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1422 03817eb8 Corentin Chary
static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
1423 03817eb8 Corentin Chary
                              int bg, int fg, int colors,
1424 ce702e93 Corentin Chary
                              VncPalette *palette, bool force)
1425 03817eb8 Corentin Chary
{
1426 03817eb8 Corentin Chary
    int ret;
1427 aa7d73fd Corentin Chary
1428 aa7d73fd Corentin Chary
    if (colors == 0) {
1429 ce702e93 Corentin Chary
        if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full &&
1430 ce702e93 Corentin Chary
                      tight_detect_smooth_image(vs, w, h))) {
1431 03817eb8 Corentin Chary
            int quality = tight_conf[vs->tight.quality].jpeg_quality;
1432 2f6f5c7a Corentin Chary
1433 03817eb8 Corentin Chary
            ret = send_jpeg_rect(vs, x, y, w, h, quality);
1434 2f6f5c7a Corentin Chary
        } else {
1435 efe556ad Corentin Chary
            ret = send_full_color_rect(vs, x, y, w, h);
1436 2f6f5c7a Corentin Chary
        }
1437 aa7d73fd Corentin Chary
    } else if (colors == 1) {
1438 aa7d73fd Corentin Chary
        ret = send_solid_rect(vs);
1439 aa7d73fd Corentin Chary
    } else if (colors == 2) {
1440 efe556ad Corentin Chary
        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
1441 aa7d73fd Corentin Chary
    } else if (colors <= 256) {
1442 ce702e93 Corentin Chary
        if (force || (colors > 96 &&
1443 ce702e93 Corentin Chary
                      tight_jpeg_conf[vs->tight.quality].jpeg_idx &&
1444 ce702e93 Corentin Chary
                      tight_detect_smooth_image(vs, w, h))) {
1445 d1af0e05 Corentin Chary
            int quality = tight_conf[vs->tight.quality].jpeg_quality;
1446 2f6f5c7a Corentin Chary
1447 2f6f5c7a Corentin Chary
            ret = send_jpeg_rect(vs, x, y, w, h, quality);
1448 2f6f5c7a Corentin Chary
        } else {
1449 efe556ad Corentin Chary
            ret = send_palette_rect(vs, x, y, w, h, palette);
1450 2f6f5c7a Corentin Chary
        }
1451 ad7ee4ad Blue Swirl
    } else {
1452 ad7ee4ad Blue Swirl
        ret = 0;
1453 03817eb8 Corentin Chary
    }
1454 03817eb8 Corentin Chary
    return ret;
1455 03817eb8 Corentin Chary
}
1456 2f6f5c7a Corentin Chary
#endif
1457 03817eb8 Corentin Chary
1458 03817eb8 Corentin Chary
static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
1459 03817eb8 Corentin Chary
{
1460 03817eb8 Corentin Chary
    VncPalette *palette = NULL;
1461 03817eb8 Corentin Chary
    uint32_t bg = 0, fg = 0;
1462 03817eb8 Corentin Chary
    int colors;
1463 03817eb8 Corentin Chary
    int ret = 0;
1464 cf76a1ce Peter Maydell
#ifdef CONFIG_VNC_JPEG
1465 ce702e93 Corentin Chary
    bool force_jpeg = false;
1466 ce702e93 Corentin Chary
    bool allow_jpeg = true;
1467 cf76a1ce Peter Maydell
#endif
1468 03817eb8 Corentin Chary
1469 03817eb8 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
1470 03817eb8 Corentin Chary
1471 03817eb8 Corentin Chary
    vnc_tight_start(vs);
1472 03817eb8 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
1473 03817eb8 Corentin Chary
    vnc_tight_stop(vs);
1474 03817eb8 Corentin Chary
1475 ce702e93 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1476 80e0c8c3 Corentin Chary
    if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) {
1477 ce702e93 Corentin Chary
        double freq = vnc_update_freq(vs, x, y, w, h);
1478 ce702e93 Corentin Chary
1479 ce702e93 Corentin Chary
        if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) {
1480 ce702e93 Corentin Chary
            allow_jpeg = false;
1481 ce702e93 Corentin Chary
        }
1482 ce702e93 Corentin Chary
        if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
1483 ce702e93 Corentin Chary
            force_jpeg = true;
1484 ce702e93 Corentin Chary
            vnc_sent_lossy_rect(vs, x, y, w, h);
1485 ce702e93 Corentin Chary
        }
1486 ce702e93 Corentin Chary
    }
1487 ce702e93 Corentin Chary
#endif
1488 ce702e93 Corentin Chary
1489 03817eb8 Corentin Chary
    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
1490 03817eb8 Corentin Chary
1491 03817eb8 Corentin Chary
#ifdef CONFIG_VNC_JPEG
1492 ce702e93 Corentin Chary
    if (allow_jpeg && vs->tight.quality != (uint8_t)-1) {
1493 ce702e93 Corentin Chary
        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette,
1494 ce702e93 Corentin Chary
                                 force_jpeg);
1495 03817eb8 Corentin Chary
    } else {
1496 03817eb8 Corentin Chary
        ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
1497 aa7d73fd Corentin Chary
    }
1498 03817eb8 Corentin Chary
#else
1499 03817eb8 Corentin Chary
    ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
1500 03817eb8 Corentin Chary
#endif
1501 03817eb8 Corentin Chary
1502 5136a052 Corentin Chary
    palette_destroy(palette);
1503 aa7d73fd Corentin Chary
    return ret;
1504 380282b0 Corentin Chary
}
1505 380282b0 Corentin Chary
1506 b4bea3f2 Corentin Chary
static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
1507 b4bea3f2 Corentin Chary
{
1508 d1af0e05 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
1509 b4bea3f2 Corentin Chary
1510 b4bea3f2 Corentin Chary
    vnc_tight_start(vs);
1511 b4bea3f2 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
1512 b4bea3f2 Corentin Chary
    vnc_tight_stop(vs);
1513 b4bea3f2 Corentin Chary
1514 b4bea3f2 Corentin Chary
    return send_solid_rect(vs);
1515 b4bea3f2 Corentin Chary
}
1516 b4bea3f2 Corentin Chary
1517 ce702e93 Corentin Chary
static int send_rect_simple(VncState *vs, int x, int y, int w, int h,
1518 ce702e93 Corentin Chary
                            bool split)
1519 380282b0 Corentin Chary
{
1520 380282b0 Corentin Chary
    int max_size, max_width;
1521 380282b0 Corentin Chary
    int max_sub_width, max_sub_height;
1522 380282b0 Corentin Chary
    int dx, dy;
1523 380282b0 Corentin Chary
    int rw, rh;
1524 380282b0 Corentin Chary
    int n = 0;
1525 380282b0 Corentin Chary
1526 d1af0e05 Corentin Chary
    max_size = tight_conf[vs->tight.compression].max_rect_size;
1527 d1af0e05 Corentin Chary
    max_width = tight_conf[vs->tight.compression].max_rect_width;
1528 380282b0 Corentin Chary
1529 ce702e93 Corentin Chary
    if (split && (w > max_width || w * h > max_size)) {
1530 380282b0 Corentin Chary
        max_sub_width = (w > max_width) ? max_width : w;
1531 380282b0 Corentin Chary
        max_sub_height = max_size / max_sub_width;
1532 380282b0 Corentin Chary
1533 380282b0 Corentin Chary
        for (dy = 0; dy < h; dy += max_sub_height) {
1534 380282b0 Corentin Chary
            for (dx = 0; dx < w; dx += max_width) {
1535 380282b0 Corentin Chary
                rw = MIN(max_sub_width, w - dx);
1536 380282b0 Corentin Chary
                rh = MIN(max_sub_height, h - dy);
1537 380282b0 Corentin Chary
                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
1538 380282b0 Corentin Chary
            }
1539 380282b0 Corentin Chary
        }
1540 380282b0 Corentin Chary
    } else {
1541 380282b0 Corentin Chary
        n += send_sub_rect(vs, x, y, w, h);
1542 380282b0 Corentin Chary
    }
1543 380282b0 Corentin Chary
1544 380282b0 Corentin Chary
    return n;
1545 380282b0 Corentin Chary
}
1546 380282b0 Corentin Chary
1547 b4bea3f2 Corentin Chary
static int find_large_solid_color_rect(VncState *vs, int x, int y,
1548 b4bea3f2 Corentin Chary
                                       int w, int h, int max_rows)
1549 b4bea3f2 Corentin Chary
{
1550 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
1551 b4bea3f2 Corentin Chary
    int n = 0;
1552 b4bea3f2 Corentin Chary
1553 b4bea3f2 Corentin Chary
    /* Try to find large solid-color areas and send them separately. */
1554 b4bea3f2 Corentin Chary
1555 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
1556 b4bea3f2 Corentin Chary
1557 b4bea3f2 Corentin Chary
        /* If a rectangle becomes too large, send its upper part now. */
1558 b4bea3f2 Corentin Chary
1559 b4bea3f2 Corentin Chary
        if (dy - y >= max_rows) {
1560 ce702e93 Corentin Chary
            n += send_rect_simple(vs, x, y, w, max_rows, true);
1561 b4bea3f2 Corentin Chary
            y += max_rows;
1562 b4bea3f2 Corentin Chary
            h -= max_rows;
1563 b4bea3f2 Corentin Chary
        }
1564 b4bea3f2 Corentin Chary
1565 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
1566 b4bea3f2 Corentin Chary
1567 b4bea3f2 Corentin Chary
        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
1568 b4bea3f2 Corentin Chary
            uint32_t color_value;
1569 b4bea3f2 Corentin Chary
            int x_best, y_best, w_best, h_best;
1570 b4bea3f2 Corentin Chary
1571 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
1572 b4bea3f2 Corentin Chary
1573 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
1574 b4bea3f2 Corentin Chary
                continue ;
1575 b4bea3f2 Corentin Chary
            }
1576 b4bea3f2 Corentin Chary
1577 b4bea3f2 Corentin Chary
            /* Get dimensions of solid-color area. */
1578 b4bea3f2 Corentin Chary
1579 b4bea3f2 Corentin Chary
            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
1580 b4bea3f2 Corentin Chary
                                 color_value, &w_best, &h_best);
1581 b4bea3f2 Corentin Chary
1582 b4bea3f2 Corentin Chary
            /* Make sure a solid rectangle is large enough
1583 b4bea3f2 Corentin Chary
               (or the whole rectangle is of the same color). */
1584 b4bea3f2 Corentin Chary
1585 b4bea3f2 Corentin Chary
            if (w_best * h_best != w * h &&
1586 b4bea3f2 Corentin Chary
                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
1587 b4bea3f2 Corentin Chary
                continue;
1588 b4bea3f2 Corentin Chary
            }
1589 b4bea3f2 Corentin Chary
1590 b4bea3f2 Corentin Chary
            /* Try to extend solid rectangle to maximum size. */
1591 b4bea3f2 Corentin Chary
1592 b4bea3f2 Corentin Chary
            x_best = dx; y_best = dy;
1593 b4bea3f2 Corentin Chary
            extend_solid_area(vs, x, y, w, h, color_value,
1594 b4bea3f2 Corentin Chary
                              &x_best, &y_best, &w_best, &h_best);
1595 b4bea3f2 Corentin Chary
1596 b4bea3f2 Corentin Chary
            /* Send rectangles at top and left to solid-color area. */
1597 b4bea3f2 Corentin Chary
1598 b4bea3f2 Corentin Chary
            if (y_best != y) {
1599 ce702e93 Corentin Chary
                n += send_rect_simple(vs, x, y, w, y_best-y, true);
1600 b4bea3f2 Corentin Chary
            }
1601 b4bea3f2 Corentin Chary
            if (x_best != x) {
1602 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x, y_best,
1603 efe556ad Corentin Chary
                                                   x_best-x, h_best);
1604 b4bea3f2 Corentin Chary
            }
1605 b4bea3f2 Corentin Chary
1606 b4bea3f2 Corentin Chary
            /* Send solid-color rectangle. */
1607 b4bea3f2 Corentin Chary
            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
1608 b4bea3f2 Corentin Chary
1609 b4bea3f2 Corentin Chary
            /* Send remaining rectangles (at right and bottom). */
1610 b4bea3f2 Corentin Chary
1611 b4bea3f2 Corentin Chary
            if (x_best + w_best != x + w) {
1612 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x_best+w_best,
1613 efe556ad Corentin Chary
                                                   y_best,
1614 efe556ad Corentin Chary
                                                   w-(x_best-x)-w_best,
1615 efe556ad Corentin Chary
                                                   h_best);
1616 b4bea3f2 Corentin Chary
            }
1617 b4bea3f2 Corentin Chary
            if (y_best + h_best != y + h) {
1618 efe556ad Corentin Chary
                n += tight_send_framebuffer_update(vs, x, y_best+h_best,
1619 efe556ad Corentin Chary
                                                   w, h-(y_best-y)-h_best);
1620 b4bea3f2 Corentin Chary
            }
1621 b4bea3f2 Corentin Chary
1622 b4bea3f2 Corentin Chary
            /* Return after all recursive calls are done. */
1623 b4bea3f2 Corentin Chary
            return n;
1624 b4bea3f2 Corentin Chary
        }
1625 b4bea3f2 Corentin Chary
    }
1626 ce702e93 Corentin Chary
    return n + send_rect_simple(vs, x, y, w, h, true);
1627 b4bea3f2 Corentin Chary
}
1628 b4bea3f2 Corentin Chary
1629 efe556ad Corentin Chary
static int tight_send_framebuffer_update(VncState *vs, int x, int y,
1630 efe556ad Corentin Chary
                                         int w, int h)
1631 380282b0 Corentin Chary
{
1632 b4bea3f2 Corentin Chary
    int max_rows;
1633 b4bea3f2 Corentin Chary
1634 9f64916d Gerd Hoffmann
    if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
1635 9f64916d Gerd Hoffmann
        vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
1636 d1af0e05 Corentin Chary
        vs->tight.pixel24 = true;
1637 380282b0 Corentin Chary
    } else {
1638 d1af0e05 Corentin Chary
        vs->tight.pixel24 = false;
1639 380282b0 Corentin Chary
    }
1640 380282b0 Corentin Chary
1641 cf76a1ce Peter Maydell
#ifdef CONFIG_VNC_JPEG
1642 368d2588 Corentin Chary
    if (vs->tight.quality != (uint8_t)-1) {
1643 ce702e93 Corentin Chary
        double freq = vnc_update_freq(vs, x, y, w, h);
1644 ce702e93 Corentin Chary
1645 ce702e93 Corentin Chary
        if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) {
1646 ce702e93 Corentin Chary
            return send_rect_simple(vs, x, y, w, h, false);
1647 ce702e93 Corentin Chary
        }
1648 ce702e93 Corentin Chary
    }
1649 cf76a1ce Peter Maydell
#endif
1650 ce702e93 Corentin Chary
1651 ce702e93 Corentin Chary
    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) {
1652 ce702e93 Corentin Chary
        return send_rect_simple(vs, x, y, w, h, true);
1653 ce702e93 Corentin Chary
    }
1654 b4bea3f2 Corentin Chary
1655 b4bea3f2 Corentin Chary
    /* Calculate maximum number of rows in one non-solid rectangle. */
1656 b4bea3f2 Corentin Chary
1657 d1af0e05 Corentin Chary
    max_rows = tight_conf[vs->tight.compression].max_rect_size;
1658 d1af0e05 Corentin Chary
    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
1659 b4bea3f2 Corentin Chary
1660 b4bea3f2 Corentin Chary
    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
1661 380282b0 Corentin Chary
}
1662 380282b0 Corentin Chary
1663 efe556ad Corentin Chary
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
1664 efe556ad Corentin Chary
                                      int w, int h)
1665 efe556ad Corentin Chary
{
1666 d1af0e05 Corentin Chary
    vs->tight.type = VNC_ENCODING_TIGHT;
1667 efe556ad Corentin Chary
    return tight_send_framebuffer_update(vs, x, y, w, h);
1668 efe556ad Corentin Chary
}
1669 efe556ad Corentin Chary
1670 efe556ad Corentin Chary
int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
1671 efe556ad Corentin Chary
                                          int w, int h)
1672 efe556ad Corentin Chary
{
1673 d1af0e05 Corentin Chary
    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
1674 efe556ad Corentin Chary
    return tight_send_framebuffer_update(vs, x, y, w, h);
1675 efe556ad Corentin Chary
}
1676 efe556ad Corentin Chary
1677 380282b0 Corentin Chary
void vnc_tight_clear(VncState *vs)
1678 380282b0 Corentin Chary
{
1679 380282b0 Corentin Chary
    int i;
1680 d1af0e05 Corentin Chary
    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
1681 d1af0e05 Corentin Chary
        if (vs->tight.stream[i].opaque) {
1682 d1af0e05 Corentin Chary
            deflateEnd(&vs->tight.stream[i]);
1683 380282b0 Corentin Chary
        }
1684 380282b0 Corentin Chary
    }
1685 380282b0 Corentin Chary
1686 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.tight);
1687 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.zlib);
1688 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.gradient);
1689 2f6f5c7a Corentin Chary
#ifdef CONFIG_VNC_JPEG
1690 d1af0e05 Corentin Chary
    buffer_free(&vs->tight.jpeg);
1691 2f6f5c7a Corentin Chary
#endif
1692 b5469b11 Corentin Chary
#ifdef CONFIG_VNC_PNG
1693 b5469b11 Corentin Chary
    buffer_free(&vs->tight.png);
1694 b5469b11 Corentin Chary
#endif
1695 380282b0 Corentin Chary
}