diff options
Diffstat (limited to 'krfb/libvncserver/translate.c')
-rw-r--r-- | krfb/libvncserver/translate.c | 484 |
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 <mcguirk@incompleteness.net>. + * 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"); + } + } +} |