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