Statistics
| Branch: | Revision:

root / ui / vnc-enc-tight.c @ 7fee199c

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