Annotation of qemu/ui/vnc-enc-tight.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.