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

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

unix.superglobalmegacorp.com

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