Statistics
| Branch: | Revision:

root / vnc-encoding-tight.c @ 1884533c

History | View | Annotate | Download (36 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 aa7d73fd Corentin Chary
#include "qdict.h"
30 aa7d73fd Corentin Chary
#include "qint.h"
31 380282b0 Corentin Chary
#include "vnc.h"
32 380282b0 Corentin Chary
#include "vnc-encoding-tight.h"
33 380282b0 Corentin Chary
34 380282b0 Corentin Chary
/* Compression level stuff. The following array contains various
35 380282b0 Corentin Chary
   encoder parameters for each of 10 compression levels (0..9).
36 380282b0 Corentin Chary
   Last three parameters correspond to JPEG quality levels (0..9). */
37 380282b0 Corentin Chary
38 380282b0 Corentin Chary
static const struct {
39 380282b0 Corentin Chary
    int max_rect_size, max_rect_width;
40 380282b0 Corentin Chary
    int mono_min_rect_size, gradient_min_rect_size;
41 380282b0 Corentin Chary
    int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level;
42 380282b0 Corentin Chary
    int gradient_threshold, gradient_threshold24;
43 380282b0 Corentin Chary
    int idx_max_colors_divisor;
44 380282b0 Corentin Chary
    int jpeg_quality, jpeg_threshold, jpeg_threshold24;
45 380282b0 Corentin Chary
} tight_conf[] = {
46 380282b0 Corentin Chary
    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
47 380282b0 Corentin Chary
    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
48 380282b0 Corentin Chary
    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
49 380282b0 Corentin Chary
    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
50 380282b0 Corentin Chary
    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
51 380282b0 Corentin Chary
    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
52 380282b0 Corentin Chary
    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
53 380282b0 Corentin Chary
    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
54 380282b0 Corentin Chary
    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
55 380282b0 Corentin Chary
    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
56 380282b0 Corentin Chary
};
57 380282b0 Corentin Chary
58 b4bea3f2 Corentin Chary
/*
59 aa7d73fd Corentin Chary
 * Code to determine how many different colors used in rectangle.
60 aa7d73fd Corentin Chary
 */
61 aa7d73fd Corentin Chary
62 aa7d73fd Corentin Chary
static void tight_palette_rgb2buf(uint32_t rgb, int bpp, uint8_t buf[6])
63 aa7d73fd Corentin Chary
{
64 aa7d73fd Corentin Chary
    memset(buf, 0, 6);
65 aa7d73fd Corentin Chary
66 aa7d73fd Corentin Chary
    if (bpp == 32) {
67 aa7d73fd Corentin Chary
        buf[0] = ((rgb >> 24) & 0xFF);
68 aa7d73fd Corentin Chary
        buf[1] = ((rgb >> 16) & 0xFF);
69 aa7d73fd Corentin Chary
        buf[2] = ((rgb >>  8) & 0xFF);
70 aa7d73fd Corentin Chary
        buf[3] = ((rgb >>  0) & 0xFF);
71 aa7d73fd Corentin Chary
        buf[4] = ((buf[0] & 1) == 0) << 3 | ((buf[1] & 1) == 0) << 2;
72 aa7d73fd Corentin Chary
        buf[4]|= ((buf[2] & 1) == 0) << 1 | ((buf[3] & 1) == 0) << 0;
73 aa7d73fd Corentin Chary
        buf[0] |= 1;
74 aa7d73fd Corentin Chary
        buf[1] |= 1;
75 aa7d73fd Corentin Chary
        buf[2] |= 1;
76 aa7d73fd Corentin Chary
        buf[3] |= 1;
77 aa7d73fd Corentin Chary
    }
78 aa7d73fd Corentin Chary
    if (bpp == 16) {
79 aa7d73fd Corentin Chary
        buf[0] = ((rgb >> 8) & 0xFF);
80 aa7d73fd Corentin Chary
        buf[1] = ((rgb >> 0) & 0xFF);
81 aa7d73fd Corentin Chary
        buf[2] = ((buf[0] & 1) == 0) << 1 | ((buf[1] & 1) == 0) << 0;
82 aa7d73fd Corentin Chary
        buf[0] |= 1;
83 aa7d73fd Corentin Chary
        buf[1] |= 1;
84 aa7d73fd Corentin Chary
    }
85 aa7d73fd Corentin Chary
}
86 aa7d73fd Corentin Chary
87 aa7d73fd Corentin Chary
static uint32_t tight_palette_buf2rgb(int bpp, const uint8_t *buf)
88 aa7d73fd Corentin Chary
{
89 aa7d73fd Corentin Chary
    uint32_t rgb = 0;
90 aa7d73fd Corentin Chary
91 aa7d73fd Corentin Chary
    if (bpp == 32) {
92 aa7d73fd Corentin Chary
        rgb |= ((buf[0] & ~1) | !((buf[4] >> 3) & 1)) << 24;
93 aa7d73fd Corentin Chary
        rgb |= ((buf[1] & ~1) | !((buf[4] >> 2) & 1)) << 16;
94 aa7d73fd Corentin Chary
        rgb |= ((buf[2] & ~1) | !((buf[4] >> 1) & 1)) <<  8;
95 aa7d73fd Corentin Chary
        rgb |= ((buf[3] & ~1) | !((buf[4] >> 0) & 1)) <<  0;
96 aa7d73fd Corentin Chary
    }
97 aa7d73fd Corentin Chary
    if (bpp == 16) {
98 aa7d73fd Corentin Chary
        rgb |= ((buf[0] & ~1) | !((buf[2] >> 1) & 1)) << 8;
99 aa7d73fd Corentin Chary
        rgb |= ((buf[1] & ~1) | !((buf[2] >> 0) & 1)) << 0;
100 aa7d73fd Corentin Chary
    }
101 aa7d73fd Corentin Chary
    return rgb;
102 aa7d73fd Corentin Chary
}
103 aa7d73fd Corentin Chary
104 aa7d73fd Corentin Chary
105 aa7d73fd Corentin Chary
static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
106 aa7d73fd Corentin Chary
{
107 aa7d73fd Corentin Chary
    uint8_t key[6];
108 aa7d73fd Corentin Chary
    int idx = qdict_size(palette);
109 aa7d73fd Corentin Chary
    bool present;
110 aa7d73fd Corentin Chary
111 aa7d73fd Corentin Chary
    tight_palette_rgb2buf(rgb, bpp, key);
112 aa7d73fd Corentin Chary
    present = qdict_haskey(palette, (char *)key);
113 aa7d73fd Corentin Chary
    if (idx >= max && !present) {
114 aa7d73fd Corentin Chary
        return 0;
115 aa7d73fd Corentin Chary
    }
116 aa7d73fd Corentin Chary
    if (!present) {
117 aa7d73fd Corentin Chary
        qdict_put(palette, (char *)key, qint_from_int(idx));
118 aa7d73fd Corentin Chary
    }
119 aa7d73fd Corentin Chary
    return qdict_size(palette);
120 aa7d73fd Corentin Chary
}
121 aa7d73fd Corentin Chary
122 aa7d73fd Corentin Chary
#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
123 aa7d73fd Corentin Chary
                                                                        \
124 aa7d73fd Corentin Chary
    static int                                                          \
125 aa7d73fd Corentin Chary
    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
126 aa7d73fd Corentin Chary
                            int max, size_t count,                      \
127 aa7d73fd Corentin Chary
                            uint32_t *bg, uint32_t *fg,                 \
128 aa7d73fd Corentin Chary
                            struct QDict **palette) {                   \
129 aa7d73fd Corentin Chary
        uint##bpp##_t *data;                                            \
130 aa7d73fd Corentin Chary
        uint##bpp##_t c0, c1, ci;                                       \
131 aa7d73fd Corentin Chary
        int i, n0, n1;                                                  \
132 aa7d73fd Corentin Chary
                                                                        \
133 aa7d73fd Corentin Chary
        data = (uint##bpp##_t *)vs->tight.buffer;                       \
134 aa7d73fd Corentin Chary
                                                                        \
135 aa7d73fd Corentin Chary
        c0 = data[0];                                                   \
136 aa7d73fd Corentin Chary
        i = 1;                                                          \
137 aa7d73fd Corentin Chary
        while (i < count && data[i] == c0)                              \
138 aa7d73fd Corentin Chary
            i++;                                                        \
139 aa7d73fd Corentin Chary
        if (i >= count) {                                               \
140 aa7d73fd Corentin Chary
            *bg = *fg = c0;                                             \
141 aa7d73fd Corentin Chary
            return 1;                                                   \
142 aa7d73fd Corentin Chary
        }                                                               \
143 aa7d73fd Corentin Chary
                                                                        \
144 aa7d73fd Corentin Chary
        if (max < 2) {                                                  \
145 aa7d73fd Corentin Chary
            return 0;                                                   \
146 aa7d73fd Corentin Chary
        }                                                               \
147 aa7d73fd Corentin Chary
                                                                        \
148 aa7d73fd Corentin Chary
        n0 = i;                                                         \
149 aa7d73fd Corentin Chary
        c1 = data[i];                                                   \
150 aa7d73fd Corentin Chary
        n1 = 0;                                                         \
151 aa7d73fd Corentin Chary
        for (i++; i < count; i++) {                                     \
152 aa7d73fd Corentin Chary
            ci = data[i];                                               \
153 aa7d73fd Corentin Chary
            if (ci == c0) {                                             \
154 aa7d73fd Corentin Chary
                n0++;                                                   \
155 aa7d73fd Corentin Chary
            } else if (ci == c1) {                                      \
156 aa7d73fd Corentin Chary
                n1++;                                                   \
157 aa7d73fd Corentin Chary
            } else                                                      \
158 aa7d73fd Corentin Chary
                break;                                                  \
159 aa7d73fd Corentin Chary
        }                                                               \
160 aa7d73fd Corentin Chary
        if (i >= count) {                                               \
161 aa7d73fd Corentin Chary
            if (n0 > n1) {                                              \
162 aa7d73fd Corentin Chary
                *bg = (uint32_t)c0;                                     \
163 aa7d73fd Corentin Chary
                *fg = (uint32_t)c1;                                     \
164 aa7d73fd Corentin Chary
            } else {                                                    \
165 aa7d73fd Corentin Chary
                *bg = (uint32_t)c1;                                     \
166 aa7d73fd Corentin Chary
                *fg = (uint32_t)c0;                                     \
167 aa7d73fd Corentin Chary
            }                                                           \
168 aa7d73fd Corentin Chary
            return 2;                                                   \
169 aa7d73fd Corentin Chary
        }                                                               \
170 aa7d73fd Corentin Chary
                                                                        \
171 aa7d73fd Corentin Chary
        if (max == 2) {                                                 \
172 aa7d73fd Corentin Chary
            return 0;                                                   \
173 aa7d73fd Corentin Chary
        }                                                               \
174 aa7d73fd Corentin Chary
                                                                        \
175 aa7d73fd Corentin Chary
        *palette = qdict_new();                                         \
176 aa7d73fd Corentin Chary
        tight_palette_insert(*palette, c0, bpp, max);                   \
177 aa7d73fd Corentin Chary
        tight_palette_insert(*palette, c1, bpp, max);                   \
178 270ec219 Corentin Chary
        tight_palette_insert(*palette, ci, bpp, max);                   \
179 aa7d73fd Corentin Chary
                                                                        \
180 aa7d73fd Corentin Chary
        for (i++; i < count; i++) {                                     \
181 aa7d73fd Corentin Chary
            if (data[i] == ci) {                                        \
182 aa7d73fd Corentin Chary
                continue;                                               \
183 aa7d73fd Corentin Chary
            } else {                                                    \
184 aa7d73fd Corentin Chary
                if (!tight_palette_insert(*palette, (uint32_t)ci,       \
185 aa7d73fd Corentin Chary
                                          bpp, max)) {                  \
186 aa7d73fd Corentin Chary
                    return 0;                                           \
187 aa7d73fd Corentin Chary
                }                                                       \
188 aa7d73fd Corentin Chary
                ci = data[i];                                           \
189 aa7d73fd Corentin Chary
            }                                                           \
190 aa7d73fd Corentin Chary
        }                                                               \
191 aa7d73fd Corentin Chary
                                                                        \
192 aa7d73fd Corentin Chary
        return qdict_size(*palette);                                    \
193 aa7d73fd Corentin Chary
    }
194 aa7d73fd Corentin Chary
195 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(8)
196 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(16)
197 aa7d73fd Corentin Chary
DEFINE_FILL_PALETTE_FUNCTION(32)
198 aa7d73fd Corentin Chary
199 aa7d73fd Corentin Chary
static int tight_fill_palette(VncState *vs, int x, int y,
200 aa7d73fd Corentin Chary
                              size_t count, uint32_t *bg, uint32_t *fg,
201 aa7d73fd Corentin Chary
                              struct QDict **palette)
202 aa7d73fd Corentin Chary
{
203 aa7d73fd Corentin Chary
    int max;
204 aa7d73fd Corentin Chary
205 aa7d73fd Corentin Chary
    max = count / tight_conf[vs->tight_compression].idx_max_colors_divisor;
206 aa7d73fd Corentin Chary
    if (max < 2 &&
207 aa7d73fd Corentin Chary
        count >= tight_conf[vs->tight_compression].mono_min_rect_size) {
208 aa7d73fd Corentin Chary
        max = 2;
209 aa7d73fd Corentin Chary
    }
210 aa7d73fd Corentin Chary
    if (max >= 256) {
211 aa7d73fd Corentin Chary
        max = 256;
212 aa7d73fd Corentin Chary
    }
213 aa7d73fd Corentin Chary
214 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
215 aa7d73fd Corentin Chary
    case 4:
216 aa7d73fd Corentin Chary
        return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
217 aa7d73fd Corentin Chary
    case 2:
218 aa7d73fd Corentin Chary
        return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette);
219 aa7d73fd Corentin Chary
    default:
220 aa7d73fd Corentin Chary
        max = 2;
221 aa7d73fd Corentin Chary
        return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette);
222 aa7d73fd Corentin Chary
    }
223 aa7d73fd Corentin Chary
    return 0;
224 aa7d73fd Corentin Chary
}
225 aa7d73fd Corentin Chary
226 aa7d73fd Corentin Chary
/* Callback to dump a palette with qdict_iter
227 aa7d73fd Corentin Chary
static void print_palette(const char *key, QObject *obj, void *opaque)
228 aa7d73fd Corentin Chary
{
229 aa7d73fd Corentin Chary
    uint8_t idx = qint_get_int(qobject_to_qint(obj));
230 aa7d73fd Corentin Chary
    uint32_t rgb = tight_palette_buf2rgb(32, (uint8_t *)key);
231 aa7d73fd Corentin Chary

232 aa7d73fd Corentin Chary
    fprintf(stderr, "%.2x ", (unsigned char)*key);
233 aa7d73fd Corentin Chary
    while (*key++)
234 aa7d73fd Corentin Chary
        fprintf(stderr, "%.2x ", (unsigned char)*key);
235 aa7d73fd Corentin Chary

236 aa7d73fd Corentin Chary
    fprintf(stderr, ": idx: %x rgb: %x\n", idx, rgb);
237 aa7d73fd Corentin Chary
}
238 aa7d73fd Corentin Chary
*/
239 aa7d73fd Corentin Chary
240 aa7d73fd Corentin Chary
/*
241 aa7d73fd Corentin Chary
 * Converting truecolor samples into palette indices.
242 aa7d73fd Corentin Chary
 */
243 aa7d73fd Corentin Chary
#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
244 aa7d73fd Corentin Chary
                                                                        \
245 aa7d73fd Corentin Chary
    static void                                                         \
246 aa7d73fd Corentin Chary
    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
247 aa7d73fd Corentin Chary
                                   struct QDict *palette) {             \
248 aa7d73fd Corentin Chary
        uint##bpp##_t *src;                                             \
249 aa7d73fd Corentin Chary
        uint##bpp##_t rgb;                                              \
250 aa7d73fd Corentin Chary
        uint8_t key[6];                                                 \
251 54d43eac Corentin Chary
        int i, rep;                                                     \
252 aa7d73fd Corentin Chary
        uint8_t idx;                                                    \
253 aa7d73fd Corentin Chary
                                                                        \
254 aa7d73fd Corentin Chary
        src = (uint##bpp##_t *) buf;                                    \
255 aa7d73fd Corentin Chary
                                                                        \
256 54d43eac Corentin Chary
        for (i = 0; i < count; i++) {                                   \
257 aa7d73fd Corentin Chary
            rgb = *src++;                                               \
258 aa7d73fd Corentin Chary
            rep = 0;                                                    \
259 54d43eac Corentin Chary
            while (i < count && *src == rgb) {                          \
260 54d43eac Corentin Chary
                rep++, src++, i++;                                      \
261 aa7d73fd Corentin Chary
            }                                                           \
262 aa7d73fd Corentin Chary
            tight_palette_rgb2buf(rgb, bpp, key);                       \
263 aa7d73fd Corentin Chary
            if (!qdict_haskey(palette, (char *)key)) {                  \
264 aa7d73fd Corentin Chary
                /*                                                      \
265 aa7d73fd Corentin Chary
                 * Should never happen, but don't break everything      \
266 aa7d73fd Corentin Chary
                 * if it does, use the first color instead              \
267 aa7d73fd Corentin Chary
                 */                                                     \
268 aa7d73fd Corentin Chary
                idx = 0;                                                \
269 aa7d73fd Corentin Chary
            } else {                                                    \
270 aa7d73fd Corentin Chary
                idx = qdict_get_int(palette, (char *)key);              \
271 aa7d73fd Corentin Chary
            }                                                           \
272 aa7d73fd Corentin Chary
            while (rep >= 0) {                                          \
273 aa7d73fd Corentin Chary
                *buf++ = idx;                                           \
274 aa7d73fd Corentin Chary
                rep--;                                                  \
275 aa7d73fd Corentin Chary
            }                                                           \
276 aa7d73fd Corentin Chary
        }                                                               \
277 aa7d73fd Corentin Chary
    }
278 aa7d73fd Corentin Chary
279 aa7d73fd Corentin Chary
DEFINE_IDX_ENCODE_FUNCTION(16)
280 aa7d73fd Corentin Chary
DEFINE_IDX_ENCODE_FUNCTION(32)
281 aa7d73fd Corentin Chary
282 aa7d73fd Corentin Chary
#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
283 aa7d73fd Corentin Chary
                                                                        \
284 aa7d73fd Corentin Chary
    static void                                                         \
285 aa7d73fd Corentin Chary
    tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h,             \
286 aa7d73fd Corentin Chary
                                uint##bpp##_t bg, uint##bpp##_t fg) {   \
287 aa7d73fd Corentin Chary
        uint##bpp##_t *ptr;                                             \
288 aa7d73fd Corentin Chary
        unsigned int value, mask;                                       \
289 aa7d73fd Corentin Chary
        int aligned_width;                                              \
290 aa7d73fd Corentin Chary
        int x, y, bg_bits;                                              \
291 aa7d73fd Corentin Chary
                                                                        \
292 aa7d73fd Corentin Chary
        ptr = (uint##bpp##_t *) buf;                                    \
293 aa7d73fd Corentin Chary
        aligned_width = w - w % 8;                                      \
294 aa7d73fd Corentin Chary
                                                                        \
295 aa7d73fd Corentin Chary
        for (y = 0; y < h; y++) {                                       \
296 aa7d73fd Corentin Chary
            for (x = 0; x < aligned_width; x += 8) {                    \
297 aa7d73fd Corentin Chary
                for (bg_bits = 0; bg_bits < 8; bg_bits++) {             \
298 aa7d73fd Corentin Chary
                    if (*ptr++ != bg) {                                 \
299 aa7d73fd Corentin Chary
                        break;                                          \
300 aa7d73fd Corentin Chary
                    }                                                   \
301 aa7d73fd Corentin Chary
                }                                                       \
302 aa7d73fd Corentin Chary
                if (bg_bits == 8) {                                     \
303 aa7d73fd Corentin Chary
                    *buf++ = 0;                                         \
304 aa7d73fd Corentin Chary
                    continue;                                           \
305 aa7d73fd Corentin Chary
                }                                                       \
306 aa7d73fd Corentin Chary
                mask = 0x80 >> bg_bits;                                 \
307 aa7d73fd Corentin Chary
                value = mask;                                           \
308 aa7d73fd Corentin Chary
                for (bg_bits++; bg_bits < 8; bg_bits++) {               \
309 aa7d73fd Corentin Chary
                    mask >>= 1;                                         \
310 aa7d73fd Corentin Chary
                    if (*ptr++ != bg) {                                 \
311 aa7d73fd Corentin Chary
                        value |= mask;                                  \
312 aa7d73fd Corentin Chary
                    }                                                   \
313 aa7d73fd Corentin Chary
                }                                                       \
314 aa7d73fd Corentin Chary
                *buf++ = (uint8_t)value;                                \
315 aa7d73fd Corentin Chary
            }                                                           \
316 aa7d73fd Corentin Chary
                                                                        \
317 aa7d73fd Corentin Chary
            mask = 0x80;                                                \
318 aa7d73fd Corentin Chary
            value = 0;                                                  \
319 aa7d73fd Corentin Chary
            if (x >= w) {                                               \
320 aa7d73fd Corentin Chary
                continue;                                               \
321 aa7d73fd Corentin Chary
            }                                                           \
322 aa7d73fd Corentin Chary
                                                                        \
323 aa7d73fd Corentin Chary
            for (; x < w; x++) {                                        \
324 aa7d73fd Corentin Chary
                if (*ptr++ != bg) {                                     \
325 aa7d73fd Corentin Chary
                    value |= mask;                                      \
326 aa7d73fd Corentin Chary
                }                                                       \
327 aa7d73fd Corentin Chary
                mask >>= 1;                                             \
328 aa7d73fd Corentin Chary
            }                                                           \
329 aa7d73fd Corentin Chary
            *buf++ = (uint8_t)value;                                    \
330 aa7d73fd Corentin Chary
        }                                                               \
331 aa7d73fd Corentin Chary
    }
332 aa7d73fd Corentin Chary
333 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(8)
334 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(16)
335 aa7d73fd Corentin Chary
DEFINE_MONO_ENCODE_FUNCTION(32)
336 aa7d73fd Corentin Chary
337 aa7d73fd Corentin Chary
/*
338 b4bea3f2 Corentin Chary
 * Check if a rectangle is all of the same color. If needSameColor is
339 b4bea3f2 Corentin Chary
 * set to non-zero, then also check that its color equals to the
340 b4bea3f2 Corentin Chary
 * *colorPtr value. The result is 1 if the test is successfull, and in
341 b4bea3f2 Corentin Chary
 * that case new color will be stored in *colorPtr.
342 b4bea3f2 Corentin Chary
 */
343 b4bea3f2 Corentin Chary
344 b4bea3f2 Corentin Chary
#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                \
345 b4bea3f2 Corentin Chary
                                                                        \
346 b4bea3f2 Corentin Chary
    static bool                                                         \
347 b4bea3f2 Corentin Chary
    check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h,     \
348 b4bea3f2 Corentin Chary
                          uint32_t* color, bool samecolor)              \
349 b4bea3f2 Corentin Chary
    {                                                                   \
350 b4bea3f2 Corentin Chary
        VncDisplay *vd = vs->vd;                                        \
351 b4bea3f2 Corentin Chary
        uint##bpp##_t *fbptr;                                           \
352 b4bea3f2 Corentin Chary
        uint##bpp##_t c;                                                \
353 b4bea3f2 Corentin Chary
        int dx, dy;                                                     \
354 b4bea3f2 Corentin Chary
                                                                        \
355 b4bea3f2 Corentin Chary
        fbptr = (uint##bpp##_t *)                                       \
356 b4bea3f2 Corentin Chary
            (vd->server->data + y * ds_get_linesize(vs->ds) +           \
357 b4bea3f2 Corentin Chary
             x * ds_get_bytes_per_pixel(vs->ds));                       \
358 b4bea3f2 Corentin Chary
                                                                        \
359 b4bea3f2 Corentin Chary
        c = *fbptr;                                                     \
360 b4bea3f2 Corentin Chary
        if (samecolor && (uint32_t)c != *color) {                       \
361 b4bea3f2 Corentin Chary
            return false;                                               \
362 b4bea3f2 Corentin Chary
        }                                                               \
363 b4bea3f2 Corentin Chary
                                                                        \
364 b4bea3f2 Corentin Chary
        for (dy = 0; dy < h; dy++) {                                    \
365 b4bea3f2 Corentin Chary
            for (dx = 0; dx < w; dx++) {                                \
366 b4bea3f2 Corentin Chary
                if (c != fbptr[dx]) {                                   \
367 b4bea3f2 Corentin Chary
                    return false;                                       \
368 b4bea3f2 Corentin Chary
                }                                                       \
369 b4bea3f2 Corentin Chary
            }                                                           \
370 b4bea3f2 Corentin Chary
            fbptr = (uint##bpp##_t *)                                   \
371 b4bea3f2 Corentin Chary
                ((uint8_t *)fbptr + ds_get_linesize(vs->ds));           \
372 b4bea3f2 Corentin Chary
        }                                                               \
373 b4bea3f2 Corentin Chary
                                                                        \
374 b4bea3f2 Corentin Chary
        *color = (uint32_t)c;                                           \
375 b4bea3f2 Corentin Chary
        return true;                                                    \
376 b4bea3f2 Corentin Chary
    }
377 b4bea3f2 Corentin Chary
378 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(32)
379 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(16)
380 b4bea3f2 Corentin Chary
DEFINE_CHECK_SOLID_FUNCTION(8)
381 b4bea3f2 Corentin Chary
382 b4bea3f2 Corentin Chary
static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
383 b4bea3f2 Corentin Chary
                             uint32_t* color, bool samecolor)
384 b4bea3f2 Corentin Chary
{
385 b4bea3f2 Corentin Chary
    VncDisplay *vd = vs->vd;
386 b4bea3f2 Corentin Chary
387 b4bea3f2 Corentin Chary
    switch(vd->server->pf.bytes_per_pixel) {
388 b4bea3f2 Corentin Chary
    case 4:
389 b4bea3f2 Corentin Chary
        return check_solid_tile32(vs, x, y, w, h, color, samecolor);
390 b4bea3f2 Corentin Chary
    case 2:
391 b4bea3f2 Corentin Chary
        return check_solid_tile16(vs, x, y, w, h, color, samecolor);
392 b4bea3f2 Corentin Chary
    default:
393 b4bea3f2 Corentin Chary
        return check_solid_tile8(vs, x, y, w, h, color, samecolor);
394 b4bea3f2 Corentin Chary
    }
395 b4bea3f2 Corentin Chary
}
396 b4bea3f2 Corentin Chary
397 b4bea3f2 Corentin Chary
static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
398 b4bea3f2 Corentin Chary
                                 uint32_t color, int *w_ptr, int *h_ptr)
399 b4bea3f2 Corentin Chary
{
400 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
401 b4bea3f2 Corentin Chary
    int w_prev;
402 b4bea3f2 Corentin Chary
    int w_best = 0, h_best = 0;
403 b4bea3f2 Corentin Chary
404 b4bea3f2 Corentin Chary
    w_prev = w;
405 b4bea3f2 Corentin Chary
406 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
407 b4bea3f2 Corentin Chary
408 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy);
409 b4bea3f2 Corentin Chary
        dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev);
410 b4bea3f2 Corentin Chary
411 b4bea3f2 Corentin Chary
        if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) {
412 b4bea3f2 Corentin Chary
            break;
413 b4bea3f2 Corentin Chary
        }
414 b4bea3f2 Corentin Chary
415 b4bea3f2 Corentin Chary
        for (dx = x + dw; dx < x + w_prev;) {
416 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx);
417 b4bea3f2 Corentin Chary
418 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) {
419 b4bea3f2 Corentin Chary
                break;
420 b4bea3f2 Corentin Chary
            }
421 b4bea3f2 Corentin Chary
            dx += dw;
422 b4bea3f2 Corentin Chary
        }
423 b4bea3f2 Corentin Chary
424 b4bea3f2 Corentin Chary
        w_prev = dx - x;
425 b4bea3f2 Corentin Chary
        if (w_prev * (dy + dh - y) > w_best * h_best) {
426 b4bea3f2 Corentin Chary
            w_best = w_prev;
427 b4bea3f2 Corentin Chary
            h_best = dy + dh - y;
428 b4bea3f2 Corentin Chary
        }
429 b4bea3f2 Corentin Chary
    }
430 b4bea3f2 Corentin Chary
431 b4bea3f2 Corentin Chary
    *w_ptr = w_best;
432 b4bea3f2 Corentin Chary
    *h_ptr = h_best;
433 b4bea3f2 Corentin Chary
}
434 b4bea3f2 Corentin Chary
435 b4bea3f2 Corentin Chary
static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
436 b4bea3f2 Corentin Chary
                              uint32_t color, int *x_ptr, int *y_ptr,
437 b4bea3f2 Corentin Chary
                              int *w_ptr, int *h_ptr)
438 b4bea3f2 Corentin Chary
{
439 b4bea3f2 Corentin Chary
    int cx, cy;
440 b4bea3f2 Corentin Chary
441 b4bea3f2 Corentin Chary
    /* Try to extend the area upwards. */
442 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr - 1;
443 b4bea3f2 Corentin Chary
          cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
444 b4bea3f2 Corentin Chary
          cy-- );
445 b4bea3f2 Corentin Chary
    *h_ptr += *y_ptr - (cy + 1);
446 b4bea3f2 Corentin Chary
    *y_ptr = cy + 1;
447 b4bea3f2 Corentin Chary
448 b4bea3f2 Corentin Chary
    /* ... downwards. */
449 b4bea3f2 Corentin Chary
    for ( cy = *y_ptr + *h_ptr;
450 b4bea3f2 Corentin Chary
          cy < y + h &&
451 b4bea3f2 Corentin Chary
              check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true);
452 b4bea3f2 Corentin Chary
          cy++ );
453 b4bea3f2 Corentin Chary
    *h_ptr += cy - (*y_ptr + *h_ptr);
454 b4bea3f2 Corentin Chary
455 b4bea3f2 Corentin Chary
    /* ... to the left. */
456 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr - 1;
457 b4bea3f2 Corentin Chary
          cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
458 b4bea3f2 Corentin Chary
          cx-- );
459 b4bea3f2 Corentin Chary
    *w_ptr += *x_ptr - (cx + 1);
460 b4bea3f2 Corentin Chary
    *x_ptr = cx + 1;
461 b4bea3f2 Corentin Chary
462 b4bea3f2 Corentin Chary
    /* ... to the right. */
463 b4bea3f2 Corentin Chary
    for ( cx = *x_ptr + *w_ptr;
464 b4bea3f2 Corentin Chary
          cx < x + w &&
465 b4bea3f2 Corentin Chary
              check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true);
466 b4bea3f2 Corentin Chary
          cx++ );
467 b4bea3f2 Corentin Chary
    *w_ptr += cx - (*x_ptr + *w_ptr);
468 b4bea3f2 Corentin Chary
}
469 b4bea3f2 Corentin Chary
470 380282b0 Corentin Chary
static int tight_init_stream(VncState *vs, int stream_id,
471 380282b0 Corentin Chary
                             int level, int strategy)
472 380282b0 Corentin Chary
{
473 380282b0 Corentin Chary
    z_streamp zstream = &vs->tight_stream[stream_id];
474 380282b0 Corentin Chary
475 380282b0 Corentin Chary
    if (zstream->opaque == NULL) {
476 380282b0 Corentin Chary
        int err;
477 380282b0 Corentin Chary
478 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
479 380282b0 Corentin Chary
        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
480 380282b0 Corentin Chary
        zstream->zalloc = vnc_zlib_zalloc;
481 380282b0 Corentin Chary
        zstream->zfree = vnc_zlib_zfree;
482 380282b0 Corentin Chary
483 380282b0 Corentin Chary
        err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
484 380282b0 Corentin Chary
                           MAX_MEM_LEVEL, strategy);
485 380282b0 Corentin Chary
486 380282b0 Corentin Chary
        if (err != Z_OK) {
487 380282b0 Corentin Chary
            fprintf(stderr, "VNC: error initializing zlib\n");
488 380282b0 Corentin Chary
            return -1;
489 380282b0 Corentin Chary
        }
490 380282b0 Corentin Chary
491 380282b0 Corentin Chary
        vs->tight_levels[stream_id] = level;
492 380282b0 Corentin Chary
        zstream->opaque = vs;
493 380282b0 Corentin Chary
    }
494 380282b0 Corentin Chary
495 380282b0 Corentin Chary
    if (vs->tight_levels[stream_id] != level) {
496 380282b0 Corentin Chary
        if (deflateParams(zstream, level, strategy) != Z_OK) {
497 380282b0 Corentin Chary
            return -1;
498 380282b0 Corentin Chary
        }
499 380282b0 Corentin Chary
        vs->tight_levels[stream_id] = level;
500 380282b0 Corentin Chary
    }
501 380282b0 Corentin Chary
    return 0;
502 380282b0 Corentin Chary
}
503 380282b0 Corentin Chary
504 380282b0 Corentin Chary
static void tight_send_compact_size(VncState *vs, size_t len)
505 380282b0 Corentin Chary
{
506 380282b0 Corentin Chary
    int lpc = 0;
507 380282b0 Corentin Chary
    int bytes = 0;
508 380282b0 Corentin Chary
    char buf[3] = {0, 0, 0};
509 380282b0 Corentin Chary
510 380282b0 Corentin Chary
    buf[bytes++] = len & 0x7F;
511 380282b0 Corentin Chary
    if (len > 0x7F) {
512 380282b0 Corentin Chary
        buf[bytes-1] |= 0x80;
513 380282b0 Corentin Chary
        buf[bytes++] = (len >> 7) & 0x7F;
514 380282b0 Corentin Chary
        if (len > 0x3FFF) {
515 380282b0 Corentin Chary
            buf[bytes-1] |= 0x80;
516 380282b0 Corentin Chary
            buf[bytes++] = (len >> 14) & 0xFF;
517 380282b0 Corentin Chary
        }
518 380282b0 Corentin Chary
    }
519 b4bea3f2 Corentin Chary
    for (lpc = 0; lpc < bytes; lpc++) {
520 380282b0 Corentin Chary
        vnc_write_u8(vs, buf[lpc]);
521 380282b0 Corentin Chary
    }
522 380282b0 Corentin Chary
}
523 380282b0 Corentin Chary
524 380282b0 Corentin Chary
static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
525 380282b0 Corentin Chary
                               int level, int strategy)
526 380282b0 Corentin Chary
{
527 380282b0 Corentin Chary
    z_streamp zstream = &vs->tight_stream[stream_id];
528 380282b0 Corentin Chary
    int previous_out;
529 380282b0 Corentin Chary
530 380282b0 Corentin Chary
    if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
531 380282b0 Corentin Chary
        vnc_write(vs, vs->tight.buffer, vs->tight.offset);
532 380282b0 Corentin Chary
        return bytes;
533 380282b0 Corentin Chary
    }
534 380282b0 Corentin Chary
535 380282b0 Corentin Chary
    if (tight_init_stream(vs, stream_id, level, strategy)) {
536 380282b0 Corentin Chary
        return -1;
537 380282b0 Corentin Chary
    }
538 380282b0 Corentin Chary
539 380282b0 Corentin Chary
    /* reserve memory in output buffer */
540 380282b0 Corentin Chary
    buffer_reserve(&vs->tight_zlib, bytes + 64);
541 380282b0 Corentin Chary
542 380282b0 Corentin Chary
    /* set pointers */
543 380282b0 Corentin Chary
    zstream->next_in = vs->tight.buffer;
544 380282b0 Corentin Chary
    zstream->avail_in = vs->tight.offset;
545 380282b0 Corentin Chary
    zstream->next_out = vs->tight_zlib.buffer + vs->tight_zlib.offset;
546 380282b0 Corentin Chary
    zstream->avail_out = vs->tight_zlib.capacity - vs->tight_zlib.offset;
547 380282b0 Corentin Chary
    zstream->data_type = Z_BINARY;
548 380282b0 Corentin Chary
    previous_out = zstream->total_out;
549 380282b0 Corentin Chary
550 380282b0 Corentin Chary
    /* start encoding */
551 380282b0 Corentin Chary
    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
552 380282b0 Corentin Chary
        fprintf(stderr, "VNC: error during tight compression\n");
553 380282b0 Corentin Chary
        return -1;
554 380282b0 Corentin Chary
    }
555 380282b0 Corentin Chary
556 380282b0 Corentin Chary
    vs->tight_zlib.offset = vs->tight_zlib.capacity - zstream->avail_out;
557 380282b0 Corentin Chary
    bytes = zstream->total_out - previous_out;
558 380282b0 Corentin Chary
559 380282b0 Corentin Chary
    tight_send_compact_size(vs, bytes);
560 380282b0 Corentin Chary
    vnc_write(vs, vs->tight_zlib.buffer, bytes);
561 380282b0 Corentin Chary
562 380282b0 Corentin Chary
    buffer_reset(&vs->tight_zlib);
563 380282b0 Corentin Chary
564 380282b0 Corentin Chary
    return bytes;
565 380282b0 Corentin Chary
}
566 380282b0 Corentin Chary
567 380282b0 Corentin Chary
/*
568 380282b0 Corentin Chary
 * Subencoding implementations.
569 380282b0 Corentin Chary
 */
570 aa7d73fd Corentin Chary
static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
571 380282b0 Corentin Chary
{
572 380282b0 Corentin Chary
    uint32_t *buf32;
573 380282b0 Corentin Chary
    uint32_t pix;
574 380282b0 Corentin Chary
    int rshift, gshift, bshift;
575 380282b0 Corentin Chary
576 380282b0 Corentin Chary
    buf32 = (uint32_t *)buf;
577 380282b0 Corentin Chary
578 380282b0 Corentin Chary
    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
579 380282b0 Corentin Chary
        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
580 380282b0 Corentin Chary
        rshift = vs->clientds.pf.rshift;
581 380282b0 Corentin Chary
        gshift = vs->clientds.pf.gshift;
582 380282b0 Corentin Chary
        bshift = vs->clientds.pf.bshift;
583 380282b0 Corentin Chary
    } else {
584 380282b0 Corentin Chary
        rshift = 24 - vs->clientds.pf.rshift;
585 380282b0 Corentin Chary
        gshift = 24 - vs->clientds.pf.gshift;
586 380282b0 Corentin Chary
        bshift = 24 - vs->clientds.pf.bshift;
587 380282b0 Corentin Chary
    }
588 380282b0 Corentin Chary
589 aa7d73fd Corentin Chary
    if (ret) {
590 aa7d73fd Corentin Chary
        *ret = count * 3;
591 aa7d73fd Corentin Chary
    }
592 380282b0 Corentin Chary
593 380282b0 Corentin Chary
    while (count--) {
594 380282b0 Corentin Chary
        pix = *buf32++;
595 380282b0 Corentin Chary
        *buf++ = (char)(pix >> rshift);
596 380282b0 Corentin Chary
        *buf++ = (char)(pix >> gshift);
597 380282b0 Corentin Chary
        *buf++ = (char)(pix >> bshift);
598 380282b0 Corentin Chary
    }
599 380282b0 Corentin Chary
}
600 380282b0 Corentin Chary
601 380282b0 Corentin Chary
static int send_full_color_rect(VncState *vs, int w, int h)
602 380282b0 Corentin Chary
{
603 380282b0 Corentin Chary
    int stream = 0;
604 380282b0 Corentin Chary
    size_t bytes;
605 380282b0 Corentin Chary
606 380282b0 Corentin Chary
    vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
607 380282b0 Corentin Chary
608 380282b0 Corentin Chary
    if (vs->tight_pixel24) {
609 aa7d73fd Corentin Chary
        tight_pack24(vs, vs->tight.buffer, w * h, &vs->tight.offset);
610 380282b0 Corentin Chary
        bytes = 3;
611 380282b0 Corentin Chary
    } else {
612 380282b0 Corentin Chary
        bytes = vs->clientds.pf.bytes_per_pixel;
613 380282b0 Corentin Chary
    }
614 380282b0 Corentin Chary
615 380282b0 Corentin Chary
    bytes = tight_compress_data(vs, stream, w * h * bytes,
616 380282b0 Corentin Chary
                                tight_conf[vs->tight_compression].raw_zlib_level,
617 380282b0 Corentin Chary
                                Z_DEFAULT_STRATEGY);
618 380282b0 Corentin Chary
619 380282b0 Corentin Chary
    return (bytes >= 0);
620 380282b0 Corentin Chary
}
621 380282b0 Corentin Chary
622 b4bea3f2 Corentin Chary
static int send_solid_rect(VncState *vs)
623 b4bea3f2 Corentin Chary
{
624 b4bea3f2 Corentin Chary
    size_t bytes;
625 b4bea3f2 Corentin Chary
626 b4bea3f2 Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
627 b4bea3f2 Corentin Chary
628 b4bea3f2 Corentin Chary
    if (vs->tight_pixel24) {
629 aa7d73fd Corentin Chary
        tight_pack24(vs, vs->tight.buffer, 1, &vs->tight.offset);
630 b4bea3f2 Corentin Chary
        bytes = 3;
631 b4bea3f2 Corentin Chary
    } else {
632 b4bea3f2 Corentin Chary
        bytes = vs->clientds.pf.bytes_per_pixel;
633 b4bea3f2 Corentin Chary
    }
634 b4bea3f2 Corentin Chary
635 b4bea3f2 Corentin Chary
    vnc_write(vs, vs->tight.buffer, bytes);
636 b4bea3f2 Corentin Chary
    return 1;
637 b4bea3f2 Corentin Chary
}
638 b4bea3f2 Corentin Chary
639 aa7d73fd Corentin Chary
static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
640 aa7d73fd Corentin Chary
{
641 aa7d73fd Corentin Chary
    size_t bytes;
642 aa7d73fd Corentin Chary
    int stream = 1;
643 aa7d73fd Corentin Chary
    int level = tight_conf[vs->tight_compression].mono_zlib_level;
644 aa7d73fd Corentin Chary
645 aa7d73fd Corentin Chary
    bytes = ((w + 7) / 8) * h;
646 aa7d73fd Corentin Chary
647 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
648 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
649 aa7d73fd Corentin Chary
    vnc_write_u8(vs, 1);
650 aa7d73fd Corentin Chary
651 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
652 aa7d73fd Corentin Chary
    case 4:
653 aa7d73fd Corentin Chary
    {
654 aa7d73fd Corentin Chary
        uint32_t buf[2] = {bg, fg};
655 aa7d73fd Corentin Chary
        size_t ret = sizeof (buf);
656 aa7d73fd Corentin Chary
657 aa7d73fd Corentin Chary
        if (vs->tight_pixel24) {
658 aa7d73fd Corentin Chary
            tight_pack24(vs, (unsigned char*)buf, 2, &ret);
659 aa7d73fd Corentin Chary
        }
660 aa7d73fd Corentin Chary
        vnc_write(vs, buf, ret);
661 aa7d73fd Corentin Chary
662 aa7d73fd Corentin Chary
        tight_encode_mono_rect32(vs->tight.buffer, w, h, bg, fg);
663 aa7d73fd Corentin Chary
        break;
664 aa7d73fd Corentin Chary
    }
665 aa7d73fd Corentin Chary
    case 2:
666 aa7d73fd Corentin Chary
        vnc_write(vs, &bg, 2);
667 aa7d73fd Corentin Chary
        vnc_write(vs, &fg, 2);
668 aa7d73fd Corentin Chary
        tight_encode_mono_rect16(vs->tight.buffer, w, h, bg, fg);
669 aa7d73fd Corentin Chary
        break;
670 aa7d73fd Corentin Chary
    default:
671 aa7d73fd Corentin Chary
        vnc_write_u8(vs, bg);
672 aa7d73fd Corentin Chary
        vnc_write_u8(vs, fg);
673 aa7d73fd Corentin Chary
        tight_encode_mono_rect8(vs->tight.buffer, w, h, bg, fg);
674 aa7d73fd Corentin Chary
        break;
675 aa7d73fd Corentin Chary
    }
676 aa7d73fd Corentin Chary
    vs->tight.offset = bytes;
677 aa7d73fd Corentin Chary
678 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
679 aa7d73fd Corentin Chary
    return (bytes >= 0);
680 aa7d73fd Corentin Chary
}
681 aa7d73fd Corentin Chary
682 aa7d73fd Corentin Chary
struct palette_cb_priv {
683 aa7d73fd Corentin Chary
    VncState *vs;
684 aa7d73fd Corentin Chary
    uint8_t *header;
685 aa7d73fd Corentin Chary
};
686 aa7d73fd Corentin Chary
687 aa7d73fd Corentin Chary
static void write_palette(const char *key, QObject *obj, void *opaque)
688 aa7d73fd Corentin Chary
{
689 aa7d73fd Corentin Chary
    struct palette_cb_priv *priv = opaque;
690 aa7d73fd Corentin Chary
    VncState *vs = priv->vs;
691 aa7d73fd Corentin Chary
    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
692 aa7d73fd Corentin Chary
    uint8_t idx = qint_get_int(qobject_to_qint(obj));
693 aa7d73fd Corentin Chary
694 aa7d73fd Corentin Chary
    if (bytes == 4) {
695 aa7d73fd Corentin Chary
        uint32_t color = tight_palette_buf2rgb(32, (uint8_t *)key);
696 aa7d73fd Corentin Chary
697 aa7d73fd Corentin Chary
        ((uint32_t*)priv->header)[idx] = color;
698 aa7d73fd Corentin Chary
    } else {
699 aa7d73fd Corentin Chary
        uint16_t color = tight_palette_buf2rgb(16, (uint8_t *)key);
700 aa7d73fd Corentin Chary
701 aa7d73fd Corentin Chary
        ((uint16_t*)priv->header)[idx] = color;
702 aa7d73fd Corentin Chary
    }
703 aa7d73fd Corentin Chary
}
704 aa7d73fd Corentin Chary
705 aa7d73fd Corentin Chary
static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
706 aa7d73fd Corentin Chary
{
707 aa7d73fd Corentin Chary
    int stream = 2;
708 aa7d73fd Corentin Chary
    int level = tight_conf[vs->tight_compression].idx_zlib_level;
709 aa7d73fd Corentin Chary
    int colors;
710 aa7d73fd Corentin Chary
    size_t bytes;
711 aa7d73fd Corentin Chary
712 aa7d73fd Corentin Chary
    colors = qdict_size(palette);
713 aa7d73fd Corentin Chary
714 aa7d73fd Corentin Chary
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
715 aa7d73fd Corentin Chary
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
716 aa7d73fd Corentin Chary
    vnc_write_u8(vs, colors - 1);
717 aa7d73fd Corentin Chary
718 aa7d73fd Corentin Chary
    switch(vs->clientds.pf.bytes_per_pixel) {
719 aa7d73fd Corentin Chary
    case 4:
720 aa7d73fd Corentin Chary
    {
721 aa7d73fd Corentin Chary
        size_t old_offset, offset;
722 aa7d73fd Corentin Chary
        uint32_t header[qdict_size(palette)];
723 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
724 aa7d73fd Corentin Chary
725 aa7d73fd Corentin Chary
        old_offset = vs->output.offset;
726 aa7d73fd Corentin Chary
        qdict_iter(palette, write_palette, &priv);
727 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
728 aa7d73fd Corentin Chary
729 aa7d73fd Corentin Chary
        if (vs->tight_pixel24) {
730 aa7d73fd Corentin Chary
            tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
731 aa7d73fd Corentin Chary
            vs->output.offset = old_offset + offset;
732 aa7d73fd Corentin Chary
        }
733 aa7d73fd Corentin Chary
734 aa7d73fd Corentin Chary
        tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
735 aa7d73fd Corentin Chary
        break;
736 aa7d73fd Corentin Chary
    }
737 aa7d73fd Corentin Chary
    case 2:
738 aa7d73fd Corentin Chary
    {
739 aa7d73fd Corentin Chary
        uint16_t header[qdict_size(palette)];
740 aa7d73fd Corentin Chary
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
741 aa7d73fd Corentin Chary
742 aa7d73fd Corentin Chary
        qdict_iter(palette, write_palette, &priv);
743 aa7d73fd Corentin Chary
        vnc_write(vs, header, sizeof(header));
744 aa7d73fd Corentin Chary
        tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
745 aa7d73fd Corentin Chary
        break;
746 aa7d73fd Corentin Chary
    }
747 aa7d73fd Corentin Chary
    default:
748 aa7d73fd Corentin Chary
        return -1; /* No palette for 8bits colors */
749 aa7d73fd Corentin Chary
        break;
750 aa7d73fd Corentin Chary
    }
751 aa7d73fd Corentin Chary
    bytes = w * h;
752 aa7d73fd Corentin Chary
    vs->tight.offset = bytes;
753 aa7d73fd Corentin Chary
754 aa7d73fd Corentin Chary
    bytes = tight_compress_data(vs, stream, bytes,
755 aa7d73fd Corentin Chary
                                level, Z_DEFAULT_STRATEGY);
756 aa7d73fd Corentin Chary
    return (bytes >= 0);
757 aa7d73fd Corentin Chary
}
758 aa7d73fd Corentin Chary
759 380282b0 Corentin Chary
static void vnc_tight_start(VncState *vs)
760 380282b0 Corentin Chary
{
761 380282b0 Corentin Chary
    buffer_reset(&vs->tight);
762 380282b0 Corentin Chary
763 380282b0 Corentin Chary
    // make the output buffer be the zlib buffer, so we can compress it later
764 380282b0 Corentin Chary
    vs->tight_tmp = vs->output;
765 380282b0 Corentin Chary
    vs->output = vs->tight;
766 380282b0 Corentin Chary
}
767 380282b0 Corentin Chary
768 380282b0 Corentin Chary
static void vnc_tight_stop(VncState *vs)
769 380282b0 Corentin Chary
{
770 380282b0 Corentin Chary
    // switch back to normal output/zlib buffers
771 380282b0 Corentin Chary
    vs->tight = vs->output;
772 380282b0 Corentin Chary
    vs->output = vs->tight_tmp;
773 380282b0 Corentin Chary
}
774 380282b0 Corentin Chary
775 380282b0 Corentin Chary
static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
776 380282b0 Corentin Chary
{
777 aa7d73fd Corentin Chary
    struct QDict *palette = NULL;
778 aa7d73fd Corentin Chary
    uint32_t bg = 0, fg = 0;
779 aa7d73fd Corentin Chary
    int colors;
780 aa7d73fd Corentin Chary
    int ret = 0;
781 aa7d73fd Corentin Chary
782 380282b0 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
783 380282b0 Corentin Chary
784 380282b0 Corentin Chary
    vnc_tight_start(vs);
785 380282b0 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
786 380282b0 Corentin Chary
    vnc_tight_stop(vs);
787 380282b0 Corentin Chary
788 aa7d73fd Corentin Chary
    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
789 aa7d73fd Corentin Chary
790 aa7d73fd Corentin Chary
    if (colors == 0) {
791 aa7d73fd Corentin Chary
        ret = send_full_color_rect(vs, w, h);
792 aa7d73fd Corentin Chary
    } else if (colors == 1) {
793 aa7d73fd Corentin Chary
        ret = send_solid_rect(vs);
794 aa7d73fd Corentin Chary
    } else if (colors == 2) {
795 aa7d73fd Corentin Chary
        ret = send_mono_rect(vs, w, h, bg, fg);
796 aa7d73fd Corentin Chary
    } else if (colors <= 256) {
797 aa7d73fd Corentin Chary
        ret = send_palette_rect(vs, w, h, palette);
798 aa7d73fd Corentin Chary
    }
799 aa7d73fd Corentin Chary
    QDECREF(palette);
800 aa7d73fd Corentin Chary
    return ret;
801 380282b0 Corentin Chary
}
802 380282b0 Corentin Chary
803 b4bea3f2 Corentin Chary
static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
804 b4bea3f2 Corentin Chary
{
805 b4bea3f2 Corentin Chary
    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
806 b4bea3f2 Corentin Chary
807 b4bea3f2 Corentin Chary
    vnc_tight_start(vs);
808 b4bea3f2 Corentin Chary
    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
809 b4bea3f2 Corentin Chary
    vnc_tight_stop(vs);
810 b4bea3f2 Corentin Chary
811 b4bea3f2 Corentin Chary
    return send_solid_rect(vs);
812 b4bea3f2 Corentin Chary
}
813 b4bea3f2 Corentin Chary
814 380282b0 Corentin Chary
static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
815 380282b0 Corentin Chary
{
816 380282b0 Corentin Chary
    int max_size, max_width;
817 380282b0 Corentin Chary
    int max_sub_width, max_sub_height;
818 380282b0 Corentin Chary
    int dx, dy;
819 380282b0 Corentin Chary
    int rw, rh;
820 380282b0 Corentin Chary
    int n = 0;
821 380282b0 Corentin Chary
822 380282b0 Corentin Chary
    max_size = tight_conf[vs->tight_compression].max_rect_size;
823 380282b0 Corentin Chary
    max_width = tight_conf[vs->tight_compression].max_rect_width;
824 380282b0 Corentin Chary
825 380282b0 Corentin Chary
    if (w > max_width || w * h > max_size) {
826 380282b0 Corentin Chary
        max_sub_width = (w > max_width) ? max_width : w;
827 380282b0 Corentin Chary
        max_sub_height = max_size / max_sub_width;
828 380282b0 Corentin Chary
829 380282b0 Corentin Chary
        for (dy = 0; dy < h; dy += max_sub_height) {
830 380282b0 Corentin Chary
            for (dx = 0; dx < w; dx += max_width) {
831 380282b0 Corentin Chary
                rw = MIN(max_sub_width, w - dx);
832 380282b0 Corentin Chary
                rh = MIN(max_sub_height, h - dy);
833 380282b0 Corentin Chary
                n += send_sub_rect(vs, x+dx, y+dy, rw, rh);
834 380282b0 Corentin Chary
            }
835 380282b0 Corentin Chary
        }
836 380282b0 Corentin Chary
    } else {
837 380282b0 Corentin Chary
        n += send_sub_rect(vs, x, y, w, h);
838 380282b0 Corentin Chary
    }
839 380282b0 Corentin Chary
840 380282b0 Corentin Chary
    return n;
841 380282b0 Corentin Chary
}
842 380282b0 Corentin Chary
843 b4bea3f2 Corentin Chary
static int find_large_solid_color_rect(VncState *vs, int x, int y,
844 b4bea3f2 Corentin Chary
                                       int w, int h, int max_rows)
845 b4bea3f2 Corentin Chary
{
846 b4bea3f2 Corentin Chary
    int dx, dy, dw, dh;
847 b4bea3f2 Corentin Chary
    int n = 0;
848 b4bea3f2 Corentin Chary
849 b4bea3f2 Corentin Chary
    /* Try to find large solid-color areas and send them separately. */
850 b4bea3f2 Corentin Chary
851 b4bea3f2 Corentin Chary
    for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
852 b4bea3f2 Corentin Chary
853 b4bea3f2 Corentin Chary
        /* If a rectangle becomes too large, send its upper part now. */
854 b4bea3f2 Corentin Chary
855 b4bea3f2 Corentin Chary
        if (dy - y >= max_rows) {
856 b4bea3f2 Corentin Chary
            n += send_rect_simple(vs, x, y, w, max_rows);
857 b4bea3f2 Corentin Chary
            y += max_rows;
858 b4bea3f2 Corentin Chary
            h -= max_rows;
859 b4bea3f2 Corentin Chary
        }
860 b4bea3f2 Corentin Chary
861 b4bea3f2 Corentin Chary
        dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy));
862 b4bea3f2 Corentin Chary
863 b4bea3f2 Corentin Chary
        for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) {
864 b4bea3f2 Corentin Chary
            uint32_t color_value;
865 b4bea3f2 Corentin Chary
            int x_best, y_best, w_best, h_best;
866 b4bea3f2 Corentin Chary
867 b4bea3f2 Corentin Chary
            dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx));
868 b4bea3f2 Corentin Chary
869 b4bea3f2 Corentin Chary
            if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) {
870 b4bea3f2 Corentin Chary
                continue ;
871 b4bea3f2 Corentin Chary
            }
872 b4bea3f2 Corentin Chary
873 b4bea3f2 Corentin Chary
            /* Get dimensions of solid-color area. */
874 b4bea3f2 Corentin Chary
875 b4bea3f2 Corentin Chary
            find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y),
876 b4bea3f2 Corentin Chary
                                 color_value, &w_best, &h_best);
877 b4bea3f2 Corentin Chary
878 b4bea3f2 Corentin Chary
            /* Make sure a solid rectangle is large enough
879 b4bea3f2 Corentin Chary
               (or the whole rectangle is of the same color). */
880 b4bea3f2 Corentin Chary
881 b4bea3f2 Corentin Chary
            if (w_best * h_best != w * h &&
882 b4bea3f2 Corentin Chary
                w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) {
883 b4bea3f2 Corentin Chary
                continue;
884 b4bea3f2 Corentin Chary
            }
885 b4bea3f2 Corentin Chary
886 b4bea3f2 Corentin Chary
            /* Try to extend solid rectangle to maximum size. */
887 b4bea3f2 Corentin Chary
888 b4bea3f2 Corentin Chary
            x_best = dx; y_best = dy;
889 b4bea3f2 Corentin Chary
            extend_solid_area(vs, x, y, w, h, color_value,
890 b4bea3f2 Corentin Chary
                              &x_best, &y_best, &w_best, &h_best);
891 b4bea3f2 Corentin Chary
892 b4bea3f2 Corentin Chary
            /* Send rectangles at top and left to solid-color area. */
893 b4bea3f2 Corentin Chary
894 b4bea3f2 Corentin Chary
            if (y_best != y) {
895 b4bea3f2 Corentin Chary
                n += send_rect_simple(vs, x, y, w, y_best-y);
896 b4bea3f2 Corentin Chary
            }
897 b4bea3f2 Corentin Chary
            if (x_best != x) {
898 b4bea3f2 Corentin Chary
                n += vnc_tight_send_framebuffer_update(vs, x, y_best,
899 b4bea3f2 Corentin Chary
                                                       x_best-x, h_best);
900 b4bea3f2 Corentin Chary
            }
901 b4bea3f2 Corentin Chary
902 b4bea3f2 Corentin Chary
            /* Send solid-color rectangle. */
903 b4bea3f2 Corentin Chary
            n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best);
904 b4bea3f2 Corentin Chary
905 b4bea3f2 Corentin Chary
            /* Send remaining rectangles (at right and bottom). */
906 b4bea3f2 Corentin Chary
907 b4bea3f2 Corentin Chary
            if (x_best + w_best != x + w) {
908 b4bea3f2 Corentin Chary
                n += vnc_tight_send_framebuffer_update(vs, x_best+w_best,
909 b4bea3f2 Corentin Chary
                                                       y_best,
910 b4bea3f2 Corentin Chary
                                                       w-(x_best-x)-w_best,
911 b4bea3f2 Corentin Chary
                                                       h_best);
912 b4bea3f2 Corentin Chary
            }
913 b4bea3f2 Corentin Chary
            if (y_best + h_best != y + h) {
914 b4bea3f2 Corentin Chary
                n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best,
915 b4bea3f2 Corentin Chary
                                                       w, h-(y_best-y)-h_best);
916 b4bea3f2 Corentin Chary
            }
917 b4bea3f2 Corentin Chary
918 b4bea3f2 Corentin Chary
            /* Return after all recursive calls are done. */
919 b4bea3f2 Corentin Chary
            return n;
920 b4bea3f2 Corentin Chary
        }
921 b4bea3f2 Corentin Chary
    }
922 b4bea3f2 Corentin Chary
    return n + send_rect_simple(vs, x, y, w, h);
923 b4bea3f2 Corentin Chary
}
924 b4bea3f2 Corentin Chary
925 380282b0 Corentin Chary
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
926 380282b0 Corentin Chary
                                      int w, int h)
927 380282b0 Corentin Chary
{
928 b4bea3f2 Corentin Chary
    int max_rows;
929 b4bea3f2 Corentin Chary
930 380282b0 Corentin Chary
    if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
931 380282b0 Corentin Chary
        vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
932 380282b0 Corentin Chary
        vs->tight_pixel24 = true;
933 380282b0 Corentin Chary
    } else {
934 380282b0 Corentin Chary
        vs->tight_pixel24 = false;
935 380282b0 Corentin Chary
    }
936 380282b0 Corentin Chary
937 b4bea3f2 Corentin Chary
    if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE)
938 b4bea3f2 Corentin Chary
        return send_rect_simple(vs, x, y, w, h);
939 b4bea3f2 Corentin Chary
940 b4bea3f2 Corentin Chary
    /* Calculate maximum number of rows in one non-solid rectangle. */
941 b4bea3f2 Corentin Chary
942 b4bea3f2 Corentin Chary
    max_rows = tight_conf[vs->tight_compression].max_rect_size;
943 b4bea3f2 Corentin Chary
    max_rows /= MIN(tight_conf[vs->tight_compression].max_rect_width, w);
944 b4bea3f2 Corentin Chary
945 b4bea3f2 Corentin Chary
    return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
946 380282b0 Corentin Chary
}
947 380282b0 Corentin Chary
948 380282b0 Corentin Chary
void vnc_tight_clear(VncState *vs)
949 380282b0 Corentin Chary
{
950 380282b0 Corentin Chary
    int i;
951 380282b0 Corentin Chary
    for (i=0; i<ARRAY_SIZE(vs->tight_stream); i++) {
952 380282b0 Corentin Chary
        if (vs->tight_stream[i].opaque) {
953 380282b0 Corentin Chary
            deflateEnd(&vs->tight_stream[i]);
954 380282b0 Corentin Chary
        }
955 380282b0 Corentin Chary
    }
956 380282b0 Corentin Chary
957 380282b0 Corentin Chary
    buffer_free(&vs->tight);
958 380282b0 Corentin Chary
    buffer_free(&vs->tight_zlib);
959 380282b0 Corentin Chary
}