Home | History | Annotate | Download | only in turbovnc
      1 /*
      2  * tight.c
      3  *
      4  * Routines to implement Tight Encoding
      5  */
      6 
      7 /*
      8  *  Copyright (C) 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
      9  *  Copyright (C) 2004 Landmark Graphics Corporation.  All Rights Reserved.
     10  *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
     11  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
     12  *
     13  *  This is free software; you can redistribute it and/or modify
     14  *  it under the terms of the GNU General Public License as published by
     15  *  the Free Software Foundation; either version 2 of the License, or
     16  *  (at your option) any later version.
     17  *
     18  *  This software is distributed in the hope that it will be useful,
     19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21  *  GNU General Public License for more details.
     22  *
     23  *  You should have received a copy of the GNU General Public License
     24  *  along with this software; if not, write to the Free Software
     25  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
     26  *  USA.
     27  */
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include "rfb.h"
     33 #include "turbojpeg.h"
     34 
     35 /* Note: The following constant should not be changed. */
     36 #define TIGHT_MIN_TO_COMPRESS 12
     37 
     38 /* The parameters below may be adjusted. */
     39 #define MIN_SPLIT_RECT_SIZE     4096
     40 #define MIN_SOLID_SUBRECT_SIZE  2048
     41 #define MAX_SPLIT_TILE_SIZE       16
     42 
     43 /* This variable is set on every rfbSendRectEncodingTight() call. */
     44 static Bool usePixelFormat24;
     45 
     46 
     47 /* Compression level stuff. The following array contains various
     48    encoder parameters for each of 10 compression levels (0..9).
     49    Last three parameters correspond to JPEG quality levels (0..9). */
     50 
     51 typedef struct TIGHT_CONF_s {
     52     int maxRectSize, maxRectWidth;
     53     int monoMinRectSize;
     54     int idxZlibLevel, monoZlibLevel, rawZlibLevel;
     55     int idxMaxColorsDivisor;
     56 } TIGHT_CONF;
     57 
     58 static TIGHT_CONF tightConf[2] = {
     59     { 65536, 2048,   6, 0, 0, 0,   4 },
     60 #if 0
     61     {  2048,  128,   6, 1, 1, 1,   8 },
     62     {  6144,  256,   8, 3, 3, 2,  24 },
     63     { 10240, 1024,  12, 5, 5, 3,  32 },
     64     { 16384, 2048,  12, 6, 6, 4,  32 },
     65     { 32768, 2048,  12, 7, 7, 5,  32 },
     66     { 65536, 2048,  16, 7, 7, 6,  48 },
     67     { 65536, 2048,  16, 8, 8, 7,  64 },
     68     { 65536, 2048,  32, 9, 9, 8,  64 },
     69 #endif
     70     { 65536, 2048,  32, 1, 1, 1,  96 }
     71 };
     72 
     73 static int compressLevel;
     74 static int qualityLevel;
     75 static int subsampLevel;
     76 
     77 static const int subsampLevel2tjsubsamp[4] = {
     78     TJ_444, TJ_411, TJ_422, TJ_GRAYSCALE
     79 };
     80 
     81 /* Stuff dealing with palettes. */
     82 
     83 typedef struct COLOR_LIST_s {
     84     struct COLOR_LIST_s *next;
     85     int idx;
     86     CARD32 rgb;
     87 } COLOR_LIST;
     88 
     89 typedef struct PALETTE_ENTRY_s {
     90     COLOR_LIST *listNode;
     91     int numPixels;
     92 } PALETTE_ENTRY;
     93 
     94 typedef struct PALETTE_s {
     95     PALETTE_ENTRY entry[256];
     96     COLOR_LIST *hash[256];
     97     COLOR_LIST list[256];
     98 } PALETTE;
     99 
    100 static int paletteNumColors, paletteMaxColors;
    101 static CARD32 monoBackground, monoForeground;
    102 static PALETTE palette;
    103 
    104 /* Pointers to dynamically-allocated buffers. */
    105 
    106 static int tightBeforeBufSize = 0;
    107 static char *tightBeforeBuf = NULL;
    108 
    109 static int tightAfterBufSize = 0;
    110 static char *tightAfterBuf = NULL;
    111 
    112 static int *prevRowBuf = NULL;
    113 
    114 
    115 /* Prototypes for static functions. */
    116 
    117 static void FindBestSolidArea (int x, int y, int w, int h,
    118                                CARD32 colorValue, int *w_ptr, int *h_ptr);
    119 static void ExtendSolidArea   (int x, int y, int w, int h,
    120                                CARD32 colorValue,
    121                                int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
    122 static Bool CheckSolidTile    (int x, int y, int w, int h,
    123                                CARD32 *colorPtr, Bool needSameColor);
    124 static Bool CheckSolidTile8   (int x, int y, int w, int h,
    125                                CARD32 *colorPtr, Bool needSameColor);
    126 static Bool CheckSolidTile16  (int x, int y, int w, int h,
    127                                CARD32 *colorPtr, Bool needSameColor);
    128 static Bool CheckSolidTile32  (int x, int y, int w, int h,
    129                                CARD32 *colorPtr, Bool needSameColor);
    130 
    131 static Bool SendRectSimple    (rfbClientPtr cl, int x, int y, int w, int h);
    132 static Bool SendSubrect       (rfbClientPtr cl, int x, int y, int w, int h);
    133 static Bool SendTightHeader   (rfbClientPtr cl, int x, int y, int w, int h);
    134 
    135 static Bool SendSolidRect     (rfbClientPtr cl);
    136 static Bool SendMonoRect      (rfbClientPtr cl, int w, int h);
    137 static Bool SendIndexedRect   (rfbClientPtr cl, int w, int h);
    138 static Bool SendFullColorRect (rfbClientPtr cl, int w, int h);
    139 
    140 static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen,
    141                          int zlibLevel, int zlibStrategy);
    142 static Bool SendCompressedData(rfbClientPtr cl, char *buf, int compressedLen);
    143 
    144 static void FillPalette8(int count);
    145 static void FillPalette16(int count);
    146 static void FillPalette32(int count);
    147 static void FastFillPalette16(rfbClientPtr cl, CARD16 *data, int w, int pitch,
    148                               int h);
    149 static void FastFillPalette32(rfbClientPtr cl, CARD32 *data, int w, int pitch,
    150                               int h);
    151 
    152 static void PaletteReset(void);
    153 static int PaletteInsert(CARD32 rgb, int numPixels, int bpp);
    154 
    155 static void Pack24(char *buf, rfbPixelFormat *fmt, int count);
    156 
    157 static void EncodeIndexedRect16(CARD8 *buf, int count);
    158 static void EncodeIndexedRect32(CARD8 *buf, int count);
    159 
    160 static void EncodeMonoRect8(CARD8 *buf, int w, int h);
    161 static void EncodeMonoRect16(CARD8 *buf, int w, int h);
    162 static void EncodeMonoRect32(CARD8 *buf, int w, int h);
    163 
    164 static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
    165                          int quality);
    166 
    167 /*
    168  * Tight encoding implementation.
    169  */
    170 
    171 int
    172 rfbNumCodedRectsTight(cl, x, y, w, h)
    173     rfbClientPtr cl;
    174     int x, y, w, h;
    175 {
    176     int maxRectSize, maxRectWidth;
    177     int subrectMaxWidth, subrectMaxHeight;
    178 
    179     /* No matter how many rectangles we will send if LastRect markers
    180        are used to terminate rectangle stream. */
    181     if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
    182       return 0;
    183 
    184     maxRectSize = tightConf[compressLevel].maxRectSize;
    185     maxRectWidth = tightConf[compressLevel].maxRectWidth;
    186 
    187     if (w > maxRectWidth || w * h > maxRectSize) {
    188         subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    189         subrectMaxHeight = maxRectSize / subrectMaxWidth;
    190         return (((w - 1) / maxRectWidth + 1) *
    191                 ((h - 1) / subrectMaxHeight + 1));
    192     } else {
    193         return 1;
    194     }
    195 }
    196 
    197 Bool
    198 rfbSendRectEncodingTight(cl, x, y, w, h)
    199     rfbClientPtr cl;
    200     int x, y, w, h;
    201 {
    202     int nMaxRows;
    203     CARD32 colorValue;
    204     int dx, dy, dw, dh;
    205     int x_best, y_best, w_best, h_best;
    206     char *fbptr;
    207 
    208     compressLevel = cl->tightCompressLevel > 0 ? 1 : 0;
    209     qualityLevel = cl->tightQualityLevel;
    210     if (qualityLevel != -1) {
    211         compressLevel = 1;
    212         tightConf[compressLevel].idxZlibLevel = 1;
    213         tightConf[compressLevel].monoZlibLevel = 1;
    214         tightConf[compressLevel].rawZlibLevel = 1;
    215     } else {
    216         tightConf[compressLevel].idxZlibLevel = cl->tightCompressLevel;
    217         tightConf[compressLevel].monoZlibLevel = cl->tightCompressLevel;
    218         tightConf[compressLevel].rawZlibLevel = cl->tightCompressLevel;
    219     }
    220     subsampLevel = cl->tightSubsampLevel;
    221 
    222     if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
    223          cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
    224         usePixelFormat24 = TRUE;
    225     } else {
    226         usePixelFormat24 = FALSE;
    227     }
    228 
    229     if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
    230         return SendRectSimple(cl, x, y, w, h);
    231 
    232     /* Make sure we can write at least one pixel into tightBeforeBuf. */
    233 
    234     if (tightBeforeBufSize < 4) {
    235         tightBeforeBufSize = 4;
    236         if (tightBeforeBuf == NULL)
    237             tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
    238         else
    239             tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
    240                                               tightBeforeBufSize);
    241     }
    242 
    243     /* Calculate maximum number of rows in one non-solid rectangle. */
    244 
    245     {
    246         int maxRectSize, maxRectWidth, nMaxWidth;
    247 
    248         maxRectSize = tightConf[compressLevel].maxRectSize;
    249         maxRectWidth = tightConf[compressLevel].maxRectWidth;
    250         nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    251         nMaxRows = maxRectSize / nMaxWidth;
    252     }
    253 
    254     /* Try to find large solid-color areas and send them separately. */
    255 
    256     for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
    257 
    258         /* If a rectangle becomes too large, send its upper part now. */
    259 
    260         if (dy - y >= nMaxRows) {
    261             if (!SendRectSimple(cl, x, y, w, nMaxRows))
    262                 return 0;
    263             y += nMaxRows;
    264             h -= nMaxRows;
    265         }
    266 
    267         dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
    268             MAX_SPLIT_TILE_SIZE : (y + h - dy);
    269 
    270         for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
    271 
    272             dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
    273                 MAX_SPLIT_TILE_SIZE : (x + w - dx);
    274 
    275             if (CheckSolidTile(dx, dy, dw, dh, &colorValue, FALSE)) {
    276 
    277                 if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) {
    278 		    CARD32 r=(colorValue>>16)&0xFF;
    279 		    CARD32 g=(colorValue>>8)&0xFF;
    280 		    CARD32 b=(colorValue)&0xFF;
    281 		    double y=(0.257*(double)r)+(0.504*(double)g)
    282 		        +(0.098*(double)b)+16.;
    283 		    colorValue=(int)y+(((int)y)<<8)+(((int)y)<<16);
    284 		}
    285 
    286                 /* Get dimensions of solid-color area. */
    287 
    288                 FindBestSolidArea(dx, dy, w - (dx - x), h - (dy - y),
    289 				  colorValue, &w_best, &h_best);
    290 
    291                 /* Make sure a solid rectangle is large enough
    292                    (or the whole rectangle is of the same color). */
    293 
    294                 if ( w_best * h_best != w * h &&
    295                      w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
    296                     continue;
    297 
    298                 /* Try to extend solid rectangle to maximum size. */
    299 
    300                 x_best = dx; y_best = dy;
    301                 ExtendSolidArea(x, y, w, h, colorValue,
    302                                 &x_best, &y_best, &w_best, &h_best);
    303 
    304                 /* Send rectangles at top and left to solid-color area. */
    305 
    306                 if ( y_best != y &&
    307                      !SendRectSimple(cl, x, y, w, y_best-y) )
    308                     return FALSE;
    309                 if ( x_best != x &&
    310                      !rfbSendRectEncodingTight(cl, x, y_best,
    311                                                x_best-x, h_best) )
    312                     return FALSE;
    313 
    314                 /* Send solid-color rectangle. */
    315 
    316                 if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
    317                     return FALSE;
    318 
    319                 fbptr = (rfbScreen.pfbMemory +
    320                          (rfbScreen.paddedWidthInBytes * y_best) +
    321                          (x_best * (rfbScreen.bitsPerPixel / 8)));
    322 
    323                 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
    324                                    &cl->format, fbptr, tightBeforeBuf,
    325                                    rfbScreen.paddedWidthInBytes, 1, 1);
    326 
    327                 if (!SendSolidRect(cl))
    328                     return FALSE;
    329 
    330                 /* Send remaining rectangles (at right and bottom). */
    331 
    332                 if ( x_best + w_best != x + w &&
    333                      !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
    334                                                w-(x_best-x)-w_best, h_best) )
    335                     return FALSE;
    336                 if ( y_best + h_best != y + h &&
    337                      !rfbSendRectEncodingTight(cl, x, y_best+h_best,
    338                                                w, h-(y_best-y)-h_best) )
    339                     return FALSE;
    340 
    341                 /* Return after all recursive calls are done. */
    342 
    343                 return TRUE;
    344             }
    345 
    346         }
    347 
    348     }
    349 
    350     /* No suitable solid-color rectangles found. */
    351 
    352     return SendRectSimple(cl, x, y, w, h);
    353 }
    354 
    355 static void
    356 FindBestSolidArea(x, y, w, h, colorValue, w_ptr, h_ptr)
    357     int x, y, w, h;
    358     CARD32 colorValue;
    359     int *w_ptr, *h_ptr;
    360 {
    361     int dx, dy, dw, dh;
    362     int w_prev;
    363     int w_best = 0, h_best = 0;
    364 
    365     w_prev = w;
    366 
    367     for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
    368 
    369         dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
    370             MAX_SPLIT_TILE_SIZE : (y + h - dy);
    371         dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
    372             MAX_SPLIT_TILE_SIZE : w_prev;
    373 
    374         if (!CheckSolidTile(x, dy, dw, dh, &colorValue, TRUE))
    375             break;
    376 
    377         for (dx = x + dw; dx < x + w_prev;) {
    378             dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
    379                 MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
    380             if (!CheckSolidTile(dx, dy, dw, dh, &colorValue, TRUE))
    381                 break;
    382 	    dx += dw;
    383         }
    384 
    385         w_prev = dx - x;
    386         if (w_prev * (dy + dh - y) > w_best * h_best) {
    387             w_best = w_prev;
    388             h_best = dy + dh - y;
    389         }
    390     }
    391 
    392     *w_ptr = w_best;
    393     *h_ptr = h_best;
    394 }
    395 
    396 static void
    397 ExtendSolidArea(x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
    398     int x, y, w, h;
    399     CARD32 colorValue;
    400     int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
    401 {
    402     int cx, cy;
    403 
    404     /* Try to extend the area upwards. */
    405     for ( cy = *y_ptr - 1;
    406           cy >= y && CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
    407           cy-- );
    408     *h_ptr += *y_ptr - (cy + 1);
    409     *y_ptr = cy + 1;
    410 
    411     /* ... downwards. */
    412     for ( cy = *y_ptr + *h_ptr;
    413           cy < y + h &&
    414               CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
    415           cy++ );
    416     *h_ptr += cy - (*y_ptr + *h_ptr);
    417 
    418     /* ... to the left. */
    419     for ( cx = *x_ptr - 1;
    420           cx >= x && CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
    421           cx-- );
    422     *w_ptr += *x_ptr - (cx + 1);
    423     *x_ptr = cx + 1;
    424 
    425     /* ... to the right. */
    426     for ( cx = *x_ptr + *w_ptr;
    427           cx < x + w &&
    428               CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
    429           cx++ );
    430     *w_ptr += cx - (*x_ptr + *w_ptr);
    431 }
    432 
    433 /*
    434  * Check if a rectangle is all of the same color. If needSameColor is
    435  * set to non-zero, then also check that its color equals to the
    436  * *colorPtr value. The result is 1 if the test is successfull, and in
    437  * that case new color will be stored in *colorPtr.
    438  */
    439 
    440 static Bool
    441 CheckSolidTile(x, y, w, h, colorPtr, needSameColor)
    442     int x, y, w, h;
    443     CARD32 *colorPtr;
    444     Bool needSameColor;
    445 {
    446     switch(rfbServerFormat.bitsPerPixel) {
    447     case 32:
    448         return CheckSolidTile32(x, y, w, h, colorPtr, needSameColor);
    449     case 16:
    450         return CheckSolidTile16(x, y, w, h, colorPtr, needSameColor);
    451     default:
    452         return CheckSolidTile8(x, y, w, h, colorPtr, needSameColor);
    453     }
    454 }
    455 
    456 #define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                      \
    457                                                                               \
    458 static Bool                                                                   \
    459 CheckSolidTile##bpp(x, y, w, h, colorPtr, needSameColor)                      \
    460     int x, y, w, h;                                                           \
    461     CARD32 *colorPtr;                                                         \
    462     Bool needSameColor;                                                       \
    463 {                                                                             \
    464     CARD##bpp *fbptr;                                                         \
    465     CARD##bpp colorValue;                                                     \
    466     int dx, dy;                                                               \
    467                                                                               \
    468     fbptr = (CARD##bpp *)                                                     \
    469         &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes + x * (bpp/8)]; \
    470                                                                               \
    471     colorValue = *fbptr;                                                      \
    472     if (needSameColor && (CARD32)colorValue != *colorPtr)                     \
    473         return FALSE;                                                         \
    474                                                                               \
    475     for (dy = 0; dy < h; dy++) {                                              \
    476         for (dx = 0; dx < w; dx++) {                                          \
    477             if (colorValue != fbptr[dx])                                      \
    478                 return FALSE;                                                 \
    479         }                                                                     \
    480         fbptr = (CARD##bpp *)((CARD8 *)fbptr + rfbScreen.paddedWidthInBytes); \
    481     }                                                                         \
    482                                                                               \
    483     *colorPtr = (CARD32)colorValue;                                           \
    484     return TRUE;                                                              \
    485 }
    486 
    487 DEFINE_CHECK_SOLID_FUNCTION(8)
    488 DEFINE_CHECK_SOLID_FUNCTION(16)
    489 DEFINE_CHECK_SOLID_FUNCTION(32)
    490 
    491 static Bool
    492 SendRectSimple(cl, x, y, w, h)
    493     rfbClientPtr cl;
    494     int x, y, w, h;
    495 {
    496     int maxBeforeSize, maxAfterSize;
    497     int maxRectSize, maxRectWidth;
    498     int subrectMaxWidth, subrectMaxHeight;
    499     int dx, dy;
    500     int rw, rh;
    501 
    502     maxRectSize = tightConf[compressLevel].maxRectSize;
    503     maxRectWidth = tightConf[compressLevel].maxRectWidth;
    504 
    505     maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
    506     maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
    507 
    508     if (tightBeforeBufSize < maxBeforeSize) {
    509         tightBeforeBufSize = maxBeforeSize;
    510         if (tightBeforeBuf == NULL)
    511             tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
    512         else
    513             tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
    514                                               tightBeforeBufSize);
    515     }
    516 
    517     if (tightAfterBufSize < maxAfterSize) {
    518         tightAfterBufSize = maxAfterSize;
    519         if (tightAfterBuf == NULL)
    520             tightAfterBuf = (char *)xalloc(tightAfterBufSize);
    521         else
    522             tightAfterBuf = (char *)xrealloc(tightAfterBuf,
    523                                              tightAfterBufSize);
    524     }
    525 
    526     if (w > maxRectWidth || w * h > maxRectSize) {
    527         subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
    528         subrectMaxHeight = maxRectSize / subrectMaxWidth;
    529 
    530         for (dy = 0; dy < h; dy += subrectMaxHeight) {
    531             for (dx = 0; dx < w; dx += maxRectWidth) {
    532                 rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
    533                 rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
    534                 if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
    535                     return FALSE;
    536             }
    537         }
    538     } else {
    539         if (!SendSubrect(cl, x, y, w, h))
    540             return FALSE;
    541     }
    542 
    543     return TRUE;
    544 }
    545 
    546 static Bool
    547 SendSubrect(cl, x, y, w, h)
    548     rfbClientPtr cl;
    549     int x, y, w, h;
    550 {
    551     char *fbptr;
    552     Bool success = FALSE;
    553 
    554     /* Send pending data if there is more than 128 bytes. */
    555     if (ublen > 128) {
    556         if (!rfbSendUpdateBuf(cl))
    557             return FALSE;
    558     }
    559 
    560     if (!SendTightHeader(cl, x, y, w, h))
    561         return FALSE;
    562 
    563     fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y)
    564              + (x * (rfbScreen.bitsPerPixel / 8)));
    565 
    566     if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1)
    567         return SendJpegRect(cl, x, y, w, h, qualityLevel);
    568 
    569     paletteMaxColors = w * h / tightConf[compressLevel].idxMaxColorsDivisor;
    570     if(qualityLevel != -1)
    571         paletteMaxColors = 24;
    572     if ( paletteMaxColors < 2 &&
    573          w * h >= tightConf[compressLevel].monoMinRectSize ) {
    574         paletteMaxColors = 2;
    575     }
    576 
    577     if (cl->format.bitsPerPixel == rfbServerFormat.bitsPerPixel &&
    578         cl->format.redMax == rfbServerFormat.redMax &&
    579         cl->format.greenMax == rfbServerFormat.greenMax &&
    580         cl->format.blueMax == rfbServerFormat.blueMax &&
    581         cl->format.bitsPerPixel >= 16) {
    582 
    583         /* This is so we can avoid translating the pixels when compressing
    584            with JPEG, since it is unnecessary */
    585         switch (cl->format.bitsPerPixel) {
    586         case 16:
    587             FastFillPalette16(cl, (CARD16 *)fbptr, w,
    588                               rfbScreen.paddedWidthInBytes/2, h);
    589             break;
    590         default:
    591             FastFillPalette32(cl, (CARD32 *)fbptr, w,
    592                               rfbScreen.paddedWidthInBytes/4, h);
    593         }
    594 
    595         if(paletteNumColors != 0 || qualityLevel == -1) {
    596             (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
    597                                &cl->format, fbptr, tightBeforeBuf,
    598                                rfbScreen.paddedWidthInBytes, w, h);
    599         }
    600     }
    601     else {
    602         (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
    603                            &cl->format, fbptr, tightBeforeBuf,
    604                            rfbScreen.paddedWidthInBytes, w, h);
    605 
    606         switch (cl->format.bitsPerPixel) {
    607         case 8:
    608             FillPalette8(w * h);
    609             break;
    610         case 16:
    611             FillPalette16(w * h);
    612             break;
    613         default:
    614             FillPalette32(w * h);
    615         }
    616     }
    617 
    618     switch (paletteNumColors) {
    619     case 0:
    620         /* Truecolor image */
    621         if (qualityLevel != -1) {
    622             success = SendJpegRect(cl, x, y, w, h, qualityLevel);
    623         } else {
    624             success = SendFullColorRect(cl, w, h);
    625         }
    626         break;
    627     case 1:
    628         /* Solid rectangle */
    629         success = SendSolidRect(cl);
    630         break;
    631     case 2:
    632         /* Two-color rectangle */
    633         success = SendMonoRect(cl, w, h);
    634         break;
    635     default:
    636         /* Up to 256 different colors */
    637         success = SendIndexedRect(cl, w, h);
    638     }
    639     return success;
    640 }
    641 
    642 static Bool
    643 SendTightHeader(cl, x, y, w, h)
    644     rfbClientPtr cl;
    645     int x, y, w, h;
    646 {
    647     rfbFramebufferUpdateRectHeader rect;
    648 
    649     if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
    650         if (!rfbSendUpdateBuf(cl))
    651             return FALSE;
    652     }
    653 
    654     rect.r.x = Swap16IfLE(x);
    655     rect.r.y = Swap16IfLE(y);
    656     rect.r.w = Swap16IfLE(w);
    657     rect.r.h = Swap16IfLE(h);
    658     rect.encoding = Swap32IfLE(rfbEncodingTight);
    659 
    660     memcpy(&updateBuf[ublen], (char *)&rect,
    661            sz_rfbFramebufferUpdateRectHeader);
    662     ublen += sz_rfbFramebufferUpdateRectHeader;
    663 
    664     cl->rfbRectanglesSent[rfbEncodingTight]++;
    665     cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
    666 
    667     return TRUE;
    668 }
    669 
    670 /*
    671  * Subencoding implementations.
    672  */
    673 
    674 static Bool
    675 SendSolidRect(cl)
    676     rfbClientPtr cl;
    677 {
    678     int len;
    679 
    680     if (usePixelFormat24) {
    681         Pack24(tightBeforeBuf, &cl->format, 1);
    682         len = 3;
    683     } else
    684         len = cl->format.bitsPerPixel / 8;
    685 
    686     if (ublen + 1 + len > UPDATE_BUF_SIZE) {
    687         if (!rfbSendUpdateBuf(cl))
    688             return FALSE;
    689     }
    690 
    691     updateBuf[ublen++] = (char)(rfbTightFill << 4);
    692     memcpy (&updateBuf[ublen], tightBeforeBuf, len);
    693     ublen += len;
    694 
    695     cl->rfbBytesSent[rfbEncodingTight] += len + 1;
    696 
    697     return TRUE;
    698 }
    699 
    700 static Bool
    701 SendMonoRect(cl, w, h)
    702     rfbClientPtr cl;
    703     int w, h;
    704 {
    705     int streamId = 1;
    706     int paletteLen, dataLen;
    707 
    708     if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 +
    709           2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
    710         if (!rfbSendUpdateBuf(cl))
    711             return FALSE;
    712     }
    713 
    714     /* Prepare tight encoding header. */
    715     dataLen = (w + 7) / 8;
    716     dataLen *= h;
    717 
    718     if (tightConf[compressLevel].monoZlibLevel == 0)
    719         updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
    720     else
    721         updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4;
    722     updateBuf[ublen++] = rfbTightFilterPalette;
    723     updateBuf[ublen++] = 1;
    724 
    725     /* Prepare palette, convert image. */
    726     switch (cl->format.bitsPerPixel) {
    727 
    728     case 32:
    729         EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h);
    730 
    731         ((CARD32 *)tightAfterBuf)[0] = monoBackground;
    732         ((CARD32 *)tightAfterBuf)[1] = monoForeground;
    733         if (usePixelFormat24) {
    734             Pack24(tightAfterBuf, &cl->format, 2);
    735             paletteLen = 6;
    736         } else
    737             paletteLen = 8;
    738 
    739         memcpy(&updateBuf[ublen], tightAfterBuf, paletteLen);
    740         ublen += paletteLen;
    741         cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
    742         break;
    743 
    744     case 16:
    745         EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h);
    746 
    747         ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground;
    748         ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground;
    749 
    750         memcpy(&updateBuf[ublen], tightAfterBuf, 4);
    751         ublen += 4;
    752         cl->rfbBytesSent[rfbEncodingTight] += 7;
    753         break;
    754 
    755     default:
    756         EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h);
    757 
    758         updateBuf[ublen++] = (char)monoBackground;
    759         updateBuf[ublen++] = (char)monoForeground;
    760         cl->rfbBytesSent[rfbEncodingTight] += 5;
    761     }
    762 
    763     return CompressData(cl, streamId, dataLen,
    764                         tightConf[compressLevel].monoZlibLevel,
    765                         Z_DEFAULT_STRATEGY);
    766 }
    767 
    768 static Bool
    769 SendIndexedRect(cl, w, h)
    770     rfbClientPtr cl;
    771     int w, h;
    772 {
    773     int streamId = 2;
    774     int i, entryLen;
    775 
    776     if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 +
    777           paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
    778         if (!rfbSendUpdateBuf(cl))
    779             return FALSE;
    780     }
    781 
    782     /* Prepare tight encoding header. */
    783     if (tightConf[compressLevel].idxZlibLevel == 0)
    784         updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
    785     else
    786         updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4;
    787     updateBuf[ublen++] = rfbTightFilterPalette;
    788     updateBuf[ublen++] = (char)(paletteNumColors - 1);
    789 
    790     /* Prepare palette, convert image. */
    791     switch (cl->format.bitsPerPixel) {
    792 
    793     case 32:
    794         EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h);
    795 
    796         for (i = 0; i < paletteNumColors; i++) {
    797             ((CARD32 *)tightAfterBuf)[i] =
    798                 palette.entry[i].listNode->rgb;
    799         }
    800         if (usePixelFormat24) {
    801             Pack24(tightAfterBuf, &cl->format, paletteNumColors);
    802             entryLen = 3;
    803         } else
    804             entryLen = 4;
    805 
    806         memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * entryLen);
    807         ublen += paletteNumColors * entryLen;
    808         cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
    809         break;
    810 
    811     case 16:
    812         EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h);
    813 
    814         for (i = 0; i < paletteNumColors; i++) {
    815             ((CARD16 *)tightAfterBuf)[i] =
    816                 (CARD16)palette.entry[i].listNode->rgb;
    817         }
    818 
    819         memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * 2);
    820         ublen += paletteNumColors * 2;
    821         cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
    822         break;
    823 
    824     default:
    825         return FALSE;           /* Should never happen. */
    826     }
    827 
    828     return CompressData(cl, streamId, w * h,
    829                         tightConf[compressLevel].idxZlibLevel,
    830                         Z_DEFAULT_STRATEGY);
    831 }
    832 
    833 static Bool
    834 SendFullColorRect(cl, w, h)
    835     rfbClientPtr cl;
    836     int w, h;
    837 {
    838     int streamId = 0;
    839     int len;
    840 
    841     if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
    842         if (!rfbSendUpdateBuf(cl))
    843             return FALSE;
    844     }
    845 
    846     if (tightConf[compressLevel].rawZlibLevel == 0)
    847         updateBuf[ublen++] = (char)(rfbTightNoZlib << 4);
    848     else
    849         updateBuf[ublen++] = 0x00;  /* stream id = 0, no flushing, no filter */
    850     cl->rfbBytesSent[rfbEncodingTight]++;
    851 
    852     if (usePixelFormat24) {
    853         Pack24(tightBeforeBuf, &cl->format, w * h);
    854         len = 3;
    855     } else
    856         len = cl->format.bitsPerPixel / 8;
    857 
    858     return CompressData(cl, streamId, w * h * len,
    859                         tightConf[compressLevel].rawZlibLevel,
    860                         Z_DEFAULT_STRATEGY);
    861 }
    862 
    863 static Bool
    864 CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
    865     rfbClientPtr cl;
    866     int streamId, dataLen, zlibLevel, zlibStrategy;
    867 {
    868     z_streamp pz;
    869     int err, i;
    870 
    871     if (dataLen < TIGHT_MIN_TO_COMPRESS) {
    872         memcpy(&updateBuf[ublen], tightBeforeBuf, dataLen);
    873         ublen += dataLen;
    874         cl->rfbBytesSent[rfbEncodingTight] += dataLen;
    875         return TRUE;
    876     }
    877 
    878     if (zlibLevel == 0)
    879         return SendCompressedData (cl, tightBeforeBuf, dataLen);
    880 
    881     pz = &cl->zsStruct[streamId];
    882 
    883     /* Initialize compression stream if needed. */
    884     if (!cl->zsActive[streamId]) {
    885         pz->zalloc = Z_NULL;
    886         pz->zfree = Z_NULL;
    887         pz->opaque = Z_NULL;
    888 
    889         err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
    890                             MAX_MEM_LEVEL, zlibStrategy);
    891         if (err != Z_OK)
    892             return FALSE;
    893 
    894         cl->zsActive[streamId] = TRUE;
    895         cl->zsLevel[streamId] = zlibLevel;
    896     }
    897 
    898     /* Prepare buffer pointers. */
    899     pz->next_in = (Bytef *)tightBeforeBuf;
    900     pz->avail_in = dataLen;
    901     pz->next_out = (Bytef *)tightAfterBuf;
    902     pz->avail_out = tightAfterBufSize;
    903 
    904     /* Change compression parameters if needed. */
    905     if (zlibLevel != cl->zsLevel[streamId]) {
    906         if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
    907             return FALSE;
    908         }
    909         cl->zsLevel[streamId] = zlibLevel;
    910     }
    911 
    912     /* Actual compression. */
    913     if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
    914          pz->avail_in != 0 || pz->avail_out == 0 ) {
    915         return FALSE;
    916     }
    917 
    918     return SendCompressedData(cl, tightAfterBuf,
    919         tightAfterBufSize - pz->avail_out);
    920 }
    921 
    922 static Bool SendCompressedData(cl, buf, compressedLen)
    923     rfbClientPtr cl;
    924     char *buf;
    925     int compressedLen;
    926 {
    927     int i, portionLen;
    928 
    929     updateBuf[ublen++] = compressedLen & 0x7F;
    930     cl->rfbBytesSent[rfbEncodingTight]++;
    931     if (compressedLen > 0x7F) {
    932         updateBuf[ublen-1] |= 0x80;
    933         updateBuf[ublen++] = compressedLen >> 7 & 0x7F;
    934         cl->rfbBytesSent[rfbEncodingTight]++;
    935         if (compressedLen > 0x3FFF) {
    936             updateBuf[ublen-1] |= 0x80;
    937             updateBuf[ublen++] = compressedLen >> 14 & 0xFF;
    938             cl->rfbBytesSent[rfbEncodingTight]++;
    939         }
    940     }
    941 
    942     portionLen = UPDATE_BUF_SIZE;
    943     for (i = 0; i < compressedLen; i += portionLen) {
    944         if (i + portionLen > compressedLen) {
    945             portionLen = compressedLen - i;
    946         }
    947         if (ublen + portionLen > UPDATE_BUF_SIZE) {
    948             if (!rfbSendUpdateBuf(cl))
    949                 return FALSE;
    950         }
    951         memcpy(&updateBuf[ublen], &buf[i], portionLen);
    952         ublen += portionLen;
    953     }
    954     cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
    955     return TRUE;
    956 }
    957 
    958 /*
    959  * Code to determine how many different colors used in rectangle.
    960  */
    961 
    962 static void
    963 FillPalette8(count)
    964     int count;
    965 {
    966     CARD8 *data = (CARD8 *)tightBeforeBuf;
    967     CARD8 c0, c1;
    968     int i, n0, n1;
    969 
    970     paletteNumColors = 0;
    971 
    972     c0 = data[0];
    973     for (i = 1; i < count && data[i] == c0; i++);
    974     if (i == count) {
    975         paletteNumColors = 1;
    976         return;                 /* Solid rectangle */
    977     }
    978 
    979     if (paletteMaxColors < 2)
    980         return;
    981 
    982     n0 = i;
    983     c1 = data[i];
    984     n1 = 0;
    985     for (i++; i < count; i++) {
    986         if (data[i] == c0) {
    987             n0++;
    988         } else if (data[i] == c1) {
    989             n1++;
    990         } else
    991             break;
    992     }
    993     if (i == count) {
    994         if (n0 > n1) {
    995             monoBackground = (CARD32)c0;
    996             monoForeground = (CARD32)c1;
    997         } else {
    998             monoBackground = (CARD32)c1;
    999             monoForeground = (CARD32)c0;
   1000         }
   1001         paletteNumColors = 2;   /* Two colors */
   1002     }
   1003 }
   1004 
   1005 #define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
   1006                                                                         \
   1007 static void                                                             \
   1008 FillPalette##bpp(count)                                                 \
   1009     int count;                                                          \
   1010 {                                                                       \
   1011     CARD##bpp *data = (CARD##bpp *)tightBeforeBuf;                      \
   1012     CARD##bpp c0, c1, ci;                                               \
   1013     int i, n0, n1, ni;                                                  \
   1014                                                                         \
   1015     c0 = data[0];                                                       \
   1016     for (i = 1; i < count && data[i] == c0; i++);                       \
   1017     if (i >= count) {                                                   \
   1018         paletteNumColors = 1;   /* Solid rectangle */                   \
   1019         return;                                                         \
   1020     }                                                                   \
   1021                                                                         \
   1022     if (paletteMaxColors < 2) {                                         \
   1023         paletteNumColors = 0;   /* Full-color encoding preferred */     \
   1024         return;                                                         \
   1025     }                                                                   \
   1026                                                                         \
   1027     n0 = i;                                                             \
   1028     c1 = data[i];                                                       \
   1029     n1 = 0;                                                             \
   1030     for (i++; i < count; i++) {                                         \
   1031         ci = data[i];                                                   \
   1032         if (ci == c0) {                                                 \
   1033             n0++;                                                       \
   1034         } else if (ci == c1) {                                          \
   1035             n1++;                                                       \
   1036         } else                                                          \
   1037             break;                                                      \
   1038     }                                                                   \
   1039     if (i >= count) {                                                   \
   1040         if (n0 > n1) {                                                  \
   1041             monoBackground = (CARD32)c0;                                \
   1042             monoForeground = (CARD32)c1;                                \
   1043         } else {                                                        \
   1044             monoBackground = (CARD32)c1;                                \
   1045             monoForeground = (CARD32)c0;                                \
   1046         }                                                               \
   1047         paletteNumColors = 2;   /* Two colors */                        \
   1048         return;                                                         \
   1049     }                                                                   \
   1050                                                                         \
   1051     PaletteReset();                                                     \
   1052     PaletteInsert (c0, (CARD32)n0, bpp);                                \
   1053     PaletteInsert (c1, (CARD32)n1, bpp);                                \
   1054                                                                         \
   1055     ni = 1;                                                             \
   1056     for (i++; i < count; i++) {                                         \
   1057         if (data[i] == ci) {                                            \
   1058             ni++;                                                       \
   1059         } else {                                                        \
   1060             if (!PaletteInsert (ci, (CARD32)ni, bpp))                   \
   1061                 return;                                                 \
   1062             ci = data[i];                                               \
   1063             ni = 1;                                                     \
   1064         }                                                               \
   1065     }                                                                   \
   1066     PaletteInsert (ci, (CARD32)ni, bpp);                                \
   1067 }
   1068 
   1069 DEFINE_FILL_PALETTE_FUNCTION(16)
   1070 DEFINE_FILL_PALETTE_FUNCTION(32)
   1071 
   1072 #define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp)                          \
   1073                                                                         \
   1074 static void                                                             \
   1075 FastFillPalette##bpp(cl, data, w, pitch, h)                             \
   1076     rfbClientPtr cl;                                                    \
   1077     CARD##bpp *data;                                                    \
   1078     int w, pitch, h;                                                    \
   1079 {                                                                       \
   1080     CARD##bpp c0, c1, ci, mask, c0t, c1t, cit;                          \
   1081     int i, j, i2, j2, n0, n1, ni;                                       \
   1082                                                                         \
   1083     if (cl->translateFn != rfbTranslateNone) {                          \
   1084         mask = rfbServerFormat.redMax << rfbServerFormat.redShift;      \
   1085         mask |= rfbServerFormat.greenMax << rfbServerFormat.greenShift; \
   1086         mask |= rfbServerFormat.blueMax << rfbServerFormat.blueShift;   \
   1087     } else mask = ~0;                                                   \
   1088                                                                         \
   1089     c0 = data[0] & mask;                                                \
   1090     for (j = 0; j < h; j++) {                                           \
   1091         for (i = 0; i < w; i++) {                                       \
   1092             if ((data[j * pitch + i] & mask) != c0)                     \
   1093                 goto done;                                              \
   1094         }                                                               \
   1095     }                                                                   \
   1096     done:                                                               \
   1097     if (j >= h) {                                                       \
   1098         paletteNumColors = 1;   /* Solid rectangle */                   \
   1099         return;                                                         \
   1100     }                                                                   \
   1101     if (paletteMaxColors < 2) {                                         \
   1102         paletteNumColors = 0;   /* Full-color encoding preferred */     \
   1103         return;                                                         \
   1104     }                                                                   \
   1105                                                                         \
   1106     n0 = j * w + i;                                                     \
   1107     c1 = data[j * pitch + i] & mask;                                    \
   1108     n1 = 0;                                                             \
   1109     i++;  if (i >= w) {i = 0;  j++;}                                    \
   1110     for (j2 = j; j2 < h; j2++) {                                        \
   1111         for (i2 = i; i2 < w; i2++) {                                    \
   1112             ci = data[j2 * pitch + i2] & mask;                          \
   1113             if (ci == c0) {                                             \
   1114                 n0++;                                                   \
   1115             } else if (ci == c1) {                                      \
   1116                 n1++;                                                   \
   1117             } else                                                      \
   1118                 goto done2;                                             \
   1119         }                                                               \
   1120         i = 0;                                                          \
   1121     }                                                                   \
   1122     done2:                                                              \
   1123     (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,      \
   1124                        &cl->format, (char *)&c0, (char *)&c0t, bpp/8,   \
   1125                        1, 1);                                           \
   1126     (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,      \
   1127                        &cl->format, (char *)&c1, (char *)&c1t, bpp/8,   \
   1128                        1, 1);                                           \
   1129     if (j2 >= h) {                                                      \
   1130         if (n0 > n1) {                                                  \
   1131             monoBackground = (CARD32)c0t;                               \
   1132             monoForeground = (CARD32)c1t;                               \
   1133         } else {                                                        \
   1134             monoBackground = (CARD32)c1t;                               \
   1135             monoForeground = (CARD32)c0t;                               \
   1136         }                                                               \
   1137         paletteNumColors = 2;   /* Two colors */                        \
   1138         return;                                                         \
   1139     }                                                                   \
   1140                                                                         \
   1141     PaletteReset();                                                     \
   1142     PaletteInsert (c0t, (CARD32)n0, bpp);                               \
   1143     PaletteInsert (c1t, (CARD32)n1, bpp);                               \
   1144                                                                         \
   1145     ni = 1;                                                             \
   1146     i2++;  if (i2 >= w) {i2 = 0;  j2++;}                                \
   1147     for (j = j2; j < h; j++) {                                          \
   1148         for (i = i2; i < w; i++) {                                      \
   1149             if ((data[j * pitch + i] & mask) == ci) {                   \
   1150                 ni++;                                                   \
   1151             } else {                                                    \
   1152                 (*cl->translateFn)(cl->translateLookupTable,            \
   1153                                    &rfbServerFormat, &cl->format,       \
   1154                                    (char *)&ci, (char *)&cit, bpp/8,    \
   1155                                    1, 1);                               \
   1156                 if (!PaletteInsert (cit, (CARD32)ni, bpp))              \
   1157                     return;                                             \
   1158                 ci = data[j * pitch + i] & mask;                        \
   1159                 ni = 1;                                                 \
   1160             }                                                           \
   1161         }                                                               \
   1162         i2 = 0;                                                         \
   1163     }                                                                   \
   1164                                                                         \
   1165     (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,      \
   1166                        &cl->format, (char *)&ci, (char *)&cit, bpp/8,   \
   1167                        1, 1);                                           \
   1168     PaletteInsert (cit, (CARD32)ni, bpp);                               \
   1169 }
   1170 
   1171 DEFINE_FAST_FILL_PALETTE_FUNCTION(16)
   1172 DEFINE_FAST_FILL_PALETTE_FUNCTION(32)
   1173 
   1174 
   1175 /*
   1176  * Functions to operate with palette structures.
   1177  */
   1178 
   1179 #define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
   1180 #define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
   1181 
   1182 static void
   1183 PaletteReset(void)
   1184 {
   1185     paletteNumColors = 0;
   1186     memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
   1187 }
   1188 
   1189 static int
   1190 PaletteInsert(rgb, numPixels, bpp)
   1191     CARD32 rgb;
   1192     int numPixels;
   1193     int bpp;
   1194 {
   1195     COLOR_LIST *pnode;
   1196     COLOR_LIST *prev_pnode = NULL;
   1197     int hash_key, idx, new_idx, count;
   1198 
   1199     hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
   1200 
   1201     pnode = palette.hash[hash_key];
   1202 
   1203     while (pnode != NULL) {
   1204         if (pnode->rgb == rgb) {
   1205             /* Such palette entry already exists. */
   1206             new_idx = idx = pnode->idx;
   1207             count = palette.entry[idx].numPixels + numPixels;
   1208             if (new_idx && palette.entry[new_idx-1].numPixels < count) {
   1209                 do {
   1210                     palette.entry[new_idx] = palette.entry[new_idx-1];
   1211                     palette.entry[new_idx].listNode->idx = new_idx;
   1212                     new_idx--;
   1213                 }
   1214                 while (new_idx && palette.entry[new_idx-1].numPixels < count);
   1215                 palette.entry[new_idx].listNode = pnode;
   1216                 pnode->idx = new_idx;
   1217             }
   1218             palette.entry[new_idx].numPixels = count;
   1219             return paletteNumColors;
   1220         }
   1221         prev_pnode = pnode;
   1222         pnode = pnode->next;
   1223     }
   1224 
   1225     /* Check if palette is full. */
   1226     if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
   1227         paletteNumColors = 0;
   1228         return 0;
   1229     }
   1230 
   1231     /* Move palette entries with lesser pixel counts. */
   1232     for ( idx = paletteNumColors;
   1233           idx > 0 && palette.entry[idx-1].numPixels < numPixels;
   1234           idx-- ) {
   1235         palette.entry[idx] = palette.entry[idx-1];
   1236         palette.entry[idx].listNode->idx = idx;
   1237     }
   1238 
   1239     /* Add new palette entry into the freed slot. */
   1240     pnode = &palette.list[paletteNumColors];
   1241     if (prev_pnode != NULL) {
   1242         prev_pnode->next = pnode;
   1243     } else {
   1244         palette.hash[hash_key] = pnode;
   1245     }
   1246     pnode->next = NULL;
   1247     pnode->idx = idx;
   1248     pnode->rgb = rgb;
   1249     palette.entry[idx].listNode = pnode;
   1250     palette.entry[idx].numPixels = numPixels;
   1251 
   1252     return (++paletteNumColors);
   1253 }
   1254 
   1255 
   1256 /*
   1257  * Converting 32-bit color samples into 24-bit colors.
   1258  * Should be called only when redMax, greenMax and blueMax are 255.
   1259  * Color components assumed to be byte-aligned.
   1260  */
   1261 
   1262 static void Pack24(buf, fmt, count)
   1263     char *buf;
   1264     rfbPixelFormat *fmt;
   1265     int count;
   1266 {
   1267     CARD32 *buf32;
   1268     CARD32 pix;
   1269     int r_shift, g_shift, b_shift;
   1270 
   1271     buf32 = (CARD32 *)buf;
   1272 
   1273     if (!rfbServerFormat.bigEndian == !fmt->bigEndian) {
   1274         r_shift = fmt->redShift;
   1275         g_shift = fmt->greenShift;
   1276         b_shift = fmt->blueShift;
   1277     } else {
   1278         r_shift = 24 - fmt->redShift;
   1279         g_shift = 24 - fmt->greenShift;
   1280         b_shift = 24 - fmt->blueShift;
   1281     }
   1282 
   1283     while (count--) {
   1284         pix = *buf32++;
   1285         *buf++ = (char)(pix >> r_shift);
   1286         *buf++ = (char)(pix >> g_shift);
   1287         *buf++ = (char)(pix >> b_shift);
   1288     }
   1289 }
   1290 
   1291 
   1292 /*
   1293  * Converting truecolor samples into palette indices.
   1294  */
   1295 
   1296 #define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
   1297                                                                         \
   1298 static void                                                             \
   1299 EncodeIndexedRect##bpp(buf, count)                                      \
   1300     CARD8 *buf;                                                         \
   1301     int count;                                                          \
   1302 {                                                                       \
   1303     COLOR_LIST *pnode;                                                  \
   1304     CARD##bpp *src;                                                     \
   1305     CARD##bpp rgb;                                                      \
   1306     int rep = 0;                                                        \
   1307                                                                         \
   1308     src = (CARD##bpp *) buf;                                            \
   1309                                                                         \
   1310     while (count--) {                                                   \
   1311         rgb = *src++;                                                   \
   1312         while (count && *src == rgb) {                                  \
   1313             rep++, src++, count--;                                      \
   1314         }                                                               \
   1315         pnode = palette.hash[HASH_FUNC##bpp(rgb)];                      \
   1316         while (pnode != NULL) {                                         \
   1317             if ((CARD##bpp)pnode->rgb == rgb) {                         \
   1318                 *buf++ = (CARD8)pnode->idx;                             \
   1319                 while (rep) {                                           \
   1320                     *buf++ = (CARD8)pnode->idx;                         \
   1321                     rep--;                                              \
   1322                 }                                                       \
   1323                 break;                                                  \
   1324             }                                                           \
   1325             pnode = pnode->next;                                        \
   1326         }                                                               \
   1327     }                                                                   \
   1328 }
   1329 
   1330 DEFINE_IDX_ENCODE_FUNCTION(16)
   1331 DEFINE_IDX_ENCODE_FUNCTION(32)
   1332 
   1333 #define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
   1334                                                                         \
   1335 static void                                                             \
   1336 EncodeMonoRect##bpp(buf, w, h)                                          \
   1337     CARD8 *buf;                                                         \
   1338     int w, h;                                                           \
   1339 {                                                                       \
   1340     CARD##bpp *ptr;                                                     \
   1341     CARD##bpp bg;                                                       \
   1342     unsigned int value, mask;                                           \
   1343     int aligned_width;                                                  \
   1344     int x, y, bg_bits;                                                  \
   1345                                                                         \
   1346     ptr = (CARD##bpp *) buf;                                            \
   1347     bg = (CARD##bpp) monoBackground;                                    \
   1348     aligned_width = w - w % 8;                                          \
   1349                                                                         \
   1350     for (y = 0; y < h; y++) {                                           \
   1351         for (x = 0; x < aligned_width; x += 8) {                        \
   1352             for (bg_bits = 0; bg_bits < 8; bg_bits++) {                 \
   1353                 if (*ptr++ != bg)                                       \
   1354                     break;                                              \
   1355             }                                                           \
   1356             if (bg_bits == 8) {                                         \
   1357                 *buf++ = 0;                                             \
   1358                 continue;                                               \
   1359             }                                                           \
   1360             mask = 0x80 >> bg_bits;                                     \
   1361             value = mask;                                               \
   1362             for (bg_bits++; bg_bits < 8; bg_bits++) {                   \
   1363                 mask >>= 1;                                             \
   1364                 if (*ptr++ != bg) {                                     \
   1365                     value |= mask;                                      \
   1366                 }                                                       \
   1367             }                                                           \
   1368             *buf++ = (CARD8)value;                                      \
   1369         }                                                               \
   1370                                                                         \
   1371         mask = 0x80;                                                    \
   1372         value = 0;                                                      \
   1373         if (x >= w)                                                     \
   1374             continue;                                                   \
   1375                                                                         \
   1376         for (; x < w; x++) {                                            \
   1377             if (*ptr++ != bg) {                                         \
   1378                 value |= mask;                                          \
   1379             }                                                           \
   1380             mask >>= 1;                                                 \
   1381         }                                                               \
   1382         *buf++ = (CARD8)value;                                          \
   1383     }                                                                   \
   1384 }
   1385 
   1386 DEFINE_MONO_ENCODE_FUNCTION(8)
   1387 DEFINE_MONO_ENCODE_FUNCTION(16)
   1388 DEFINE_MONO_ENCODE_FUNCTION(32)
   1389 
   1390 /*
   1391  * JPEG compression stuff.
   1392  */
   1393 
   1394 static unsigned long jpegDstDataLen;
   1395 static tjhandle j=NULL;
   1396 
   1397 static Bool
   1398 SendJpegRect(cl, x, y, w, h, quality)
   1399     rfbClientPtr cl;
   1400     int x, y, w, h;
   1401     int quality;
   1402 {
   1403     int dy;
   1404     unsigned char *srcbuf;
   1405     int ps=rfbServerFormat.bitsPerPixel/8;
   1406     int subsamp=subsampLevel2tjsubsamp[subsampLevel];
   1407     unsigned long size=0;
   1408     int flags=0, pitch;
   1409     unsigned char *tmpbuf=NULL;
   1410 
   1411     if (rfbServerFormat.bitsPerPixel == 8)
   1412         return SendFullColorRect(cl, w, h);
   1413 
   1414 
   1415     if(ps<2) {
   1416       rfbLog("Error: JPEG requires 16-bit, 24-bit, or 32-bit pixel format.\n");
   1417       return 0;
   1418     }
   1419     if(!j) {
   1420       if((j=tjInitCompress())==NULL) {
   1421         rfbLog("JPEG Error: %s\n", tjGetErrorStr());  return 0;
   1422       }
   1423     }
   1424 
   1425     if (tightAfterBufSize < TJBUFSIZE(w,h)) {
   1426         if (tightAfterBuf == NULL)
   1427             tightAfterBuf = (char *)xalloc(TJBUFSIZE(w,h));
   1428         else
   1429             tightAfterBuf = (char *)xrealloc(tightAfterBuf,
   1430                                              TJBUFSIZE(w,h));
   1431         if(!tightAfterBuf) {
   1432             rfbLog("Memory allocation failure!\n");
   1433             return 0;
   1434         }
   1435         tightAfterBufSize = TJBUFSIZE(w,h);
   1436     }
   1437 
   1438     if (ps == 2) {
   1439         CARD16 *srcptr, pix;
   1440         unsigned char *dst;
   1441         int inRed, inGreen, inBlue, i, j;
   1442 
   1443         if((tmpbuf=(unsigned char *)malloc(w*h*3))==NULL)
   1444             rfbLog("Memory allocation failure!\n");
   1445         srcptr = (CARD16 *)
   1446             &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes +
   1447                                  x * ps];
   1448         dst = tmpbuf;
   1449         for(j=0; j<h; j++) {
   1450             CARD16 *srcptr2=srcptr;
   1451             unsigned char *dst2=dst;
   1452             for(i=0; i<w; i++) {
   1453                 pix = *srcptr2++;
   1454                 inRed = (int)
   1455                     (pix >> rfbServerFormat.redShift   & rfbServerFormat.redMax);
   1456                 inGreen = (int)
   1457                     (pix >> rfbServerFormat.greenShift & rfbServerFormat.greenMax);
   1458                 inBlue  = (int)
   1459                     (pix >> rfbServerFormat.blueShift  & rfbServerFormat.blueMax);
   1460                 *dst2++ = (CARD8)((inRed   * 255 + rfbServerFormat.redMax / 2) /
   1461                           rfbServerFormat.redMax);
   1462                	*dst2++ = (CARD8)((inGreen * 255 + rfbServerFormat.greenMax / 2) /
   1463                           rfbServerFormat.greenMax);
   1464                 *dst2++ = (CARD8)((inBlue  * 255 + rfbServerFormat.blueMax / 2) /
   1465                           rfbServerFormat.blueMax);
   1466             }
   1467             srcptr+=rfbScreen.paddedWidthInBytes/ps;
   1468             dst+=w*3;
   1469         }
   1470         srcbuf = tmpbuf;
   1471         pitch = w*3;
   1472         ps = 3;
   1473     } else {
   1474         if(rfbServerFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST;
   1475         if(rfbServerFormat.redShift==16 && rfbServerFormat.blueShift==0)
   1476             flags|=TJ_BGR;
   1477         if(rfbServerFormat.bigEndian) flags^=TJ_BGR;
   1478         srcbuf=(unsigned char *)&rfbScreen.pfbMemory[y *
   1479             rfbScreen.paddedWidthInBytes + x * ps];
   1480         pitch=rfbScreen.paddedWidthInBytes;
   1481     }
   1482 
   1483     if(tjCompress(j, srcbuf, w, pitch, h, ps, (unsigned char *)tightAfterBuf,
   1484       &size, subsamp, quality, flags)==-1) {
   1485       rfbLog("JPEG Error: %s\n", tjGetErrorStr());
   1486       if(tmpbuf) {free(tmpbuf);  tmpbuf=NULL;}
   1487       return 0;
   1488     }
   1489     jpegDstDataLen=(int)size;
   1490 
   1491     if(tmpbuf) {free(tmpbuf);  tmpbuf=NULL;}
   1492 
   1493     if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
   1494         if (!rfbSendUpdateBuf(cl))
   1495             return FALSE;
   1496     }
   1497 
   1498     updateBuf[ublen++] = (char)(rfbTightJpeg << 4);
   1499     cl->rfbBytesSent[rfbEncodingTight]++;
   1500 
   1501     return SendCompressedData(cl, tightAfterBuf, jpegDstDataLen);
   1502 }
   1503