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
#if defined(CAIRO_HAS_XLIB_SURFACE) || defined(CAIRO_HAS_XLIB_XRENDER_SURFACE)
45
static const cairo_user_data_key_t _key;
46
#endif
47

            
48
#define SINGLE_SURFACE 1
49

            
50
#if SINGLE_SURFACE
51
static cairo_surface_t *
52
_similar_surface_create (void *closure,
53
			 cairo_content_t content,
54
			 double width, double height,
55
			 long uid)
56
{
57
    return cairo_surface_create_similar (closure, content, width, height);
58
}
59

            
60
static struct list {
61
    struct list *next;
62
    cairo_t *context;
63
    cairo_surface_t *surface;
64
} *list;
65

            
66
static cairo_t *
67
_context_create (void *closure, cairo_surface_t *surface)
68
{
69
    cairo_t *cr = cairo_create (surface);
70
    struct list *l = malloc (sizeof (*l));
71
    l->next = list;
72
    l->context = cr;
73
    l->surface = cairo_surface_reference (surface);
74
    list = l;
75
    return cr;
76
}
77

            
78
static void
79
_context_destroy (void *closure, void *ptr)
80
{
81
    struct list *l, **prev = &list;
82
    while ((l = *prev) != NULL) {
83
	if (l->context == ptr) {
84
	    if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
85
		cairo_t *cr = cairo_create (closure);
86
		cairo_set_source_surface (cr, l->surface, 0, 0);
87
		cairo_paint (cr);
88
		cairo_destroy (cr);
89
	    }
90

            
91
	    cairo_surface_destroy (l->surface);
92
	    *prev = l->next;
93
	    free (l);
94
	    return;
95
	}
96
	prev = &l->next;
97
    }
98
}
99
#endif
100

            
101
#if CAIRO_HAS_XLIB_SURFACE
102
#include <cairo-xlib.h>
103
static Display *
104
_get_display (void)
105
{
106
    static Display *dpy;
107

            
108
    if (dpy != NULL)
109
	return dpy;
110

            
111
    dpy = XOpenDisplay (NULL);
112
    if (dpy == NULL) {
113
	fprintf (stderr, "Failed to open display.\n");
114
	exit (1);
115
    }
116

            
117
    return dpy;
118
}
119

            
120
static void
121
_destroy_window (void *closure)
122
{
123
    XFlush (_get_display ());
124
    XDestroyWindow (_get_display(), (Window) closure);
125
}
126

            
127
static cairo_surface_t *
128
_xlib_surface_create (void *closure,
129
		      cairo_content_t content,
130
		      double width, double height,
131
		      long uid)
132
{
133
    Display *dpy;
134
    XSetWindowAttributes attr;
135
    Visual *visual;
136
    int depth;
137
    Window w;
138
    cairo_surface_t *surface;
139

            
140
    dpy = _get_display ();
141

            
142
    visual = DefaultVisual (dpy, DefaultScreen (dpy));
143
    depth = DefaultDepth (dpy, DefaultScreen (dpy));
144
    attr.override_redirect = True;
145
    w = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
146
		       width <= 0 ? 1 : width,
147
		       height <= 0 ? 1 : height,
148
		       0, depth,
149
		       InputOutput, visual, CWOverrideRedirect, &attr);
150
    XMapWindow (dpy, w);
151

            
152
    surface = cairo_xlib_surface_create (dpy, w, visual, width, height);
153
    cairo_surface_set_user_data (surface, &_key, (void *) w, _destroy_window);
154

            
155
    return surface;
156
}
157

            
158
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
159
#include <cairo-xlib-xrender.h>
160

            
161
static void
162
_destroy_pixmap (void *closure)
163
{
164
    XFreePixmap (_get_display(), (Pixmap) closure);
165
}
166

            
167
static cairo_surface_t *
168
_xrender_surface_create (void *closure,
169
			 cairo_content_t content,
170
			 double width, double height,
171
			 long uid)
172
{
173
    Display *dpy;
174
    Pixmap pixmap;
175
    XRenderPictFormat *xrender_format;
176
    cairo_surface_t *surface;
177

            
178
    dpy = _get_display ();
179

            
180
    content = CAIRO_CONTENT_COLOR_ALPHA;
181

            
182
    switch (content) {
183
    case CAIRO_CONTENT_COLOR_ALPHA:
184
	xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
185
	break;
186
    case CAIRO_CONTENT_COLOR:
187
	xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24);
188
	break;
189
    case CAIRO_CONTENT_ALPHA:
190
    default:
191
	xrender_format = XRenderFindStandardFormat (dpy, PictStandardA8);
192
    }
193

            
194
    pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
195
		       width, height, xrender_format->depth);
196

            
197
    surface = cairo_xlib_surface_create_with_xrender_format (dpy, pixmap,
198
							     DefaultScreenOfDisplay (dpy),
199
							     xrender_format,
200
							     width, height);
201
    cairo_surface_set_user_data (surface, &_key,
202
				 (void *) pixmap, _destroy_pixmap);
203

            
204
    return surface;
205
}
206
#endif
207
#endif
208

            
209
#if CAIRO_HAS_PDF_SURFACE
210
#include <cairo-pdf.h>
211
static cairo_surface_t *
212
_pdf_surface_create (void *closure,
213
		     cairo_content_t content,
214
		     double width, double height,
215
		     long uid)
216
{
217
    return cairo_pdf_surface_create_for_stream (NULL, NULL, width, height);
218
}
219
#endif
220

            
221
#if CAIRO_HAS_PS_SURFACE
222
#include <cairo-ps.h>
223
static cairo_surface_t *
224
_ps_surface_create (void *closure,
225
		    cairo_content_t content,
226
		    double width, double height,
227
		    long uid)
228
{
229
    return cairo_ps_surface_create_for_stream (NULL, NULL, width, height);
230
}
231
#endif
232

            
233
#if CAIRO_HAS_SVG_SURFACE
234
#include <cairo-svg.h>
235
static cairo_surface_t *
236
_svg_surface_create (void *closure,
237
		     cairo_content_t content,
238
		     double width, double height,
239
		     long uid)
240
{
241
    return cairo_svg_surface_create_for_stream (NULL, NULL, width, height);
242
}
243
#endif
244

            
245
static cairo_surface_t *
246
_image_surface_create (void *closure,
247
		       cairo_content_t content,
248
		       double width, double height,
249
		       long uid)
250
{
251
    return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
252
}
253

            
254
int
255
main (int argc, char **argv)
256
{
257
    cairo_script_interpreter_t *csi;
258
    cairo_script_interpreter_hooks_t hooks = {
259
#if SINGLE_SURFACE
260
	.surface_create = _similar_surface_create,
261
	.context_create = _context_create,
262
	.context_destroy = _context_destroy
263
#elif CAIRO_HAS_XLIB_XRENDER_SURFACE
264
	.surface_create = _xrender_surface_create
265
#elif CAIRO_HAS_XLIB_SURFACE
266
	.surface_create = _xlib_surface_create
267
#elif CAIRO_PDF_SURFACE
268
	.surface_create = _pdf_surface_create
269
#elif CAIRO_PS_SURFACE
270
	.surface_create = _ps_surface_create
271
#elif CAIRO_SVG_SURFACE
272
	.surface_create = _svg_surface_create
273
#else
274
	.surface_create = _image_surface_create
275
#endif
276
    };
277
    int i;
278
    const struct backends {
279
	const char *name;
280
	csi_surface_create_func_t create;
281
    } backends[] = {
282
	{ "--image", _image_surface_create },
283
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
284
	{ "--xrender", _xrender_surface_create },
285
#endif
286
#if CAIRO_HAS_XLIB_SURFACE
287
	{ "--xlib", _xlib_surface_create },
288
#endif
289
#if CAIRO_HAS_PDF_SURFACE
290
	{ "--pdf", _pdf_surface_create },
291
#endif
292
#if CAIRO_HAS_PS_SURFACE
293
	{ "--ps", _ps_surface_create },
294
#endif
295
#if CAIRO_HAS_SVG_SURFACE
296
	{ "--svg", _svg_surface_create },
297
#endif
298
	{ NULL, NULL }
299
    };
300

            
301
#if SINGLE_SURFACE
302
    hooks.closure = backends[0].create (NULL,
303
					CAIRO_CONTENT_COLOR_ALPHA,
304
					512, 512,
305
					0);
306
#endif
307

            
308

            
309
    csi = cairo_script_interpreter_create ();
310
    cairo_script_interpreter_install_hooks (csi, &hooks);
311

            
312
    for (i = 1; i < argc; i++) {
313
	const struct backends *b;
314

            
315
	for (b = backends; b->name != NULL; b++) {
316
	    if (strcmp (b->name, argv[i]) == 0) {
317
#if SINGLE_SURFACE
318
		cairo_surface_destroy (hooks.closure);
319
		hooks.closure = b->create (NULL,
320
					   CAIRO_CONTENT_COLOR_ALPHA,
321
					   512, 512,
322
					   0);
323
#else
324
		hooks.surface_create = b->create;
325
#endif
326
		cairo_script_interpreter_install_hooks (csi, &hooks);
327
		break;
328
	    }
329
	}
330

            
331
	if (b->name == NULL)
332
	    cairo_script_interpreter_run (csi, argv[i]);
333
    }
334
    cairo_surface_destroy (hooks.closure);
335

            
336
    return cairo_script_interpreter_destroy (csi);
337
}