/apps/desktop/libvncserver/translate.c

http://ftk.googlecode.com/ · C · 475 lines · 335 code · 75 blank · 65 comment · 62 complexity · aa05984a3710235814f2f4a1bdeb65d3 MD5 · raw file

  1. /*
  2. * translate.c - translate between different pixel formats
  3. */
  4. /*
  5. * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
  6. * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
  7. * All Rights Reserved.
  8. *
  9. * This is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This software is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this software; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  22. * USA.
  23. */
  24. #include <rfb/rfb.h>
  25. #include <rfb/rfbregion.h>
  26. static void PrintPixelFormat(rfbPixelFormat *pf);
  27. static rfbBool rfbSetClientColourMapBGR233(rfbClientPtr cl);
  28. rfbBool rfbEconomicTranslate = FALSE;
  29. /*
  30. * Some standard pixel formats.
  31. */
  32. static const rfbPixelFormat BGR233Format = {
  33. 8, 8, 0, 1, 7, 7, 3, 0, 3, 6, 0, 0
  34. };
  35. /*
  36. * Macro to compare pixel formats.
  37. */
  38. #define PF_EQ(x,y) \
  39. ((x.bitsPerPixel == y.bitsPerPixel) && \
  40. (x.depth == y.depth) && \
  41. ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
  42. (x.trueColour == y.trueColour) && \
  43. (!x.trueColour || ((x.redMax == y.redMax) && \
  44. (x.greenMax == y.greenMax) && \
  45. (x.blueMax == y.blueMax) && \
  46. (x.redShift == y.redShift) && \
  47. (x.greenShift == y.greenShift) && \
  48. (x.blueShift == y.blueShift))))
  49. #define CONCAT2(a,b) a##b
  50. #define CONCAT2E(a,b) CONCAT2(a,b)
  51. #define CONCAT3(a,b,c) a##b##c
  52. #define CONCAT3E(a,b,c) CONCAT3(a,b,c)
  53. #define CONCAT4(a,b,c,d) a##b##c##d
  54. #define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
  55. #undef OUT
  56. #undef IN
  57. #define OUT 8
  58. #include "tableinitcmtemplate.c"
  59. #include "tableinittctemplate.c"
  60. #define IN 8
  61. #include "tabletranstemplate.c"
  62. #undef IN
  63. #define IN 16
  64. #include "tabletranstemplate.c"
  65. #undef IN
  66. #define IN 32
  67. #include "tabletranstemplate.c"
  68. #undef IN
  69. #undef OUT
  70. #define OUT 16
  71. #include "tableinitcmtemplate.c"
  72. #include "tableinittctemplate.c"
  73. #define IN 8
  74. #include "tabletranstemplate.c"
  75. #undef IN
  76. #define IN 16
  77. #include "tabletranstemplate.c"
  78. #undef IN
  79. #define IN 32
  80. #include "tabletranstemplate.c"
  81. #undef IN
  82. #undef OUT
  83. #define OUT 32
  84. #include "tableinitcmtemplate.c"
  85. #include "tableinittctemplate.c"
  86. #define IN 8
  87. #include "tabletranstemplate.c"
  88. #undef IN
  89. #define IN 16
  90. #include "tabletranstemplate.c"
  91. #undef IN
  92. #define IN 32
  93. #include "tabletranstemplate.c"
  94. #undef IN
  95. #undef OUT
  96. #ifdef LIBVNCSERVER_ALLOW24BPP
  97. #define COUNT_OFFSETS 4
  98. #define BPP2OFFSET(bpp) ((bpp)/8-1)
  99. #include "tableinit24.c"
  100. #define BPP 8
  101. #include "tabletrans24template.c"
  102. #undef BPP
  103. #define BPP 16
  104. #include "tabletrans24template.c"
  105. #undef BPP
  106. #define BPP 24
  107. #include "tabletrans24template.c"
  108. #undef BPP
  109. #define BPP 32
  110. #include "tabletrans24template.c"
  111. #undef BPP
  112. #else
  113. #define COUNT_OFFSETS 3
  114. #define BPP2OFFSET(bpp) ((int)(bpp)/16)
  115. #endif
  116. typedef void (*rfbInitCMTableFnType)(char **table, rfbPixelFormat *in,
  117. rfbPixelFormat *out,rfbColourMap* cm);
  118. typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
  119. rfbPixelFormat *out);
  120. static rfbInitCMTableFnType rfbInitColourMapSingleTableFns[COUNT_OFFSETS] = {
  121. rfbInitColourMapSingleTable8,
  122. rfbInitColourMapSingleTable16,
  123. #ifdef LIBVNCSERVER_ALLOW24BPP
  124. rfbInitColourMapSingleTable24,
  125. #endif
  126. rfbInitColourMapSingleTable32
  127. };
  128. static rfbInitTableFnType rfbInitTrueColourSingleTableFns[COUNT_OFFSETS] = {
  129. rfbInitTrueColourSingleTable8,
  130. rfbInitTrueColourSingleTable16,
  131. #ifdef LIBVNCSERVER_ALLOW24BPP
  132. rfbInitTrueColourSingleTable24,
  133. #endif
  134. rfbInitTrueColourSingleTable32
  135. };
  136. static rfbInitTableFnType rfbInitTrueColourRGBTablesFns[COUNT_OFFSETS] = {
  137. rfbInitTrueColourRGBTables8,
  138. rfbInitTrueColourRGBTables16,
  139. #ifdef LIBVNCSERVER_ALLOW24BPP
  140. rfbInitTrueColourRGBTables24,
  141. #endif
  142. rfbInitTrueColourRGBTables32
  143. };
  144. static rfbTranslateFnType rfbTranslateWithSingleTableFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
  145. { rfbTranslateWithSingleTable8to8,
  146. rfbTranslateWithSingleTable8to16,
  147. #ifdef LIBVNCSERVER_ALLOW24BPP
  148. rfbTranslateWithSingleTable8to24,
  149. #endif
  150. rfbTranslateWithSingleTable8to32 },
  151. { rfbTranslateWithSingleTable16to8,
  152. rfbTranslateWithSingleTable16to16,
  153. #ifdef LIBVNCSERVER_ALLOW24BPP
  154. rfbTranslateWithSingleTable16to24,
  155. #endif
  156. rfbTranslateWithSingleTable16to32 },
  157. #ifdef LIBVNCSERVER_ALLOW24BPP
  158. { rfbTranslateWithSingleTable24to8,
  159. rfbTranslateWithSingleTable24to16,
  160. rfbTranslateWithSingleTable24to24,
  161. rfbTranslateWithSingleTable24to32 },
  162. #endif
  163. { rfbTranslateWithSingleTable32to8,
  164. rfbTranslateWithSingleTable32to16,
  165. #ifdef LIBVNCSERVER_ALLOW24BPP
  166. rfbTranslateWithSingleTable32to24,
  167. #endif
  168. rfbTranslateWithSingleTable32to32 }
  169. };
  170. static rfbTranslateFnType rfbTranslateWithRGBTablesFns[COUNT_OFFSETS][COUNT_OFFSETS] = {
  171. { rfbTranslateWithRGBTables8to8,
  172. rfbTranslateWithRGBTables8to16,
  173. #ifdef LIBVNCSERVER_ALLOW24BPP
  174. rfbTranslateWithRGBTables8to24,
  175. #endif
  176. rfbTranslateWithRGBTables8to32 },
  177. { rfbTranslateWithRGBTables16to8,
  178. rfbTranslateWithRGBTables16to16,
  179. #ifdef LIBVNCSERVER_ALLOW24BPP
  180. rfbTranslateWithRGBTables16to24,
  181. #endif
  182. rfbTranslateWithRGBTables16to32 },
  183. #ifdef LIBVNCSERVER_ALLOW24BPP
  184. { rfbTranslateWithRGBTables24to8,
  185. rfbTranslateWithRGBTables24to16,
  186. rfbTranslateWithRGBTables24to24,
  187. rfbTranslateWithRGBTables24to32 },
  188. #endif
  189. { rfbTranslateWithRGBTables32to8,
  190. rfbTranslateWithRGBTables32to16,
  191. #ifdef LIBVNCSERVER_ALLOW24BPP
  192. rfbTranslateWithRGBTables32to24,
  193. #endif
  194. rfbTranslateWithRGBTables32to32 }
  195. };
  196. /*
  197. * rfbTranslateNone is used when no translation is required.
  198. */
  199. void
  200. rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
  201. char *iptr, char *optr, int bytesBetweenInputLines,
  202. int width, int height)
  203. {
  204. int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
  205. while (height > 0) {
  206. memcpy(optr, iptr, bytesPerOutputLine);
  207. iptr += bytesBetweenInputLines;
  208. optr += bytesPerOutputLine;
  209. height--;
  210. }
  211. }
  212. /*
  213. * rfbSetTranslateFunction sets the translation function.
  214. */
  215. rfbBool
  216. rfbSetTranslateFunction(rfbClientPtr cl)
  217. {
  218. rfbLog("Pixel format for client %s:\n",cl->host);
  219. PrintPixelFormat(&cl->format);
  220. /*
  221. * Check that bits per pixel values are valid
  222. */
  223. if ((cl->screen->serverFormat.bitsPerPixel != 8) &&
  224. (cl->screen->serverFormat.bitsPerPixel != 16) &&
  225. #ifdef LIBVNCSERVER_ALLOW24BPP
  226. (cl->screen->serverFormat.bitsPerPixel != 24) &&
  227. #endif
  228. (cl->screen->serverFormat.bitsPerPixel != 32))
  229. {
  230. rfbErr("%s: server bits per pixel not 8, 16 or 32 (is %d)\n",
  231. "rfbSetTranslateFunction",
  232. cl->screen->serverFormat.bitsPerPixel);
  233. rfbCloseClient(cl);
  234. return FALSE;
  235. }
  236. if ((cl->format.bitsPerPixel != 8) &&
  237. (cl->format.bitsPerPixel != 16) &&
  238. #ifdef LIBVNCSERVER_ALLOW24BPP
  239. (cl->format.bitsPerPixel != 24) &&
  240. #endif
  241. (cl->format.bitsPerPixel != 32))
  242. {
  243. rfbErr("%s: client bits per pixel not 8, 16 or 32\n",
  244. "rfbSetTranslateFunction");
  245. rfbCloseClient(cl);
  246. return FALSE;
  247. }
  248. if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
  249. rfbErr("rfbSetTranslateFunction: client has colour map "
  250. "but %d-bit - can only cope with 8-bit colour maps\n",
  251. cl->format.bitsPerPixel);
  252. rfbCloseClient(cl);
  253. return FALSE;
  254. }
  255. /*
  256. * bpp is valid, now work out how to translate
  257. */
  258. if (!cl->format.trueColour) {
  259. /*
  260. * truecolour -> colour map
  261. *
  262. * Set client's colour map to BGR233, then effectively it's
  263. * truecolour as well
  264. */
  265. if (!rfbSetClientColourMapBGR233(cl))
  266. return FALSE;
  267. cl->format = BGR233Format;
  268. }
  269. /* truecolour -> truecolour */
  270. if (PF_EQ(cl->format,cl->screen->serverFormat)) {
  271. /* client & server the same */
  272. rfbLog("no translation needed\n");
  273. cl->translateFn = rfbTranslateNone;
  274. return TRUE;
  275. }
  276. if ((cl->screen->serverFormat.bitsPerPixel < 16) ||
  277. ((!cl->screen->serverFormat.trueColour || !rfbEconomicTranslate) &&
  278. (cl->screen->serverFormat.bitsPerPixel == 16))) {
  279. /* we can use a single lookup table for <= 16 bpp */
  280. cl->translateFn = rfbTranslateWithSingleTableFns
  281. [BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
  282. [BPP2OFFSET(cl->format.bitsPerPixel)];
  283. if(cl->screen->serverFormat.trueColour)
  284. (*rfbInitTrueColourSingleTableFns
  285. [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
  286. &(cl->screen->serverFormat), &cl->format);
  287. else
  288. (*rfbInitColourMapSingleTableFns
  289. [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
  290. &(cl->screen->serverFormat), &cl->format,&cl->screen->colourMap);
  291. } else {
  292. /* otherwise we use three separate tables for red, green and blue */
  293. cl->translateFn = rfbTranslateWithRGBTablesFns
  294. [BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)]
  295. [BPP2OFFSET(cl->format.bitsPerPixel)];
  296. (*rfbInitTrueColourRGBTablesFns
  297. [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
  298. &(cl->screen->serverFormat), &cl->format);
  299. }
  300. return TRUE;
  301. }
  302. /*
  303. * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
  304. * just like an 8-bit BGR233 true colour client.
  305. */
  306. static rfbBool
  307. rfbSetClientColourMapBGR233(rfbClientPtr cl)
  308. {
  309. char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
  310. rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
  311. uint16_t *rgb = (uint16_t *)(&buf[sz_rfbSetColourMapEntriesMsg]);
  312. int i, len;
  313. int r, g, b;
  314. if (cl->format.bitsPerPixel != 8 ) {
  315. rfbErr("%s: client not 8 bits per pixel\n",
  316. "rfbSetClientColourMapBGR233");
  317. rfbCloseClient(cl);
  318. return FALSE;
  319. }
  320. scme->type = rfbSetColourMapEntries;
  321. scme->firstColour = Swap16IfLE(0);
  322. scme->nColours = Swap16IfLE(256);
  323. len = sz_rfbSetColourMapEntriesMsg;
  324. i = 0;
  325. for (b = 0; b < 4; b++) {
  326. for (g = 0; g < 8; g++) {
  327. for (r = 0; r < 8; r++) {
  328. rgb[i++] = Swap16IfLE(r * 65535 / 7);
  329. rgb[i++] = Swap16IfLE(g * 65535 / 7);
  330. rgb[i++] = Swap16IfLE(b * 65535 / 3);
  331. }
  332. }
  333. }
  334. len += 256 * 3 * 2;
  335. if (rfbWriteExact(cl, buf, len) < 0) {
  336. rfbLogPerror("rfbSetClientColourMapBGR233: write");
  337. rfbCloseClient(cl);
  338. return FALSE;
  339. }
  340. return TRUE;
  341. }
  342. /* this function is not called very often, so it needn't be
  343. efficient. */
  344. /*
  345. * rfbSetClientColourMap is called to set the client's colour map. If the
  346. * client is a true colour client, we simply update our own translation table
  347. * and mark the whole screen as having been modified.
  348. */
  349. rfbBool
  350. rfbSetClientColourMap(rfbClientPtr cl, int firstColour, int nColours)
  351. {
  352. if (cl->screen->serverFormat.trueColour || !cl->readyForSetColourMapEntries) {
  353. return TRUE;
  354. }
  355. if (nColours == 0) {
  356. nColours = cl->screen->colourMap.count;
  357. }
  358. if (cl->format.trueColour) {
  359. (*rfbInitColourMapSingleTableFns
  360. [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable,
  361. &cl->screen->serverFormat, &cl->format,&cl->screen->colourMap);
  362. sraRgnDestroy(cl->modifiedRegion);
  363. cl->modifiedRegion =
  364. sraRgnCreateRect(0,0,cl->screen->width,cl->screen->height);
  365. return TRUE;
  366. }
  367. return rfbSendSetColourMapEntries(cl, firstColour, nColours);
  368. }
  369. /*
  370. * rfbSetClientColourMaps sets the colour map for each RFB client.
  371. */
  372. void
  373. rfbSetClientColourMaps(rfbScreenInfoPtr rfbScreen, int firstColour, int nColours)
  374. {
  375. rfbClientIteratorPtr i;
  376. rfbClientPtr cl;
  377. i = rfbGetClientIterator(rfbScreen);
  378. while((cl = rfbClientIteratorNext(i)))
  379. rfbSetClientColourMap(cl, firstColour, nColours);
  380. rfbReleaseClientIterator(i);
  381. }
  382. static void
  383. PrintPixelFormat(rfbPixelFormat *pf)
  384. {
  385. if (pf->bitsPerPixel == 1) {
  386. rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
  387. (pf->bigEndian ? "most" : "least"));
  388. } else {
  389. rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
  390. ((pf->bitsPerPixel == 8) ? ""
  391. : (pf->bigEndian ? ", big endian" : ", little endian")));
  392. if (pf->trueColour) {
  393. rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
  394. pf->redMax, pf->greenMax, pf->blueMax,
  395. pf->redShift, pf->greenShift, pf->blueShift);
  396. } else {
  397. rfbLog(" uses a colour map (not true colour).\n");
  398. }
  399. }
  400. }