~ubuntu-branches/ubuntu/dapper/vino/dapper

« back to all changes in this revision

Viewing changes to server/libvncserver/tight.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2004-10-12 19:36:40 UTC
  • Revision ID: james.westby@ubuntu.com-20041012193640-ybetkwuqt7e04dke
Tags: upstream-2.8.1
ImportĀ upstreamĀ versionĀ 2.8.1

Show diffs side-by-side

added added

removed removed

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