PageRenderTime 28ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/mupdf/apps/x11_image.c

https://code.google.com/
C | 703 lines | 591 code | 84 blank | 28 comment | 130 complexity | ac63792e23fbdd6d4889cd87361f7026 MD5 | raw file
Possible License(s): BSD-2-Clause, GPL-3.0, BSD-3-Clause
  1. /*
  2. * Blit RGBA images to X with X(Shm)Images
  3. */
  4. #ifndef _XOPEN_SOURCE
  5. # define _XOPEN_SOURCE 1
  6. #endif
  7. #ifndef _XOPEN_SOURCE
  8. # define _XOPEN_SOURCE 1
  9. #endif
  10. #define noSHOWINFO
  11. #include "fitz.h"
  12. #include <X11/Xlib.h>
  13. #include <X11/Xutil.h>
  14. #include <sys/ipc.h>
  15. #include <sys/shm.h>
  16. #include <X11/extensions/XShm.h>
  17. extern int ffs(int);
  18. static int is_big_endian(void)
  19. {
  20. static const int one = 1;
  21. return *(char*)&one == 0;
  22. }
  23. typedef void (*ximage_convert_func_t)
  24. (
  25. const unsigned char *src,
  26. int srcstride,
  27. unsigned char *dst,
  28. int dststride,
  29. int w,
  30. int h
  31. );
  32. #define POOLSIZE 4
  33. #define WIDTH 256
  34. #define HEIGHT 256
  35. enum {
  36. ARGB8888,
  37. BGRA8888,
  38. RGBA8888,
  39. ABGR8888,
  40. RGB888,
  41. BGR888,
  42. RGB565,
  43. RGB565_BR,
  44. RGB555,
  45. RGB555_BR,
  46. BGR233,
  47. UNKNOWN
  48. };
  49. #ifdef SHOWINFO
  50. static char *modename[] = {
  51. "ARGB8888",
  52. "BGRA8888",
  53. "RGBA8888",
  54. "ABGR8888",
  55. "RGB888",
  56. "BGR888",
  57. "RGB565",
  58. "RGB565_BR",
  59. "RGB555",
  60. "RGB555_BR",
  61. "BGR233",
  62. "UNKNOWN"
  63. };
  64. #endif
  65. extern ximage_convert_func_t ximage_convert_funcs[];
  66. static struct
  67. {
  68. Display *display;
  69. int screen;
  70. XVisualInfo visual;
  71. Colormap colormap;
  72. int bitsperpixel;
  73. int mode;
  74. XColor rgbcube[256];
  75. ximage_convert_func_t convert_func;
  76. int useshm;
  77. int shmcode;
  78. XImage *pool[POOLSIZE];
  79. /* MUST exist during the lifetime of the shared ximage according to the
  80. xc/doc/hardcopy/Xext/mit-shm.PS.gz */
  81. XShmSegmentInfo shminfo[POOLSIZE];
  82. int lastused;
  83. } info;
  84. static XImage *
  85. createximage(Display *dpy, Visual *vis, XShmSegmentInfo *xsi, int depth, int w, int h)
  86. {
  87. XImage *img;
  88. Status status;
  89. if (!XShmQueryExtension(dpy))
  90. goto fallback;
  91. if (!info.useshm)
  92. goto fallback;
  93. img = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, xsi, w, h);
  94. if (!img)
  95. {
  96. fprintf(stderr, "warn: could not XShmCreateImage\n");
  97. goto fallback;
  98. }
  99. xsi->shmid = shmget(IPC_PRIVATE,
  100. img->bytes_per_line * img->height,
  101. IPC_CREAT | 0777);
  102. if (xsi->shmid < 0)
  103. {
  104. XDestroyImage(img);
  105. fprintf(stderr, "warn: could not shmget\n");
  106. goto fallback;
  107. }
  108. img->data = xsi->shmaddr = shmat(xsi->shmid, NULL, 0);
  109. if (img->data == (char*)-1)
  110. {
  111. XDestroyImage(img);
  112. fprintf(stderr, "warn: could not shmat\n");
  113. goto fallback;
  114. }
  115. xsi->readOnly = False;
  116. status = XShmAttach(dpy, xsi);
  117. if (!status)
  118. {
  119. shmdt(xsi->shmaddr);
  120. XDestroyImage(img);
  121. fprintf(stderr, "warn: could not XShmAttach\n");
  122. goto fallback;
  123. }
  124. XSync(dpy, False);
  125. shmctl(xsi->shmid, IPC_RMID, NULL);
  126. return img;
  127. fallback:
  128. info.useshm = 0;
  129. img = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0);
  130. if (!img)
  131. {
  132. fprintf(stderr, "fail: could not XCreateImage");
  133. abort();
  134. }
  135. img->data = malloc(h * img->bytes_per_line);
  136. if (!img->data)
  137. {
  138. fprintf(stderr, "fail: could not malloc");
  139. abort();
  140. }
  141. return img;
  142. }
  143. static void
  144. make_colormap(void)
  145. {
  146. if (info.visual.class == PseudoColor && info.visual.depth == 8)
  147. {
  148. int i, r, g, b;
  149. i = 0;
  150. for (b = 0; b < 4; b++) {
  151. for (g = 0; g < 8; g++) {
  152. for (r = 0; r < 8; r++) {
  153. info.rgbcube[i].pixel = i;
  154. info.rgbcube[i].red = (r * 36) << 8;
  155. info.rgbcube[i].green = (g * 36) << 8;
  156. info.rgbcube[i].blue = (b * 85) << 8;
  157. info.rgbcube[i].flags =
  158. DoRed | DoGreen | DoBlue;
  159. i++;
  160. }
  161. }
  162. }
  163. info.colormap = XCreateColormap(info.display,
  164. RootWindow(info.display, info.screen),
  165. info.visual.visual,
  166. AllocAll);
  167. XStoreColors(info.display, info.colormap, info.rgbcube, 256);
  168. return;
  169. }
  170. else if (info.visual.class == TrueColor)
  171. {
  172. info.colormap = 0;
  173. return;
  174. }
  175. fprintf(stderr, "Cannot handle visual class %d with depth: %d\n",
  176. info.visual.class, info.visual.depth);
  177. return;
  178. }
  179. static void
  180. select_mode(void)
  181. {
  182. int byteorder;
  183. int byterev;
  184. unsigned long rm, gm, bm;
  185. unsigned long rs, gs, bs;
  186. byteorder = ImageByteOrder(info.display);
  187. if (is_big_endian())
  188. byterev = byteorder != MSBFirst;
  189. else
  190. byterev = byteorder != LSBFirst;
  191. rm = info.visual.red_mask;
  192. gm = info.visual.green_mask;
  193. bm = info.visual.blue_mask;
  194. rs = ffs(rm) - 1;
  195. gs = ffs(gm) - 1;
  196. bs = ffs(bm) - 1;
  197. #ifdef SHOWINFO
  198. printf("ximage: mode %d/%d %08lx %08lx %08lx (%ld,%ld,%ld) %s%s\n",
  199. info.visual.depth,
  200. info.bitsperpixel,
  201. rm, gm, bm, rs, gs, bs,
  202. byteorder == MSBFirst ? "msb" : "lsb",
  203. byterev ? " <swap>":"");
  204. #endif
  205. info.mode = UNKNOWN;
  206. if (info.bitsperpixel == 8) {
  207. /* Either PseudoColor with BGR233 colormap, or TrueColor */
  208. info.mode = BGR233;
  209. }
  210. else if (info.bitsperpixel == 16) {
  211. if (rm == 0xF800 && gm == 0x07E0 && bm == 0x001F)
  212. info.mode = !byterev ? RGB565 : RGB565_BR;
  213. if (rm == 0x7C00 && gm == 0x03E0 && bm == 0x001F)
  214. info.mode = !byterev ? RGB555 : RGB555_BR;
  215. }
  216. else if (info.bitsperpixel == 24) {
  217. if (rs == 0 && gs == 8 && bs == 16)
  218. info.mode = byteorder == MSBFirst ? RGB888 : BGR888;
  219. if (rs == 16 && gs == 8 && bs == 0)
  220. info.mode = byteorder == MSBFirst ? BGR888 : RGB888;
  221. }
  222. else if (info.bitsperpixel == 32) {
  223. if (rs == 0 && gs == 8 && bs == 16)
  224. info.mode = byteorder == MSBFirst ? ABGR8888 : RGBA8888;
  225. if (rs == 8 && gs == 16 && bs == 24)
  226. info.mode = byteorder == MSBFirst ? BGRA8888 : ARGB8888;
  227. if (rs == 16 && gs == 8 && bs == 0)
  228. info.mode = byteorder == MSBFirst ? ARGB8888 : BGRA8888;
  229. if (rs == 24 && gs == 16 && bs == 8)
  230. info.mode = byteorder == MSBFirst ? RGBA8888 : ABGR8888;
  231. }
  232. #ifdef SHOWINFO
  233. printf("ximage: RGBA8888 to %s\n", modename[info.mode]);
  234. #endif
  235. /* select conversion function */
  236. info.convert_func = ximage_convert_funcs[info.mode];
  237. }
  238. static int
  239. create_pool(void)
  240. {
  241. int i;
  242. info.lastused = 0;
  243. for (i = 0; i < POOLSIZE; i++) {
  244. info.pool[i] = NULL;
  245. }
  246. for (i = 0; i < POOLSIZE; i++) {
  247. info.pool[i] = createximage(info.display,
  248. info.visual.visual, &info.shminfo[i], info.visual.depth,
  249. WIDTH, HEIGHT);
  250. if (!info.pool[i]) {
  251. return 0;
  252. }
  253. }
  254. return 1;
  255. }
  256. static XImage *
  257. next_pool_image(void)
  258. {
  259. if (info.lastused + 1 >= POOLSIZE) {
  260. if (info.useshm)
  261. XSync(info.display, False);
  262. else
  263. XFlush(info.display);
  264. info.lastused = 0;
  265. }
  266. return info.pool[info.lastused ++];
  267. }
  268. static int
  269. ximage_error_handler(Display *display, XErrorEvent *event)
  270. {
  271. /* Turn off shared memory images if we get an error from the MIT-SHM extension */
  272. if (event->request_code == info.shmcode)
  273. {
  274. char buf[80];
  275. XGetErrorText(display, event->error_code, buf, sizeof buf);
  276. fprintf(stderr, "ximage: disabling shared memory extension: %s\n", buf);
  277. info.useshm = 0;
  278. return 0;
  279. }
  280. XSetErrorHandler(NULL);
  281. return (XSetErrorHandler(ximage_error_handler))(display, event);
  282. }
  283. int
  284. ximage_init(Display *display, int screen, Visual *visual)
  285. {
  286. XVisualInfo template;
  287. XVisualInfo *visuals;
  288. int nvisuals;
  289. XPixmapFormatValues *formats;
  290. int nformats;
  291. int ok;
  292. int i;
  293. int major;
  294. int event;
  295. int error;
  296. info.display = display;
  297. info.screen = screen;
  298. info.colormap = 0;
  299. /* Get XVisualInfo for this visual */
  300. template.visualid = XVisualIDFromVisual(visual);
  301. visuals = XGetVisualInfo(display, VisualIDMask, &template, &nvisuals);
  302. if (nvisuals != 1) {
  303. fprintf(stderr, "Visual not found!\n");
  304. XFree(visuals);
  305. return 0;
  306. }
  307. memcpy(&info.visual, visuals, sizeof (XVisualInfo));
  308. XFree(visuals);
  309. /* Get appropriate PixmapFormat for this visual */
  310. formats = XListPixmapFormats(info.display, &nformats);
  311. for (i = 0; i < nformats; i++) {
  312. if (formats[i].depth == info.visual.depth) {
  313. info.bitsperpixel = formats[i].bits_per_pixel;
  314. break;
  315. }
  316. }
  317. XFree(formats);
  318. if (i == nformats) {
  319. fprintf(stderr, "PixmapFormat not found!\n");
  320. return 0;
  321. }
  322. /* extract mode */
  323. select_mode();
  324. /* prepare colormap */
  325. make_colormap();
  326. /* identify code for MIT-SHM extension */
  327. if (XQueryExtension(display, "MIT-SHM", &major, &event, &error) &&
  328. XShmQueryExtension(display))
  329. info.shmcode = major;
  330. /* intercept errors looking for SHM code */
  331. XSetErrorHandler(ximage_error_handler);
  332. /* prepare pool of XImages */
  333. info.useshm = 1;
  334. ok = create_pool();
  335. if (!ok)
  336. return 0;
  337. #ifdef SHOWINFO
  338. printf("ximage: %sPutImage\n", info.useshm ? "XShm" : "X");
  339. #endif
  340. return 1;
  341. }
  342. int
  343. ximage_get_depth(void)
  344. {
  345. return info.visual.depth;
  346. }
  347. Visual *
  348. ximage_get_visual(void)
  349. {
  350. return info.visual.visual;
  351. }
  352. Colormap
  353. ximage_get_colormap(void)
  354. {
  355. return info.colormap;
  356. }
  357. void
  358. ximage_blit(Drawable d, GC gc,
  359. int dstx, int dsty,
  360. unsigned char *srcdata,
  361. int srcx, int srcy,
  362. int srcw, int srch,
  363. int srcstride)
  364. {
  365. XImage *image;
  366. int ax, ay;
  367. int w, h;
  368. unsigned char *srcptr;
  369. for (ay = 0; ay < srch; ay += HEIGHT)
  370. {
  371. h = MIN(srch - ay, HEIGHT);
  372. for (ax = 0; ax < srcw; ax += WIDTH)
  373. {
  374. w = MIN(srcw - ax, WIDTH);
  375. image = next_pool_image();
  376. srcptr = srcdata +
  377. (ay + srcy) * srcstride +
  378. (ax + srcx) * 4;
  379. info.convert_func(srcptr, srcstride,
  380. (unsigned char *) image->data,
  381. image->bytes_per_line, w, h);
  382. if (info.useshm)
  383. {
  384. XShmPutImage(info.display, d, gc, image,
  385. 0, 0, dstx + ax, dsty + ay,
  386. w, h, False);
  387. }
  388. else
  389. {
  390. XPutImage(info.display, d, gc, image,
  391. 0, 0,
  392. dstx + ax,
  393. dsty + ay,
  394. w, h);
  395. }
  396. }
  397. }
  398. }
  399. /*
  400. * Primitive conversion functions
  401. */
  402. #ifndef restrict
  403. #ifndef _C99
  404. #ifdef __GNUC__
  405. #define restrict __restrict__
  406. #else
  407. #define restrict
  408. #endif
  409. #endif
  410. #endif
  411. #define PARAMS \
  412. const unsigned char * restrict src, \
  413. int srcstride, \
  414. unsigned char * restrict dst, \
  415. int dststride, \
  416. int w, \
  417. int h
  418. /*
  419. * Convert byte:RGBA8888 to various formats
  420. */
  421. static void
  422. ximage_convert_argb8888(PARAMS)
  423. {
  424. int x, y;
  425. for (y = 0; y < h; y++) {
  426. for (x = 0; x < w; x ++) {
  427. dst[x * 4 + 0] = src[x * 4 + 3]; /* a */
  428. dst[x * 4 + 1] = src[x * 4 + 0]; /* r */
  429. dst[x * 4 + 2] = src[x * 4 + 1]; /* g */
  430. dst[x * 4 + 3] = src[x * 4 + 2]; /* b */
  431. }
  432. dst += dststride;
  433. src += srcstride;
  434. }
  435. }
  436. static void
  437. ximage_convert_bgra8888(PARAMS)
  438. {
  439. int x, y;
  440. for (y = 0; y < h; y++) {
  441. for (x = 0; x < w; x++) {
  442. dst[x * 4 + 0] = src[x * 4 + 2];
  443. dst[x * 4 + 1] = src[x * 4 + 1];
  444. dst[x * 4 + 2] = src[x * 4 + 0];
  445. dst[x * 4 + 3] = src[x * 4 + 3];
  446. }
  447. dst += dststride;
  448. src += srcstride;
  449. }
  450. }
  451. static void
  452. ximage_convert_abgr8888(PARAMS)
  453. {
  454. int x, y;
  455. for (y = 0; y < h; y++) {
  456. for (x = 0; x < w; x++) {
  457. dst[x * 4 + 0] = src[x * 4 + 3];
  458. dst[x * 4 + 1] = src[x * 4 + 2];
  459. dst[x * 4 + 2] = src[x * 4 + 1];
  460. dst[x * 4 + 3] = src[x * 4 + 0];
  461. }
  462. dst += dststride;
  463. src += srcstride;
  464. }
  465. }
  466. static void
  467. ximage_convert_rgba8888(PARAMS)
  468. {
  469. int x, y;
  470. for (y = 0; y < h; y++) {
  471. for (x = 0; x < w; x++) {
  472. dst[x] = src[x];
  473. }
  474. dst += dststride;
  475. src += srcstride;
  476. }
  477. }
  478. static void
  479. ximage_convert_bgr888(PARAMS)
  480. {
  481. int x, y;
  482. for (y = 0; y < h; y++) {
  483. for (x = 0; x < w; x++) {
  484. dst[3*x + 0] = src[4*x + 2];
  485. dst[3*x + 1] = src[4*x + 1];
  486. dst[3*x + 2] = src[4*x + 0];
  487. }
  488. src += srcstride;
  489. dst += dststride;
  490. }
  491. }
  492. static void
  493. ximage_convert_rgb888(PARAMS)
  494. {
  495. int x, y;
  496. for (y = 0; y < h; y++) {
  497. for (x = 0; x < w; x++) {
  498. dst[3*x + 0] = src[4*x + 0];
  499. dst[3*x + 1] = src[4*x + 1];
  500. dst[3*x + 2] = src[4*x + 2];
  501. }
  502. src += srcstride;
  503. dst += dststride;
  504. }
  505. }
  506. static void
  507. ximage_convert_rgb565(PARAMS)
  508. {
  509. unsigned char r, g, b;
  510. int x, y;
  511. for (y = 0; y < h; y++) {
  512. for (x = 0; x < w; x++) {
  513. r = src[4*x + 0];
  514. g = src[4*x + 1];
  515. b = src[4*x + 2];
  516. ((unsigned short *)dst)[x] =
  517. ((r & 0xF8) << 8) |
  518. ((g & 0xFC) << 3) |
  519. (b >> 3);
  520. }
  521. src += srcstride;
  522. dst += dststride;
  523. }
  524. }
  525. static void
  526. ximage_convert_rgb565_br(PARAMS)
  527. {
  528. unsigned char r, g, b;
  529. int x, y;
  530. for (y = 0; y < h; y++) {
  531. for (x = 0; x < w; x++) {
  532. r = src[4*x + 0];
  533. g = src[4*x + 1];
  534. b = src[4*x + 2];
  535. /* final word is:
  536. g4 g3 g2 b7 b6 b5 b4 b3 : r7 r6 r5 r4 r3 g7 g6 g5
  537. */
  538. ((unsigned short *)dst)[x] =
  539. (r & 0xF8) |
  540. ((g & 0xE0) >> 5) |
  541. ((g & 0x1C) << 11) |
  542. ((b & 0xF8) << 5);
  543. }
  544. src += srcstride;
  545. dst += dststride;
  546. }
  547. }
  548. static void
  549. ximage_convert_rgb555(PARAMS)
  550. {
  551. unsigned char r, g, b;
  552. int x, y;
  553. for (y = 0; y < h; y++) {
  554. for (x = 0; x < w; x++) {
  555. r = src[4*x + 0];
  556. g = src[4*x + 1];
  557. b = src[4*x + 2];
  558. ((unsigned short *)dst)[x] =
  559. ((r & 0xF8) << 7) |
  560. ((g & 0xF8) << 2) |
  561. (b >> 3);
  562. }
  563. src += srcstride;
  564. dst += dststride;
  565. }
  566. }
  567. static void
  568. ximage_convert_rgb555_br(PARAMS)
  569. {
  570. unsigned char r, g, b;
  571. int x, y;
  572. for (y = 0; y < h; y++) {
  573. for (x = 0; x < w; x++) {
  574. r = src[4*x + 0];
  575. g = src[4*x + 1];
  576. b = src[4*x + 2];
  577. /* final word is:
  578. g5 g4 g3 b7 b6 b5 b4 b3 : 0 r7 r6 r5 r4 r3 g7 g6
  579. */
  580. ((unsigned short *)dst)[x] =
  581. ((r & 0xF8) >> 1) |
  582. ((g & 0xC0) >> 6) |
  583. ((g & 0x38) << 10) |
  584. ((b & 0xF8) << 5);
  585. }
  586. src += srcstride;
  587. dst += dststride;
  588. }
  589. }
  590. static void
  591. ximage_convert_bgr233(PARAMS)
  592. {
  593. unsigned char r, g, b;
  594. int x,y;
  595. for(y = 0; y < h; y++) {
  596. for(x = 0; x < w; x++) {
  597. r = src[4*x + 0];
  598. g = src[4*x + 1];
  599. b = src[4*x + 2];
  600. /* format: b7 b6 g7 g6 g5 r7 r6 r5 */
  601. dst[x] = (b&0xC0) | ((g>>2)&0x38) | ((r>>5)&0x7);
  602. }
  603. src += srcstride;
  604. dst += dststride;
  605. }
  606. }
  607. ximage_convert_func_t ximage_convert_funcs[] = {
  608. ximage_convert_argb8888,
  609. ximage_convert_bgra8888,
  610. ximage_convert_rgba8888,
  611. ximage_convert_abgr8888,
  612. ximage_convert_rgb888,
  613. ximage_convert_bgr888,
  614. ximage_convert_rgb565,
  615. ximage_convert_rgb565_br,
  616. ximage_convert_rgb555,
  617. ximage_convert_rgb555_br,
  618. ximage_convert_bgr233,
  619. };