1 /* cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2005 Red Hat, Inc
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
12 *
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
18 *
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
23 *
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
27 *
28 * The Original Code is the cairo graphics library.
29 *
30 * The Initial Developer of the Original Code is Red Hat, Inc.
31 *
32 * Contributor(s):
33 * Carl Worth <cworth@cworth.org>
34 */
35
36 /* This isn't a "real" surface, but just something to be used by the
37 * test suite to help exercise the meta-surface paths in cairo.
38 *
39 * The defining feature of this backend is that it uses a meta surface
40 * to record all operations, and then replays everything to an image
41 * surface.
42 *
43 * It's possible that this code might serve as a good starting point
44 * for someone working on bringing up a new meta-surface-based
45 * backend.
46 */
47
48 #include "cairoint.h"
49
50 #include "test-meta-surface.h"
51
52 #include "cairo-meta-surface-private.h"
53
54 typedef struct _test_meta_surface {
55 cairo_surface_t base;
56
57 /* This is a cairo_meta_surface to record all operations. */
58 cairo_surface_t *meta;
59
60 /* And this is a cairo_image_surface to hold the final result. */
61 cairo_surface_t *image;
62
63 cairo_bool_t image_reflects_meta;
64 } test_meta_surface_t;
65
66 static const cairo_surface_backend_t test_meta_surface_backend;
67
68 static cairo_int_status_t
69 _test_meta_surface_show_page (void *abstract_surface);
70
71 cairo_surface_t *
_cairo_test_meta_surface_create(cairo_content_t content,int width,int height)72 _cairo_test_meta_surface_create (cairo_content_t content,
73 int width,
74 int height)
75 {
76 test_meta_surface_t *surface;
77 cairo_status_t status;
78
79 surface = malloc (sizeof (test_meta_surface_t));
80 if (unlikely (surface == NULL)) {
81 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
82 goto FAIL;
83 }
84
85 _cairo_surface_init (&surface->base, &test_meta_surface_backend,
86 content);
87
88 surface->meta = _cairo_meta_surface_create (content, width, height);
89 status = cairo_surface_status (surface->meta);
90 if (status)
91 goto FAIL_CLEANUP_SURFACE;
92
93 surface->image = _cairo_image_surface_create_with_content (content,
94 width, height);
95 status = cairo_surface_status (surface->image);
96 if (status)
97 goto FAIL_CLEANUP_META;
98
99 surface->image_reflects_meta = FALSE;
100
101 return &surface->base;
102
103 FAIL_CLEANUP_META:
104 cairo_surface_destroy (surface->meta);
105 FAIL_CLEANUP_SURFACE:
106 free (surface);
107 FAIL:
108 return _cairo_surface_create_in_error (status);
109 }
110
111 static cairo_status_t
_test_meta_surface_finish(void * abstract_surface)112 _test_meta_surface_finish (void *abstract_surface)
113 {
114 test_meta_surface_t *surface = abstract_surface;
115
116 cairo_surface_destroy (surface->meta);
117 cairo_surface_destroy (surface->image);
118
119 return CAIRO_STATUS_SUCCESS;
120 }
121
122 static cairo_status_t
_test_meta_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)123 _test_meta_surface_acquire_source_image (void *abstract_surface,
124 cairo_image_surface_t **image_out,
125 void **image_extra)
126 {
127 test_meta_surface_t *surface = abstract_surface;
128 cairo_status_t status;
129
130 if (! surface->image_reflects_meta) {
131 status = _test_meta_surface_show_page (abstract_surface);
132 if (status)
133 return status;
134 }
135
136 return _cairo_surface_acquire_source_image (surface->image,
137 image_out, image_extra);
138 }
139
140 static void
_test_meta_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)141 _test_meta_surface_release_source_image (void *abstract_surface,
142 cairo_image_surface_t *image,
143 void *image_extra)
144 {
145 test_meta_surface_t *surface = abstract_surface;
146
147 _cairo_surface_release_source_image (surface->image,
148 image, image_extra);
149 }
150
151 static cairo_int_status_t
_test_meta_surface_show_page(void * abstract_surface)152 _test_meta_surface_show_page (void *abstract_surface)
153 {
154 test_meta_surface_t *surface = abstract_surface;
155 cairo_status_t status;
156
157 if (surface->image_reflects_meta)
158 return CAIRO_STATUS_SUCCESS;
159
160 status = _cairo_meta_surface_replay (surface->meta, surface->image);
161 if (status)
162 return status;
163
164 surface->image_reflects_meta = TRUE;
165
166 return CAIRO_STATUS_SUCCESS;
167 }
168
169 static cairo_int_status_t
_test_meta_surface_intersect_clip_path(void * abstract_surface,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias)170 _test_meta_surface_intersect_clip_path (void *abstract_surface,
171 cairo_path_fixed_t *path,
172 cairo_fill_rule_t fill_rule,
173 double tolerance,
174 cairo_antialias_t antialias)
175 {
176 test_meta_surface_t *surface = abstract_surface;
177
178 return _cairo_surface_intersect_clip_path (surface->meta,
179 path, fill_rule,
180 tolerance, antialias);
181 }
182
183 static cairo_int_status_t
_test_meta_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)184 _test_meta_surface_get_extents (void *abstract_surface,
185 cairo_rectangle_int_t *rectangle)
186 {
187 test_meta_surface_t *surface = abstract_surface;
188
189 surface->image_reflects_meta = FALSE;
190
191 return _cairo_surface_get_extents (surface->image, rectangle);
192 }
193
194 static cairo_int_status_t
_test_meta_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_rectangle_int_t * extents)195 _test_meta_surface_paint (void *abstract_surface,
196 cairo_operator_t op,
197 const cairo_pattern_t *source,
198 cairo_rectangle_int_t *extents)
199 {
200 test_meta_surface_t *surface = abstract_surface;
201
202 surface->image_reflects_meta = FALSE;
203
204 return _cairo_surface_paint (surface->meta, op, source, extents);
205 }
206
207 static cairo_int_status_t
_test_meta_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_rectangle_int_t * extents)208 _test_meta_surface_mask (void *abstract_surface,
209 cairo_operator_t op,
210 const cairo_pattern_t *source,
211 const cairo_pattern_t *mask,
212 cairo_rectangle_int_t *extents)
213 {
214 test_meta_surface_t *surface = abstract_surface;
215
216 surface->image_reflects_meta = FALSE;
217
218 return _cairo_surface_mask (surface->meta, op, source, mask, extents);
219 }
220
221 static cairo_int_status_t
_test_meta_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_stroke_style_t * style,cairo_matrix_t * ctm,cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_rectangle_int_t * extents)222 _test_meta_surface_stroke (void *abstract_surface,
223 cairo_operator_t op,
224 const cairo_pattern_t *source,
225 cairo_path_fixed_t *path,
226 cairo_stroke_style_t *style,
227 cairo_matrix_t *ctm,
228 cairo_matrix_t *ctm_inverse,
229 double tolerance,
230 cairo_antialias_t antialias,
231 cairo_rectangle_int_t *extents)
232 {
233 test_meta_surface_t *surface = abstract_surface;
234
235 surface->image_reflects_meta = FALSE;
236
237 return _cairo_surface_stroke (surface->meta, op, source,
238 path, style,
239 ctm, ctm_inverse,
240 tolerance, antialias, extents);
241 }
242
243 static cairo_int_status_t
_test_meta_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_rectangle_int_t * extents)244 _test_meta_surface_fill (void *abstract_surface,
245 cairo_operator_t op,
246 const cairo_pattern_t *source,
247 cairo_path_fixed_t *path,
248 cairo_fill_rule_t fill_rule,
249 double tolerance,
250 cairo_antialias_t antialias,
251 cairo_rectangle_int_t *extents)
252 {
253 test_meta_surface_t *surface = abstract_surface;
254
255 surface->image_reflects_meta = FALSE;
256
257 return _cairo_surface_fill (surface->meta, op, source,
258 path, fill_rule,
259 tolerance, antialias, extents);
260 }
261
262 static cairo_bool_t
_test_meta_surface_has_show_text_glyphs(void * abstract_surface)263 _test_meta_surface_has_show_text_glyphs (void *abstract_surface)
264 {
265 test_meta_surface_t *surface = abstract_surface;
266
267 return cairo_surface_has_show_text_glyphs (surface->meta);
268 }
269
270 static cairo_int_status_t
_test_meta_surface_show_text_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const char * utf8,int utf8_len,cairo_glyph_t * glyphs,int num_glyphs,const cairo_text_cluster_t * clusters,int num_clusters,cairo_text_cluster_flags_t cluster_flags,cairo_scaled_font_t * scaled_font,cairo_rectangle_int_t * extents)271 _test_meta_surface_show_text_glyphs (void *abstract_surface,
272 cairo_operator_t op,
273 const cairo_pattern_t *source,
274 const char *utf8,
275 int utf8_len,
276 cairo_glyph_t *glyphs,
277 int num_glyphs,
278 const cairo_text_cluster_t *clusters,
279 int num_clusters,
280 cairo_text_cluster_flags_t cluster_flags,
281 cairo_scaled_font_t *scaled_font,
282 cairo_rectangle_int_t *extents)
283 {
284 test_meta_surface_t *surface = abstract_surface;
285
286 surface->image_reflects_meta = FALSE;
287
288 return _cairo_surface_show_text_glyphs (surface->meta, op, source,
289 utf8, utf8_len,
290 glyphs, num_glyphs,
291 clusters, num_clusters, cluster_flags,
292 scaled_font, extents);
293 }
294
295
296 static cairo_surface_t *
_test_meta_surface_snapshot(void * abstract_other)297 _test_meta_surface_snapshot (void *abstract_other)
298 {
299 test_meta_surface_t *other = abstract_other;
300
301 return _cairo_surface_snapshot (other->meta);
302 }
303
304 static const cairo_surface_backend_t test_meta_surface_backend = {
305 CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
306 NULL, /* create_similar */
307 _test_meta_surface_finish,
308 _test_meta_surface_acquire_source_image,
309 _test_meta_surface_release_source_image,
310 NULL, /* acquire_dest_image */
311 NULL, /* release_dest_image */
312 NULL, /* clone_similar */
313 NULL, /* composite */
314 NULL, /* fill_rectangles */
315 NULL, /* composite_trapezoids */
316 NULL, /* create_span_renderer */
317 NULL, /* check_span_renderer */
318 NULL, /* copy_page */
319 _test_meta_surface_show_page,
320 NULL, /* set_clip_region */
321 _test_meta_surface_intersect_clip_path,
322 _test_meta_surface_get_extents,
323 NULL, /* old_show_glyphs */
324 NULL, /* get_font_options */
325 NULL, /* flush */
326 NULL, /* mark_dirty_rectangle */
327 NULL, /* scaled_font_fini */
328 NULL, /* scaled_glyph_fini */
329 _test_meta_surface_paint,
330 _test_meta_surface_mask,
331 _test_meta_surface_stroke,
332 _test_meta_surface_fill,
333 NULL, /* show_glyphs */
334 _test_meta_surface_snapshot,
335 NULL, /* is_similar */
336 NULL, /* reset */
337 NULL, /* fill_stroke */
338 NULL, /* create_solid_pattern_surface */
339 NULL, /* can_repaint_solid_pattern_surface */
340 _test_meta_surface_has_show_text_glyphs,
341 _test_meta_surface_show_text_glyphs
342 };
343