Home | History | Annotate | Download | only in libvncserver
      1 /*
      2  * tight.c
      3  *
      4  * Routines to implement Tight Encoding
      5  *
      6  * Our Tight encoder is based roughly on the TurboVNC v0.6 encoder with some
      7  * additional enhancements from TurboVNC 1.1.  For lower compression levels,
      8  * this encoder provides a tremendous reduction in CPU usage (and subsequently,
      9  * an increase in throughput for CPU-limited environments) relative to the
     10  * TightVNC encoder, whereas Compression Level 9 provides a low-bandwidth mode
     11  * that behaves similarly to Compression Levels 5-9 in the old TightVNC
     12  * encoder.
     13  */
     14 
     15 /*
     16  *  Copyright (C) 2010-2012 D. R. Commander.  All Rights Reserved.
     17  *  Copyright (C) 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
     18  *  Copyright (C) 2004 Landmark Graphics Corporation.  All Rights Reserved.
     19  *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
     20  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
     21  *
     22  *  This is free software; you can redistribute it and/or modify
     23  *  it under the terms of the GNU General Public License as published by
     24  *  the Free Software Foundation; either version 2 of the License, or
     25  *  (at your option) any later version.
     26  *
     27  *  This software is distributed in the hope that it will be useful,
     28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     30  *  GNU General Public License for more details.
     31  *
     32  *  You should have received a copy of the GNU General Public License
     33  *  along with this software; if not, write to the Free Software
     34  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
     35  *  USA.
     36  */
     37 
     38 #include <rfb/rfb.h>
     39 #include "private.h"
     40 
     41 #ifdef LIBVNCSERVER_HAVE_LIBPNG
     42 #include <png.h>
     43 #endif
     44 #include "turbojpeg.h"
     45 
     46 
     47 /* Note: The following constant should not be changed. */
     48 #define TIGHT_MIN_TO_COMPRESS 12
     49 
     50 /* The parameters below may be adjusted. */
     51 #define MIN_SPLIT_RECT_SIZE     4096
     52 #define MIN_SOLID_SUBRECT_SIZE  2048
     53 #define MAX_SPLIT_TILE_SIZE       16
     54 
     55 /*
     56  * There is so much access of the Tight encoding static data buffers
     57  * that we resort to using thread local storage instead of having
     58  * per-client data.
     59  */
     60 #if LIBVNCSERVER_HAVE_LIBPTHREAD && LIBVNCSERVER_HAVE_TLS && !defined(TLS) && defined(__linux__)
     61 #define TLS __thread
     62 #endif
     63 #ifndef TLS
     64 #define TLS
     65 #endif
     66 
     67 /* This variable is set on every rfbSendRectEncodingTight() call. */
     68 static TLS rfbBool usePixelFormat24 = FALSE;
     69 
     70 
     71 /* Compression level stuff. The following array contains various
     72    encoder parameters for each of 10 compression levels (0..9).
     73    Last three parameters correspond to JPEG quality levels (0..9). */
     74 
     75 typedef struct TIGHT_CONF_s {
     76     int maxRectSize, maxRectWidth;
     77     int monoMinRectSize;
     78     int idxZlibLevel, monoZlibLevel, rawZlibLevel;
     79     int idxMaxColorsDivisor;
     80     int palMaxColorsWithJPEG;
     81 } TIGHT_CONF;
     82 
     83 static TIGHT_CONF tightConf[4] = {
     84     { 65536, 2048,   6, 0, 0, 0,   4, 24 }, /* 0  (used only without JPEG) */
     85     { 65536, 2048,  32, 1, 1, 1,  96, 24 }, /* 1 */
     86     { 65536, 2048,  32, 3, 3, 2,  96, 96 }, /* 2  (used only with JPEG) */
     87     { 65536, 2048,  32, 7, 7, 5,  96, 256 } /* 9 */
     88 };
     89 
     90 #ifdef LIBVNCSERVER_HAVE_LIBPNG
     91 typedef struct TIGHT_PNG_CONF_s {
     92     int png_zlib_level, png_filters;
     93 } TIGHT_PNG_CONF;
     94 
     95 static TIGHT_PNG_CONF tightPngConf[10] = {
     96     { 0, PNG_NO_FILTERS },
     97     { 1, PNG_NO_FILTERS },
     98     { 2, PNG_NO_FILTERS },
     99     { 3, PNG_NO_FILTERS },
    100     { 4, PNG_NO_FILTERS },
    101     { 5, PNG_ALL_FILTERS },
    102     { 6, PNG_ALL_FILTERS },
    103     { 7, PNG_ALL_FILTERS },
    104     { 8, PNG_ALL_FILTERS },
    105     { 9, PNG_ALL_FILTERS },
    106 };
    107 #endif
    108 
    109 static TLS int compressLevel = 1;
    110 static TLS int qualityLevel = 95;
    111 static TLS int subsampLevel = TJ_444;
    112 
    113 static const int subsampLevel2tjsubsamp[4] = {
    114     TJ_444, TJ_420, TJ_422, TJ_GRAYSCALE
    115 };
    116 
    117 
    118 /* Stuff dealing with palettes. */
    119 
    120 typedef struct COLOR_LIST_s {
    121     struct COLOR_LIST_s *next;
    122     int idx;
    123     uint32_t rgb;
    124 } COLOR_LIST;
    125 
    126 typedef struct PALETTE_ENTRY_s {
    127     COLOR_LIST *listNode;
    128     int numPixels;
    129 } PALETTE_ENTRY;
    130 
    131 typedef struct PALETTE_s {
    132     PALETTE_ENTRY entry[256];
    133     COLOR_LIST *hash[256];
    134     COLOR_LIST list[256];
    135 } PALETTE;
    136 
    137 /* TODO: move into rfbScreen struct */
    138 static TLS int paletteNumColors = 0;
    139 static TLS int paletteMaxColors = 0;
    140 static TLS uint32_t monoBackground = 0;
    141 static TLS uint32_t monoForeground = 0;
    142 static TLS PALETTE palette;
    143 
    144 /* Pointers to dynamically-allocated buffers. */
    145 
    146 static TLS int tightBeforeBufSize = 0;
    147 static TLS char *tightBeforeBuf = NULL;
    148 
    149 static TLS int tightAfterBufSize = 0;
    150 static TLS char *tightAfterBuf = NULL;
    151 
    152 static TLS tjhandle j = NULL;
    153 
    154 void rfbTightCleanup (rfbScreenInfoPtr screen)
    155 {
    156     if (tightBeforeBufSize) {
    157         free (tightBeforeBuf);
    158         tightBeforeBufSize = 0;
    159         tightBeforeBuf = NULL;
    160     }
    161     if (tightAfterBufSize) {
    162         free (tightAfterBuf);
    163         tightAfterBufSize = 0;
    164         tightAfterBuf = NULL;
    165     }
    166     if (j) tjDestroy(j);
    167 }
    168 
    169 
    170 /* Prototypes for static functions. */
    171 
    172 static rfbBool SendRectEncodingTight(rfbClientPtr cl, int x, int y,
    173                                      int w, int h);
    174 static void FindBestSolidArea (rfbClientPtr cl, int x, int y, int w, int h,
    175                                uint32_t colorValue, int *w_ptr, int *h_ptr);
    176 static void ExtendSolidArea   (rfbClientPtr cl, int x, int y, int w, int h,
    177                                uint32_t colorValue,
    178                                int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
    179 static rfbBool CheckSolidTile    (rfbClientPtr cl, int x, int y, int w, int h,
    180                                   uint32_t *colorPtr, rfbBool needSameColor);
    181 static rfbBool CheckSolidTile8   (rfbClientPtr cl, int x, int y, int w, int h,
    182                                   uint32_t *colorPtr, rfbBool needSameColor);
    183 static rfbBool CheckSolidTile16  (rfbClientPtr cl, int x, int y, int w, int h,
    184                                   uint32_t *colorPtr, rfbBool needSameColor);
    185 static rfbBool CheckSolidTile32  (rfbClientPtr cl, int x, int y, int w, int h,
    186                                   uint32_t *colorPtr, rfbBool needSameColor);
    187 
    188 static rfbBool SendRectSimple    (rfbClientPtr cl, int x, int y, int w, int h);
    189 static rfbBool SendSubrect       (rfbClientPtr cl, int x, int y, int w, int h);
    190 static rfbBool SendTightHeader   (rfbClientPtr cl, int x, int y, int w, int h);
    191 
    192 static rfbBool SendSolidRect     (rfbClientPtr cl);
    193 static rfbBool SendMonoRect      (rfbClientPtr cl, int x, int y, int w, int h);
    194 static rfbBool SendIndexedRect   (rfbClientPtr cl, int x, int y, int w, int h);
    195 static rfbBool SendFullColorRect (rfbClientPtr cl, int x, int y, int w, int h);
    196 
    197 static rfbBool CompressData (rfbClientPtr cl, int streamId, int dataLen,
    198                              int zlibLevel, int zlibStrategy);
    199 static rfbBool SendCompressedData (rfbClientPtr cl, char *buf,
    200                                    int compressedLen);
    201 
    202 static void FillPalette8 (int count);
    203 static void FillPalette16 (int count);
    204 static void FillPalette32 (int count);
    205 static void FastFillPalette16 (rfbClientPtr cl, uint16_t *data, int w,
    206                                int pitch, int h);
    207 static void FastFillPalette32 (rfbClientPtr cl, uint32_t *data, int w,
    208                                int pitch, int h);
    209 
    210 static void PaletteReset (void);
    211 static int PaletteInsert (uint32_t rgb, int numPixels, int bpp);
    212 
    213 static void Pack24 (rfbClientPtr cl, char *buf, rfbPixelFormat *fmt,
    214                     int count);
    215 
    216 static void EncodeIndexedRect16 (uint8_t *buf, int count);
    217 static void EncodeIndexedRect32 (uint8_t *buf, int count);
    218 
    219 static void EncodeMonoRect8 (uint8_t *buf, int w, int h);
    220 static void EncodeMonoRect16 (uint8_t *buf, int w, int h);
    221 static void EncodeMonoRect32 (uint8_t *buf, int w, int h);
    222 
    223 static rfbBool SendJpegRect (rfbClientPtr cl, int x, int y, int w, int h,
    224                              int quality);
    225 static void PrepareRowForImg(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
    226 static void PrepareRowForImg24(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
    227 static void PrepareRowForImg16(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
    228 static void PrepareRowForImg32(rfbClientPtr cl, uint8_t *dst, int x, int y, int count);
    229 
    230 #ifdef LIBVNCSERVER_HAVE_LIBPNG
    231 static rfbBool SendPngRect(rfbClientPtr cl, int x, int y, int w, int h);
    232 static rfbBool CanSendPngRect(rfbClientPtr cl, int w, int h);
    233 #endif
    234 
    235 /*
    236  * Tight encoding implementation.
    237  */
    238 
    239 int
    240 rfbNumCodedRectsTight(rfbClientPtr cl,
    241                       int x,
    242                       int y,
    243                       int w,
    244                       int h)
    245 {
    246     int maxRectSize, maxRectWidth;
    247     int subrectMaxWidth, subrectMaxHeight;
    248 
    249     /* No matter how many rectangles we will send if LastRect markers
    250        are used to terminate rectangle stream. */
    251     if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
    252         return 0;
    253 
    254     maxRectSize = tightConf[compressLevel].maxRectSize;
    255     maxRectWidth = tightConf[compressLevel].maxRectWidth;
    256 
    257     if (w > maxRectWidth || w * h > maxRectSize) {
    258         subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    259         subrectMaxHeight = maxRectSize / subrectMaxWidth;
    260         return (((w - 1) / maxRectWidth + 1) *
    261                 ((h - 1) / subrectMaxHeight + 1));
    262     } else {
    263         return 1;
    264     }
    265 }
    266 
    267 rfbBool
    268 rfbSendRectEncodingTight(rfbClientPtr cl,
    269                          int x,
    270                          int y,
    271                          int w,
    272                          int h)
    273 {
    274     cl->tightEncoding = rfbEncodingTight;
    275     return SendRectEncodingTight(cl, x, y, w, h);
    276 }
    277 
    278 rfbBool
    279 rfbSendRectEncodingTightPng(rfbClientPtr cl,
    280                          int x,
    281                          int y,
    282                          int w,
    283                          int h)
    284 {
    285     cl->tightEncoding = rfbEncodingTightPng;
    286     return SendRectEncodingTight(cl, x, y, w, h);
    287 }
    288 
    289 
    290 rfbBool
    291 SendRectEncodingTight(rfbClientPtr cl,
    292                          int x,
    293                          int y,
    294                          int w,
    295                          int h)
    296 {
    297     int nMaxRows;
    298     uint32_t colorValue;
    299     int dx, dy, dw, dh;
    300     int x_best, y_best, w_best, h_best;
    301     char *fbptr;
    302 
    303     rfbSendUpdateBuf(cl);
    304 
    305     compressLevel = cl->tightCompressLevel;
    306     qualityLevel = cl->turboQualityLevel;
    307     subsampLevel = cl->turboSubsampLevel;
    308 
    309     /* We only allow compression levels that have a demonstrable performance
    310        benefit.  CL 0 with JPEG reduces CPU usage for workloads that have low
    311        numbers of unique colors, but the same thing can be accomplished by
    312        using CL 0 without JPEG (AKA "Lossless Tight.")  For those same
    313        low-color workloads, CL 2 can provide typically 20-40% better
    314        compression than CL 1 (with a commensurate increase in CPU usage.)  For
    315        high-color workloads, CL 1 should always be used, as higher compression
    316        levels increase CPU usage for these workloads without providing any
    317        significant reduction in bandwidth. */
    318     if (qualityLevel != -1) {
    319         if (compressLevel < 1) compressLevel = 1;
    320         if (compressLevel > 2) compressLevel = 2;
    321     }
    322 
    323     /* With JPEG disabled, CL 2 offers no significant bandwidth savings over
    324        CL 1, so we don't include it. */
    325     else if (compressLevel > 1) compressLevel = 1;
    326 
    327     /* CL 9 (which maps internally to CL 3) is included mainly for backward
    328        compatibility with TightVNC Compression Levels 5-9.  It should be used
    329        only in extremely low-bandwidth cases in which it can be shown to have a
    330        benefit.  For low-color workloads, it provides typically only 10-20%
    331        better compression than CL 2 with JPEG and CL 1 without JPEG, and it
    332        uses, on average, twice as much CPU time. */
    333     if (cl->tightCompressLevel == 9) compressLevel = 3;
    334 
    335     if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
    336          cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
    337         usePixelFormat24 = TRUE;
    338     } else {
    339         usePixelFormat24 = FALSE;
    340     }
    341 
    342     if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
    343         return SendRectSimple(cl, x, y, w, h);
    344 
    345     /* Make sure we can write at least one pixel into tightBeforeBuf. */
    346 
    347     if (tightBeforeBufSize < 4) {
    348         tightBeforeBufSize = 4;
    349         if (tightBeforeBuf == NULL)
    350             tightBeforeBuf = (char *)malloc(tightBeforeBufSize);
    351         else
    352             tightBeforeBuf = (char *)realloc(tightBeforeBuf,
    353                                              tightBeforeBufSize);
    354     }
    355 
    356     /* Calculate maximum number of rows in one non-solid rectangle. */
    357 
    358     {
    359         int maxRectSize, maxRectWidth, nMaxWidth;
    360 
    361         maxRectSize = tightConf[compressLevel].maxRectSize;
    362         maxRectWidth = tightConf[compressLevel].maxRectWidth;
    363         nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    364         nMaxRows = maxRectSize / nMaxWidth;
    365     }
    366 
    367     /* Try to find large solid-color areas and send them separately. */
    368 
    369     for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
    370 
    371         /* If a rectangle becomes too large, send its upper part now. */
    372 
    373         if (dy - y >= nMaxRows) {
    374             if (!SendRectSimple(cl, x, y, w, nMaxRows))
    375                 return 0;
    376             y += nMaxRows;
    377             h -= nMaxRows;
    378         }
    379 
    380         dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
    381              MAX_SPLIT_TILE_SIZE : (y + h - dy);
    382 
    383         for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
    384 
    385             dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
    386                  MAX_SPLIT_TILE_SIZE : (x + w - dx);
    387 
    388             if (CheckSolidTile(cl, dx, dy, dw, dh, &colorValue, FALSE)) {
    389 
    390                 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) {
    391                     uint32_t r = (colorValue >> 16) & 0xFF;
    392                     uint32_t g = (colorValue >> 8) & 0xFF;
    393                     uint32_t b = (colorValue) & 0xFF;
    394                     double y = (0.257 * (double)r) + (0.504 * (double)g)
    395                              + (0.098 * (double)b) + 16.;
    396                     colorValue = (int)y + (((int)y) << 8) + (((int)y) << 16);
    397                 }
    398 
    399                 /* Get dimensions of solid-color area. */
    400 
    401                 FindBestSolidArea(cl, dx, dy, w - (dx - x), h - (dy - y),
    402 				  colorValue, &w_best, &h_best);
    403 
    404                 /* Make sure a solid rectangle is large enough
    405                    (or the whole rectangle is of the same color). */
    406 
    407                 if ( w_best * h_best != w * h &&
    408                      w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
    409                     continue;
    410 
    411                 /* Try to extend solid rectangle to maximum size. */
    412 
    413                 x_best = dx; y_best = dy;
    414                 ExtendSolidArea(cl, x, y, w, h, colorValue,
    415                                 &x_best, &y_best, &w_best, &h_best);
    416 
    417                 /* Send rectangles at top and left to solid-color area. */
    418 
    419                 if ( y_best != y &&
    420                      !SendRectSimple(cl, x, y, w, y_best-y) )
    421                     return FALSE;
    422                 if ( x_best != x &&
    423                      !SendRectEncodingTight(cl, x, y_best,
    424                                                x_best-x, h_best) )
    425                     return FALSE;
    426 
    427                 /* Send solid-color rectangle. */
    428 
    429                 if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
    430                     return FALSE;
    431 
    432                 fbptr = (cl->scaledScreen->frameBuffer +
    433                          (cl->scaledScreen->paddedWidthInBytes * y_best) +
    434                          (x_best * (cl->scaledScreen->bitsPerPixel / 8)));
    435 
    436                 (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
    437                                    &cl->format, fbptr, tightBeforeBuf,
    438                                    cl->scaledScreen->paddedWidthInBytes, 1, 1);
    439 
    440                 if (!SendSolidRect(cl))
    441                     return FALSE;
    442 
    443                 /* Send remaining rectangles (at right and bottom). */
    444 
    445                 if ( x_best + w_best != x + w &&
    446                      !SendRectEncodingTight(cl, x_best + w_best, y_best,
    447                                                w - (x_best-x) - w_best, h_best) )
    448                     return FALSE;
    449                 if ( y_best + h_best != y + h &&
    450                      !SendRectEncodingTight(cl, x, y_best + h_best,
    451                                                w, h - (y_best-y) - h_best) )
    452                     return FALSE;
    453 
    454                 /* Return after all recursive calls are done. */
    455 
    456                 return TRUE;
    457             }
    458 
    459         }
    460 
    461     }
    462 
    463     /* No suitable solid-color rectangles found. */
    464 
    465     return SendRectSimple(cl, x, y, w, h);
    466 }
    467 
    468 
    469 static void
    470 FindBestSolidArea(rfbClientPtr cl,
    471                   int x,
    472                   int y,
    473                   int w,
    474                   int h,
    475                   uint32_t colorValue,
    476                   int *w_ptr,
    477                   int *h_ptr)
    478 {
    479     int dx, dy, dw, dh;
    480     int w_prev;
    481     int w_best = 0, h_best = 0;
    482 
    483     w_prev = w;
    484 
    485     for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
    486 
    487         dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
    488              MAX_SPLIT_TILE_SIZE : (y + h - dy);
    489         dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
    490              MAX_SPLIT_TILE_SIZE : w_prev;
    491 
    492         if (!CheckSolidTile(cl, x, dy, dw, dh, &colorValue, TRUE))
    493             break;
    494 
    495         for (dx = x + dw; dx < x + w_prev;) {
    496             dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
    497                  MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
    498             if (!CheckSolidTile(cl, dx, dy, dw, dh, &colorValue, TRUE))
    499                 break;
    500 	    dx += dw;
    501         }
    502 
    503         w_prev = dx - x;
    504         if (w_prev * (dy + dh - y) > w_best * h_best) {
    505             w_best = w_prev;
    506             h_best = dy + dh - y;
    507         }
    508     }
    509 
    510     *w_ptr = w_best;
    511     *h_ptr = h_best;
    512 }
    513 
    514 
    515 static void
    516 ExtendSolidArea(rfbClientPtr cl,
    517                 int x,
    518                 int y,
    519                 int w,
    520                 int h,
    521                 uint32_t colorValue,
    522                 int *x_ptr,
    523                 int *y_ptr,
    524                 int *w_ptr,
    525                 int *h_ptr)
    526 {
    527     int cx, cy;
    528 
    529     /* Try to extend the area upwards. */
    530     for ( cy = *y_ptr - 1;
    531           cy >= y && CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
    532           cy-- );
    533     *h_ptr += *y_ptr - (cy + 1);
    534     *y_ptr = cy + 1;
    535 
    536     /* ... downwards. */
    537     for ( cy = *y_ptr + *h_ptr;
    538           cy < y + h &&
    539               CheckSolidTile(cl, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
    540           cy++ );
    541     *h_ptr += cy - (*y_ptr + *h_ptr);
    542 
    543     /* ... to the left. */
    544     for ( cx = *x_ptr - 1;
    545           cx >= x && CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
    546           cx-- );
    547     *w_ptr += *x_ptr - (cx + 1);
    548     *x_ptr = cx + 1;
    549 
    550     /* ... to the right. */
    551     for ( cx = *x_ptr + *w_ptr;
    552           cx < x + w &&
    553               CheckSolidTile(cl, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
    554           cx++ );
    555     *w_ptr += cx - (*x_ptr + *w_ptr);
    556 }
    557 
    558 
    559 /*
    560  * Check if a rectangle is all of the same color. If needSameColor is
    561  * set to non-zero, then also check that its color equals to the
    562  * *colorPtr value. The result is 1 if the test is successfull, and in
    563  * that case new color will be stored in *colorPtr.
    564  */
    565 
    566 static rfbBool CheckSolidTile(rfbClientPtr cl, int x, int y, int w, int h, uint32_t* colorPtr, rfbBool needSameColor)
    567 {
    568     switch(cl->screen->serverFormat.bitsPerPixel) {
    569     case 32:
    570         return CheckSolidTile32(cl, x, y, w, h, colorPtr, needSameColor);
    571     case 16:
    572         return CheckSolidTile16(cl, x, y, w, h, colorPtr, needSameColor);
    573     default:
    574         return CheckSolidTile8(cl, x, y, w, h, colorPtr, needSameColor);
    575     }
    576 }
    577 
    578 
    579 #define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                      \
    580                                                                               \
    581 static rfbBool                                                                \
    582 CheckSolidTile##bpp(rfbClientPtr cl, int x, int y, int w, int h,              \
    583 		uint32_t* colorPtr, rfbBool needSameColor)                    \
    584 {                                                                             \
    585     uint##bpp##_t *fbptr;                                                     \
    586     uint##bpp##_t colorValue;                                                 \
    587     int dx, dy;                                                               \
    588                                                                               \
    589     fbptr = (uint##bpp##_t *)&cl->scaledScreen->frameBuffer                   \
    590         [y * cl->scaledScreen->paddedWidthInBytes + x * (bpp/8)];             \
    591                                                                               \
    592     colorValue = *fbptr;                                                      \
    593     if (needSameColor && (uint32_t)colorValue != *colorPtr)                   \
    594         return FALSE;                                                         \
    595                                                                               \
    596     for (dy = 0; dy < h; dy++) {                                              \
    597         for (dx = 0; dx < w; dx++) {                                          \
    598             if (colorValue != fbptr[dx])                                      \
    599                 return FALSE;                                                 \
    600         }                                                                     \
    601         fbptr = (uint##bpp##_t *)((uint8_t *)fbptr                            \
    602                  + cl->scaledScreen->paddedWidthInBytes);                     \
    603     }                                                                         \
    604                                                                               \
    605     *colorPtr = (uint32_t)colorValue;                                         \
    606     return TRUE;                                                              \
    607 }
    608 
    609 DEFINE_CHECK_SOLID_FUNCTION(8)
    610 DEFINE_CHECK_SOLID_FUNCTION(16)
    611 DEFINE_CHECK_SOLID_FUNCTION(32)
    612 
    613 static rfbBool
    614 SendRectSimple(rfbClientPtr cl, int x, int y, int w, int h)
    615 {
    616     int maxBeforeSize, maxAfterSize;
    617     int maxRectSize, maxRectWidth;
    618     int subrectMaxWidth, subrectMaxHeight;
    619     int dx, dy;
    620     int rw, rh;
    621 
    622     maxRectSize = tightConf[compressLevel].maxRectSize;
    623     maxRectWidth = tightConf[compressLevel].maxRectWidth;
    624 
    625     maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
    626     maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
    627 
    628     if (tightBeforeBufSize < maxBeforeSize) {
    629         tightBeforeBufSize = maxBeforeSize;
    630         if (tightBeforeBuf == NULL)
    631             tightBeforeBuf = (char *)malloc(tightBeforeBufSize);
    632         else
    633             tightBeforeBuf = (char *)realloc(tightBeforeBuf,
    634                                              tightBeforeBufSize);
    635     }
    636 
    637     if (tightAfterBufSize < maxAfterSize) {
    638         tightAfterBufSize = maxAfterSize;
    639         if (tightAfterBuf == NULL)
    640             tightAfterBuf = (char *)malloc(tightAfterBufSize);
    641         else
    642             tightAfterBuf = (char *)realloc(tightAfterBuf,
    643                                             tightAfterBufSize);
    644     }
    645 
    646     if (w > maxRectWidth || w * h > maxRectSize) {
    647         subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    648         subrectMaxHeight = maxRectSize / subrectMaxWidth;
    649 
    650         for (dy = 0; dy < h; dy += subrectMaxHeight) {
    651             for (dx = 0; dx < w; dx += maxRectWidth) {
    652                 rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
    653                 rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
    654                 if (!SendSubrect(cl, x + dx, y + dy, rw, rh))
    655                     return FALSE;
    656             }
    657         }
    658     } else {
    659         if (!SendSubrect(cl, x, y, w, h))
    660             return FALSE;
    661     }
    662 
    663     return TRUE;
    664 }
    665 
    666 static rfbBool
    667 SendSubrect(rfbClientPtr cl,
    668             int x,
    669             int y,
    670             int w,
    671             int h)
    672 {
    673     char *fbptr;
    674     rfbBool success = FALSE;
    675 
    676     /* Send pending data if there is more than 128 bytes. */
    677     if (cl->ublen > 128) {
    678         if (!rfbSendUpdateBuf(cl))
    679             return FALSE;
    680     }
    681 
    682     if (!SendTightHeader(cl, x, y, w, h))
    683         return FALSE;
    684 
    685     fbptr = (cl->scaledScreen->frameBuffer
    686              + (cl->scaledScreen->paddedWidthInBytes * y)
    687              + (x * (cl->scaledScreen->bitsPerPixel / 8)));
    688 
    689     if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1)
    690         return SendJpegRect(cl, x, y, w, h, qualityLevel);
    691 
    692     paletteMaxColors = w * h / tightConf[compressLevel].idxMaxColorsDivisor;
    693     if(qualityLevel != -1)
    694         paletteMaxColors = tightConf[compressLevel].palMaxColorsWithJPEG;
    695     if ( paletteMaxColors < 2 &&
    696          w * h >= tightConf[compressLevel].monoMinRectSize ) {
    697         paletteMaxColors = 2;
    698     }
    699 
    700     if (cl->format.bitsPerPixel == cl->screen->serverFormat.bitsPerPixel &&
    701         cl->format.redMax == cl->screen->serverFormat.redMax &&
    702         cl->format.greenMax == cl->screen->serverFormat.greenMax &&
    703         cl->format.blueMax == cl->screen->serverFormat.blueMax &&
    704         cl->format.bitsPerPixel >= 16) {
    705 
    706         /* This is so we can avoid translating the pixels when compressing
    707            with JPEG, since it is unnecessary */
    708         switch (cl->format.bitsPerPixel) {
    709         case 16:
    710             FastFillPalette16(cl, (uint16_t *)fbptr, w,
    711                               cl->scaledScreen->paddedWidthInBytes / 2, h);
    712             break;
    713         default:
    714             FastFillPalette32(cl, (uint32_t *)fbptr, w,
    715                               cl->scaledScreen->paddedWidthInBytes / 4, h);
    716         }
    717 
    718         if(paletteNumColors != 0 || qualityLevel == -1) {
    719             (*cl->translateFn)(cl->translateLookupTable,
    720                                &cl->screen->serverFormat, &cl->format, fbptr,
    721                                tightBeforeBuf,
    722                                cl->scaledScreen->paddedWidthInBytes, w, h);
    723         }
    724     }
    725     else {
    726         (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
    727                            &cl->format, fbptr, tightBeforeBuf,
    728                            cl->scaledScreen->paddedWidthInBytes, w, h);
    729 
    730         switch (cl->format.bitsPerPixel) {
    731         case 8:
    732             FillPalette8(w * h);
    733             break;
    734         case 16:
    735             FillPalette16(w * h);
    736             break;
    737         default:
    738             FillPalette32(w * h);
    739         }
    740     }
    741 
    742     switch (paletteNumColors) {
    743     case 0:
    744         /* Truecolor image */
    745         if (qualityLevel != -1) {
    746             success = SendJpegRect(cl, x, y, w, h, qualityLevel);
    747         } else {
    748             success = SendFullColorRect(cl, x, y, w, h);
    749         }
    750         break;
    751     case 1:
    752         /* Solid rectangle */
    753         success = SendSolidRect(cl);
    754         break;
    755     case 2:
    756         /* Two-color rectangle */
    757         success = SendMonoRect(cl, x, y, w, h);
    758         break;
    759     default:
    760         /* Up to 256 different colors */
    761         success = SendIndexedRect(cl, x, y, w, h);
    762     }
    763     return success;
    764 }
    765 
    766 static rfbBool
    767 SendTightHeader(rfbClientPtr cl,
    768                 int x,
    769                 int y,
    770                 int w,
    771                 int h)
    772 {
    773     rfbFramebufferUpdateRectHeader rect;
    774 
    775     if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
    776         if (!rfbSendUpdateBuf(cl))
    777             return FALSE;
    778     }
    779 
    780     rect.r.x = Swap16IfLE(x);
    781     rect.r.y = Swap16IfLE(y);
    782     rect.r.w = Swap16IfLE(w);
    783     rect.r.h = Swap16IfLE(h);
    784     rect.encoding = Swap32IfLE(cl->tightEncoding);
    785 
    786     memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
    787            sz_rfbFramebufferUpdateRectHeader);
    788     cl->ublen += sz_rfbFramebufferUpdateRectHeader;
    789 
    790     rfbStatRecordEncodingSent(cl, cl->tightEncoding,
    791                               sz_rfbFramebufferUpdateRectHeader,
    792                               sz_rfbFramebufferUpdateRectHeader
    793                                   + w * (cl->format.bitsPerPixel / 8) * h);
    794 
    795     return TRUE;
    796 }
    797 
    798 /*
    799  * Subencoding implementations.
    800  */
    801 
    802 static rfbBool
    803 SendSolidRect(rfbClientPtr cl)
    804 {
    805     int len;
    806 
    807     if (usePixelFormat24) {
    808         Pack24(cl, tightBeforeBuf, &cl->format, 1);
    809         len = 3;
    810     } else
    811         len = cl->format.bitsPerPixel / 8;
    812 
    813     if (cl->ublen + 1 + len > UPDATE_BUF_SIZE) {
    814         if (!rfbSendUpdateBuf(cl))
    815             return FALSE;
    816     }
    817 
    818     cl->updateBuf[cl->ublen++] = (char)(rfbTightFill << 4);
    819     memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
    820     cl->ublen += len;
    821 
    822     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, len + 1);
    823 
    824     return TRUE;
    825 }
    826 
    827 static rfbBool
    828 SendMonoRect(rfbClientPtr cl,
    829              int x,
    830              int y,
    831              int w,
    832              int h)
    833 {
    834     int streamId = 1;
    835     int paletteLen, dataLen;
    836 
    837 #ifdef LIBVNCSERVER_HAVE_LIBPNG
    838     if (CanSendPngRect(cl, w, h)) {
    839         /* TODO: setup palette maybe */
    840         return SendPngRect(cl, x, y, w, h);
    841         /* TODO: destroy palette maybe */
    842     }
    843 #endif
    844 
    845     if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
    846 	 2 * cl->format.bitsPerPixel / 8 > UPDATE_BUF_SIZE ) {
    847         if (!rfbSendUpdateBuf(cl))
    848             return FALSE;
    849     }
    850 
    851     /* Prepare tight encoding header. */
    852     dataLen = (w + 7) / 8;
    853     dataLen *= h;
    854 
    855     if (tightConf[compressLevel].monoZlibLevel == 0 &&
    856         cl->tightEncoding != rfbEncodingTightPng)
    857         cl->updateBuf[cl->ublen++] =
    858             (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
    859     else
    860         cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
    861     cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
    862     cl->updateBuf[cl->ublen++] = 1;
    863 
    864     /* Prepare palette, convert image. */
    865     switch (cl->format.bitsPerPixel) {
    866 
    867     case 32:
    868         EncodeMonoRect32((uint8_t *)tightBeforeBuf, w, h);
    869 
    870         ((uint32_t *)tightAfterBuf)[0] = monoBackground;
    871         ((uint32_t *)tightAfterBuf)[1] = monoForeground;
    872         if (usePixelFormat24) {
    873             Pack24(cl, tightAfterBuf, &cl->format, 2);
    874             paletteLen = 6;
    875         } else
    876             paletteLen = 8;
    877 
    878         memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
    879         cl->ublen += paletteLen;
    880         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 3 + paletteLen);
    881         break;
    882 
    883     case 16:
    884         EncodeMonoRect16((uint8_t *)tightBeforeBuf, w, h);
    885 
    886         ((uint16_t *)tightAfterBuf)[0] = (uint16_t)monoBackground;
    887         ((uint16_t *)tightAfterBuf)[1] = (uint16_t)monoForeground;
    888 
    889         memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
    890         cl->ublen += 4;
    891         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 7);
    892         break;
    893 
    894     default:
    895         EncodeMonoRect8((uint8_t *)tightBeforeBuf, w, h);
    896 
    897         cl->updateBuf[cl->ublen++] = (char)monoBackground;
    898         cl->updateBuf[cl->ublen++] = (char)monoForeground;
    899         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 5);
    900     }
    901 
    902     return CompressData(cl, streamId, dataLen,
    903                         tightConf[compressLevel].monoZlibLevel,
    904                         Z_DEFAULT_STRATEGY);
    905 }
    906 
    907 static rfbBool
    908 SendIndexedRect(rfbClientPtr cl,
    909                 int x,
    910                 int y,
    911                 int w,
    912                 int h)
    913 {
    914     int streamId = 2;
    915     int i, entryLen;
    916 
    917 #ifdef LIBVNCSERVER_HAVE_LIBPNG
    918     if (CanSendPngRect(cl, w, h)) {
    919         return SendPngRect(cl, x, y, w, h);
    920     }
    921 #endif
    922 
    923     if ( cl->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
    924 	 paletteNumColors * cl->format.bitsPerPixel / 8 >
    925          UPDATE_BUF_SIZE ) {
    926         if (!rfbSendUpdateBuf(cl))
    927             return FALSE;
    928     }
    929 
    930     /* Prepare tight encoding header. */
    931     if (tightConf[compressLevel].idxZlibLevel == 0 &&
    932         cl->tightEncoding != rfbEncodingTightPng)
    933         cl->updateBuf[cl->ublen++] =
    934             (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
    935     else
    936         cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
    937     cl->updateBuf[cl->ublen++] = rfbTightFilterPalette;
    938     cl->updateBuf[cl->ublen++] = (char)(paletteNumColors - 1);
    939 
    940     /* Prepare palette, convert image. */
    941     switch (cl->format.bitsPerPixel) {
    942 
    943     case 32:
    944         EncodeIndexedRect32((uint8_t *)tightBeforeBuf, w * h);
    945 
    946         for (i = 0; i < paletteNumColors; i++) {
    947             ((uint32_t *)tightAfterBuf)[i] =
    948                 palette.entry[i].listNode->rgb;
    949         }
    950         if (usePixelFormat24) {
    951             Pack24(cl, tightAfterBuf, &cl->format, paletteNumColors);
    952             entryLen = 3;
    953         } else
    954             entryLen = 4;
    955 
    956         memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf,
    957                paletteNumColors * entryLen);
    958         cl->ublen += paletteNumColors * entryLen;
    959         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding,
    960                                      3 + paletteNumColors * entryLen);
    961         break;
    962 
    963     case 16:
    964         EncodeIndexedRect16((uint8_t *)tightBeforeBuf, w * h);
    965 
    966         for (i = 0; i < paletteNumColors; i++) {
    967             ((uint16_t *)tightAfterBuf)[i] =
    968                 (uint16_t)palette.entry[i].listNode->rgb;
    969         }
    970 
    971         memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
    972         cl->ublen += paletteNumColors * 2;
    973         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding,
    974                                      3 + paletteNumColors * 2);
    975         break;
    976 
    977     default:
    978         return FALSE;           /* Should never happen. */
    979     }
    980 
    981     return CompressData(cl, streamId, w * h,
    982                         tightConf[compressLevel].idxZlibLevel,
    983                         Z_DEFAULT_STRATEGY);
    984 }
    985 
    986 static rfbBool
    987 SendFullColorRect(rfbClientPtr cl,
    988                   int x,
    989                   int y,
    990                   int w,
    991                   int h)
    992 {
    993     int streamId = 0;
    994     int len;
    995 
    996 #ifdef LIBVNCSERVER_HAVE_LIBPNG
    997     if (CanSendPngRect(cl, w, h)) {
    998         return SendPngRect(cl, x, y, w, h);
    999     }
   1000 #endif
   1001 
   1002     if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
   1003         if (!rfbSendUpdateBuf(cl))
   1004             return FALSE;
   1005     }
   1006 
   1007     if (tightConf[compressLevel].rawZlibLevel == 0 &&
   1008         cl->tightEncoding != rfbEncodingTightPng)
   1009         cl->updateBuf[cl->ublen++] = (char)(rfbTightNoZlib << 4);
   1010     else
   1011         cl->updateBuf[cl->ublen++] = 0x00;  /* stream id = 0, no flushing, no filter */
   1012     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1013 
   1014     if (usePixelFormat24) {
   1015         Pack24(cl, tightBeforeBuf, &cl->format, w * h);
   1016         len = 3;
   1017     } else
   1018         len = cl->format.bitsPerPixel / 8;
   1019 
   1020     return CompressData(cl, streamId, w * h * len,
   1021                         tightConf[compressLevel].rawZlibLevel,
   1022                         Z_DEFAULT_STRATEGY);
   1023 }
   1024 
   1025 static rfbBool
   1026 CompressData(rfbClientPtr cl,
   1027              int streamId,
   1028              int dataLen,
   1029              int zlibLevel,
   1030              int zlibStrategy)
   1031 {
   1032     z_streamp pz;
   1033     int err;
   1034 
   1035     if (dataLen < TIGHT_MIN_TO_COMPRESS) {
   1036         memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
   1037         cl->ublen += dataLen;
   1038         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, dataLen);
   1039         return TRUE;
   1040     }
   1041 
   1042     if (zlibLevel == 0)
   1043         return SendCompressedData (cl, tightBeforeBuf, dataLen);
   1044 
   1045     pz = &cl->zsStruct[streamId];
   1046 
   1047     /* Initialize compression stream if needed. */
   1048     if (!cl->zsActive[streamId]) {
   1049         pz->zalloc = Z_NULL;
   1050         pz->zfree = Z_NULL;
   1051         pz->opaque = Z_NULL;
   1052 
   1053         err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
   1054                             MAX_MEM_LEVEL, zlibStrategy);
   1055         if (err != Z_OK)
   1056             return FALSE;
   1057 
   1058         cl->zsActive[streamId] = TRUE;
   1059         cl->zsLevel[streamId] = zlibLevel;
   1060     }
   1061 
   1062     /* Prepare buffer pointers. */
   1063     pz->next_in = (Bytef *)tightBeforeBuf;
   1064     pz->avail_in = dataLen;
   1065     pz->next_out = (Bytef *)tightAfterBuf;
   1066     pz->avail_out = tightAfterBufSize;
   1067 
   1068     /* Change compression parameters if needed. */
   1069     if (zlibLevel != cl->zsLevel[streamId]) {
   1070         if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
   1071             return FALSE;
   1072         }
   1073         cl->zsLevel[streamId] = zlibLevel;
   1074     }
   1075 
   1076     /* Actual compression. */
   1077     if (deflate(pz, Z_SYNC_FLUSH) != Z_OK ||
   1078         pz->avail_in != 0 || pz->avail_out == 0) {
   1079         return FALSE;
   1080     }
   1081 
   1082     return SendCompressedData(cl, tightAfterBuf,
   1083                               tightAfterBufSize - pz->avail_out);
   1084 }
   1085 
   1086 static rfbBool SendCompressedData(rfbClientPtr cl, char *buf,
   1087                                   int compressedLen)
   1088 {
   1089     int i, portionLen;
   1090 
   1091     cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
   1092     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1093     if (compressedLen > 0x7F) {
   1094         cl->updateBuf[cl->ublen-1] |= 0x80;
   1095         cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
   1096         rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1097         if (compressedLen > 0x3FFF) {
   1098             cl->updateBuf[cl->ublen-1] |= 0x80;
   1099             cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
   1100             rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1101         }
   1102     }
   1103 
   1104     portionLen = UPDATE_BUF_SIZE;
   1105     for (i = 0; i < compressedLen; i += portionLen) {
   1106         if (i + portionLen > compressedLen) {
   1107             portionLen = compressedLen - i;
   1108         }
   1109         if (cl->ublen + portionLen > UPDATE_BUF_SIZE) {
   1110             if (!rfbSendUpdateBuf(cl))
   1111                 return FALSE;
   1112         }
   1113         memcpy(&cl->updateBuf[cl->ublen], &buf[i], portionLen);
   1114         cl->ublen += portionLen;
   1115     }
   1116     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, compressedLen);
   1117 
   1118     return TRUE;
   1119 }
   1120 
   1121 
   1122 /*
   1123  * Code to determine how many different colors used in rectangle.
   1124  */
   1125 
   1126 static void
   1127 FillPalette8(int count)
   1128 {
   1129     uint8_t *data = (uint8_t *)tightBeforeBuf;
   1130     uint8_t c0, c1;
   1131     int i, n0, n1;
   1132 
   1133     paletteNumColors = 0;
   1134 
   1135     c0 = data[0];
   1136     for (i = 1; i < count && data[i] == c0; i++);
   1137     if (i == count) {
   1138         paletteNumColors = 1;
   1139         return;                 /* Solid rectangle */
   1140     }
   1141 
   1142     if (paletteMaxColors < 2)
   1143         return;
   1144 
   1145     n0 = i;
   1146     c1 = data[i];
   1147     n1 = 0;
   1148     for (i++; i < count; i++) {
   1149         if (data[i] == c0) {
   1150             n0++;
   1151         } else if (data[i] == c1) {
   1152             n1++;
   1153         } else
   1154             break;
   1155     }
   1156     if (i == count) {
   1157         if (n0 > n1) {
   1158             monoBackground = (uint32_t)c0;
   1159             monoForeground = (uint32_t)c1;
   1160         } else {
   1161             monoBackground = (uint32_t)c1;
   1162             monoForeground = (uint32_t)c0;
   1163         }
   1164         paletteNumColors = 2;   /* Two colors */
   1165     }
   1166 }
   1167 
   1168 
   1169 #define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
   1170                                                                         \
   1171 static void                                                             \
   1172 FillPalette##bpp(int count) {                                           \
   1173     uint##bpp##_t *data = (uint##bpp##_t *)tightBeforeBuf;              \
   1174     uint##bpp##_t c0, c1, ci;                                           \
   1175     int i, n0, n1, ni;                                                  \
   1176                                                                         \
   1177     c0 = data[0];                                                       \
   1178     for (i = 1; i < count && data[i] == c0; i++);                       \
   1179     if (i >= count) {                                                   \
   1180         paletteNumColors = 1;   /* Solid rectangle */                   \
   1181         return;                                                         \
   1182     }                                                                   \
   1183                                                                         \
   1184     if (paletteMaxColors < 2) {                                         \
   1185         paletteNumColors = 0;   /* Full-color encoding preferred */     \
   1186         return;                                                         \
   1187     }                                                                   \
   1188                                                                         \
   1189     n0 = i;                                                             \
   1190     c1 = data[i];                                                       \
   1191     n1 = 0;                                                             \
   1192     for (i++; i < count; i++) {                                         \
   1193         ci = data[i];                                                   \
   1194         if (ci == c0) {                                                 \
   1195             n0++;                                                       \
   1196         } else if (ci == c1) {                                          \
   1197             n1++;                                                       \
   1198         } else                                                          \
   1199             break;                                                      \
   1200     }                                                                   \
   1201     if (i >= count) {                                                   \
   1202         if (n0 > n1) {                                                  \
   1203             monoBackground = (uint32_t)c0;                              \
   1204             monoForeground = (uint32_t)c1;                              \
   1205         } else {                                                        \
   1206             monoBackground = (uint32_t)c1;                              \
   1207             monoForeground = (uint32_t)c0;                              \
   1208         }                                                               \
   1209         paletteNumColors = 2;   /* Two colors */                        \
   1210         return;                                                         \
   1211     }                                                                   \
   1212                                                                         \
   1213     PaletteReset();                                                     \
   1214     PaletteInsert (c0, (uint32_t)n0, bpp);                              \
   1215     PaletteInsert (c1, (uint32_t)n1, bpp);                              \
   1216                                                                         \
   1217     ni = 1;                                                             \
   1218     for (i++; i < count; i++) {                                         \
   1219         if (data[i] == ci) {                                            \
   1220             ni++;                                                       \
   1221         } else {                                                        \
   1222             if (!PaletteInsert (ci, (uint32_t)ni, bpp))                 \
   1223                 return;                                                 \
   1224             ci = data[i];                                               \
   1225             ni = 1;                                                     \
   1226         }                                                               \
   1227     }                                                                   \
   1228     PaletteInsert (ci, (uint32_t)ni, bpp);                              \
   1229 }
   1230 
   1231 DEFINE_FILL_PALETTE_FUNCTION(16)
   1232 DEFINE_FILL_PALETTE_FUNCTION(32)
   1233 
   1234 #define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp)                          \
   1235                                                                         \
   1236 static void                                                             \
   1237 FastFillPalette##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w,       \
   1238                      int pitch, int h)                                  \
   1239 {                                                                       \
   1240     uint##bpp##_t c0, c1, ci, mask, c0t, c1t, cit;                      \
   1241     int i, j, i2 = 0, j2, n0, n1, ni;                                   \
   1242                                                                         \
   1243     if (cl->translateFn != rfbTranslateNone) {                          \
   1244         mask = cl->screen->serverFormat.redMax                          \
   1245             << cl->screen->serverFormat.redShift;                       \
   1246         mask |= cl->screen->serverFormat.greenMax                       \
   1247              << cl->screen->serverFormat.greenShift;                    \
   1248         mask |= cl->screen->serverFormat.blueMax                        \
   1249              << cl->screen->serverFormat.blueShift;                     \
   1250     } else mask = ~0;                                                   \
   1251                                                                         \
   1252     c0 = data[0] & mask;                                                \
   1253     for (j = 0; j < h; j++) {                                           \
   1254         for (i = 0; i < w; i++) {                                       \
   1255             if ((data[j * pitch + i] & mask) != c0)                     \
   1256                 goto done;                                              \
   1257         }                                                               \
   1258     }                                                                   \
   1259     done:                                                               \
   1260     if (j >= h) {                                                       \
   1261         paletteNumColors = 1;   /* Solid rectangle */                   \
   1262         return;                                                         \
   1263     }                                                                   \
   1264     if (paletteMaxColors < 2) {                                         \
   1265         paletteNumColors = 0;   /* Full-color encoding preferred */     \
   1266         return;                                                         \
   1267     }                                                                   \
   1268                                                                         \
   1269     n0 = j * w + i;                                                     \
   1270     c1 = data[j * pitch + i] & mask;                                    \
   1271     n1 = 0;                                                             \
   1272     i++;  if (i >= w) {i = 0;  j++;}                                    \
   1273     for (j2 = j; j2 < h; j2++) {                                        \
   1274         for (i2 = i; i2 < w; i2++) {                                    \
   1275             ci = data[j2 * pitch + i2] & mask;                          \
   1276             if (ci == c0) {                                             \
   1277                 n0++;                                                   \
   1278             } else if (ci == c1) {                                      \
   1279                 n1++;                                                   \
   1280             } else                                                      \
   1281                 goto done2;                                             \
   1282         }                                                               \
   1283         i = 0;                                                          \
   1284     }                                                                   \
   1285     done2:                                                              \
   1286     (*cl->translateFn)(cl->translateLookupTable,                        \
   1287                        &cl->screen->serverFormat, &cl->format,          \
   1288                        (char *)&c0, (char *)&c0t, bpp/8, 1, 1);         \
   1289     (*cl->translateFn)(cl->translateLookupTable,                        \
   1290                        &cl->screen->serverFormat, &cl->format,          \
   1291                        (char *)&c1, (char *)&c1t, bpp/8, 1, 1);         \
   1292     if (j2 >= h) {                                                      \
   1293         if (n0 > n1) {                                                  \
   1294             monoBackground = (uint32_t)c0t;                             \
   1295             monoForeground = (uint32_t)c1t;                             \
   1296         } else {                                                        \
   1297             monoBackground = (uint32_t)c1t;                             \
   1298             monoForeground = (uint32_t)c0t;                             \
   1299         }                                                               \
   1300         paletteNumColors = 2;   /* Two colors */                        \
   1301         return;                                                         \
   1302     }                                                                   \
   1303                                                                         \
   1304     PaletteReset();                                                     \
   1305     PaletteInsert (c0t, (uint32_t)n0, bpp);                             \
   1306     PaletteInsert (c1t, (uint32_t)n1, bpp);                             \
   1307                                                                         \
   1308     ni = 1;                                                             \
   1309     i2++;  if (i2 >= w) {i2 = 0;  j2++;}                                \
   1310     for (j = j2; j < h; j++) {                                          \
   1311         for (i = i2; i < w; i++) {                                      \
   1312             if ((data[j * pitch + i] & mask) == ci) {                   \
   1313                 ni++;                                                   \
   1314             } else {                                                    \
   1315                 (*cl->translateFn)(cl->translateLookupTable,            \
   1316                                    &cl->screen->serverFormat,           \
   1317                                    &cl->format, (char *)&ci,            \
   1318                                    (char *)&cit, bpp/8, 1, 1);          \
   1319                 if (!PaletteInsert (cit, (uint32_t)ni, bpp))            \
   1320                     return;                                             \
   1321                 ci = data[j * pitch + i] & mask;                        \
   1322                 ni = 1;                                                 \
   1323             }                                                           \
   1324         }                                                               \
   1325         i2 = 0;                                                         \
   1326     }                                                                   \
   1327                                                                         \
   1328     (*cl->translateFn)(cl->translateLookupTable,                        \
   1329                        &cl->screen->serverFormat, &cl->format,          \
   1330                        (char *)&ci, (char *)&cit, bpp/8, 1, 1);         \
   1331     PaletteInsert (cit, (uint32_t)ni, bpp);                             \
   1332 }
   1333 
   1334 DEFINE_FAST_FILL_PALETTE_FUNCTION(16)
   1335 DEFINE_FAST_FILL_PALETTE_FUNCTION(32)
   1336 
   1337 
   1338 /*
   1339  * Functions to operate with palette structures.
   1340  */
   1341 
   1342 #define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
   1343 #define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
   1344 
   1345 
   1346 static void
   1347 PaletteReset(void)
   1348 {
   1349     paletteNumColors = 0;
   1350     memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
   1351 }
   1352 
   1353 
   1354 static int
   1355 PaletteInsert(uint32_t rgb,
   1356               int numPixels,
   1357               int bpp)
   1358 {
   1359     COLOR_LIST *pnode;
   1360     COLOR_LIST *prev_pnode = NULL;
   1361     int hash_key, idx, new_idx, count;
   1362 
   1363     hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
   1364 
   1365     pnode = palette.hash[hash_key];
   1366 
   1367     while (pnode != NULL) {
   1368         if (pnode->rgb == rgb) {
   1369             /* Such palette entry already exists. */
   1370             new_idx = idx = pnode->idx;
   1371             count = palette.entry[idx].numPixels + numPixels;
   1372             if (new_idx && palette.entry[new_idx-1].numPixels < count) {
   1373                 do {
   1374                     palette.entry[new_idx] = palette.entry[new_idx-1];
   1375                     palette.entry[new_idx].listNode->idx = new_idx;
   1376                     new_idx--;
   1377                 }
   1378                 while (new_idx && palette.entry[new_idx-1].numPixels < count);
   1379                 palette.entry[new_idx].listNode = pnode;
   1380                 pnode->idx = new_idx;
   1381             }
   1382             palette.entry[new_idx].numPixels = count;
   1383             return paletteNumColors;
   1384         }
   1385         prev_pnode = pnode;
   1386         pnode = pnode->next;
   1387     }
   1388 
   1389     /* Check if palette is full. */
   1390     if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
   1391         paletteNumColors = 0;
   1392         return 0;
   1393     }
   1394 
   1395     /* Move palette entries with lesser pixel counts. */
   1396     for ( idx = paletteNumColors;
   1397           idx > 0 && palette.entry[idx-1].numPixels < numPixels;
   1398           idx-- ) {
   1399         palette.entry[idx] = palette.entry[idx-1];
   1400         palette.entry[idx].listNode->idx = idx;
   1401     }
   1402 
   1403     /* Add new palette entry into the freed slot. */
   1404     pnode = &palette.list[paletteNumColors];
   1405     if (prev_pnode != NULL) {
   1406         prev_pnode->next = pnode;
   1407     } else {
   1408         palette.hash[hash_key] = pnode;
   1409     }
   1410     pnode->next = NULL;
   1411     pnode->idx = idx;
   1412     pnode->rgb = rgb;
   1413     palette.entry[idx].listNode = pnode;
   1414     palette.entry[idx].numPixels = numPixels;
   1415 
   1416     return (++paletteNumColors);
   1417 }
   1418 
   1419 
   1420 /*
   1421  * Converting 32-bit color samples into 24-bit colors.
   1422  * Should be called only when redMax, greenMax and blueMax are 255.
   1423  * Color components assumed to be byte-aligned.
   1424  */
   1425 
   1426 static void Pack24(rfbClientPtr cl,
   1427                    char *buf,
   1428                    rfbPixelFormat *fmt,
   1429                    int count)
   1430 {
   1431     uint32_t *buf32;
   1432     uint32_t pix;
   1433     int r_shift, g_shift, b_shift;
   1434 
   1435     buf32 = (uint32_t *)buf;
   1436 
   1437     if (!cl->screen->serverFormat.bigEndian == !fmt->bigEndian) {
   1438         r_shift = fmt->redShift;
   1439         g_shift = fmt->greenShift;
   1440         b_shift = fmt->blueShift;
   1441     } else {
   1442         r_shift = 24 - fmt->redShift;
   1443         g_shift = 24 - fmt->greenShift;
   1444         b_shift = 24 - fmt->blueShift;
   1445     }
   1446 
   1447     while (count--) {
   1448         pix = *buf32++;
   1449         *buf++ = (char)(pix >> r_shift);
   1450         *buf++ = (char)(pix >> g_shift);
   1451         *buf++ = (char)(pix >> b_shift);
   1452     }
   1453 }
   1454 
   1455 
   1456 /*
   1457  * Converting truecolor samples into palette indices.
   1458  */
   1459 
   1460 #define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
   1461                                                                         \
   1462 static void                                                             \
   1463 EncodeIndexedRect##bpp(uint8_t *buf, int count) {                       \
   1464     COLOR_LIST *pnode;                                                  \
   1465     uint##bpp##_t *src;                                                 \
   1466     uint##bpp##_t rgb;                                                  \
   1467     int rep = 0;                                                        \
   1468                                                                         \
   1469     src = (uint##bpp##_t *) buf;                                        \
   1470                                                                         \
   1471     while (count--) {                                                   \
   1472         rgb = *src++;                                                   \
   1473         while (count && *src == rgb) {                                  \
   1474             rep++, src++, count--;                                      \
   1475         }                                                               \
   1476         pnode = palette.hash[HASH_FUNC##bpp(rgb)];                      \
   1477         while (pnode != NULL) {                                         \
   1478             if ((uint##bpp##_t)pnode->rgb == rgb) {                     \
   1479                 *buf++ = (uint8_t)pnode->idx;                           \
   1480                 while (rep) {                                           \
   1481                     *buf++ = (uint8_t)pnode->idx;                       \
   1482                     rep--;                                              \
   1483                 }                                                       \
   1484                 break;                                                  \
   1485             }                                                           \
   1486             pnode = pnode->next;                                        \
   1487         }                                                               \
   1488     }                                                                   \
   1489 }
   1490 
   1491 DEFINE_IDX_ENCODE_FUNCTION(16)
   1492 DEFINE_IDX_ENCODE_FUNCTION(32)
   1493 
   1494 
   1495 #define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
   1496                                                                         \
   1497 static void                                                             \
   1498 EncodeMonoRect##bpp(uint8_t *buf, int w, int h) {                       \
   1499     uint##bpp##_t *ptr;                                                 \
   1500     uint##bpp##_t bg;                                                   \
   1501     unsigned int value, mask;                                           \
   1502     int aligned_width;                                                  \
   1503     int x, y, bg_bits;                                                  \
   1504                                                                         \
   1505     ptr = (uint##bpp##_t *) buf;                                        \
   1506     bg = (uint##bpp##_t) monoBackground;                                \
   1507     aligned_width = w - w % 8;                                          \
   1508                                                                         \
   1509     for (y = 0; y < h; y++) {                                           \
   1510         for (x = 0; x < aligned_width; x += 8) {                        \
   1511             for (bg_bits = 0; bg_bits < 8; bg_bits++) {                 \
   1512                 if (*ptr++ != bg)                                       \
   1513                     break;                                              \
   1514             }                                                           \
   1515             if (bg_bits == 8) {                                         \
   1516                 *buf++ = 0;                                             \
   1517                 continue;                                               \
   1518             }                                                           \
   1519             mask = 0x80 >> bg_bits;                                     \
   1520             value = mask;                                               \
   1521             for (bg_bits++; bg_bits < 8; bg_bits++) {                   \
   1522                 mask >>= 1;                                             \
   1523                 if (*ptr++ != bg) {                                     \
   1524                     value |= mask;                                      \
   1525                 }                                                       \
   1526             }                                                           \
   1527             *buf++ = (uint8_t)value;                                    \
   1528         }                                                               \
   1529                                                                         \
   1530         mask = 0x80;                                                    \
   1531         value = 0;                                                      \
   1532         if (x >= w)                                                     \
   1533             continue;                                                   \
   1534                                                                         \
   1535         for (; x < w; x++) {                                            \
   1536             if (*ptr++ != bg) {                                         \
   1537                 value |= mask;                                          \
   1538             }                                                           \
   1539             mask >>= 1;                                                 \
   1540         }                                                               \
   1541         *buf++ = (uint8_t)value;                                        \
   1542     }                                                                   \
   1543 }
   1544 
   1545 DEFINE_MONO_ENCODE_FUNCTION(8)
   1546 DEFINE_MONO_ENCODE_FUNCTION(16)
   1547 DEFINE_MONO_ENCODE_FUNCTION(32)
   1548 
   1549 
   1550 /*
   1551  * JPEG compression stuff.
   1552  */
   1553 
   1554 static rfbBool
   1555 SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
   1556 {
   1557     unsigned char *srcbuf;
   1558     int ps = cl->screen->serverFormat.bitsPerPixel / 8;
   1559     int subsamp = subsampLevel2tjsubsamp[subsampLevel];
   1560     unsigned long size = 0;
   1561     int flags = 0, pitch;
   1562     unsigned char *tmpbuf = NULL;
   1563 
   1564     if (cl->screen->serverFormat.bitsPerPixel == 8)
   1565         return SendFullColorRect(cl, x, y, w, h);
   1566 
   1567     if (ps < 2) {
   1568         rfbLog("Error: JPEG requires 16-bit, 24-bit, or 32-bit pixel format.\n");
   1569         return 0;
   1570     }
   1571     if (!j) {
   1572         if ((j = tjInitCompress()) == NULL) {
   1573             rfbLog("JPEG Error: %s\n", tjGetErrorStr());
   1574             return 0;
   1575         }
   1576     }
   1577 
   1578     if (tightAfterBufSize < TJBUFSIZE(w, h)) {
   1579         if (tightAfterBuf == NULL)
   1580             tightAfterBuf = (char *)malloc(TJBUFSIZE(w, h));
   1581         else
   1582             tightAfterBuf = (char *)realloc(tightAfterBuf,
   1583                                             TJBUFSIZE(w, h));
   1584         if (!tightAfterBuf) {
   1585             rfbLog("Memory allocation failure!\n");
   1586             return 0;
   1587         }
   1588         tightAfterBufSize = TJBUFSIZE(w, h);
   1589     }
   1590 
   1591     if (ps == 2) {
   1592         uint16_t *srcptr, pix;
   1593         unsigned char *dst;
   1594         int inRed, inGreen, inBlue, i, j;
   1595 
   1596         if((tmpbuf = (unsigned char *)malloc(w * h * 3)) == NULL)
   1597             rfbLog("Memory allocation failure!\n");
   1598         srcptr = (uint16_t *)&cl->scaledScreen->frameBuffer
   1599             [y * cl->scaledScreen->paddedWidthInBytes + x * ps];
   1600         dst = tmpbuf;
   1601         for(j = 0; j < h; j++) {
   1602             uint16_t *srcptr2 = srcptr;
   1603             unsigned char *dst2 = dst;
   1604             for (i = 0; i < w; i++) {
   1605                 pix = *srcptr2++;
   1606                 inRed = (int) (pix >> cl->screen->serverFormat.redShift
   1607                                & cl->screen->serverFormat.redMax);
   1608                 inGreen = (int) (pix >> cl->screen->serverFormat.greenShift
   1609                                  & cl->screen->serverFormat.greenMax);
   1610                 inBlue  = (int) (pix >> cl->screen->serverFormat.blueShift
   1611                                  & cl->screen->serverFormat.blueMax);
   1612                 *dst2++ = (uint8_t)((inRed * 255
   1613                                      + cl->screen->serverFormat.redMax / 2)
   1614                                     / cl->screen->serverFormat.redMax);
   1615                	*dst2++ = (uint8_t)((inGreen * 255
   1616                                      + cl->screen->serverFormat.greenMax / 2)
   1617                                     / cl->screen->serverFormat.greenMax);
   1618                 *dst2++ = (uint8_t)((inBlue * 255
   1619                                      + cl->screen->serverFormat.blueMax / 2)
   1620                                     / cl->screen->serverFormat.blueMax);
   1621             }
   1622             srcptr += cl->scaledScreen->paddedWidthInBytes / ps;
   1623             dst += w * 3;
   1624         }
   1625         srcbuf = tmpbuf;
   1626         pitch = w * 3;
   1627         ps = 3;
   1628     } else {
   1629         if (cl->screen->serverFormat.bigEndian && ps == 4)
   1630             flags |= TJ_ALPHAFIRST;
   1631         if (cl->screen->serverFormat.redShift == 16
   1632             && cl->screen->serverFormat.blueShift == 0)
   1633             flags |= TJ_BGR;
   1634         if (cl->screen->serverFormat.bigEndian)
   1635             flags ^= TJ_BGR;
   1636         pitch = cl->scaledScreen->paddedWidthInBytes;
   1637         srcbuf = (unsigned char *)&cl->scaledScreen->frameBuffer
   1638             [y * pitch + x * ps];
   1639     }
   1640 
   1641     if (tjCompress(j, srcbuf, w, pitch, h, ps, (unsigned char *)tightAfterBuf,
   1642                    &size, subsamp, quality, flags) == -1) {
   1643         rfbLog("JPEG Error: %s\n", tjGetErrorStr());
   1644         if (tmpbuf) {
   1645             free(tmpbuf);
   1646             tmpbuf = NULL;
   1647         }
   1648         return 0;
   1649     }
   1650 
   1651     if (tmpbuf) {
   1652         free(tmpbuf);
   1653         tmpbuf = NULL;
   1654     }
   1655 
   1656     if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
   1657         if (!rfbSendUpdateBuf(cl))
   1658             return FALSE;
   1659     }
   1660 
   1661     cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
   1662     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1663 
   1664     return SendCompressedData(cl, tightAfterBuf, (int)size);
   1665 }
   1666 
   1667 static void
   1668 PrepareRowForImg(rfbClientPtr cl,
   1669                   uint8_t *dst,
   1670                   int x,
   1671                   int y,
   1672                   int count)
   1673 {
   1674     if (cl->screen->serverFormat.bitsPerPixel == 32) {
   1675         if ( cl->screen->serverFormat.redMax == 0xFF &&
   1676              cl->screen->serverFormat.greenMax == 0xFF &&
   1677              cl->screen->serverFormat.blueMax == 0xFF ) {
   1678             PrepareRowForImg24(cl, dst, x, y, count);
   1679         } else {
   1680             PrepareRowForImg32(cl, dst, x, y, count);
   1681         }
   1682     } else {
   1683         /* 16 bpp assumed. */
   1684         PrepareRowForImg16(cl, dst, x, y, count);
   1685     }
   1686 }
   1687 
   1688 static void
   1689 PrepareRowForImg24(rfbClientPtr cl,
   1690                     uint8_t *dst,
   1691                     int x,
   1692                     int y,
   1693                     int count)
   1694 {
   1695     uint32_t *fbptr;
   1696     uint32_t pix;
   1697 
   1698     fbptr = (uint32_t *)
   1699         &cl->scaledScreen->frameBuffer[y * cl->scaledScreen->paddedWidthInBytes + x * 4];
   1700 
   1701     while (count--) {
   1702         pix = *fbptr++;
   1703         *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.redShift);
   1704         *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.greenShift);
   1705         *dst++ = (uint8_t)(pix >> cl->screen->serverFormat.blueShift);
   1706     }
   1707 }
   1708 
   1709 #define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                                   \
   1710                                                                             \
   1711 static void                                                                 \
   1712 PrepareRowForImg##bpp(rfbClientPtr cl, uint8_t *dst, int x, int y, int count) { \
   1713     uint##bpp##_t *fbptr;                                                   \
   1714     uint##bpp##_t pix;                                                      \
   1715     int inRed, inGreen, inBlue;                                             \
   1716                                                                             \
   1717     fbptr = (uint##bpp##_t *)                                               \
   1718         &cl->scaledScreen->frameBuffer[y * cl->scaledScreen->paddedWidthInBytes +       \
   1719                              x * (bpp / 8)];                                \
   1720                                                                             \
   1721     while (count--) {                                                       \
   1722         pix = *fbptr++;                                                     \
   1723                                                                             \
   1724         inRed = (int)                                                       \
   1725             (pix >> cl->screen->serverFormat.redShift   & cl->screen->serverFormat.redMax); \
   1726         inGreen = (int)                                                     \
   1727             (pix >> cl->screen->serverFormat.greenShift & cl->screen->serverFormat.greenMax); \
   1728         inBlue  = (int)                                                     \
   1729             (pix >> cl->screen->serverFormat.blueShift  & cl->screen->serverFormat.blueMax); \
   1730                                                                             \
   1731 	*dst++ = (uint8_t)((inRed   * 255 + cl->screen->serverFormat.redMax / 2) / \
   1732                          cl->screen->serverFormat.redMax);                  \
   1733 	*dst++ = (uint8_t)((inGreen * 255 + cl->screen->serverFormat.greenMax / 2) / \
   1734                          cl->screen->serverFormat.greenMax);                \
   1735 	*dst++ = (uint8_t)((inBlue  * 255 + cl->screen->serverFormat.blueMax / 2) / \
   1736                          cl->screen->serverFormat.blueMax);                 \
   1737     }                                                                       \
   1738 }
   1739 
   1740 DEFINE_JPEG_GET_ROW_FUNCTION(16)
   1741 DEFINE_JPEG_GET_ROW_FUNCTION(32)
   1742 
   1743 /*
   1744  * PNG compression stuff.
   1745  */
   1746 
   1747 #ifdef LIBVNCSERVER_HAVE_LIBPNG
   1748 
   1749 static TLS int pngDstDataLen = 0;
   1750 
   1751 static rfbBool CanSendPngRect(rfbClientPtr cl, int w, int h) {
   1752     if (cl->tightEncoding != rfbEncodingTightPng) {
   1753         return FALSE;
   1754     }
   1755 
   1756     if ( cl->screen->serverFormat.bitsPerPixel == 8 ||
   1757          cl->format.bitsPerPixel == 8) {
   1758         return FALSE;
   1759     }
   1760 
   1761     return TRUE;
   1762 }
   1763 
   1764 static void pngWriteData(png_structp png_ptr, png_bytep data,
   1765                            png_size_t length)
   1766 {
   1767 #if 0
   1768     rfbClientPtr cl = png_get_io_ptr(png_ptr);
   1769 
   1770     buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
   1771     memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
   1772 #endif
   1773     memcpy(tightAfterBuf + pngDstDataLen, data, length);
   1774 
   1775     pngDstDataLen += length;
   1776 }
   1777 
   1778 static void pngFlushData(png_structp png_ptr)
   1779 {
   1780 }
   1781 
   1782 
   1783 static void *pngMalloc(png_structp png_ptr, png_size_t size)
   1784 {
   1785     return malloc(size);
   1786 }
   1787 
   1788 static void pngFree(png_structp png_ptr, png_voidp ptr)
   1789 {
   1790     free(ptr);
   1791 }
   1792 
   1793 static rfbBool SendPngRect(rfbClientPtr cl, int x, int y, int w, int h) {
   1794     /* rfbLog(">> SendPngRect x:%d, y:%d, w:%d, h:%d\n", x, y, w, h); */
   1795 
   1796     png_byte color_type;
   1797     png_structp png_ptr;
   1798     png_infop info_ptr;
   1799     png_colorp png_palette = NULL;
   1800     int level = tightPngConf[cl->tightCompressLevel].png_zlib_level;
   1801     int filters = tightPngConf[cl->tightCompressLevel].png_filters;
   1802     uint8_t *buf;
   1803     int dy;
   1804 
   1805     pngDstDataLen = 0;
   1806 
   1807     png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
   1808                                         NULL, pngMalloc, pngFree);
   1809 
   1810     if (png_ptr == NULL)
   1811         return FALSE;
   1812 
   1813     info_ptr = png_create_info_struct(png_ptr);
   1814 
   1815     if (info_ptr == NULL) {
   1816         png_destroy_write_struct(&png_ptr, NULL);
   1817         return FALSE;
   1818     }
   1819 
   1820     png_set_write_fn(png_ptr, (void *) cl, pngWriteData, pngFlushData);
   1821     png_set_compression_level(png_ptr, level);
   1822     png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
   1823 
   1824 #if 0
   1825     /* TODO: */
   1826     if (palette) {
   1827         color_type = PNG_COLOR_TYPE_PALETTE;
   1828     } else {
   1829         color_type = PNG_COLOR_TYPE_RGB;
   1830     }
   1831 #else
   1832     color_type = PNG_COLOR_TYPE_RGB;
   1833 #endif
   1834     png_set_IHDR(png_ptr, info_ptr, w, h,
   1835                  8, color_type, PNG_INTERLACE_NONE,
   1836                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   1837 
   1838 #if 0
   1839     if (color_type == PNG_COLOR_TYPE_PALETTE) {
   1840         struct palette_cb_priv priv;
   1841 
   1842         png_palette = pngMalloc(png_ptr, sizeof(*png_palette) *
   1843                                  palette_size(palette));
   1844 
   1845         priv.vs = vs;
   1846         priv.png_palette = png_palette;
   1847         palette_iter(palette, write_png_palette, &priv);
   1848 
   1849         png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
   1850 
   1851         offset = vs->tight.tight.offset;
   1852         if (vs->clientds.pf.bytes_per_pixel == 4) {
   1853             tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
   1854         } else {
   1855             tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
   1856         }
   1857     }
   1858 
   1859     buffer_reserve(&vs->tight.png, 2048);
   1860 #endif
   1861 
   1862     png_write_info(png_ptr, info_ptr);
   1863     buf = malloc(w * 3);
   1864     for (dy = 0; dy < h; dy++)
   1865     {
   1866 #if 0
   1867         if (color_type == PNG_COLOR_TYPE_PALETTE) {
   1868             memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
   1869         } else {
   1870             PrepareRowForImg(cl, buf, x, y + dy, w);
   1871         }
   1872 #else
   1873         PrepareRowForImg(cl, buf, x, y + dy, w);
   1874 #endif
   1875         png_write_row(png_ptr, buf);
   1876     }
   1877     free(buf);
   1878 
   1879     png_write_end(png_ptr, NULL);
   1880 
   1881     if (color_type == PNG_COLOR_TYPE_PALETTE) {
   1882         pngFree(png_ptr, png_palette);
   1883     }
   1884 
   1885     png_destroy_write_struct(&png_ptr, &info_ptr);
   1886 
   1887     /* done v */
   1888 
   1889     if (cl->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
   1890         if (!rfbSendUpdateBuf(cl))
   1891             return FALSE;
   1892     }
   1893 
   1894     cl->updateBuf[cl->ublen++] = (char)(rfbTightPng << 4);
   1895     rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1);
   1896 
   1897     /* rfbLog("<< SendPngRect\n"); */
   1898     return SendCompressedData(cl, tightAfterBuf, pngDstDataLen);
   1899 }
   1900 #endif
   1901