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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 paginated-surface paths in cairo.
38  *
39  * The defining feature of this backend is that it uses a paginated
40  * surface to record all operations, and then replays everything to an
41  * image 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 paginated-surface-based
45  * backend.
46  */
47 
48 #include "cairoint.h"
49 
50 #include "test-paginated-surface.h"
51 
52 #include "cairo-error-private.h"
53 #include "cairo-paginated-private.h"
54 
55 typedef struct _test_paginated_surface {
56     cairo_surface_t base;
57     cairo_surface_t *target;
58     cairo_paginated_mode_t paginated_mode;
59 } test_paginated_surface_t;
60 
61 static const cairo_surface_backend_t test_paginated_surface_backend;
62 static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend;
63 
64 cairo_surface_t *
_cairo_test_paginated_surface_create(cairo_surface_t * target)65 _cairo_test_paginated_surface_create (cairo_surface_t *target)
66 {
67     cairo_status_t status;
68     cairo_surface_t *paginated;
69     test_paginated_surface_t *surface;
70 
71     status = cairo_surface_status (target);
72     if (unlikely (status))
73 	return _cairo_surface_create_in_error (status);
74 
75     surface = malloc (sizeof (test_paginated_surface_t));
76     if (unlikely (surface == NULL))
77 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
78 
79     _cairo_surface_init (&surface->base,
80 			 &test_paginated_surface_backend,
81 			 NULL, /* device */
82 			 target->content);
83 
84     surface->target = cairo_surface_reference (target);
85 
86     paginated =  _cairo_paginated_surface_create (&surface->base,
87 						  target->content,
88 						  &test_paginated_surface_paginated_backend);
89     status = paginated->status;
90     if (status == CAIRO_STATUS_SUCCESS) {
91 	/* paginated keeps the only reference to surface now, drop ours */
92 	cairo_surface_destroy (&surface->base);
93 	return paginated;
94     }
95 
96     cairo_surface_destroy (target);
97     free (surface);
98     return _cairo_surface_create_in_error (status);
99 }
100 
101 static cairo_status_t
_test_paginated_surface_finish(void * abstract_surface)102 _test_paginated_surface_finish (void *abstract_surface)
103 {
104     test_paginated_surface_t *surface = abstract_surface;
105 
106     cairo_surface_destroy (surface->target);
107 
108     return CAIRO_STATUS_SUCCESS;
109 }
110 
111 static cairo_bool_t
_test_paginated_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)112 _test_paginated_surface_get_extents (void			*abstract_surface,
113 				     cairo_rectangle_int_t	*rectangle)
114 {
115     test_paginated_surface_t *surface = abstract_surface;
116 
117     return _cairo_surface_get_extents (surface->target, rectangle);
118 }
119 
120 static cairo_int_status_t
_test_paginated_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)121 _test_paginated_surface_paint (void		*abstract_surface,
122 			       cairo_operator_t	 op,
123 			       const cairo_pattern_t	*source,
124 			       cairo_clip_t		*clip)
125 {
126     test_paginated_surface_t *surface = abstract_surface;
127 
128     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
129 	return CAIRO_STATUS_SUCCESS;
130 
131     return _cairo_surface_paint (surface->target, op, source, clip);
132 }
133 
134 static cairo_int_status_t
_test_paginated_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_clip_t * clip)135 _test_paginated_surface_mask (void		*abstract_surface,
136 			      cairo_operator_t	 op,
137 			      const cairo_pattern_t	*source,
138 			      const cairo_pattern_t	*mask,
139 			      cairo_clip_t		*clip)
140 {
141     test_paginated_surface_t *surface = abstract_surface;
142 
143     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
144 	return CAIRO_STATUS_SUCCESS;
145 
146     return _cairo_surface_mask (surface->target,
147 				op, source, mask, clip);
148 }
149 
150 static cairo_int_status_t
_test_paginated_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)151 _test_paginated_surface_stroke (void				*abstract_surface,
152 				cairo_operator_t		 op,
153 				const cairo_pattern_t		*source,
154 				cairo_path_fixed_t		*path,
155 				const cairo_stroke_style_t		*style,
156 				const cairo_matrix_t			*ctm,
157 				const cairo_matrix_t			*ctm_inverse,
158 				double				 tolerance,
159 				cairo_antialias_t		 antialias,
160 				cairo_clip_t			*clip)
161 {
162     test_paginated_surface_t *surface = abstract_surface;
163 
164     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
165 	return CAIRO_STATUS_SUCCESS;
166 
167     return _cairo_surface_stroke (surface->target, op, source,
168 				  path, style,
169 				  ctm, ctm_inverse,
170 				  tolerance, antialias,
171 				  clip);
172 }
173 
174 static cairo_int_status_t
_test_paginated_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_clip_t * clip)175 _test_paginated_surface_fill (void				*abstract_surface,
176 			      cairo_operator_t			 op,
177 			      const cairo_pattern_t		*source,
178 			      cairo_path_fixed_t		*path,
179 			      cairo_fill_rule_t			 fill_rule,
180 			      double				 tolerance,
181 			      cairo_antialias_t			 antialias,
182 			      cairo_clip_t			*clip)
183 {
184     test_paginated_surface_t *surface = abstract_surface;
185 
186     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
187 	return CAIRO_STATUS_SUCCESS;
188 
189     return _cairo_surface_fill (surface->target, op, source,
190 				path, fill_rule,
191 				tolerance, antialias,
192 				clip);
193 }
194 
195 static cairo_bool_t
_test_paginated_surface_has_show_text_glyphs(void * abstract_surface)196 _test_paginated_surface_has_show_text_glyphs (void *abstract_surface)
197 {
198     test_paginated_surface_t *surface = abstract_surface;
199 
200     return cairo_surface_has_show_text_glyphs (surface->target);
201 }
202 
203 static cairo_int_status_t
_test_paginated_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_clip_t * clip)204 _test_paginated_surface_show_text_glyphs (void			    *abstract_surface,
205 					  cairo_operator_t	     op,
206 					  const cairo_pattern_t	    *source,
207 					  const char		    *utf8,
208 					  int			     utf8_len,
209 					  cairo_glyph_t		    *glyphs,
210 					  int			     num_glyphs,
211 					  const cairo_text_cluster_t *clusters,
212 					  int			     num_clusters,
213 					  cairo_text_cluster_flags_t cluster_flags,
214 					  cairo_scaled_font_t	    *scaled_font,
215 					  cairo_clip_t		    *clip)
216 {
217     test_paginated_surface_t *surface = abstract_surface;
218 
219     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
220 	return CAIRO_STATUS_SUCCESS;
221 
222     return _cairo_surface_show_text_glyphs (surface->target, op, source,
223 					    utf8, utf8_len,
224 					    glyphs, num_glyphs,
225 					    clusters, num_clusters,
226 					    cluster_flags,
227 					    scaled_font,
228 					    clip);
229 }
230 
231 
232 static void
_test_paginated_surface_set_paginated_mode(void * abstract_surface,cairo_paginated_mode_t mode)233 _test_paginated_surface_set_paginated_mode (void			*abstract_surface,
234 					    cairo_paginated_mode_t	 mode)
235 {
236     test_paginated_surface_t *surface = abstract_surface;
237 
238     surface->paginated_mode = mode;
239 }
240 
241 static const cairo_surface_backend_t test_paginated_surface_backend = {
242     CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
243 
244     /* Since we are a paginated user, we get to regard most of the
245      * surface backend interface as historical cruft and ignore it. */
246 
247     NULL, /* create_similar */
248     _test_paginated_surface_finish,
249     NULL, /* acquire_source_image */
250     NULL, /* release_source_image */
251     NULL, /* acquire_dest_image */
252     NULL, /* release_dest_image */
253     NULL, /* clone_similar */
254     NULL, /* composite */
255     NULL, /* fill_rectangles */
256     NULL, /* composite_trapezoids */
257     NULL, /* create_span_renderer */
258     NULL, /* check_span_renderer */
259     NULL, /* copy_page */
260     NULL, /* show_page */
261     _test_paginated_surface_get_extents,
262     NULL, /* old_show_glyphs */
263     NULL, /* get_font_options */
264     NULL, /* flush */
265     NULL, /* mark_dirty_rectangle */
266     NULL, /* scaled_font_fini */
267     NULL, /* scaled_glyph_fini */
268 
269     /* Here is the more "modern" section of the surface backend
270      * interface which is mostly just drawing functions */
271 
272     _test_paginated_surface_paint,
273     _test_paginated_surface_mask,
274     _test_paginated_surface_stroke,
275     _test_paginated_surface_fill,
276     NULL, /* replaced by show_text_glyphs */
277 
278     NULL, /* snapshot */
279     NULL, /* is_similar */
280     NULL, /* fill_stroke */
281     NULL, /* create_solid_pattern_surface */
282     NULL, /* can_repaint_solid_pattern_surface */
283 
284     _test_paginated_surface_has_show_text_glyphs,
285     _test_paginated_surface_show_text_glyphs
286 };
287 
288 static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend = {
289     NULL, /* start_page */
290     _test_paginated_surface_set_paginated_mode
291 };
292