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

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

unix.superglobalmegacorp.com

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