summaryrefslogtreecommitdiffstats
path: root/krfb/libvncserver/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'krfb/libvncserver/translate.c')
-rw-r--r--krfb/libvncserver/translate.c484
1 files changed, 484 insertions, 0 deletions
diff --git a/krfb/libvncserver/translate.c b/krfb/libvncserver/translate.c
new file mode 100644
index 00000000..d6021d57
--- /dev/null
+++ b/krfb/libvncserver/translate.c
@@ -0,0 +1,484 @@
+/*
+ * translate.c - translate between different pixel formats
+ */
+
+/*
+ * OSXvnc Copyright (C) 2001 Dan McGuirk <[email protected]>.
+ * Original Xvnc code 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 "rfb.h"
+#include "sraRegion.h"
+
+static void PrintPixelFormat(rfbPixelFormat *pf);
+static Bool rfbSetClientColourMapBGR233(rfbClientPtr cl);
+
+Bool rfbEconomicTranslate = FALSE;
+
+/*
+ * Some standard pixel formats.
+ */
+
+static const rfbPixelFormat BGR233Format = {
+ 8, 8, 0, 1, 7, 7, 3, 0, 3, 6, 0, 0
+};
+
+
+/*
+ * Macro to compare pixel formats.
+ */
+
+#define PF_EQ(x,y) \
+ ((x.bitsPerPixel == y.bitsPerPixel) && \
+ (x.depth == y.depth) && \
+ ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
+ (x.trueColour == y.trueColour) && \
+ (!x.trueColour || ((x.redMax == y.redMax) && \
+ (x.greenMax == y.greenMax) && \
+ (x.blueMax == y.blueMax) && \
+ (x.redShift == y.redShift) && \
+ (x.greenShift == y.greenShift) && \
+ (x.blueShift == y.blueShift))))
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+
+#undef OUT
+#undef IN
+
+#define OUT 8
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 16
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 32
+#include "tableinitcmtemplate.c"
+#include "tableinittctemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#ifdef ALLOW24BPP
+#define COUNT_OFFSETS 4
+#define BPP2OFFSET(bpp) ((bpp)/8-1)
+#include "tableinit24.c"
+#define BPP 8
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 16
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 24
+#include "tabletrans24template.c"
+#undef BPP
+#define BPP 32
+#include "tabletrans24template.c"
+#undef BPP
+#else
+#define COUNT_OFFSETS 3
+#define BPP2OFFSET(bpp) ((int)(bpp)/16)
+#endif
+
+typedef void (*rfbInitCMTableFnType)(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out,rfbColourMap* cm);
+typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
+ rfbPixelFormat *out);
+
+rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
+ rfbInitColourMapSingleTable8,
+ rfbInitColourMapSingleTable16,
+#ifdef ALLOW24BPP
+ rfbInitColourMapSingleTable24,
+#endif
+ rfbInitColourMapSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
+ rfbInitTrueColourSingleTable8,
+ rfbInitTrueColourSingleTable16,
+#ifdef ALLOW24BPP
+ rfbInitTrueColourSingleTable24,
+#endif
+ rfbInitTrueColourSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
+ rfbInitTrueColourRGBTables8,
+ rfbInitTrueColourRGBTables16,
+#ifdef ALLOW24BPP
+ rfbInitTrueColourRGBTables24,
+#endif
+ rfbInitTrueColourRGBTables32
+};
+
+rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
+ { rfbTranslateWithSingleTable8to8,
+ rfbTranslateWithSingleTable8to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithSingleTable8to24,
+#endif
+ rfbTranslateWithSingleTable8to32 },
+ { rfbTranslateWithSingleTable16to8,
+ rfbTranslateWithSingleTable16to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithSingleTable16to24,
+#endif
+ rfbTranslateWithSingleTable16to32 },
+#ifdef ALLOW24BPP
+ { rfbTranslateWithSingleTable24to8,
+ rfbTranslateWithSingleTable24to16,
+ rfbTranslateWithSingleTable24to24,
+ rfbTranslateWithSingleTable24to32 },
+#endif
+ { rfbTranslateWithSingleTable32to8,
+ rfbTranslateWithSingleTable32to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithSingleTable32to24,
+#endif
+ rfbTranslateWithSingleTable32to32 }
+};
+
+rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
+ { rfbTranslateWithRGBTables8to8,
+ rfbTranslateWithRGBTables8to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithRGBTables8to24,
+#endif
+ rfbTranslateWithRGBTables8to32 },
+ { rfbTranslateWithRGBTables16to8,
+ rfbTranslateWithRGBTables16to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithRGBTables16to24,
+#endif
+ rfbTranslateWithRGBTables16to32 },
+#ifdef ALLOW24BPP
+ { rfbTranslateWithRGBTables24to8,
+ rfbTranslateWithRGBTables24to16,
+ rfbTranslateWithRGBTables24to24,
+ rfbTranslateWithRGBTables24to32 },
+#endif
+ { rfbTranslateWithRGBTables32to8,
+ rfbTranslateWithRGBTables32to16,
+#ifdef ALLOW24BPP
+ rfbTranslateWithRGBTables32to24,
+#endif
+ rfbTranslateWithRGBTables32to32 }
+};
+
+
+
+/*
+ * rfbTranslateNone is used when no translation is required.
+ */
+
+void
+rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
+ char *iptr, char *optr, int bytesBetweenInputLines,
+ int width, int height)
+{
+ int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
+
+ while (height > 0) {
+ memcpy(optr, iptr, bytesPerOutputLine);
+ iptr += bytesBetweenInputLines;
+ optr += bytesPerOutputLine;
+ height--;
+ }
+}
+
+
+/*
+ * rfbSetTranslateFunction sets the translation function.
+ */
+
+Bool
+rfbSetTranslateFunction(cl)
+ rfbClientPtr cl;
+{
+ rfbLog("Pixel format for client %s:\n",cl->host);
+ PrintPixelFormat(&cl->format);
+
+ /*
+ * Check that bits per pixel values are valid
+ */
+
+ if ((cl->screen->rfbServerFormat.bitsPerPixel != 8) &&
+ (cl->screen->rfbServerFormat.bitsPerPixel != 16) &&
+#ifdef ALLOW24BPP
+ (cl->screen->rfbServerFormat.bitsPerPixel != 24) &&
+#endif
+ (cl->screen->rfbServerFormat.bitsPerPixel != 32))
+ {
+ rfbLog("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
+ "rfbSetTranslateFunction",
+ cl->screen->rfbServerFormat.bitsPerPixel);
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ if ((cl->format.bitsPerPixel != 8) &&
+ (cl->format.bitsPerPixel != 16) &&
+#ifdef ALLOW24BPP
+ (cl->format.bitsPerPixel != 24) &&
+#endif
+ (cl->format.bitsPerPixel != 32))
+ {
+ rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
+ "rfbSetTranslateFunction");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
+ rfbLog("rfbSetTranslateFunction: client has colour map "
+ "but %d-bit - can only cope with 8-bit colour maps\n",
+ cl->format.bitsPerPixel);
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ /*
+ * bpp is valid, now work out how to translate
+ */
+
+ if (!cl->format.trueColour) {
+ /*
+ * truecolour -> colour map
+ *
+ * Set client's colour map to BGR233, then effectively it's
+ * truecolour as well
+ */
+
+ if (!rfbSetClientColourMapBGR233(cl))
+ return FALSE;
+
+ cl->format = BGR233Format;
+ }
+
+ /* truecolour -> truecolour */
+
+ if (PF_EQ(cl->format,cl->screen->rfbServerFormat)) {
+
+ /* client & server the same */
+
+ rfbLog("no translation needed\n");
+ cl->translateFn = rfbTranslateNone;
+ return TRUE;
+ }
+
+ if ((cl->screen->rfbServerFormat.bitsPerPixel < 16) ||
+ ((!cl->screen->rfbServerFormat.trueColour || !rfbEconomicTranslate) &&
+ (cl->screen->rfbServerFormat.bitsPerPixel == 16))) {
+
+ /* we can use a single lookup table for <= 16 bpp */
+
+ cl->translateFn = rfbTranslateWithSingleTableFns
+ [BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
+ [BPP2OFFSET(cl->format.bitsPerPixel)];
+
+ if(cl->screen->rfbServerFormat.trueColour)
+ (*rfbInitTrueColourSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format);
+ else
+ (*rfbInitColourMapSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format,&cl->screen->colourMap);
+
+ } else {
+
+ /* otherwise we use three separate tables for red, green and blue */
+
+ cl->translateFn = rfbTranslateWithRGBTablesFns
+ [BPP2OFFSET(cl->screen->rfbServerFormat.bitsPerPixel)]
+ [BPP2OFFSET(cl->format.bitsPerPixel)];
+
+ (*rfbInitTrueColourRGBTablesFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &(cl->screen->rfbServerFormat), &cl->format);
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
+ * just like an 8-bit BGR233 true colour client.
+ */
+
+static Bool
+rfbSetClientColourMapBGR233(cl)
+ rfbClientPtr cl;
+{
+ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+ int i, len;
+ int r, g, b;
+
+ if (cl->format.bitsPerPixel != 8 ) {
+ rfbLog("%s: client not 8 bits per pixel\n",
+ "rfbSetClientColourMapBGR233");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ scme->type = rfbSetColourMapEntries;
+
+ scme->firstColour = Swap16IfLE(0);
+ scme->nColours = Swap16IfLE(256);
+
+ len = sz_rfbSetColourMapEntriesMsg;
+
+ i = 0;
+
+ for (b = 0; b < 4; b++) {
+ for (g = 0; g < 8; g++) {
+ for (r = 0; r < 8; r++) {
+ rgb[i++] = Swap16IfLE(r * 65535 / 7);
+ rgb[i++] = Swap16IfLE(g * 65535 / 7);
+ rgb[i++] = Swap16IfLE(b * 65535 / 3);
+ }
+ }
+ }
+
+ len += 256 * 3 * 2;
+
+ if (WriteExact(cl, buf, len) < 0) {
+ rfbLogPerror("rfbSetClientColourMapBGR233: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* this function is not called very often, so it needn't be
+ efficient. */
+
+/*
+ * rfbSetClientColourMap is called to set the client's colour map. If the
+ * client is a true colour client, we simply update our own translation table
+ * and mark the whole screen as having been modified.
+ */
+
+Bool
+rfbSetClientColourMap(cl, firstColour, nColours)
+ rfbClientPtr cl;
+ int firstColour;
+ int nColours;
+{
+ if (cl->screen->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
+ return TRUE;
+ }
+
+ if (nColours == 0) {
+ nColours = cl->screen->colourMap.count;
+ }
+
+ if (cl->format.trueColour) {
+ (*rfbInitColourMapSingleTableFns
+ [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
+ &cl->screen->rfbServerFormat, &cl->format,&cl->screen->colourMap);
+
+ sraRgnDestroy(cl->modifiedRegion);
+ cl->modifiedRegion =
+ sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
+
+ return TRUE;
+ }
+
+ return rfbSendSetColourMapEntries(cl, firstColour, nColours);
+}
+
+
+/*
+ * rfbSetClientColourMaps sets the colour map for each RFB client.
+ */
+
+void
+rfbSetClientColourMaps(rfbScreen, firstColour, nColours)
+ rfbScreenInfoPtr rfbScreen;
+ int firstColour;
+ int nColours;
+{
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl;
+
+ i = rfbGetClientIterator(rfbScreen);
+ while((cl = rfbClientIteratorNext(i)))
+ rfbSetClientColourMap(cl, firstColour, nColours);
+ rfbReleaseClientIterator(i);
+}
+
+static void
+PrintPixelFormat(pf)
+ rfbPixelFormat *pf;
+{
+ if (pf->bitsPerPixel == 1) {
+ rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
+ (pf->bigEndian ? "most" : "least"));
+ } else {
+ rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
+ ((pf->bitsPerPixel == 8) ? ""
+ : (pf->bigEndian ? ", big endian" : ", little endian")));
+ if (pf->trueColour) {
+ rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
+ pf->redMax, pf->greenMax, pf->blueMax,
+ pf->redShift, pf->greenShift, pf->blueShift);
+ } else {
+ rfbLog(" uses a colour map (not true colour).\n");
+ }
+ }
+}