Graph.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "cairodriver.h"
  2. #include <cairo-ps.h>
  3. #include <cairo-pdf.h>
  4. #include <cairo-svg.h>
  5. #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
  6. #include <cairo-xlib.h>
  7. #endif
  8. #include <unistd.h>
  9. #ifndef __MINGW32__
  10. #include <fcntl.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <sys/mman.h>
  14. #endif
  15. #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
  16. #include <X11/X.h>
  17. #include <X11/Xlib.h>
  18. #include <X11/Xutil.h>
  19. #endif
  20. struct cairo_state ca;
  21. /* cairo objects */
  22. cairo_surface_t *surface;
  23. cairo_t *cairo;
  24. static void init_cairo(void);
  25. static int ends_with(const char *string, const char *suffix);
  26. static void map_file(void);
  27. static void init_xlib(void)
  28. {
  29. #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
  30. Display *dpy;
  31. Drawable win;
  32. unsigned long xid;
  33. XVisualInfo templ;
  34. XVisualInfo *vinfo;
  35. int count;
  36. Window root;
  37. unsigned int depth;
  38. int si;
  39. unsigned int ui;
  40. Visual *visual;
  41. char *p;
  42. p = getenv("GRASS_CAIRO_DRAWABLE");
  43. if (!p || sscanf(p, "%li", &xid) != 1)
  44. G_fatal_error("invalid Drawable XID: %s", p);
  45. win = xid;
  46. dpy = XOpenDisplay(NULL);
  47. if (!dpy)
  48. G_fatal_error("Unable to open display");
  49. p = getenv("GRASS_CAIRO_VISUAL");
  50. if (!p || sscanf(p, "%li", &xid) != 1)
  51. G_fatal_error("invalid Visual XID: %s", p);
  52. templ.visualid = xid;
  53. vinfo = XGetVisualInfo(dpy, VisualIDMask, &templ, &count);
  54. if (!vinfo || !count)
  55. G_fatal_error("Unable to obtain visual");
  56. visual = vinfo[0].visual;
  57. if (!XGetGeometry
  58. (dpy, win, &root, &si, &si, &width, &height, &ui, &depth))
  59. G_fatal_error("Unable to query drawable");
  60. surface = cairo_xlib_surface_create(dpy, win, visual, width, height);
  61. if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
  62. G_fatal_error("Failed to initialize Xlib surface");
  63. cairo = cairo_create(surface);
  64. ca.file_name = "<X11>";
  65. file_type = FTYPE_X11;
  66. screen_right = screen_left + ca.width;
  67. screen_bottom = screen_top + ca.height;
  68. #endif
  69. }
  70. static void init_file(void)
  71. {
  72. int is_vector = 0;
  73. int do_read = 0;
  74. int do_map = 0;
  75. char *p;
  76. /* set image properties */
  77. ca.width = screen_width;
  78. ca.height = screen_height;
  79. ca.stride = ca.width * 4;
  80. /* get file name */
  81. p = getenv("GRASS_PNGFILE");
  82. if (!p || strlen(p) == 0)
  83. p = DEFAULT_FILE_NAME;
  84. ca.file_name = p;
  85. /* get file type (from extension) */
  86. if (ca.file_type == FTYPE_X11) ; /* skip */
  87. else if (ends_with(ca.file_name, ".ppm"))
  88. ca.file_type = FTYPE_PPM;
  89. else if (ends_with(ca.file_name, ".bmp"))
  90. ca.file_type = FTYPE_BMP;
  91. #if CAIRO_HAS_PNG_FUNCTIONS
  92. else if (ends_with(ca.file_name, ".png"))
  93. ca.file_type = FTYPE_PNG;
  94. #endif
  95. #if CAIRO_HAS_PDF_SURFACE
  96. else if (ends_with(ca.file_name, ".pdf"))
  97. ca.file_type = FTYPE_PDF;
  98. #endif
  99. #if CAIRO_HAS_PS_SURFACE
  100. else if (ends_with(ca.file_name, ".ps"))
  101. ca.file_type = FTYPE_PS;
  102. #endif
  103. #if CAIRO_HAS_SVG_SURFACE
  104. else if (ends_with(ca.file_name, ".svg"))
  105. ca.file_type = FTYPE_SVG;
  106. #endif
  107. else
  108. G_fatal_error("Unknown file extension: %s", p);
  109. G_debug(1, "File type: %s (%d)", ca.file_name, ca.file_type);
  110. switch (ca.file_type) {
  111. case FTYPE_PDF:
  112. case FTYPE_PS:
  113. case FTYPE_SVG:
  114. is_vector = 1;
  115. break;
  116. }
  117. p = getenv("GRASS_PNG_MAPPED");
  118. do_map = p && strcmp(p, "TRUE") == 0 && ends_with(ca.file_name, ".bmp");
  119. p = getenv("GRASS_PNG_READ");
  120. do_read = p && strcmp(p, "TRUE") == 0;
  121. if (is_vector) {
  122. do_read = do_map = 0;
  123. ca.bgcolor_a = 1.0;
  124. }
  125. if (do_read && access(ca.file_name, 0) != 0)
  126. do_read = 0;
  127. G_message
  128. ("cairo: collecting to file: %s,\n GRASS_WIDTH=%d, GRASS_HEIGHT=%d",
  129. ca.file_name, ca.width, ca.height);
  130. if (do_read && do_map)
  131. map_file();
  132. if (!ca.mapped && !is_vector)
  133. ca.grid = G_malloc(ca.height * ca.stride);
  134. init_cairo();
  135. if (!do_read && !is_vector) {
  136. Cairo_Erase();
  137. ca.modified = 1;
  138. }
  139. if (do_read && !ca.mapped)
  140. cairo_read_image();
  141. if (do_map && !ca.mapped) {
  142. cairo_write_image();
  143. map_file();
  144. init_cairo();
  145. }
  146. }
  147. int Cairo_Graph_set(void)
  148. {
  149. cairo_antialias_t antialias;
  150. char *p;
  151. G_gisinit("Cairo driver");
  152. G_debug(1, "Cairo_Graph_set");
  153. /* get background color */
  154. p = getenv("GRASS_BACKGROUNDCOLOR");
  155. if (p && *p) {
  156. unsigned int red, green, blue;
  157. if (sscanf(p, "%02x%02x%02x", &red, &green, &blue) == 3) {
  158. ca.bgcolor_r = CAIROCOLOR(red);
  159. ca.bgcolor_g = CAIROCOLOR(green);
  160. ca.bgcolor_b = CAIROCOLOR(blue);
  161. }
  162. else
  163. G_fatal_error("Unknown background color: %s", p);
  164. }
  165. else
  166. ca.bgcolor_r = ca.bgcolor_g = ca.bgcolor_b = 1.0;
  167. /* get background transparency setting */
  168. p = getenv("GRASS_TRANSPARENT");
  169. if (p && strcmp(p, "TRUE") == 0)
  170. ca.bgcolor_a = 0.0;
  171. else
  172. ca.bgcolor_a = 1.0;
  173. p = getenv("GRASS_PNG_AUTO_WRITE");
  174. ca.auto_write = p && strcmp(p, "TRUE") == 0;
  175. antialias = CAIRO_ANTIALIAS_DEFAULT;
  176. p = getenv("GRASS_ANTIALIAS");
  177. if (p && G_strcasecmp(p, "default") == 0)
  178. antialias = CAIRO_ANTIALIAS_DEFAULT;
  179. if (p && G_strcasecmp(p, "none") == 0)
  180. antialias = CAIRO_ANTIALIAS_NONE;
  181. if (p && G_strcasecmp(p, "gray") == 0)
  182. antialias = CAIRO_ANTIALIAS_GRAY;
  183. if (p && G_strcasecmp(p, "subpixel") == 0)
  184. antialias = CAIRO_ANTIALIAS_SUBPIXEL;
  185. p = getenv("GRASS_CAIRO_DRAWABLE");
  186. if (p)
  187. init_xlib();
  188. else
  189. init_file();
  190. cairo_set_antialias(cairo, antialias);
  191. return 0;
  192. }
  193. void Cairo_Graph_close(void)
  194. {
  195. G_debug(1, "Cairo_Graph_close");
  196. cairo_write_image();
  197. if (cairo) {
  198. cairo_destroy(cairo);
  199. cairo = NULL;
  200. }
  201. if (surface) {
  202. cairo_surface_destroy(surface);
  203. surface = NULL;
  204. }
  205. }
  206. static void init_cairo(void)
  207. {
  208. G_debug(1, "init_cairo");
  209. /* create cairo surface */
  210. switch (ca.file_type) {
  211. case FTYPE_PPM:
  212. case FTYPE_BMP:
  213. case FTYPE_PNG:
  214. surface =
  215. (cairo_surface_t *) cairo_image_surface_create_for_data(
  216. ca.grid, CAIRO_FORMAT_ARGB32, ca.width, ca.height, ca.stride);
  217. break;
  218. #if CAIRO_HAS_PDF_SURFACE
  219. case FTYPE_PDF:
  220. surface =
  221. (cairo_surface_t *) cairo_pdf_surface_create(
  222. ca.file_name, (double) ca.width, (double) ca.height);
  223. break;
  224. #endif
  225. #if CAIRO_HAS_PS_SURFACE
  226. case FTYPE_PS:
  227. surface =
  228. (cairo_surface_t *) cairo_ps_surface_create(
  229. ca.file_name, (double) ca.width, (double) ca.height);
  230. break;
  231. #endif
  232. #if CAIRO_HAS_SVG_SURFACE
  233. case FTYPE_SVG:
  234. surface =
  235. (cairo_surface_t *) cairo_svg_surface_create(
  236. ca.file_name, (double) ca.width, (double) ca.height);
  237. break;
  238. #endif
  239. default:
  240. G_fatal_error("Unknown Cairo surface type");
  241. break;
  242. }
  243. if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
  244. G_fatal_error("Failed to initialize Cairo surface");
  245. cairo = cairo_create(surface);
  246. }
  247. /* Returns TRUE if string ends with suffix (case insensitive) */
  248. static int ends_with(const char *string, const char *suffix)
  249. {
  250. if (strlen(string) < strlen(suffix))
  251. return FALSE;
  252. return G_strcasecmp(suffix,
  253. string + strlen(string) - strlen(suffix)) == 0;
  254. }
  255. static void map_file(void)
  256. {
  257. #ifndef __MINGW32__
  258. size_t size = HEADER_SIZE + ca.width * ca.height * sizeof(unsigned int);
  259. void *ptr;
  260. int fd;
  261. fd = open(ca.file_name, O_RDWR);
  262. if (fd < 0)
  263. return;
  264. ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t) 0);
  265. if (ptr == MAP_FAILED)
  266. return;
  267. if (ca.grid) {
  268. cairo_destroy(cairo);
  269. cairo_surface_destroy(surface);
  270. G_free(ca.grid);
  271. }
  272. ca.grid = (char *)ptr + HEADER_SIZE;
  273. close(fd);
  274. ca.mapped = 1;
  275. #endif
  276. }