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