qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vnc-enc-tight.c (63197B)


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