GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
cairodriver/graph.c
Go to the documentation of this file.
1/*!
2 \file lib/cairodriver/graph.c
3
4 \brief GRASS cairo display driver - driver settings
5
6 SPDX-FileCopyrightText: 2007-2008, 2011 Lars Ahlzen
7 SPDX-FileCopyrightText: GRASS Development Team
8 SPDX-License-Identifier: GPL-2.0-or-later
9
10 \author Lars Ahlzen <lars ahlzen.com> (original contributor)
11 \author Glynn Clements
12 */
13
14#include "cairodriver.h"
15
16#if CAIRO_HAS_PS_SURFACE
17#include <cairo-ps.h>
18#endif
19#if CAIRO_HAS_PDF_SURFACE
20#include <cairo-pdf.h>
21#endif
22#if CAIRO_HAS_SVG_SURFACE
23#include <cairo-svg.h>
24#endif
25#if CAIRO_HAS_XLIB_XRENDER_SURFACE
26#include <cairo-xlib.h>
27#include <cairo-xlib-xrender.h>
28#endif
29
30#include <unistd.h>
31#ifndef _WIN32
32#include <fcntl.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/mman.h>
36#endif
37
38#include <grass/colors.h>
39#include <grass/glocale.h>
40
42
43/* cairo objects */
46
47static void init_cairo(void);
48static int ends_with(const char *string, const char *suffix);
49static void map_file(void);
50
51#if CAIRO_HAS_XLIB_XRENDER_SURFACE
52static void init_xlib(void)
53{
54 char *p;
55 unsigned long xid;
58 int count;
60 int scrn;
61 Pixmap pix;
63
64 ca.dpy = XOpenDisplay(NULL);
65 if (!ca.dpy)
66 G_fatal_error(_("Unable to open display"));
67
68 p = getenv("GRASS_RENDER_CAIRO_SCREEN");
69 if (!p || sscanf(p, "%i", &scrn) != 1) {
70 G_debug(1, "cairo: GRASS_RENDER_CAIRO_SCREEN=%s", p);
71 scrn = DefaultScreen(ca.dpy);
72 }
73
74 p = getenv("GRASS_RENDER_CAIRO_VISUAL");
75 if (!p || sscanf(p, "%lu", &xid) != 1) {
76 G_debug(1, "cairo: GRASS_RENDER_CAIRO_VISUAL=%s", p);
77 xid = DefaultVisual(ca.dpy, scrn)->visualid;
78 }
79 templ.visualid = xid;
80 templ.screen = scrn;
81
82 vinfo =
84 if (!vinfo || !count)
85 G_fatal_error(_("Unable to obtain visual"));
86 visual = vinfo[0].visual;
87
88 ca.screen = ScreenOfDisplay(ca.dpy, scrn);
89 pix = XCreatePixmap(ca.dpy, RootWindow(ca.dpy, scrn), 1, 1, vinfo[0].depth);
96 XFreePixmap(ca.dpy, pix);
97
98 if (!ca.win)
99 ca.win = XCreatePixmap(ca.dpy, RootWindow(ca.dpy, scrn), ca.width,
100 ca.height, ca.depth);
101}
102
103static void fini_xlib(void)
104{
106 XCloseDisplay(ca.dpy);
107}
108#endif
109
110static void init_file(void)
111{
112 int is_vector = 0;
113
114#if CAIRO_HAS_XLIB_XRENDER_SURFACE
115 int is_xlib = 0;
116#endif
117 int do_read = 0;
118 int do_map = 0;
119 char *p;
120
121 /* set image properties */
122 ca.width = screen_width;
123 ca.height = screen_height;
124 ca.stride = ca.width * 4;
125
126 /* get file name */
127 p = getenv("GRASS_RENDER_FILE");
128 if (!p || strlen(p) == 0)
130 G_debug(1, "cairo: GRASS_RENDER_FILE=%s", p);
131
132 ca.file_name = p;
133
134 /* get file type (from extension) */
135 if (ends_with(ca.file_name, ".ppm"))
136 ca.file_type = FTYPE_PPM;
137 else if (ends_with(ca.file_name, ".bmp"))
138 ca.file_type = FTYPE_BMP;
139#if CAIRO_HAS_PNG_FUNCTIONS
140 else if (ends_with(ca.file_name, ".png"))
141 ca.file_type = FTYPE_PNG;
142#endif
143#if CAIRO_HAS_PDF_SURFACE
144 else if (ends_with(ca.file_name, ".pdf"))
145 ca.file_type = FTYPE_PDF;
146#endif
147#if CAIRO_HAS_PS_SURFACE
148 else if (ends_with(ca.file_name, ".ps"))
149 ca.file_type = FTYPE_PS;
150#endif
151#if CAIRO_HAS_SVG_SURFACE
152 else if (ends_with(ca.file_name, ".svg"))
153 ca.file_type = FTYPE_SVG;
154#endif
155#if CAIRO_HAS_XLIB_XRENDER_SURFACE
156 else if (ends_with(ca.file_name, ".xid"))
157 ca.file_type = FTYPE_X11;
158#endif
159 else
160 G_fatal_error(_("Unknown file extension: %s"), p);
161 G_debug(1, "cairo: file type=%d", ca.file_type);
162
163 switch (ca.file_type) {
164 case FTYPE_PDF:
165 case FTYPE_PS:
166 case FTYPE_SVG:
167 is_vector = 1;
168 break;
169#if CAIRO_HAS_XLIB_XRENDER_SURFACE
170 case FTYPE_X11:
171 is_xlib = 1;
172 break;
173#endif
174 }
175
176 p = getenv("GRASS_RENDER_FILE_MAPPED");
177 do_map = p && strcmp(p, "TRUE") == 0 && ends_with(ca.file_name, ".bmp");
178 G_debug(1, "cairo: GRASS_RENDER_FILE_MAPPED=%d", do_map);
179
180 p = getenv("GRASS_RENDER_FILE_READ");
181 do_read = p && strcmp(p, "TRUE") == 0;
182 G_debug(1, "cairo: GRASS_RENDER_FILE_READ=%d", do_read);
183
184 if (is_vector) {
185 do_read = do_map = 0;
186 ca.bgcolor_a = 1.0;
187 }
188
189 if (do_read && access(ca.file_name, 0) != 0)
190 do_read = 0;
191
192 G_verbose_message(_("cairo: collecting to file '%s'"), ca.file_name);
193 G_verbose_message(_("cairo: image size %dx%d"), ca.width, ca.height);
194
195 if (do_read && do_map)
196 map_file();
197
198#if CAIRO_HAS_XLIB_XRENDER_SURFACE
199 if (is_xlib) {
200 if (do_read)
202 else
203 ca.win = 0;
204 init_xlib();
205 ca.mapped = 1;
206 }
207#endif
208
209 if (!ca.mapped && !is_vector)
210 ca.grid = G_malloc(ca.height * ca.stride);
211
212 init_cairo();
213
214 if (!do_read && !is_vector) {
215 Cairo_Erase();
216 ca.modified = 1;
217 }
218
219 if (do_read && !ca.mapped)
221
222 if (do_map && !ca.mapped) {
224 map_file();
225 init_cairo();
226 }
227}
228
229/*!
230 \brief Initialize driver
231
232 Set background color, transparency, drawable, antialias mode, etc.
233
234 \return 0
235 */
237{
239 char *p;
240
241 G_gisinit("Cairo driver");
242
243 /* get background color */
244 p = getenv("GRASS_RENDER_BACKGROUNDCOLOR");
245 if (p && *p) {
246 unsigned int red, green, blue;
247
248 if (sscanf(p, "%02x%02x%02x", &red, &green, &blue) == 3 ||
249 G_str_to_color(p, (int *)&red, (int *)&green, (int *)&blue) == 1) {
250 ca.bgcolor_r = CAIROCOLOR(red);
251 ca.bgcolor_g = CAIROCOLOR(green);
252 ca.bgcolor_b = CAIROCOLOR(blue);
253 }
254 else
255 G_fatal_error("Unknown background color: %s", p);
256 G_debug(1, "cairo: GRASS_RENDER_BACKGROUNDCOLOR=%s", p);
257 }
258 else
259 ca.bgcolor_r = ca.bgcolor_g = ca.bgcolor_b = 1.0;
260
261 /* get background transparency setting */
262 p = getenv("GRASS_RENDER_TRANSPARENT");
263 if (p && strcmp(p, "TRUE") == 0)
264 ca.bgcolor_a = 0.0;
265 else
266 ca.bgcolor_a = 1.0;
267 G_debug(1, "cairo: GRASS_RENDER_TRANSPARENT=%s", p ? p : "FALSE");
268
270 p = getenv("GRASS_RENDER_ANTIALIAS");
271 if (p && G_strcasecmp(p, "default") == 0)
273 if (p && G_strcasecmp(p, "none") == 0)
275 if (p && G_strcasecmp(p, "gray") == 0)
277 if (p && G_strcasecmp(p, "subpixel") == 0)
279 G_debug(1, "cairo: GRASS_RENDER_ANTIALIAS=%s", p ? p : "FALSE");
280
281 init_file();
282
284
285 return 0;
286}
287
288/*!
289 \brief Get render file
290
291 \return file name
292 */
293const char *Cairo_Graph_get_file(void)
294{
295 return ca.file_name;
296}
297
298/*!
299 \brief Close driver
300 */
302{
303 G_debug(1, "Cairo_Graph_close");
304
305#if CAIRO_HAS_XLIB_XRENDER_SURFACE
306 if (ca.file_type == FTYPE_X11) {
308 ca.mapped = 0;
309 }
310#endif
311
313
314 if (cairo) {
316 cairo = NULL;
317 }
318 if (surface) {
320 surface = NULL;
321 }
322
323#if CAIRO_HAS_XLIB_XRENDER_SURFACE
324 if (ca.file_type == FTYPE_X11)
325 fini_xlib();
326#endif
327}
328
329static void init_cairo(void)
330{
331 G_debug(1, "init_cairo");
332
333 /* create cairo surface */
334 switch (ca.file_type) {
335 case FTYPE_PPM:
336 case FTYPE_BMP:
337 case FTYPE_PNG:
339 ca.grid, CAIRO_FORMAT_ARGB32, ca.width, ca.height, ca.stride);
340 break;
341#if CAIRO_HAS_PDF_SURFACE
342 case FTYPE_PDF:
344 ca.file_name, (double)ca.width, (double)ca.height);
345 break;
346#endif
347#if CAIRO_HAS_PS_SURFACE
348 case FTYPE_PS:
350 ca.file_name, (double)ca.width, (double)ca.height);
351 break;
352#endif
353#if CAIRO_HAS_SVG_SURFACE
354 case FTYPE_SVG:
356 ca.file_name, (double)ca.width, (double)ca.height);
357 break;
358#endif
359#if CAIRO_HAS_XLIB_XRENDER_SURFACE
360 case FTYPE_X11:
361 surface =
363 ca.dpy, ca.win, ca.screen, ca.format, ca.width, ca.height);
364 break;
365#endif
366 default:
367 G_fatal_error(_("Unknown Cairo surface type"));
368 break;
369 }
370
372 G_fatal_error(_("Failed to initialize Cairo surface"
373 " (width: %d, height: %d): %s"),
374 ca.width, ca.height,
376
378}
379
380/* Returns TRUE if string ends with suffix (case insensitive) */
381static int ends_with(const char *string, const char *suffix)
382{
383 if (strlen(string) < strlen(suffix))
384 return FALSE;
385
386 return G_strcasecmp(suffix, string + strlen(string) - strlen(suffix)) == 0;
387}
388
389static void map_file(void)
390{
391#ifndef _WIN32
392 size_t size =
393 HEADER_SIZE + (size_t)ca.width * ca.height * sizeof(unsigned int);
394 void *ptr;
395 int fd;
396
397 fd = open(ca.file_name, O_RDWR);
398 if (fd < 0) {
399 G_warning(_("Unable to open file: %s"), ca.file_name);
400 return;
401 }
402
403 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
404 if (ptr == MAP_FAILED) {
405 close(fd);
406 return;
407 }
408
409 if (ca.grid) {
412 G_free(ca.grid);
413 }
414 ca.grid = (unsigned char *)ptr + HEADER_SIZE;
415
416 close(fd);
417
418 ca.mapped = 1;
419#endif
420}
const char * Cairo_Graph_get_file(void)
Get render file.
cairo_surface_t * surface
struct cairo_state ca
int Cairo_Graph_set(void)
Initialize driver.
void Cairo_Graph_close(void)
Close driver.
cairo_t * cairo
GRASS cairo display driver - header file.
#define FTYPE_PS
Definition cairodriver.h:57
void Cairo_Erase(void)
Erase screen.
#define FTYPE_PPM
Definition cairodriver.h:53
#define FTYPE_PDF
Definition cairodriver.h:56
#define HEADER_SIZE
Definition cairodriver.h:45
#define FTYPE_X11
Definition cairodriver.h:59
void cairo_read_xid(void)
Definition read_xid.c:5
void cairo_read_image(void)
#define CAIROCOLOR(a)
Definition cairodriver.h:49
void cairo_write_image(void)
#define FTYPE_PNG
Definition cairodriver.h:55
#define FTYPE_SVG
Definition cairodriver.h:58
#define FTYPE_BMP
Definition cairodriver.h:54
#define DEFAULT_FILE_NAME
Definition cairodriver.h:43
#define NULL
Definition ccmath.h:32
int G_str_to_color(const char *, int *, int *, int *)
Parse color string and set red,green,blue.
Definition color_str.c:99
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:136
void void G_verbose_message(const char *,...) __attribute__((format(printf
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition strings.c:45
int G_debug(int, const char *,...) __attribute__((format(printf
int screen_height
Definition driver/init.c:28
int screen_width
Definition driver/init.c:27
Header file for msvc/fcntl.c.
#define open
Definition fcntl.h:32
#define G_gisinit(pgm)
Definition gis.h:68
#define FALSE
Definition gis.h:79
#define _(str)
Definition glocale.h:10
int count
#define access
Definition unistd.h:7
#define close
Definition unistd.h:8