summaryrefslogtreecommitdiffstats
path: root/x11vnc
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc')
-rw-r--r--x11vnc/ChangeLog3
-rw-r--r--x11vnc/README2
-rw-r--r--x11vnc/misc/Makefile.am2
-rw-r--r--x11vnc/misc/turbovnc/Makefile.am1
-rw-r--r--x11vnc/misc/turbovnc/README147
-rwxr-xr-xx11vnc/misc/turbovnc/apply_turbovnc33
-rwxr-xr-xx11vnc/misc/turbovnc/convert58
-rw-r--r--x11vnc/misc/turbovnc/tight.c1502
-rw-r--r--x11vnc/misc/turbovnc/turbojpeg.h229
-rwxr-xr-xx11vnc/misc/turbovnc/undo_turbovnc13
10 files changed, 1989 insertions, 1 deletions
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index 36dc615..4692571 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,6 @@
+2009-02-28 Karl Runge <runge@karlrunge.com>
+ * x11vnc: add kludge to experiment with turbovnc.
+
2009-02-25 Karl Runge <runge@karlrunge.com>
* x11vnc: fix some -QD cases for use in tkx11vnc.
diff --git a/x11vnc/README b/x11vnc/README
index ffdfa15..c6637d4 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -1,5 +1,5 @@
-x11vnc README file Date: Wed Feb 25 21:10:01 EST 2009
+x11vnc README file Date: Sat Feb 28 10:23:00 EST 2009
The following information is taken from these URLs:
diff --git a/x11vnc/misc/Makefile.am b/x11vnc/misc/Makefile.am
index 5e3a813..efc5443 100644
--- a/x11vnc/misc/Makefile.am
+++ b/x11vnc/misc/Makefile.am
@@ -1 +1,3 @@
+SUBDIRS = turbovnc
+DIST_SUBDIRS = turbovnc
EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear ranfb.pl slide.pl vcinject.pl x11vnc_loop Xdummy
diff --git a/x11vnc/misc/turbovnc/Makefile.am b/x11vnc/misc/turbovnc/Makefile.am
new file mode 100644
index 0000000..7b5dfb3
--- /dev/null
+++ b/x11vnc/misc/turbovnc/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST=README apply_turbovnc convert tight.c turbojpeg.h undo_turbovnc
diff --git a/x11vnc/misc/turbovnc/README b/x11vnc/misc/turbovnc/README
new file mode 100644
index 0000000..b8e0ac9
--- /dev/null
+++ b/x11vnc/misc/turbovnc/README
@@ -0,0 +1,147 @@
+INTRO:
+------
+
+This is a "patch" to make x11vnc/libvncserver work with TurboVNC:
+
+ http://www.virtualgl.org/About/TurboVNC
+
+It is very experimental/kludgy. Not all TurboVNC features may be enabled.
+We are currently evaluating whether TurboVNC support should be officially
+put into x11vnc/libvncserver.
+
+TurboVNC is an optimized VNC for fast refresh rates on fast networks.
+
+It does pretty well on good broadband as well. But it is not as fast
+as regular TightVNC on slow links.
+
+
+TURBOJPEG:
+---------
+
+TurboVNC uses the TurboJPEG library based on a fast proprietary JPEG
+implementation. You will need to download it from the VirtualGL
+sourceforge site:
+
+ http://sourceforge.net/project/showfiles.php?group_id=117509&package_id=166100
+
+Either install it or simply unpack the .deb or .rpm file into a directory.
+
+N.B. you can unpack a .deb via 'ar x package.deb' and the extracting
+from the data.tar.gz file. rpm2cpio can be used to unpack .rpm's.
+
+
+QUICK-START:
+------------
+
+For those in a hurry:
+
+ cd x11vnc-x.y.z/x11vnc/misc/turbovnc
+ ./apply_turbovnc
+ cd ../../..
+ env LDFLAGS='-L/DIR -Xlinker --rpath=/DIR' ./configure
+ make AM_LDFLAGS='-lturbojpeg'
+
+where you replace /DIR with your directory containing libturbojpeg.so.
+
+
+PATCHING AND BUILDING:
+----------------------
+
+After unpacking your x11vnc-x.y.z.tar.gz tarball cd to the
+x11vnc-x.y.z/x11vnc/misc/turbovnc (where this README file is) and from
+that directory run:
+
+ ./apply_turbovnc
+
+that will modify files in the libvncserver and x11vnc directories above
+this directory. (To undo these changes run: ./undo_turbovnc) The input
+sources, tight.c and turbojpeg.h are from the TurboVNC source package.
+
+After applying, go back to the top level source directory and run:
+
+ env LDFLAGS='-L/path/to/turbojpeg -Xlinker --rpath=/path/to/turbojpeg' ./configure
+
+where the turbojpeg library is:
+
+ /path/to/turbojpeg/libturbojpeg.so
+
+(change /path/to/turbojpeg to the directory where you installed or
+unpacked it.)
+
+If you are not using gnu gcc and gnu linker the options may be a little
+different (e.g. -R instead of -Xlinker --rpath).
+
+If you need additional ./configure options or env. var. settings,
+add them too.
+
+
+Next, run this make command:
+
+ make AM_LDFLAGS='-lturbojpeg'
+
+This is a hack and may not always work, if it doesn't edit x11vnc/Makefile
+and add '-lturbojpeg' to the LIBS variable.
+
+This should create a binary:
+
+ ./x11vnc/x11vnc
+
+that supports VirtualGL's TurboVNC.
+
+You will need a TurboVNC viewer, you can get one here:
+
+ http://sourceforge.net/project/showfiles.php?group_id=117509&package_id=128130
+
+Let us know how it goes.
+
+
+PERFORMANCE:
+------------
+
+Note that x11vnc has to read the display's screen pixels from the
+graphics card memory. This can be slow, e.g. 10 MB/sec.
+
+There is not a big need for graphics card manufacturers to optimize the
+read rate; the write rate is the one they optimize greatly.
+
+ http://www.karlrunge.com/x11vnc/#limitations
+
+If you run x11vnc and see lines like this:
+
+ 28/02/2009 00:52:07 Autoprobing selected port 5900
+ 28/02/2009 00:52:07 fb read rate: 10 MB/sec
+ 28/02/2009 00:52:07 screen setup finished.
+
+you have a typical slow one.
+
+Whereas if you see this:
+
+ 28/02/2009 00:54:46 Autoprobing selected port 5900
+ 28/02/2009 00:54:46 fb read rate: 321 MB/sec
+ 28/02/2009 00:54:46 fast read: reset wait ms to: 10
+ 28/02/2009 00:54:46 fast read: reset defer ms to: 10
+ 28/02/2009 00:54:46 screen setup finished.
+
+that is very fast.
+
+We have only seen it this fast on Linux by using the nvidia proprietary
+graphics drivers. The Xorg drivers are typically slow 10 MB/sec.
+
+It will also be fast if the X server is virtual: Xvfb or Xdummy
+since the screen pixels are stored in RAM:
+
+ http://www.karlrunge.com/x11vnc/faq.html#faq-xvfb
+
+And it will be fast if the ShadowFB xorg.conf option is enabled (if the
+card supports it.)
+
+
+The point we are trying to make is that even though TurboVNC uses a
+wicked fast JPEG implementation, and cuts out overhead in its attempt to
+pump out as many frames per second as it can, if it is slow for x11vnc
+to read the screen pixels in the first place then you might not even
+notice the TurboVNC speedup.
+
+So TurboVNC+x11vnc will be faster than TightVNC+x11vnc, but if there is
+a large overhead/bottleneck from reading the graphics card framebuffer,
+then the speedup will be marginal.
diff --git a/x11vnc/misc/turbovnc/apply_turbovnc b/x11vnc/misc/turbovnc/apply_turbovnc
new file mode 100755
index 0000000..0a8ca7a
--- /dev/null
+++ b/x11vnc/misc/turbovnc/apply_turbovnc
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+ldir="../../../libvncserver"
+
+fail=""
+if [ ! -f "./tight.c" ]; then
+ fail=1
+fi
+if [ ! -f "./turbojpeg.h" ]; then
+ fail=1
+fi
+if [ ! -f "./convert" ]; then
+ fail=1
+fi
+if [ ! -f "$ldir/tight.c" ]; then
+ ls -l "$ldir/tight.c"
+ fail=1
+fi
+if [ "X$fail" = "X1" ]; then
+ echo "Must be run from inside the directory containing 'apply_turbovnc'"
+ exit 1
+fi
+
+if [ -f "$ldir/tight.c.ORIG" ]; then
+ set -xv
+else
+ set -xv
+ cp -p "$ldir/tight.c" "$ldir/tight.c.ORIG"
+fi
+
+perl ./convert ./tight.c > "$ldir/tight.c"
+cp -p ./turbojpeg.h "$ldir"
+ls -l $ldir/tight.c* $ldir/turbojpeg.h
diff --git a/x11vnc/misc/turbovnc/convert b/x11vnc/misc/turbovnc/convert
new file mode 100755
index 0000000..fdd0dbb
--- /dev/null
+++ b/x11vnc/misc/turbovnc/convert
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+while (<>) {
+ if (/^#include.*"rfb.h"/) {
+ print <<END;
+#include <rfb/rfb.h>
+#define Bool rfbBool
+#define CARD32 uint32_t
+#define CARD16 uint16_t
+#define CARD8 uint8_t
+#define xalloc malloc
+#define xrealloc realloc
+#define rfbTightNoZlib 0x0A
+END
+ next;
+ }
+ foreach $func (qw(FindBestSolidArea ExtendSolidArea CheckSolidTile CheckSolidTile##bpp CheckSolidTile8 CheckSolidTile16 CheckSolidTile32 Pack24)) {
+ if (/static.*\b\Q$func\E\b/ && !exists $did_static{$func}) {
+ $_ =~ s/\b\Q$func\E\b(\s*)\(/$func$1(rfbClientPtr cl, /;
+ $did_static{$func} = 1;
+ } elsif (/\b\Q$func\E\b\s*\(/) {
+ $_ =~ s/\b\Q$func\E\b(\s*)\(/$func$1(cl, /;
+ }
+ }
+ if (/^\s*subsampLevel\s*=\s*cl/) {
+ $_ = "//$_";
+ print "subsampLevel = 0;\n";
+ }
+ $_ =~ s/cl->tightQualityLevel;/cl->tightQualityLevel * 10;/;
+
+ $_ =~ s/rfbScreen.pfbMemory/cl->scaledScreen->frameBuffer/g;
+ $_ =~ s/rfbScreen.paddedWidthInBytes/cl->scaledScreen->paddedWidthInBytes/g;
+ $_ =~ s/rfbScreen.bitsPerPixel/cl->scaledScreen->bitsPerPixel/g;
+ $_ =~ s/rfbServerFormat/cl->screen->serverFormat/g;
+
+ if (/^(FindBestSolidArea|ExtendSolidArea|static void Pack24|CheckSolidTile)\(cl/) {
+ $_ .= "rfbClientPtr cl;\n";
+ }
+ if (/^(CheckSolidTile##bpp)\(cl/) {
+ $_ .= "rfbClientPtr cl; \\\n";
+ }
+ $_ =~ s/\bublen\b/cl->ublen/;
+ $_ =~ s/\bupdateBuf\b/cl->updateBuf/;
+
+ if (/cl->(rfbRectanglesSent|rfbBytesSent)/) {
+ $_ = "//$_";
+ }
+ print;
+}
+
+print <<END;
+
+void rfbTightCleanup(rfbScreenInfoPtr screen) {
+}
+
+END
+
+
diff --git a/x11vnc/misc/turbovnc/tight.c b/x11vnc/misc/turbovnc/tight.c
new file mode 100644
index 0000000..e7b4dbd
--- /dev/null
+++ b/x11vnc/misc/turbovnc/tight.c
@@ -0,0 +1,1502 @@
+/*
+ * tight.c
+ *
+ * Routines to implement Tight Encoding
+ */
+
+/*
+ * Copyright (C) 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (C) 2004 Landmark Graphics Corporation. All Rights Reserved.
+ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+#include "turbojpeg.h"
+
+/* Note: The following constant should not be changed. */
+#define TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define MIN_SPLIT_RECT_SIZE 4096
+#define MIN_SOLID_SUBRECT_SIZE 2048
+#define MAX_SPLIT_TILE_SIZE 16
+
+/* This variable is set on every rfbSendRectEncodingTight() call. */
+static Bool usePixelFormat24;
+
+
+/* Compression level stuff. The following array contains various
+ encoder parameters for each of 10 compression levels (0..9).
+ Last three parameters correspond to JPEG quality levels (0..9). */
+
+typedef struct TIGHT_CONF_s {
+ int maxRectSize, maxRectWidth;
+ int monoMinRectSize;
+ int idxZlibLevel, monoZlibLevel, rawZlibLevel;
+ int idxMaxColorsDivisor;
+} TIGHT_CONF;
+
+static TIGHT_CONF tightConf[2] = {
+ { 65536, 2048, 6, 0, 0, 0, 4 },
+#if 0
+ { 2048, 128, 6, 1, 1, 1, 8 },
+ { 6144, 256, 8, 3, 3, 2, 24 },
+ { 10240, 1024, 12, 5, 5, 3, 32 },
+ { 16384, 2048, 12, 6, 6, 4, 32 },
+ { 32768, 2048, 12, 7, 7, 5, 32 },
+ { 65536, 2048, 16, 7, 7, 6, 48 },
+ { 65536, 2048, 16, 8, 8, 7, 64 },
+ { 65536, 2048, 32, 9, 9, 8, 64 },
+#endif
+ { 65536, 2048, 32, 1, 1, 1, 96 }
+};
+
+static int compressLevel;
+static int qualityLevel;
+static int subsampLevel;
+
+static const int subsampLevel2tjsubsamp[4] = {
+ TJ_444, TJ_411, TJ_422, TJ_GRAYSCALE
+};
+
+/* Stuff dealing with palettes. */
+
+typedef struct COLOR_LIST_s {
+ struct COLOR_LIST_s *next;
+ int idx;
+ CARD32 rgb;
+} COLOR_LIST;
+
+typedef struct PALETTE_ENTRY_s {
+ COLOR_LIST *listNode;
+ int numPixels;
+} PALETTE_ENTRY;
+
+typedef struct PALETTE_s {
+ PALETTE_ENTRY entry[256];
+ COLOR_LIST *hash[256];
+ COLOR_LIST list[256];
+} PALETTE;
+
+static int paletteNumColors, paletteMaxColors;
+static CARD32 monoBackground, monoForeground;
+static PALETTE palette;
+
+/* Pointers to dynamically-allocated buffers. */
+
+static int tightBeforeBufSize = 0;
+static char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static char *tightAfterBuf = NULL;
+
+static int *prevRowBuf = NULL;
+
+
+/* Prototypes for static functions. */
+
+static void FindBestSolidArea (int x, int y, int w, int h,
+ CARD32 colorValue, int *w_ptr, int *h_ptr);
+static void ExtendSolidArea (int x, int y, int w, int h,
+ CARD32 colorValue,
+ int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
+static Bool CheckSolidTile (int x, int y, int w, int h,
+ CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile8 (int x, int y, int w, int h,
+ CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile16 (int x, int y, int w, int h,
+ CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile32 (int x, int y, int w, int h,
+ CARD32 *colorPtr, Bool needSameColor);
+
+static Bool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h);
+
+static Bool SendSolidRect (rfbClientPtr cl);
+static Bool SendMonoRect (rfbClientPtr cl, int w, int h);
+static Bool SendIndexedRect (rfbClientPtr cl, int w, int h);
+static Bool SendFullColorRect (rfbClientPtr cl, int w, int h);
+
+static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen,
+ int zlibLevel, int zlibStrategy);
+static Bool SendCompressedData(rfbClientPtr cl, char *buf, int compressedLen);
+
+static void FillPalette8(int count);
+static void FillPalette16(int count);
+static void FillPalette32(int count);
+static void FastFillPalette16(rfbClientPtr cl, CARD16 *data, int w, int pitch,
+ int h);
+static void FastFillPalette32(rfbClientPtr cl, CARD32 *data, int w, int pitch,
+ int h);
+
+static void PaletteReset(void);
+static int PaletteInsert(CARD32 rgb, int numPixels, int bpp);
+
+static void Pack24(char *buf, rfbPixelFormat *fmt, int count);
+
+static void EncodeIndexedRect16(CARD8 *buf, int count);
+static void EncodeIndexedRect32(CARD8 *buf, int count);
+
+static void EncodeMonoRect8(CARD8 *buf, int w, int h);
+static void EncodeMonoRect16(CARD8 *buf, int w, int h);
+static void EncodeMonoRect32(CARD8 *buf, int w, int h);
+
+static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
+ int quality);
+
+/*
+ * Tight encoding implementation.
+ */
+
+int
+rfbNumCodedRectsTight(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int maxRectSize, maxRectWidth;
+ int subrectMaxWidth, subrectMaxHeight;
+
+ /* No matter how many rectangles we will send if LastRect markers
+ are used to terminate rectangle stream. */
+ if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
+ return 0;
+
+ maxRectSize = tightConf[compressLevel].maxRectSize;
+ maxRectWidth = tightConf[compressLevel].maxRectWidth;
+
+ if (w > maxRectWidth || w * h > maxRectSize) {
+ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ subrectMaxHeight = maxRectSize / subrectMaxWidth;
+ return (((w - 1) / maxRectWidth + 1) *
+ ((h - 1) / subrectMaxHeight + 1));
+ } else {
+ return 1;
+ }
+}
+
+Bool
+rfbSendRectEncodingTight(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int nMaxRows;
+ CARD32 colorValue;
+ int dx, dy, dw, dh;
+ int x_best, y_best, w_best, h_best;
+ char *fbptr;
+
+ compressLevel = cl->tightCompressLevel > 0 ? 1 : 0;
+ qualityLevel = cl->tightQualityLevel;
+ if (qualityLevel != -1) {
+ compressLevel = 1;
+ tightConf[compressLevel].idxZlibLevel = 1;
+ tightConf[compressLevel].monoZlibLevel = 1;
+ tightConf[compressLevel].rawZlibLevel = 1;
+ } else {
+ tightConf[compressLevel].idxZlibLevel = cl->tightCompressLevel;
+ tightConf[compressLevel].monoZlibLevel = cl->tightCompressLevel;
+ tightConf[compressLevel].rawZlibLevel = cl->tightCompressLevel;
+ }
+ subsampLevel = cl->tightSubsampLevel;
+
+ if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
+ cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
+ usePixelFormat24 = TRUE;
+ } else {
+ usePixelFormat24 = FALSE;
+ }
+
+ if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
+ return SendRectSimple(cl, x, y, w, h);
+
+ /* Make sure we can write at least one pixel into tightBeforeBuf. */
+
+ if (tightBeforeBufSize < 4) {
+ tightBeforeBufSize = 4;
+ if (tightBeforeBuf == NULL)
+ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+ tightBeforeBufSize);
+ }
+
+ /* Calculate maximum number of rows in one non-solid rectangle. */
+
+ {
+ int maxRectSize, maxRectWidth, nMaxWidth;
+
+ maxRectSize = tightConf[compressLevel].maxRectSize;
+ maxRectWidth = tightConf[compressLevel].maxRectWidth;
+ nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ nMaxRows = maxRectSize / nMaxWidth;
+ }
+
+ /* Try to find large solid-color areas and send them separately. */
+
+ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+ /* If a rectangle becomes too large, send its upper part now. */
+
+ if (dy - y >= nMaxRows) {
+ if (!SendRectSimple(cl, x, y, w, nMaxRows))
+ return 0;
+ y += nMaxRows;
+ h -= nMaxRows;
+ }
+
+ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+ MAX_SPLIT_TILE_SIZE : (y + h - dy);
+
+ for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
+
+ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
+ MAX_SPLIT_TILE_SIZE : (x + w - dx);
+
+ if (CheckSolidTile(dx, dy, dw, dh, &colorValue, FALSE)) {
+
+ if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1) {
+ CARD32 r=(colorValue>>16)&0xFF;
+ CARD32 g=(colorValue>>8)&0xFF;
+ CARD32 b=(colorValue)&0xFF;
+ double y=(0.257*(double)r)+(0.504*(double)g)
+ +(0.098*(double)b)+16.;
+ colorValue=(int)y+(((int)y)<<8)+(((int)y)<<16);
+ }
+
+ /* Get dimensions of solid-color area. */
+
+ FindBestSolidArea(dx, dy, w - (dx - x), h - (dy - y),
+ colorValue, &w_best, &h_best);
+
+ /* Make sure a solid rectangle is large enough
+ (or the whole rectangle is of the same color). */
+
+ if ( w_best * h_best != w * h &&
+ w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
+ continue;
+
+ /* Try to extend solid rectangle to maximum size. */
+
+ x_best = dx; y_best = dy;
+ ExtendSolidArea(x, y, w, h, colorValue,
+ &x_best, &y_best, &w_best, &h_best);
+
+ /* Send rectangles at top and left to solid-color area. */
+
+ if ( y_best != y &&
+ !SendRectSimple(cl, x, y, w, y_best-y) )
+ return FALSE;
+ if ( x_best != x &&
+ !rfbSendRectEncodingTight(cl, x, y_best,
+ x_best-x, h_best) )
+ return FALSE;
+
+ /* Send solid-color rectangle. */
+
+ if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
+ return FALSE;
+
+ fbptr = (rfbScreen.pfbMemory +
+ (rfbScreen.paddedWidthInBytes * y_best) +
+ (x_best * (rfbScreen.bitsPerPixel / 8)));
+
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
+ &cl->format, fbptr, tightBeforeBuf,
+ rfbScreen.paddedWidthInBytes, 1, 1);
+
+ if (!SendSolidRect(cl))
+ return FALSE;
+
+ /* Send remaining rectangles (at right and bottom). */
+
+ if ( x_best + w_best != x + w &&
+ !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
+ w-(x_best-x)-w_best, h_best) )
+ return FALSE;
+ if ( y_best + h_best != y + h &&
+ !rfbSendRectEncodingTight(cl, x, y_best+h_best,
+ w, h-(y_best-y)-h_best) )
+ return FALSE;
+
+ /* Return after all recursive calls are done. */
+
+ return TRUE;
+ }
+
+ }
+
+ }
+
+ /* No suitable solid-color rectangles found. */
+
+ return SendRectSimple(cl, x, y, w, h);
+}
+
+static void
+FindBestSolidArea(x, y, w, h, colorValue, w_ptr, h_ptr)
+ int x, y, w, h;
+ CARD32 colorValue;
+ int *w_ptr, *h_ptr;
+{
+ int dx, dy, dw, dh;
+ int w_prev;
+ int w_best = 0, h_best = 0;
+
+ w_prev = w;
+
+ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+ MAX_SPLIT_TILE_SIZE : (y + h - dy);
+ dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
+ MAX_SPLIT_TILE_SIZE : w_prev;
+
+ if (!CheckSolidTile(x, dy, dw, dh, &colorValue, TRUE))
+ break;
+
+ for (dx = x + dw; dx < x + w_prev;) {
+ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
+ MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
+ if (!CheckSolidTile(dx, dy, dw, dh, &colorValue, TRUE))
+ break;
+ dx += dw;
+ }
+
+ w_prev = dx - x;
+ if (w_prev * (dy + dh - y) > w_best * h_best) {
+ w_best = w_prev;
+ h_best = dy + dh - y;
+ }
+ }
+
+ *w_ptr = w_best;
+ *h_ptr = h_best;
+}
+
+static void
+ExtendSolidArea(x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
+ int x, y, w, h;
+ CARD32 colorValue;
+ int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+{
+ int cx, cy;
+
+ /* Try to extend the area upwards. */
+ for ( cy = *y_ptr - 1;
+ cy >= y && CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+ cy-- );
+ *h_ptr += *y_ptr - (cy + 1);
+ *y_ptr = cy + 1;
+
+ /* ... downwards. */
+ for ( cy = *y_ptr + *h_ptr;
+ cy < y + h &&
+ CheckSolidTile(*x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+ cy++ );
+ *h_ptr += cy - (*y_ptr + *h_ptr);
+
+ /* ... to the left. */
+ for ( cx = *x_ptr - 1;
+ cx >= x && CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+ cx-- );
+ *w_ptr += *x_ptr - (cx + 1);
+ *x_ptr = cx + 1;
+
+ /* ... to the right. */
+ for ( cx = *x_ptr + *w_ptr;
+ cx < x + w &&
+ CheckSolidTile(cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+ cx++ );
+ *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+static Bool
+CheckSolidTile(x, y, w, h, colorPtr, needSameColor)
+ int x, y, w, h;
+ CARD32 *colorPtr;
+ Bool needSameColor;
+{
+ switch(rfbServerFormat.bitsPerPixel) {
+ case 32:
+ return CheckSolidTile32(x, y, w, h, colorPtr, needSameColor);
+ case 16:
+ return CheckSolidTile16(x, y, w, h, colorPtr, needSameColor);
+ default:
+ return CheckSolidTile8(x, y, w, h, colorPtr, needSameColor);
+ }
+}
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \
+ \
+static Bool \
+CheckSolidTile##bpp(x, y, w, h, colorPtr, needSameColor) \
+ int x, y, w, h; \
+ CARD32 *colorPtr; \
+ Bool needSameColor; \
+{ \
+ CARD##bpp *fbptr; \
+ CARD##bpp colorValue; \
+ int dx, dy; \
+ \
+ fbptr = (CARD##bpp *) \
+ &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes + x * (bpp/8)]; \
+ \
+ colorValue = *fbptr; \
+ if (needSameColor && (CARD32)colorValue != *colorPtr) \
+ return FALSE; \
+ \
+ for (dy = 0; dy < h; dy++) { \
+ for (dx = 0; dx < w; dx++) { \
+ if (colorValue != fbptr[dx]) \
+ return FALSE; \
+ } \
+ fbptr = (CARD##bpp *)((CARD8 *)fbptr + rfbScreen.paddedWidthInBytes); \
+ } \
+ \
+ *colorPtr = (CARD32)colorValue; \
+ return TRUE; \
+}
+
+DEFINE_CHECK_SOLID_FUNCTION(8)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(32)
+
+static Bool
+SendRectSimple(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ int maxBeforeSize, maxAfterSize;
+ int maxRectSize, maxRectWidth;
+ int subrectMaxWidth, subrectMaxHeight;
+ int dx, dy;
+ int rw, rh;
+
+ maxRectSize = tightConf[compressLevel].maxRectSize;
+ maxRectWidth = tightConf[compressLevel].maxRectWidth;
+
+ maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
+ maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
+
+ if (tightBeforeBufSize < maxBeforeSize) {
+ tightBeforeBufSize = maxBeforeSize;
+ if (tightBeforeBuf == NULL)
+ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+ tightBeforeBufSize);
+ }
+
+ if (tightAfterBufSize < maxAfterSize) {
+ tightAfterBufSize = maxAfterSize;
+ if (tightAfterBuf == NULL)
+ tightAfterBuf = (char *)xalloc(tightAfterBufSize);
+ else
+ tightAfterBuf = (char *)xrealloc(tightAfterBuf,
+ tightAfterBufSize);
+ }
+
+ if (w > maxRectWidth || w * h > maxRectSize) {
+ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+ subrectMaxHeight = maxRectSize / subrectMaxWidth;
+
+ for (dy = 0; dy < h; dy += subrectMaxHeight) {
+ for (dx = 0; dx < w; dx += maxRectWidth) {
+ rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
+ rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+ if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
+ return FALSE;
+ }
+ }
+ } else {
+ if (!SendSubrect(cl, x, y, w, h))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+SendSubrect(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ char *fbptr;
+ Bool success = FALSE;
+
+ /* Send pending data if there is more than 128 bytes. */
+ if (ublen > 128) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ if (!SendTightHeader(cl, x, y, w, h))
+ return FALSE;
+
+ fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y)
+ + (x * (rfbScreen.bitsPerPixel / 8)));
+
+ if (subsampLevel == TJ_GRAYSCALE && qualityLevel != -1)
+ return SendJpegRect(cl, x, y, w, h, qualityLevel);
+
+ paletteMaxColors = w * h / tightConf[compressLevel].idxMaxColorsDivisor;
+ if(qualityLevel != -1)
+ paletteMaxColors = 24;
+ if ( paletteMaxColors < 2 &&
+ w * h >= tightConf[compressLevel].monoMinRectSize ) {
+ paletteMaxColors = 2;
+ }
+
+ if (cl->format.bitsPerPixel == rfbServerFormat.bitsPerPixel &&
+ cl->format.redMax == rfbServerFormat.redMax &&
+ cl->format.greenMax == rfbServerFormat.greenMax &&
+ cl->format.blueMax == rfbServerFormat.blueMax &&
+ cl->format.bitsPerPixel >= 16) {
+
+ /* This is so we can avoid translating the pixels when compressing
+ with JPEG, since it is unnecessary */
+ switch (cl->format.bitsPerPixel) {
+ case 16:
+ FastFillPalette16(cl, (CARD16 *)fbptr, w,
+ rfbScreen.paddedWidthInBytes/2, h);
+ break;
+ default:
+ FastFillPalette32(cl, (CARD32 *)fbptr, w,
+ rfbScreen.paddedWidthInBytes/4, h);
+ }
+
+ if(paletteNumColors != 0 || qualityLevel == -1) {
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
+ &cl->format, fbptr, tightBeforeBuf,
+ rfbScreen.paddedWidthInBytes, w, h);
+ }
+ }
+ else {
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
+ &cl->format, fbptr, tightBeforeBuf,
+ rfbScreen.paddedWidthInBytes, w, h);
+
+ switch (cl->format.bitsPerPixel) {
+ case 8:
+ FillPalette8(w * h);
+ break;
+ case 16:
+ FillPalette16(w * h);
+ break;
+ default:
+ FillPalette32(w * h);
+ }
+ }
+
+ switch (paletteNumColors) {
+ case 0:
+ /* Truecolor image */
+ if (qualityLevel != -1) {
+ success = SendJpegRect(cl, x, y, w, h, qualityLevel);
+ } else {
+ success = SendFullColorRect(cl, w, h);
+ }
+ break;
+ case 1:
+ /* Solid rectangle */
+ success = SendSolidRect(cl);
+ break;
+ case 2:
+ /* Two-color rectangle */
+ success = SendMonoRect(cl, w, h);
+ break;
+ default:
+ /* Up to 256 different colors */
+ success = SendIndexedRect(cl, w, h);
+ }
+ return success;
+}
+
+static Bool
+SendTightHeader(cl, x, y, w, h)
+ rfbClientPtr cl;
+ int x, y, w, h;
+{
+ rfbFramebufferUpdateRectHeader rect;
+
+ if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingTight);
+
+ memcpy(&updateBuf[ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ cl->rfbRectanglesSent[rfbEncodingTight]++;
+ cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+
+ return TRUE;
+}
+
+/*
+ * Subencoding implementations.
+ */
+
+static Bool
+SendSolidRect(cl)
+ rfbClientPtr cl;
+{
+ int len;
+
+ if (usePixelFormat24) {
+ Pack24(tightBeforeBuf, &cl->format, 1);
+ len = 3;
+ } else
+ len = cl->format.bitsPerPixel / 8;
+
+ if (ublen + 1 + len > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ updateBuf[ublen++] = (char)(rfbTightFill << 4);
+ memcpy (&updateBuf[ublen], tightBeforeBuf, len);
+ ublen += len;
+
+ cl->rfbBytesSent[rfbEncodingTight] += len + 1;
+
+ return TRUE;
+}
+
+static Bool
+SendMonoRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 1;
+ int paletteLen, dataLen;
+
+ if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+ 2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ /* Prepare tight encoding header. */
+ dataLen = (w + 7) / 8;
+ dataLen *= h;
+
+ if (tightConf[compressLevel].monoZlibLevel == 0)
+ updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
+ else
+ updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+ updateBuf[ublen++] = rfbTightFilterPalette;
+ updateBuf[ublen++] = 1;
+
+ /* Prepare palette, convert image. */
+ switch (cl->format.bitsPerPixel) {
+
+ case 32:
+ EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h);
+
+ ((CARD32 *)tightAfterBuf)[0] = monoBackground;
+ ((CARD32 *)tightAfterBuf)[1] = monoForeground;
+ if (usePixelFormat24) {
+ Pack24(tightAfterBuf, &cl->format, 2);
+ paletteLen = 6;
+ } else
+ paletteLen = 8;
+
+ memcpy(&updateBuf[ublen], tightAfterBuf, paletteLen);
+ ublen += paletteLen;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
+ break;
+
+ case 16:
+ EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h);
+
+ ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground;
+ ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground;
+
+ memcpy(&updateBuf[ublen], tightAfterBuf, 4);
+ ublen += 4;
+ cl->rfbBytesSent[rfbEncodingTight] += 7;
+ break;
+
+ default:
+ EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h);
+
+ updateBuf[ublen++] = (char)monoBackground;
+ updateBuf[ublen++] = (char)monoForeground;
+ cl->rfbBytesSent[rfbEncodingTight] += 5;
+ }
+
+ return CompressData(cl, streamId, dataLen,
+ tightConf[compressLevel].monoZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendIndexedRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 2;
+ int i, entryLen;
+
+ if ( (ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+ paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ /* Prepare tight encoding header. */
+ if (tightConf[compressLevel].idxZlibLevel == 0)
+ updateBuf[ublen++] = (char)((rfbTightNoZlib | rfbTightExplicitFilter) << 4);
+ else
+ updateBuf[ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+ updateBuf[ublen++] = rfbTightFilterPalette;
+ updateBuf[ublen++] = (char)(paletteNumColors - 1);
+
+ /* Prepare palette, convert image. */
+ switch (cl->format.bitsPerPixel) {
+
+ case 32:
+ EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h);
+
+ for (i = 0; i < paletteNumColors; i++) {
+ ((CARD32 *)tightAfterBuf)[i] =
+ palette.entry[i].listNode->rgb;
+ }
+ if (usePixelFormat24) {
+ Pack24(tightAfterBuf, &cl->format, paletteNumColors);
+ entryLen = 3;
+ } else
+ entryLen = 4;
+
+ memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * entryLen);
+ ublen += paletteNumColors * entryLen;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+ break;
+
+ case 16:
+ EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h);
+
+ for (i = 0; i < paletteNumColors; i++) {
+ ((CARD16 *)tightAfterBuf)[i] =
+ (CARD16)palette.entry[i].listNode->rgb;
+ }
+
+ memcpy(&updateBuf[ublen], tightAfterBuf, paletteNumColors * 2);
+ ublen += paletteNumColors * 2;
+ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+ break;
+
+ default:
+ return FALSE; /* Should never happen. */
+ }
+
+ return CompressData(cl, streamId, w * h,
+ tightConf[compressLevel].idxZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendFullColorRect(cl, w, h)
+ rfbClientPtr cl;
+ int w, h;
+{
+ int streamId = 0;
+ int len;
+
+ if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ if (tightConf[compressLevel].rawZlibLevel == 0)
+ updateBuf[ublen++] = (char)(rfbTightNoZlib << 4);
+ else
+ updateBuf[ublen++] = 0x00; /* stream id = 0, no flushing, no filter */
+ cl->rfbBytesSent[rfbEncodingTight]++;
+
+ if (usePixelFormat24) {
+ Pack24(tightBeforeBuf, &cl->format, w * h);
+ len = 3;
+ } else
+ len = cl->format.bitsPerPixel / 8;
+
+ return CompressData(cl, streamId, w * h * len,
+ tightConf[compressLevel].rawZlibLevel,
+ Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
+ rfbClientPtr cl;
+ int streamId, dataLen, zlibLevel, zlibStrategy;
+{
+ z_streamp pz;
+ int err, i;
+
+ if (dataLen < TIGHT_MIN_TO_COMPRESS) {
+ memcpy(&updateBuf[ublen], tightBeforeBuf, dataLen);
+ ublen += dataLen;
+ cl->rfbBytesSent[rfbEncodingTight] += dataLen;
+ return TRUE;
+ }
+
+ if (zlibLevel == 0)
+ return SendCompressedData (cl, tightBeforeBuf, dataLen);
+
+ pz = &cl->zsStruct[streamId];
+
+ /* Initialize compression stream if needed. */
+ if (!cl->zsActive[streamId]) {
+ pz->zalloc = Z_NULL;
+ pz->zfree = Z_NULL;
+ pz->opaque = Z_NULL;
+
+ err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
+ MAX_MEM_LEVEL, zlibStrategy);
+ if (err != Z_OK)
+ return FALSE;
+
+ cl->zsActive[streamId] = TRUE;
+ cl->zsLevel[streamId] = zlibLevel;
+ }
+
+ /* Prepare buffer pointers. */
+ pz->next_in = (Bytef *)tightBeforeBuf;
+ pz->avail_in = dataLen;
+ pz->next_out = (Bytef *)tightAfterBuf;
+ pz->avail_out = tightAfterBufSize;
+
+ /* Change compression parameters if needed. */
+ if (zlibLevel != cl->zsLevel[streamId]) {
+ if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
+ return FALSE;
+ }
+ cl->zsLevel[streamId] = zlibLevel;
+ }
+
+ /* Actual compression. */
+ if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
+ pz->avail_in != 0 || pz->avail_out == 0 ) {
+ return FALSE;
+ }
+
+ return SendCompressedData(cl, tightAfterBuf,
+ tightAfterBufSize - pz->avail_out);
+}
+
+static Bool SendCompressedData(cl, buf, compressedLen)
+ rfbClientPtr cl;
+ char *buf;
+ int compressedLen;
+{
+ int i, portionLen;
+
+ updateBuf[ublen++] = compressedLen & 0x7F;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ if (compressedLen > 0x7F) {
+ updateBuf[ublen-1] |= 0x80;
+ updateBuf[ublen++] = compressedLen >> 7 & 0x7F;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ if (compressedLen > 0x3FFF) {
+ updateBuf[ublen-1] |= 0x80;
+ updateBuf[ublen++] = compressedLen >> 14 & 0xFF;
+ cl->rfbBytesSent[rfbEncodingTight]++;
+ }
+ }
+
+ portionLen = UPDATE_BUF_SIZE;
+ for (i = 0; i < compressedLen; i += portionLen) {
+ if (i + portionLen > compressedLen) {
+ portionLen = compressedLen - i;
+ }
+ if (ublen + portionLen > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ memcpy(&updateBuf[ublen], &buf[i], portionLen);
+ ublen += portionLen;
+ }
+ cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
+ return TRUE;
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void
+FillPalette8(count)
+ int count;
+{
+ CARD8 *data = (CARD8 *)tightBeforeBuf;
+ CARD8 c0, c1;
+ int i, n0, n1;
+
+ paletteNumColors = 0;
+
+ c0 = data[0];
+ for (i = 1; i < count && data[i] == c0; i++);
+ if (i == count) {
+ paletteNumColors = 1;
+ return; /* Solid rectangle */
+ }
+
+ if (paletteMaxColors < 2)
+ return;
+
+ n0 = i;
+ c1 = data[i];
+ n1 = 0;
+ for (i++; i < count; i++) {
+ if (data[i] == c0) {
+ n0++;
+ } else if (data[i] == c1) {
+ n1++;
+ } else
+ break;
+ }
+ if (i == count) {
+ if (n0 > n1) {
+ monoBackground = (CARD32)c0;
+ monoForeground = (CARD32)c1;
+ } else {
+ monoBackground = (CARD32)c1;
+ monoForeground = (CARD32)c0;
+ }
+ paletteNumColors = 2; /* Two colors */
+ }
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \
+ \
+static void \
+FillPalette##bpp(count) \
+ int count; \
+{ \
+ CARD##bpp *data = (CARD##bpp *)tightBeforeBuf; \
+ CARD##bpp c0, c1, ci; \
+ int i, n0, n1, ni; \
+ \
+ c0 = data[0]; \
+ for (i = 1; i < count && data[i] == c0; i++); \
+ if (i >= count) { \
+ paletteNumColors = 1; /* Solid rectangle */ \
+ return; \
+ } \
+ \
+ if (paletteMaxColors < 2) { \
+ paletteNumColors = 0; /* Full-color encoding preferred */ \
+ return; \
+ } \
+ \
+ n0 = i; \
+ c1 = data[i]; \
+ n1 = 0; \
+ for (i++; i < count; i++) { \
+ ci = data[i]; \
+ if (ci == c0) { \
+ n0++; \
+ } else if (ci == c1) { \
+ n1++; \
+ } else \
+ break; \
+ } \
+ if (i >= count) { \
+ if (n0 > n1) { \
+ monoBackground = (CARD32)c0; \
+ monoForeground = (CARD32)c1; \
+ } else { \
+ monoBackground = (CARD32)c1; \
+ monoForeground = (CARD32)c0; \
+ } \
+ paletteNumColors = 2; /* Two colors */ \
+ return; \
+ } \
+ \
+ PaletteReset(); \
+ PaletteInsert (c0, (CARD32)n0, bpp); \
+ PaletteInsert (c1, (CARD32)n1, bpp); \
+ \
+ ni = 1; \
+ for (i++; i < count; i++) { \
+ if (data[i] == ci) { \
+ ni++; \
+ } else { \
+ if (!PaletteInsert (ci, (CARD32)ni, bpp)) \
+ return; \
+ ci = data[i]; \
+ ni = 1; \
+ } \
+ } \
+ PaletteInsert (ci, (CARD32)ni, bpp); \
+}
+
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+#define DEFINE_FAST_FILL_PALETTE_FUNCTION(bpp) \
+ \
+static void \
+FastFillPalette##bpp(cl, data, w, pitch, h) \
+ rfbClientPtr cl; \
+ CARD##bpp *data; \
+ int w, pitch, h; \
+{ \
+ CARD##bpp c0, c1, ci, mask, c0t, c1t, cit; \
+ int i, j, i2, j2, n0, n1, ni; \
+ \
+ if (cl->translateFn != rfbTranslateNone) { \
+ mask = rfbServerFormat.redMax << rfbServerFormat.redShift; \
+ mask |= rfbServerFormat.greenMax << rfbServerFormat.greenShift; \
+ mask |= rfbServerFormat.blueMax << rfbServerFormat.blueShift; \
+ } else mask = ~0; \
+ \
+ c0 = data[0] & mask; \
+ for (j = 0; j < h; j++) { \
+ for (i = 0; i < w; i++) { \
+ if ((data[j * pitch + i] & mask) != c0) \
+ goto done; \
+ } \
+ } \
+ done: \
+ if (j >= h) { \
+ paletteNumColors = 1; /* Solid rectangle */ \
+ return; \
+ } \
+ if (paletteMaxColors < 2) { \
+ paletteNumColors = 0; /* Full-color encoding preferred */ \
+ return; \
+ } \
+ \
+ n0 = j * w + i; \
+ c1 = data[j * pitch + i] & mask; \
+ n1 = 0; \
+ i++; if (i >= w) {i = 0; j++;} \
+ for (j2 = j; j2 < h; j2++) { \
+ for (i2 = i; i2 < w; i2++) { \
+ ci = data[j2 * pitch + i2] & mask; \
+ if (ci == c0) { \
+ n0++; \
+ } else if (ci == c1) { \
+ n1++; \
+ } else \
+ goto done2; \
+ } \
+ i = 0; \
+ } \
+ done2: \
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \
+ &cl->format, (char *)&c0, (char *)&c0t, bpp/8, \
+ 1, 1); \
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \
+ &cl->format, (char *)&c1, (char *)&c1t, bpp/8, \
+ 1, 1); \
+ if (j2 >= h) { \
+ if (n0 > n1) { \
+ monoBackground = (CARD32)c0t; \
+ monoForeground = (CARD32)c1t; \
+ } else { \
+ monoBackground = (CARD32)c1t; \
+ monoForeground = (CARD32)c0t; \
+ } \
+ paletteNumColors = 2; /* Two colors */ \
+ return; \
+ } \
+ \
+ PaletteReset(); \
+ PaletteInsert (c0t, (CARD32)n0, bpp); \
+ PaletteInsert (c1t, (CARD32)n1, bpp); \
+ \
+ ni = 1; \
+ i2++; if (i2 >= w) {i2 = 0; j2++;} \
+ for (j = j2; j < h; j++) { \
+ for (i = i2; i < w; i++) { \
+ if ((data[j * pitch + i] & mask) == ci) { \
+ ni++; \
+ } else { \
+ (*cl->translateFn)(cl->translateLookupTable, \
+ &rfbServerFormat, &cl->format, \
+ (char *)&ci, (char *)&cit, bpp/8, \
+ 1, 1); \
+ if (!PaletteInsert (cit, (CARD32)ni, bpp)) \
+ return; \
+ ci = data[j * pitch + i] & mask; \
+ ni = 1; \
+ } \
+ } \
+ i2 = 0; \
+ } \
+ \
+ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \
+ &cl->format, (char *)&ci, (char *)&cit, bpp/8, \
+ 1, 1); \
+ PaletteInsert (cit, (CARD32)ni, bpp); \
+}
+
+DEFINE_FAST_FILL_PALETTE_FUNCTION(16)
+DEFINE_FAST_FILL_PALETTE_FUNCTION(32)
+
+
+/*
+ * Functions to operate with palette structures.
+ */
+
+#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
+
+static void
+PaletteReset(void)
+{
+ paletteNumColors = 0;
+ memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
+}
+
+static int
+PaletteInsert(rgb, numPixels, bpp)
+ CARD32 rgb;
+ int numPixels;
+ int bpp;
+{
+ COLOR_LIST *pnode;
+ COLOR_LIST *prev_pnode = NULL;
+ int hash_key, idx, new_idx, count;
+
+ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+ pnode = palette.hash[hash_key];
+
+ while (pnode != NULL) {
+ if (pnode->rgb == rgb) {
+ /* Such palette entry already exists. */
+ new_idx = idx = pnode->idx;
+ count = palette.entry[idx].numPixels + numPixels;
+ if (new_idx && palette.entry[new_idx-1].numPixels < count) {
+ do {
+ palette.entry[new_idx] = palette.entry[new_idx-1];
+ palette.entry[new_idx].listNode->idx = new_idx;
+ new_idx--;
+ }
+ while (new_idx && palette.entry[new_idx-1].numPixels < count);
+ palette.entry[new_idx].listNode = pnode;
+ pnode->idx = new_idx;
+ }
+ palette.entry[new_idx].numPixels = count;
+ return paletteNumColors;
+ }
+ prev_pnode = pnode;
+ pnode = pnode->next;
+ }
+
+ /* Check if palette is full. */
+ if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
+ paletteNumColors = 0;
+ return 0;
+ }
+
+ /* Move palette entries with lesser pixel counts. */
+ for ( idx = paletteNumColors;
+ idx > 0 && palette.entry[idx-1].numPixels < numPixels;
+ idx-- ) {
+ palette.entry[idx] = palette.entry[idx-1];
+ palette.entry[idx].listNode->idx = idx;
+ }
+
+ /* Add new palette entry into the freed slot. */
+ pnode = &palette.list[paletteNumColors];
+ if (prev_pnode != NULL) {
+ prev_pnode->next = pnode;
+ } else {
+ palette.hash[hash_key] = pnode;
+ }
+ pnode->next = NULL;
+ pnode->idx = idx;
+ pnode->rgb = rgb;
+ palette.entry[idx].listNode = pnode;
+ palette.entry[idx].numPixels = numPixels;
+
+ return (++paletteNumColors);
+}
+
+
+/*
+ * Converting 32-bit color samples into 24-bit colors.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void Pack24(buf, fmt, count)
+ char *buf;
+ rfbPixelFormat *fmt;
+ int count;
+{
+ CARD32 *buf32;
+ CARD32 pix;
+ int r_shift, g_shift, b_shift;
+
+ buf32 = (CARD32 *)buf;
+
+ if (!rfbServerFormat.bigEndian == !fmt->bigEndian) {
+ r_shift = fmt->redShift;
+ g_shift = fmt->greenShift;
+ b_shift = fmt->blueShift;
+ } else {
+ r_shift = 24 - fmt->redShift;
+ g_shift = 24 - fmt->greenShift;
+ b_shift = 24 - fmt->blueShift;
+ }
+
+ while (count--) {
+ pix = *buf32++;
+ *buf++ = (char)(pix >> r_shift);
+ *buf++ = (char)(pix >> g_shift);
+ *buf++ = (char)(pix >> b_shift);
+ }
+}
+
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \
+ \
+static void \
+EncodeIndexedRect##bpp(buf, count) \
+ CARD8 *buf; \
+ int count; \
+{ \
+ COLOR_LIST *pnode; \
+ CARD##bpp *src; \
+ CARD##bpp rgb; \
+ int rep = 0; \
+ \
+ src = (CARD##bpp *) buf; \
+ \
+ while (count--) { \
+ rgb = *src++; \
+ while (count && *src == rgb) { \
+ rep++, src++, count--; \
+ } \
+ pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \
+ while (pnode != NULL) { \
+ if ((CARD##bpp)pnode->rgb == rgb) { \
+ *buf++ = (CARD8)pnode->idx; \
+ while (rep) { \
+ *buf++ = (CARD8)pnode->idx; \
+ rep--; \
+ } \
+ break; \
+ } \
+ pnode = pnode->next; \
+ } \
+ } \
+}
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp) \
+ \
+static void \
+EncodeMonoRect##bpp(buf, w, h) \
+ CARD8 *buf; \
+ int w, h; \
+{ \
+ CARD##bpp *ptr; \
+ CARD##bpp bg; \
+ unsigned int value, mask; \
+ int aligned_width; \
+ int x, y, bg_bits; \
+ \
+ ptr = (CARD##bpp *) buf; \
+ bg = (CARD##bpp) monoBackground; \
+ aligned_width = w - w % 8; \
+ \
+ for (y = 0; y < h; y++) { \
+ for (x = 0; x < aligned_width; x += 8) { \
+ for (bg_bits = 0; bg_bits < 8; bg_bits++) { \
+ if (*ptr++ != bg) \
+ break; \
+ } \
+ if (bg_bits == 8) { \
+ *buf++ = 0; \
+ continue; \
+ } \
+ mask = 0x80 >> bg_bits; \
+ value = mask; \
+ for (bg_bits++; bg_bits < 8; bg_bits++) { \
+ mask >>= 1; \
+ if (*ptr++ != bg) { \
+ value |= mask; \
+ } \
+ } \
+ *buf++ = (CARD8)value; \
+ } \
+ \
+ mask = 0x80; \
+ value = 0; \
+ if (x >= w) \
+ continue; \
+ \
+ for (; x < w; x++) { \
+ if (*ptr++ != bg) { \
+ value |= mask; \
+ } \
+ mask >>= 1; \
+ } \
+ *buf++ = (CARD8)value; \
+ } \
+}
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+/*
+ * JPEG compression stuff.
+ */
+
+static unsigned long jpegDstDataLen;
+static tjhandle j=NULL;
+
+static Bool
+SendJpegRect(cl, x, y, w, h, quality)
+ rfbClientPtr cl;
+ int x, y, w, h;
+ int quality;
+{
+ int dy;
+ unsigned char *srcbuf;
+ int ps=rfbServerFormat.bitsPerPixel/8;
+ int subsamp=subsampLevel2tjsubsamp[subsampLevel];
+ unsigned long size=0;
+ int flags=0, pitch;
+ unsigned char *tmpbuf=NULL;
+
+ if (rfbServerFormat.bitsPerPixel == 8)
+ return SendFullColorRect(cl, w, h);
+
+
+ if(ps<2) {
+ rfbLog("Error: JPEG requires 16-bit, 24-bit, or 32-bit pixel format.\n");
+ return 0;
+ }
+ if(!j) {
+ if((j=tjInitCompress())==NULL) {
+ rfbLog("JPEG Error: %s\n", tjGetErrorStr()); return 0;
+ }
+ }
+
+ if (tightAfterBufSize < TJBUFSIZE(w,h)) {
+ if (tightAfterBuf == NULL)
+ tightAfterBuf = (char *)xalloc(TJBUFSIZE(w,h));
+ else
+ tightAfterBuf = (char *)xrealloc(tightAfterBuf,
+ TJBUFSIZE(w,h));
+ if(!tightAfterBuf) {
+ rfbLog("Memory allocation failure!\n");
+ return 0;
+ }
+ tightAfterBufSize = TJBUFSIZE(w,h);
+ }
+
+ if (ps == 2) {
+ CARD16 *srcptr, pix;
+ unsigned char *dst;
+ int inRed, inGreen, inBlue, i, j;
+
+ if((tmpbuf=(unsigned char *)malloc(w*h*3))==NULL)
+ rfbLog("Memory allocation failure!\n");
+ srcptr = (CARD16 *)
+ &rfbScreen.pfbMemory[y * rfbScreen.paddedWidthInBytes +
+ x * ps];
+ dst = tmpbuf;
+ for(j=0; j<h; j++) {
+ CARD16 *srcptr2=srcptr;
+ unsigned char *dst2=dst;
+ for(i=0; i<w; i++) {
+ pix = *srcptr2++;
+ inRed = (int)
+ (pix >> rfbServerFormat.redShift & rfbServerFormat.redMax);
+ inGreen = (int)
+ (pix >> rfbServerFormat.greenShift & rfbServerFormat.greenMax);
+ inBlue = (int)
+ (pix >> rfbServerFormat.blueShift & rfbServerFormat.blueMax);
+ *dst2++ = (CARD8)((inRed * 255 + rfbServerFormat.redMax / 2) /
+ rfbServerFormat.redMax);
+ *dst2++ = (CARD8)((inGreen * 255 + rfbServerFormat.greenMax / 2) /
+ rfbServerFormat.greenMax);
+ *dst2++ = (CARD8)((inBlue * 255 + rfbServerFormat.blueMax / 2) /
+ rfbServerFormat.blueMax);
+ }
+ srcptr+=rfbScreen.paddedWidthInBytes/ps;
+ dst+=w*3;
+ }
+ srcbuf = tmpbuf;
+ pitch = w*3;
+ ps = 3;
+ } else {
+ if(rfbServerFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST;
+ if(rfbServerFormat.redShift==16 && rfbServerFormat.blueShift==0)
+ flags|=TJ_BGR;
+ if(rfbServerFormat.bigEndian) flags^=TJ_BGR;
+ srcbuf=(unsigned char *)&rfbScreen.pfbMemory[y *
+ rfbScreen.paddedWidthInBytes + x * ps];
+ pitch=rfbScreen.paddedWidthInBytes;
+ }
+
+ if(tjCompress(j, srcbuf, w, pitch, h, ps, (unsigned char *)tightAfterBuf,
+ &size, subsamp, quality, flags)==-1) {
+ rfbLog("JPEG Error: %s\n", tjGetErrorStr());
+ if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;}
+ return 0;
+ }
+ jpegDstDataLen=(int)size;
+
+ if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;}
+
+ if (ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ updateBuf[ublen++] = (char)(rfbTightJpeg << 4);
+ cl->rfbBytesSent[rfbEncodingTight]++;
+
+ return SendCompressedData(cl, tightAfterBuf, jpegDstDataLen);
+}
diff --git a/x11vnc/misc/turbovnc/turbojpeg.h b/x11vnc/misc/turbovnc/turbojpeg.h
new file mode 100644
index 0000000..8a6af05
--- /dev/null
+++ b/x11vnc/misc/turbovnc/turbojpeg.h
@@ -0,0 +1,229 @@
+/* Copyright (C)2004 Landmark Graphics
+ * Copyright (C)2005, 2006 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3 or (at your option)
+ * any later version. The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * wxWindows Library License for more details.
+ */
+
+#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE)
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+#define DLLCALL
+
+/* Subsampling */
+#define NUMSUBOPT 4
+
+enum {TJ_444=0, TJ_422, TJ_411, TJ_GRAYSCALE};
+
+/* Flags */
+#define TJ_BGR 1
+#define TJ_BOTTOMUP 2
+#define TJ_FORCEMMX 8 /* Force IPP to use MMX code even if SSE available */
+#define TJ_FORCESSE 16 /* Force IPP to use SSE1 code even if SSE2 available */
+#define TJ_FORCESSE2 32 /* Force IPP to use SSE2 code (useful if auto-detect is not working properly) */
+#define TJ_ALPHAFIRST 64 /* BGR buffer is ABGR and RGB buffer is ARGB */
+#define TJ_FORCESSE3 128 /* Force IPP to use SSE3 code (useful if auto-detect is not working properly) */
+
+typedef void* tjhandle;
+
+#define TJPAD(p) (((p)+3)&(~3))
+#ifndef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* API follows */
+
+
+/*
+ tjhandle tjInitCompress(void)
+
+ Creates a new JPEG compressor instance, allocates memory for the structures,
+ and returns a handle to the instance. Most applications will only
+ need to call this once at the beginning of the program or once for each
+ concurrent thread. Don't try to create a new instance every time you
+ compress an image, because this will cause performance to suffer.
+
+ RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
+
+
+/*
+ int tjCompress(tjhandle j,
+ unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+ unsigned char *dstbuf, unsigned long *size,
+ int jpegsubsamp, int jpegqual, int flags)
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitCompress()
+ [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in
+ RGB(A) or BGR(A) form
+ [INPUT] width = width (in pixels) of the source image
+ [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
+ bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+ is padded to the nearest 32-bit boundary, such as is the case for Windows
+ bitmaps. You can also be clever and use this parameter to skip lines, etc.,
+ as long as the pitch is greater than 0.)
+ [INPUT] height = height (in pixels) of the source image
+ [INPUT] pixelsize = size (in bytes) of each pixel in the source image
+ RGBA and BGRA: 4, RGB and BGR: 3
+ [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+ the JPEG image. Use the macro TJBUFSIZE(width, height) to determine
+ the appropriate size for this buffer based on the image width and height.
+ [OUTPUT] size = pointer to unsigned long which receives the size (in bytes)
+ of the compressed image
+ [INPUT] jpegsubsamp = Specifies either 4:1:1, 4:2:2, or 4:4:4 subsampling.
+ When the image is converted from the RGB to YCbCr colorspace as part of the
+ JPEG compression process, every other Cb and Cr (chrominance) pixel can be
+ discarded to produce a smaller image with little perceptible loss of
+ image clarity (the human eye is more sensitive to small changes in
+ brightness than small changes in color.)
+
+ TJ_411: 4:1:1 subsampling. Discards every other Cb, Cr pixel in both
+ horizontal and vertical directions.
+ TJ_422: 4:2:2 subsampling. Discards every other Cb, Cr pixel only in
+ the horizontal direction.
+ TJ_444: no subsampling.
+ TJ_GRAYSCALE: Generate grayscale JPEG image
+
+ [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.)
+ [INPUT] flags = the bitwise OR of one or more of the following
+
+ TJ_BGR: The components of each pixel in the source image are stored in
+ B,G,R order, not R,G,B
+ TJ_BOTTOMUP: The source image is stored in bottom-up (Windows) order,
+ not top-down
+ TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+ TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+ TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+ TJ_FORCESSE3: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use SSE3 code (bypass CPU auto-detection)
+
+ RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjCompress(tjhandle j,
+ unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+ unsigned char *dstbuf, unsigned long *size,
+ int jpegsubsamp, int jpegqual, int flags);
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
+
+/*
+ tjhandle tjInitDecompress(void)
+
+ Creates a new JPEG decompressor instance, allocates memory for the
+ structures, and returns a handle to the instance. Most applications will
+ only need to call this once at the beginning of the program or once for each
+ concurrent thread. Don't try to create a new instance every time you
+ decompress an image, because this will cause performance to suffer.
+
+ RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
+
+
+/*
+ int tjDecompressHeader(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ int *width, int *height)
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitDecompress()
+ [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+ to decompress
+ [INPUT] size = size of the JPEG image buffer (in bytes)
+ [OUTPUT] width = width (in pixels) of the JPEG image
+ [OUTPUT] height = height (in pixels) of the JPEG image
+
+ RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ int *width, int *height);
+
+
+/*
+ int tjDecompress(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+ int flags)
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitDecompress()
+ [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+ to decompress
+ [INPUT] size = size of the JPEG image buffer (in bytes)
+ [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+ the bitmap image. This buffer should normally be pitch*height
+ bytes in size, although this pointer may also be used to decompress into
+ a specific region of a larger buffer.
+ [INPUT] width = width (in pixels) of the destination image
+ [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the
+ bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+ is padded to the nearest 32-bit boundary, such as is the case for Windows
+ bitmaps. You can also be clever and use this parameter to skip lines, etc.,
+ as long as the pitch is greater than 0.)
+ [INPUT] height = height (in pixels) of the destination image
+ [INPUT] pixelsize = size (in bytes) of each pixel in the destination image
+ RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3
+ [INPUT] flags = the bitwise OR of one or more of the following
+
+ TJ_BGR: The components of each pixel in the destination image should be
+ written in B,G,R order, not R,G,B
+ TJ_BOTTOMUP: The destination image should be stored in bottom-up
+ (Windows) order, not top-down
+ TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+ TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+ TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+ of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+
+ RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompress(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+ int flags);
+
+
+/*
+ int tjDestroy(tjhandle h)
+
+ Frees structures associated with a compression or decompression instance
+
+ [INPUT] h = instance handle (returned from a previous call to
+ tjInitCompress() or tjInitDecompress()
+
+ RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDestroy(tjhandle h);
+
+
+/*
+ char *tjGetErrorStr(void)
+
+ Returns a descriptive error message explaining why the last command failed
+*/
+DLLEXPORT char* DLLCALL tjGetErrorStr(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/x11vnc/misc/turbovnc/undo_turbovnc b/x11vnc/misc/turbovnc/undo_turbovnc
new file mode 100755
index 0000000..7080680
--- /dev/null
+++ b/x11vnc/misc/turbovnc/undo_turbovnc
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+ldir="../../../libvncserver"
+
+if [ ! -f "$ldir/tight.c.ORIG" ]; then
+ ls -l "$ldir/tight.c.ORIG"
+ exit 1
+fi
+
+set -xv
+rm -f "$ldir/tight.c" "$ldir/turbojpeg.h"
+mv "$ldir/tight.c.ORIG" "$ldir/tight.c"
+ls -l $ldir/tight.c*