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