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