1
0
mirror of https://invent.kde.org/network/krfb synced 2024-07-08 12:05:49 +00:00
krfb/libvncserver/translate.c
George Kiagiadakis 9f56633c0b Sync with libvncserver from git (git describe version: 0.9.8-10-g17ce0c5).
My patches in this local fork have been merged upstream, but they
have been merged after 0.9.8 and 0.9.9 hasn't been released yet,
so we cannot yet switch back to finding libvncserver externally.

So I am syncing now with basically what is 0.9.8 + my patches and a few bugfixes.

svn path=/trunk/KDE/kdenetwork/krfb/; revision=1258493
2011-10-11 19:12:14 +00:00

478 lines
14 KiB
C

/*
* 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 "rfb/rfb.h"
#include "rfb/rfbregion.h"
static void PrintPixelFormat(rfbPixelFormat *pf);
static rfbBool rfbSetClientColourMapBGR233(rfbClientPtr cl);
rfbBool 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 CONCAT3(a,b,c) a##b##c
#define CONCAT3E(a,b,c) CONCAT3(a,b,c)
#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 LIBVNCSERVER_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);
static rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
rfbInitColourMapSingleTable8,
rfbInitColourMapSingleTable16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbInitColourMapSingleTable24,
#endif
rfbInitColourMapSingleTable32
};
static rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
rfbInitTrueColourSingleTable8,
rfbInitTrueColourSingleTable16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbInitTrueColourSingleTable24,
#endif
rfbInitTrueColourSingleTable32
};
static rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
rfbInitTrueColourRGBTables8,
rfbInitTrueColourRGBTables16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbInitTrueColourRGBTables24,
#endif
rfbInitTrueColourRGBTables32
};
static rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
{ rfbTranslateWithSingleTable8to8,
rfbTranslateWithSingleTable8to16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbTranslateWithSingleTable8to24,
#endif
rfbTranslateWithSingleTable8to32 },
{ rfbTranslateWithSingleTable16to8,
rfbTranslateWithSingleTable16to16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbTranslateWithSingleTable16to24,
#endif
rfbTranslateWithSingleTable16to32 },
#ifdef LIBVNCSERVER_ALLOW24BPP
{ rfbTranslateWithSingleTable24to8,
rfbTranslateWithSingleTable24to16,
rfbTranslateWithSingleTable24to24,
rfbTranslateWithSingleTable24to32 },
#endif
{ rfbTranslateWithSingleTable32to8,
rfbTranslateWithSingleTable32to16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbTranslateWithSingleTable32to24,
#endif
rfbTranslateWithSingleTable32to32 }
};
static rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
{ rfbTranslateWithRGBTables8to8,
rfbTranslateWithRGBTables8to16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbTranslateWithRGBTables8to24,
#endif
rfbTranslateWithRGBTables8to32 },
{ rfbTranslateWithRGBTables16to8,
rfbTranslateWithRGBTables16to16,
#ifdef LIBVNCSERVER_ALLOW24BPP
rfbTranslateWithRGBTables16to24,
#endif
rfbTranslateWithRGBTables16to32 },
#ifdef LIBVNCSERVER_ALLOW24BPP
{ rfbTranslateWithRGBTables24to8,
rfbTranslateWithRGBTables24to16,
rfbTranslateWithRGBTables24to24,
rfbTranslateWithRGBTables24to32 },
#endif
{ rfbTranslateWithRGBTables32to8,
rfbTranslateWithRGBTables32to16,
#ifdef LIBVNCSERVER_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.
*/
rfbBool
rfbSetTranslateFunction(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->serverFormat.bitsPerPixel != 8) &&
(cl->screen->serverFormat.bitsPerPixel != 16) &&
#ifdef LIBVNCSERVER_ALLOW24BPP
(cl->screen->serverFormat.bitsPerPixel != 24) &&
#endif
(cl->screen->serverFormat.bitsPerPixel != 32))
{
rfbErr("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
"rfbSetTranslateFunction",
cl->screen->serverFormat.bitsPerPixel);
rfbCloseClient(cl);
return FALSE;
}
if ((cl->format.bitsPerPixel != 8) &&
(cl->format.bitsPerPixel != 16) &&
#ifdef LIBVNCSERVER_ALLOW24BPP
(cl->format.bitsPerPixel != 24) &&
#endif
(cl->format.bitsPerPixel != 32))
{
rfbErr("%s: client bits per pixel not 8, 16 or 32\n",
"rfbSetTranslateFunction");
rfbCloseClient(cl);
return FALSE;
}
if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
rfbErr("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->serverFormat)) {
/* client & server the same */
rfbLog("no translation needed\n");
cl->translateFn = rfbTranslateNone;
return TRUE;
}
if ((cl->screen->serverFormat.bitsPerPixel < 16) ||
((!cl->screen->serverFormat.trueColour || !rfbEconomicTranslate) &&
(cl->screen->serverFormat.bitsPerPixel == 16))) {
/* we can use a single lookup table for <= 16 bpp */
cl->translateFn = rfbTranslateWithSingleTableFns
[BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
[BPP2OFFSET(cl->format.bitsPerPixel)];
if(cl->screen->serverFormat.trueColour)
(*rfbInitTrueColourSingleTableFns
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->serverFormat), &cl->format);
else
(*rfbInitColourMapSingleTableFns
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->serverFormat), &cl->format,&cl->screen->colourMap);
} else {
/* otherwise we use three separate tables for red, green and blue */
cl->translateFn = rfbTranslateWithRGBTablesFns
[BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
[BPP2OFFSET(cl->format.bitsPerPixel)];
(*rfbInitTrueColourRGBTablesFns
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&(cl->screen->serverFormat), &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 rfbBool
rfbSetClientColourMapBGR233(rfbClientPtr cl)
{
char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
uint16_t *rgb = (uint16_t *)(&buf[sz_rfbSetColourMapEntriesMsg]);
int i, len;
int r, g, b;
if (cl->format.bitsPerPixel != 8 ) {
rfbErr("%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 (rfbWriteExact(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.
*/
rfbBool
rfbSetClientColourMap(rfbClientPtr cl, int firstColour, int nColours)
{
if (cl->screen->serverFormat.trueColour || !cl->readyForSetColourMapEntries) {
return TRUE;
}
if (nColours == 0) {
nColours = cl->screen->colourMap.count;
}
if (cl->format.trueColour) {
LOCK(cl->updateMutex);
(*rfbInitColourMapSingleTableFns
[BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
&cl->screen->serverFormat, &cl->format,&cl->screen->colourMap);
sraRgnDestroy(cl->modifiedRegion);
cl->modifiedRegion =
sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
UNLOCK(cl->updateMutex);
return TRUE;
}
return rfbSendSetColourMapEntries(cl, firstColour, nColours);
}
/*
* rfbSetClientColourMaps sets the colour map for each RFB client.
*/
void
rfbSetClientColourMaps(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(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");
}
}
}