1 /*
2  * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it either under the terms of the GNU Lesser General Public
6  * License version 2.1 as published by the Free Software Foundation
7  * (the "LGPL") or, at your option, under the terms of the Mozilla
8  * Public License Version 1.1 (the "MPL"). If you do not alter this
9  * notice, a recipient may use your version of this file under either
10  * the MPL or the LGPL.
11  *
12  * You should have received a copy of the LGPL along with this library
13  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15  * You should have received a copy of the MPL along with this library
16  * in the file COPYING-MPL-1.1
17  *
18  * The contents of this file are subject to the Mozilla Public License
19  * Version 1.1 (the "License"); you may not use this file except in
20  * compliance with the License. You may obtain a copy of the License at
21  * http://www.mozilla.org/MPL/
22  *
23  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
24  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
25  * the specific language governing rights and limitations.
26  *
27  * The Original Code is the cairo graphics library.
28  *
29  * The Initial Developer of the Original Code is Chris Wilson.
30  *
31  * Contributor(s):
32  *      Chris Wilson <chris@chris-wilson.co.uk>
33  */
34 
35 #include "config.h"
36 
37 #include "cairo.h"
38 #include "cairo-script-interpreter.h"
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 static const cairo_user_data_key_t _key;
45 
46 #define SINGLE_SURFACE 1
47 
48 #if SINGLE_SURFACE
49 static cairo_surface_t *
_similar_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)50 _similar_surface_create (void *closure,
51 			 cairo_content_t content,
52 			 double width, double height,
53 			 long uid)
54 {
55     return cairo_surface_create_similar (closure, content, width, height);
56 }
57 
58 static struct list {
59     struct list *next;
60     cairo_t *context;
61     cairo_surface_t *surface;
62 } *list;
63 
64 static cairo_t *
_context_create(void * closure,cairo_surface_t * surface)65 _context_create (void *closure, cairo_surface_t *surface)
66 {
67     cairo_t *cr = cairo_create (surface);
68     struct list *l = malloc (sizeof (*l));
69     l->next = list;
70     l->context = cr;
71     l->surface = cairo_surface_reference (surface);
72     list = l;
73     return cr;
74 }
75 
76 static void
_context_destroy(void * closure,void * ptr)77 _context_destroy (void *closure, void *ptr)
78 {
79     struct list *l, **prev = &list;
80     while ((l = *prev) != NULL) {
81 	if (l->context == ptr) {
82 	    if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
83 		cairo_t *cr = cairo_create (closure);
84 		cairo_set_source_surface (cr, l->surface, 0, 0);
85 		cairo_paint (cr);
86 		cairo_destroy (cr);
87 	    }
88 
89 	    cairo_surface_destroy (l->surface);
90 	    *prev = l->next;
91 	    free (l);
92 	    return;
93 	}
94 	prev = &l->next;
95     }
96 }
97 #endif
98 
99 #if CAIRO_HAS_XLIB_SURFACE
100 #include <cairo-xlib.h>
101 static Display *
_get_display(void)102 _get_display (void)
103 {
104     static Display *dpy;
105 
106     if (dpy != NULL)
107 	return dpy;
108 
109     dpy = XOpenDisplay (NULL);
110     if (dpy == NULL) {
111 	fprintf (stderr, "Failed to open display.\n");
112 	exit (1);
113     }
114 
115     return dpy;
116 }
117 
118 static void
_destroy_window(void * closure)119 _destroy_window (void *closure)
120 {
121     XFlush (_get_display ());
122     XDestroyWindow (_get_display(), (Window) closure);
123 }
124 
125 static cairo_surface_t *
_xlib_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)126 _xlib_surface_create (void *closure,
127 		      cairo_content_t content,
128 		      double width, double height,
129 		      long uid)
130 {
131     Display *dpy;
132     XSetWindowAttributes attr;
133     Visual *visual;
134     int depth;
135     Window w;
136     cairo_surface_t *surface;
137 
138     dpy = _get_display ();
139 
140     visual = DefaultVisual (dpy, DefaultScreen (dpy));
141     depth = DefaultDepth (dpy, DefaultScreen (dpy));
142     attr.override_redirect = True;
143     w = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
144 		       width <= 0 ? 1 : width,
145 		       height <= 0 ? 1 : height,
146 		       0, depth,
147 		       InputOutput, visual, CWOverrideRedirect, &attr);
148     XMapWindow (dpy, w);
149 
150     surface = cairo_xlib_surface_create (dpy, w, visual, width, height);
151     cairo_surface_set_user_data (surface, &_key, (void *) w, _destroy_window);
152 
153     return surface;
154 }
155 
156 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
157 #include <cairo-xlib-xrender.h>
158 
159 static void
_destroy_pixmap(void * closure)160 _destroy_pixmap (void *closure)
161 {
162     XFreePixmap (_get_display(), (Pixmap) closure);
163 }
164 
165 static cairo_surface_t *
_xrender_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)166 _xrender_surface_create (void *closure,
167 			 cairo_content_t content,
168 			 double width, double height,
169 			 long uid)
170 {
171     Display *dpy;
172     Pixmap pixmap;
173     XRenderPictFormat *xrender_format;
174     cairo_surface_t *surface;
175 
176     dpy = _get_display ();
177 
178     content = CAIRO_CONTENT_COLOR_ALPHA;
179 
180     switch (content) {
181     case CAIRO_CONTENT_COLOR_ALPHA:
182 	xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
183 	break;
184     case CAIRO_CONTENT_COLOR:
185 	xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
186 	break;
187     case CAIRO_CONTENT_ALPHA:
188     default:
189 	xrender_format = XRenderFindStandardFormat (dpy, PictStandardA8);
190     }
191 
192     pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
193 		       width, height, xrender_format->depth);
194 
195     surface = cairo_xlib_surface_create_with_xrender_format (dpy, pixmap,
196 							     DefaultScreenOfDisplay (dpy),
197 							     xrender_format,
198 							     width, height);
199     cairo_surface_set_user_data (surface, &_key,
200 				 (void *) pixmap, _destroy_pixmap);
201 
202     return surface;
203 }
204 #endif
205 #endif
206 
207 #if CAIRO_HAS_GL_GLX_SURFACE
208 #include <cairo-gl.h>
209 static cairo_gl_context_t *
_glx_get_context(cairo_content_t content)210 _glx_get_context (cairo_content_t content)
211 {
212     static cairo_gl_context_t *context;
213 
214     if (context == NULL) {
215 	int rgba_attribs[] = {
216 	    GLX_RGBA,
217 	    GLX_RED_SIZE, 1,
218 	    GLX_GREEN_SIZE, 1,
219 	    GLX_BLUE_SIZE, 1,
220 	    GLX_ALPHA_SIZE, 1,
221 	    GLX_DOUBLEBUFFER,
222 	    None
223 	};
224 	XVisualInfo *visinfo;
225 	GLXContext gl_ctx;
226 	Display *dpy;
227 
228 	dpy = XOpenDisplay (NULL);
229 	if (dpy == NULL) {
230 	    fprintf (stderr, "Failed to open display.\n");
231 	    exit (1);
232 	}
233 
234 	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
235 	if (visinfo == NULL) {
236 	    fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
237 	    exit (1);
238 	}
239 
240 	gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
241 	XFree (visinfo);
242 
243 	context = cairo_glx_context_create (dpy, gl_ctx);
244     }
245 
246     return context;
247 }
248 
249 static cairo_surface_t *
_glx_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)250 _glx_surface_create (void *closure,
251 		     cairo_content_t content,
252 		     double width, double height,
253 		     long uid)
254 {
255     if (width == 0)
256 	width = 1;
257     if (height == 0)
258 	height = 1;
259 
260     return cairo_gl_surface_create (_glx_get_context (content),
261 				    content, width, height);
262 }
263 #endif
264 
265 #if CAIRO_HAS_PDF_SURFACE
266 #include <cairo-pdf.h>
267 static cairo_surface_t *
_pdf_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)268 _pdf_surface_create (void *closure,
269 		     cairo_content_t content,
270 		     double width, double height,
271 		     long uid)
272 {
273     return cairo_pdf_surface_create_for_stream (NULL, NULL, width, height);
274 }
275 #endif
276 
277 #if CAIRO_HAS_PS_SURFACE
278 #include <cairo-ps.h>
279 static cairo_surface_t *
_ps_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)280 _ps_surface_create (void *closure,
281 		    cairo_content_t content,
282 		    double width, double height,
283 		    long uid)
284 {
285     return cairo_ps_surface_create_for_stream (NULL, NULL, width, height);
286 }
287 #endif
288 
289 #if CAIRO_HAS_SVG_SURFACE
290 #include <cairo-svg.h>
291 static cairo_surface_t *
_svg_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)292 _svg_surface_create (void *closure,
293 		     cairo_content_t content,
294 		     double width, double height,
295 		     long uid)
296 {
297     return cairo_svg_surface_create_for_stream (NULL, NULL, width, height);
298 }
299 #endif
300 
301 static cairo_surface_t *
_image_surface_create(void * closure,cairo_content_t content,double width,double height,long uid)302 _image_surface_create (void *closure,
303 		       cairo_content_t content,
304 		       double width, double height,
305 		       long uid)
306 {
307     return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
308 }
309 
310 int
main(int argc,char ** argv)311 main (int argc, char **argv)
312 {
313     cairo_script_interpreter_t *csi;
314     cairo_script_interpreter_hooks_t hooks = {
315 #if SINGLE_SURFACE
316 	.surface_create = _similar_surface_create,
317 	.context_create = _context_create,
318 	.context_destroy = _context_destroy
319 #elif CAIRO_HAS_XLIB_XRENDER_SURFACE
320 	.surface_create = _xrender_surface_create
321 #elif CAIRO_HAS_XLIB_SURFACE
322 	.surface_create = _xlib_surface_create
323 #elif CAIRO_PDF_SURFACE
324 	.surface_create = _pdf_surface_create
325 #elif CAIRO_PS_SURFACE
326 	.surface_create = _ps_surface_create
327 #elif CAIRO_SVG_SURFACE
328 	.surface_create = _svg_surface_create
329 #else
330 	.surface_create = _image_surface_create
331 #endif
332     };
333     int i;
334     const struct backends {
335 	const char *name;
336 	csi_surface_create_func_t create;
337     } backends[] = {
338 	{ "--image", _image_surface_create },
339 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
340 	{ "--xrender", _xrender_surface_create },
341 #endif
342 #if CAIRO_HAS_GL_GLX_SURFACE
343 	{ "--glx", _glx_surface_create },
344 #endif
345 #if CAIRO_HAS_XLIB_SURFACE
346 	{ "--xlib", _xlib_surface_create },
347 #endif
348 #if CAIRO_HAS_PDF_SURFACE
349 	{ "--pdf", _pdf_surface_create },
350 #endif
351 #if CAIRO_HAS_PS_SURFACE
352 	{ "--ps", _ps_surface_create },
353 #endif
354 #if CAIRO_HAS_SVG_SURFACE
355 	{ "--svg", _svg_surface_create },
356 #endif
357 	{ NULL, NULL }
358     };
359 
360 #if SINGLE_SURFACE
361     hooks.closure = backends[0].create (NULL,
362 					CAIRO_CONTENT_COLOR_ALPHA,
363 					512, 512,
364 					0);
365 #endif
366 
367 
368     csi = cairo_script_interpreter_create ();
369     cairo_script_interpreter_install_hooks (csi, &hooks);
370 
371     for (i = 1; i < argc; i++) {
372 	const struct backends *b;
373 
374 	for (b = backends; b->name != NULL; b++) {
375 	    if (strcmp (b->name, argv[i]) == 0) {
376 #if SINGLE_SURFACE
377 		cairo_surface_destroy (hooks.closure);
378 		hooks.closure = b->create (NULL,
379 					   CAIRO_CONTENT_COLOR_ALPHA,
380 					   512, 512,
381 					   0);
382 #else
383 		hooks.surface_create = b->create;
384 #endif
385 		cairo_script_interpreter_install_hooks (csi, &hooks);
386 		break;
387 	    }
388 	}
389 
390 	if (b->name == NULL)
391 	    cairo_script_interpreter_run (csi, argv[i]);
392     }
393     cairo_surface_destroy (hooks.closure);
394 
395     return cairo_script_interpreter_destroy (csi);
396 }
397