1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2005 Red Hat, Inc
4  * Copyright © 2007 Adrian Johnson
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Red Hat, Inc.
32  *
33  * Contributor(s):
34  *	Carl Worth <cworth@cworth.org>
35  *	Keith Packard <keithp@keithp.com>
36  *	Adrian Johnson <ajohnson@redneon.com>
37  */
38 
39 /* The paginated surface layer exists to provide as much code sharing
40  * as possible for the various paginated surface backends in cairo
41  * (PostScript, PDF, etc.). See cairo-paginated-private.h for
42  * more details on how it works and how to use it.
43  */
44 
45 #include "cairoint.h"
46 
47 #include "cairo-paginated-private.h"
48 #include "cairo-paginated-surface-private.h"
49 #include "cairo-recording-surface-private.h"
50 #include "cairo-analysis-surface-private.h"
51 #include "cairo-error-private.h"
52 #include "cairo-image-surface-private.h"
53 #include "cairo-surface-subsurface-inline.h"
54 
55 static const cairo_surface_backend_t cairo_paginated_surface_backend;
56 
57 static cairo_int_status_t
58 _cairo_paginated_surface_show_page (void *abstract_surface);
59 
60 static cairo_surface_t *
_cairo_paginated_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)61 _cairo_paginated_surface_create_similar (void			*abstract_surface,
62 					 cairo_content_t	 content,
63 					 int			 width,
64 					 int			 height)
65 {
66     cairo_rectangle_t rect;
67     rect.x = rect.y = 0.;
68     rect.width = width;
69     rect.height = height;
70     return cairo_recording_surface_create (content, &rect);
71 }
72 
73 static cairo_surface_t *
_create_recording_surface_for_target(cairo_surface_t * target,cairo_content_t content)74 _create_recording_surface_for_target (cairo_surface_t *target,
75 				      cairo_content_t content)
76 {
77     cairo_rectangle_int_t rect;
78 
79     if (_cairo_surface_get_extents (target, &rect)) {
80 	cairo_rectangle_t recording_extents;
81 
82 	recording_extents.x = rect.x;
83 	recording_extents.y = rect.y;
84 	recording_extents.width = rect.width;
85 	recording_extents.height = rect.height;
86 
87 	return cairo_recording_surface_create (content, &recording_extents);
88     } else {
89 	return cairo_recording_surface_create (content, NULL);
90     }
91 }
92 
93 cairo_surface_t *
_cairo_paginated_surface_create(cairo_surface_t * target,cairo_content_t content,const cairo_paginated_surface_backend_t * backend)94 _cairo_paginated_surface_create (cairo_surface_t				*target,
95 				 cairo_content_t				 content,
96 				 const cairo_paginated_surface_backend_t	*backend)
97 {
98     cairo_paginated_surface_t *surface;
99     cairo_status_t status;
100 
101     surface = _cairo_malloc (sizeof (cairo_paginated_surface_t));
102     if (unlikely (surface == NULL)) {
103 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
104 	goto FAIL;
105     }
106 
107     _cairo_surface_init (&surface->base,
108 			 &cairo_paginated_surface_backend,
109 			 NULL, /* device */
110 			 content,
111 			 target->is_vector);
112 
113     /* Override surface->base.type with target's type so we don't leak
114      * evidence of the paginated wrapper out to the user. */
115     surface->base.type = target->type;
116 
117     surface->target = cairo_surface_reference (target);
118 
119     surface->content = content;
120     surface->backend = backend;
121 
122     surface->recording_surface = _create_recording_surface_for_target (target, content);
123     status = surface->recording_surface->status;
124     if (unlikely (status))
125 	goto FAIL_CLEANUP_SURFACE;
126 
127     surface->page_num = 1;
128     surface->base.is_clear = TRUE;
129 
130     return &surface->base;
131 
132   FAIL_CLEANUP_SURFACE:
133     cairo_surface_destroy (target);
134     free (surface);
135   FAIL:
136     return _cairo_surface_create_in_error (status);
137 }
138 
139 cairo_bool_t
_cairo_surface_is_paginated(cairo_surface_t * surface)140 _cairo_surface_is_paginated (cairo_surface_t *surface)
141 {
142     return surface->backend == &cairo_paginated_surface_backend;
143 }
144 
145 cairo_surface_t *
_cairo_paginated_surface_get_target(cairo_surface_t * surface)146 _cairo_paginated_surface_get_target (cairo_surface_t *surface)
147 {
148     cairo_paginated_surface_t *paginated_surface;
149 
150     assert (_cairo_surface_is_paginated (surface));
151 
152     paginated_surface = (cairo_paginated_surface_t *) surface;
153     return paginated_surface->target;
154 }
155 
156 cairo_surface_t *
_cairo_paginated_surface_get_recording(cairo_surface_t * surface)157 _cairo_paginated_surface_get_recording (cairo_surface_t *surface)
158 {
159     cairo_paginated_surface_t *paginated_surface;
160 
161     assert (_cairo_surface_is_paginated (surface));
162 
163     paginated_surface = (cairo_paginated_surface_t *) surface;
164     return paginated_surface->recording_surface;
165 }
166 
167 cairo_status_t
_cairo_paginated_surface_set_size(cairo_surface_t * surface,int width,int height)168 _cairo_paginated_surface_set_size (cairo_surface_t	*surface,
169 				   int			 width,
170 				   int			 height)
171 {
172     cairo_paginated_surface_t *paginated_surface;
173     cairo_status_t status;
174     cairo_rectangle_t recording_extents;
175 
176     assert (_cairo_surface_is_paginated (surface));
177 
178     paginated_surface = (cairo_paginated_surface_t *) surface;
179 
180     recording_extents.x = 0;
181     recording_extents.y = 0;
182     recording_extents.width = width;
183     recording_extents.height = height;
184 
185     cairo_surface_destroy (paginated_surface->recording_surface);
186     paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content,
187 									   &recording_extents);
188     status = paginated_surface->recording_surface->status;
189     if (unlikely (status))
190 	return _cairo_surface_set_error (surface, status);
191 
192     return CAIRO_STATUS_SUCCESS;
193 }
194 
195 static cairo_status_t
_cairo_paginated_surface_finish(void * abstract_surface)196 _cairo_paginated_surface_finish (void *abstract_surface)
197 {
198     cairo_paginated_surface_t *surface = abstract_surface;
199     cairo_status_t status = CAIRO_STATUS_SUCCESS;
200 
201     if (! surface->base.is_clear || surface->page_num == 1) {
202 	/* Bypass some of the sanity checking in cairo-surface.c, as we
203 	 * know that the surface is finished...
204 	 */
205 	status = _cairo_paginated_surface_show_page (surface);
206     }
207 
208      /* XXX We want to propagate any errors from destroy(), but those are not
209       * returned via the api. So we need to explicitly finish the target,
210       * and check the status afterwards. However, we can only call finish()
211       * on the target, if we own it.
212       */
213     if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
214 	cairo_surface_finish (surface->target);
215     if (status == CAIRO_STATUS_SUCCESS)
216 	status = cairo_surface_status (surface->target);
217     cairo_surface_destroy (surface->target);
218 
219     cairo_surface_finish (surface->recording_surface);
220     if (status == CAIRO_STATUS_SUCCESS)
221 	status = cairo_surface_status (surface->recording_surface);
222     cairo_surface_destroy (surface->recording_surface);
223 
224     return status;
225 }
226 
227 static cairo_surface_t *
_cairo_paginated_surface_create_image_surface(void * abstract_surface,int width,int height)228 _cairo_paginated_surface_create_image_surface (void	       *abstract_surface,
229 					       int		width,
230 					       int		height)
231 {
232     cairo_paginated_surface_t *surface = abstract_surface;
233     cairo_surface_t *image;
234     cairo_font_options_t options;
235 
236     image = _cairo_image_surface_create_with_content (surface->content,
237 						      width,
238 						      height);
239 
240     cairo_surface_get_font_options (&surface->base, &options);
241     _cairo_surface_set_font_options (image, &options);
242 
243     return image;
244 }
245 
246 static cairo_surface_t *
_cairo_paginated_surface_source(void * abstract_surface,cairo_rectangle_int_t * extents)247 _cairo_paginated_surface_source (void	       *abstract_surface,
248 				 cairo_rectangle_int_t *extents)
249 {
250     cairo_paginated_surface_t *surface = abstract_surface;
251     return _cairo_surface_get_source (surface->target, extents);
252 }
253 
254 static cairo_status_t
_cairo_paginated_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)255 _cairo_paginated_surface_acquire_source_image (void	       *abstract_surface,
256 					       cairo_image_surface_t **image_out,
257 					       void		   **image_extra)
258 {
259     cairo_paginated_surface_t *surface = abstract_surface;
260     cairo_bool_t is_bounded;
261     cairo_surface_t *image;
262     cairo_status_t status;
263     cairo_rectangle_int_t extents;
264 
265     is_bounded = _cairo_surface_get_extents (surface->target, &extents);
266     if (! is_bounded)
267 	return CAIRO_INT_STATUS_UNSUPPORTED;
268 
269     image = _cairo_paginated_surface_create_image_surface (surface,
270 							   extents.width,
271 							   extents.height);
272 
273     status = _cairo_recording_surface_replay (surface->recording_surface, image);
274     if (unlikely (status)) {
275 	cairo_surface_destroy (image);
276 	return status;
277     }
278 
279     *image_out = (cairo_image_surface_t*) image;
280     *image_extra = NULL;
281 
282     return CAIRO_STATUS_SUCCESS;
283 }
284 
285 static void
_cairo_paginated_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)286 _cairo_paginated_surface_release_source_image (void	  *abstract_surface,
287 					       cairo_image_surface_t *image,
288 					       void	       *image_extra)
289 {
290     cairo_surface_destroy (&image->base);
291 }
292 
293 static cairo_int_status_t
_paint_thumbnail_image(cairo_paginated_surface_t * surface,int width,int height)294 _paint_thumbnail_image (cairo_paginated_surface_t *surface,
295 			int                        width,
296 			int                        height)
297 {
298     cairo_surface_pattern_t pattern;
299     cairo_rectangle_int_t extents;
300     double x_scale;
301     double y_scale;
302     cairo_surface_t *image = NULL;
303     cairo_surface_t *opaque = NULL;
304     cairo_status_t status = CAIRO_STATUS_SUCCESS;
305 
306     _cairo_surface_get_extents (surface->target, &extents);
307     x_scale = (double)width / extents.width;
308     y_scale = (double)height / extents.height;
309 
310     image = _cairo_paginated_surface_create_image_surface (surface, width, height);
311     cairo_surface_set_device_scale (image, x_scale, y_scale);
312     cairo_surface_set_device_offset (image, -extents.x*x_scale, -extents.y*y_scale);
313     status = _cairo_recording_surface_replay (surface->recording_surface, image);
314     if (unlikely (status))
315 	goto cleanup;
316 
317     /* flatten transparency */
318 
319     opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
320     if (unlikely (opaque->status)) {
321 	status = opaque->status;
322 	goto cleanup;
323     }
324 
325     status = _cairo_surface_paint (opaque,
326 				   CAIRO_OPERATOR_SOURCE,
327 				   &_cairo_pattern_white.base,
328 				   NULL);
329     if (unlikely (status))
330 	goto cleanup;
331 
332     _cairo_pattern_init_for_surface (&pattern, image);
333     pattern.base.filter = CAIRO_FILTER_NEAREST;
334     status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
335     _cairo_pattern_fini (&pattern.base);
336     if (unlikely (status))
337 	goto cleanup;
338 
339     status = surface->backend->set_thumbnail_image (surface->target, (cairo_image_surface_t *)opaque);
340 
341   cleanup:
342     if (image)
343 	cairo_surface_destroy (image);
344     if (opaque)
345 	cairo_surface_destroy (opaque);
346 
347     return status;
348 }
349 
350 static cairo_int_status_t
_paint_fallback_image(cairo_paginated_surface_t * surface,cairo_rectangle_int_t * rect)351 _paint_fallback_image (cairo_paginated_surface_t *surface,
352 		       cairo_rectangle_int_t     *rect)
353 {
354     double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
355     double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
356     int x, y, width, height;
357     cairo_status_t status;
358     cairo_surface_t *image;
359     cairo_surface_pattern_t pattern;
360     cairo_clip_t *clip;
361 
362     x = rect->x;
363     y = rect->y;
364     width = rect->width;
365     height = rect->height;
366     image = _cairo_paginated_surface_create_image_surface (surface,
367 							   ceil (width  * x_scale),
368 							   ceil (height * y_scale));
369     cairo_surface_set_device_scale (image, x_scale, y_scale);
370     /* set_device_offset just sets the x0/y0 components of the matrix;
371      * so we have to do the scaling manually. */
372     cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
373 
374     status = _cairo_recording_surface_replay (surface->recording_surface, image);
375     if (unlikely (status))
376 	goto CLEANUP_IMAGE;
377 
378     _cairo_pattern_init_for_surface (&pattern, image);
379     cairo_matrix_init (&pattern.base.matrix,
380 		       x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
381     /* the fallback should be rendered at native resolution, so disable
382      * filtering (if possible) to avoid introducing potential artifacts. */
383     pattern.base.filter = CAIRO_FILTER_NEAREST;
384 
385     clip = _cairo_clip_intersect_rectangle (NULL, rect);
386     status = _cairo_surface_paint (surface->target,
387 				   CAIRO_OPERATOR_SOURCE,
388 				   &pattern.base, clip);
389     _cairo_clip_destroy (clip);
390     _cairo_pattern_fini (&pattern.base);
391 
392 CLEANUP_IMAGE:
393     cairo_surface_destroy (image);
394 
395     return status;
396 }
397 
398 static cairo_int_status_t
_paint_page(cairo_paginated_surface_t * surface)399 _paint_page (cairo_paginated_surface_t *surface)
400 {
401     cairo_surface_t *analysis;
402     cairo_int_status_t status;
403     cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
404 
405     if (unlikely (surface->target->status))
406 	return surface->target->status;
407 
408     analysis = _cairo_analysis_surface_create (surface->target);
409     if (unlikely (analysis->status))
410 	return _cairo_surface_set_error (surface->target, analysis->status);
411 
412     status = surface->backend->set_paginated_mode (surface->target,
413 	                                  CAIRO_PAGINATED_MODE_ANALYZE);
414     if (unlikely (status))
415 	goto FAIL;
416 
417     status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
418 								 NULL, analysis, FALSE);
419     if (status)
420 	goto FAIL;
421 
422     assert (analysis->status == CAIRO_STATUS_SUCCESS);
423 
424      if (surface->backend->set_bounding_box) {
425 	 cairo_box_t bbox;
426 
427 	 _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
428 	 status = surface->backend->set_bounding_box (surface->target, &bbox);
429 	 if (unlikely (status))
430 	     goto FAIL;
431      }
432 
433     if (surface->backend->set_fallback_images_required) {
434 	cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
435 
436 	status = surface->backend->set_fallback_images_required (surface->target,
437 								 has_fallbacks);
438 	if (unlikely (status))
439 	    goto FAIL;
440     }
441 
442     /* Finer grained fallbacks are currently only supported for some
443      * surface types */
444     if (surface->backend->supports_fine_grained_fallbacks != NULL &&
445 	surface->backend->supports_fine_grained_fallbacks (surface->target))
446     {
447 	has_supported = _cairo_analysis_surface_has_supported (analysis);
448 	has_page_fallback = FALSE;
449 	has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
450     }
451     else
452     {
453 	if (_cairo_analysis_surface_has_unsupported (analysis)) {
454 	    has_supported = FALSE;
455 	    has_page_fallback = TRUE;
456 	} else {
457 	    has_supported = TRUE;
458 	    has_page_fallback = FALSE;
459 	}
460 	has_finegrained_fallback = FALSE;
461     }
462 
463     if (has_supported) {
464 	status = surface->backend->set_paginated_mode (surface->target,
465 						       CAIRO_PAGINATED_MODE_RENDER);
466 	if (unlikely (status))
467 	    goto FAIL;
468 
469 	status = _cairo_recording_surface_replay_region (surface->recording_surface,
470 							 NULL,
471 							 surface->target,
472 							 CAIRO_RECORDING_REGION_NATIVE);
473 	assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
474 	if (unlikely (status))
475 	    goto FAIL;
476     }
477 
478     if (has_page_fallback) {
479 	cairo_rectangle_int_t extents;
480 	cairo_bool_t is_bounded;
481 
482 	status = surface->backend->set_paginated_mode (surface->target,
483 						       CAIRO_PAGINATED_MODE_FALLBACK);
484 	if (unlikely (status))
485 	    goto FAIL;
486 
487 	is_bounded = _cairo_surface_get_extents (surface->target, &extents);
488 	if (! is_bounded) {
489 	    status = CAIRO_INT_STATUS_UNSUPPORTED;
490 	    goto FAIL;
491 	}
492 
493 	status = _paint_fallback_image (surface, &extents);
494 	if (unlikely (status))
495 	    goto FAIL;
496     }
497 
498     if (has_finegrained_fallback) {
499         cairo_region_t *region;
500         int num_rects, i;
501 
502 	status = surface->backend->set_paginated_mode (surface->target,
503 		                              CAIRO_PAGINATED_MODE_FALLBACK);
504 	if (unlikely (status))
505 	    goto FAIL;
506 
507 	region = _cairo_analysis_surface_get_unsupported (analysis);
508 
509 	num_rects = cairo_region_num_rectangles (region);
510 	for (i = 0; i < num_rects; i++) {
511 	    cairo_rectangle_int_t rect;
512 
513 	    cairo_region_get_rectangle (region, i, &rect);
514 	    status = _paint_fallback_image (surface, &rect);
515 	    if (unlikely (status))
516 		goto FAIL;
517 	}
518     }
519 
520     if (surface->backend->requires_thumbnail_image) {
521 	int width, height;
522 
523 	if (surface->backend->requires_thumbnail_image (surface->target, &width, &height))
524 	    _paint_thumbnail_image (surface, width, height);
525     }
526 
527   FAIL:
528     cairo_surface_destroy (analysis);
529 
530     return _cairo_surface_set_error (surface->target, status);
531 }
532 
533 static cairo_status_t
_start_page(cairo_paginated_surface_t * surface)534 _start_page (cairo_paginated_surface_t *surface)
535 {
536     if (surface->target->status)
537 	return surface->target->status;
538 
539     if (! surface->backend->start_page)
540 	return CAIRO_STATUS_SUCCESS;
541 
542     return _cairo_surface_set_error (surface->target,
543 	                        surface->backend->start_page (surface->target));
544 }
545 
546 static cairo_int_status_t
_cairo_paginated_surface_copy_page(void * abstract_surface)547 _cairo_paginated_surface_copy_page (void *abstract_surface)
548 {
549     cairo_status_t status;
550     cairo_paginated_surface_t *surface = abstract_surface;
551 
552     status = _start_page (surface);
553     if (unlikely (status))
554 	return status;
555 
556     status = _paint_page (surface);
557     if (unlikely (status))
558 	return status;
559 
560     surface->page_num++;
561 
562     /* XXX: It might make sense to add some support here for calling
563      * cairo_surface_copy_page on the target surface. It would be an
564      * optimization for the output, but the interaction with image
565      * fallbacks gets tricky. For now, we just let the target see a
566      * show_page and we implement the copying by simply not destroying
567      * the recording-surface. */
568 
569     cairo_surface_show_page (surface->target);
570     return cairo_surface_status (surface->target);
571 }
572 
573 static cairo_int_status_t
_cairo_paginated_surface_show_page(void * abstract_surface)574 _cairo_paginated_surface_show_page (void *abstract_surface)
575 {
576     cairo_status_t status;
577     cairo_paginated_surface_t *surface = abstract_surface;
578 
579     status = _start_page (surface);
580     if (unlikely (status))
581 	return status;
582 
583     status = _paint_page (surface);
584     if (unlikely (status))
585 	return status;
586 
587     cairo_surface_show_page (surface->target);
588     status = surface->target->status;
589     if (unlikely (status))
590 	return status;
591 
592     status = surface->recording_surface->status;
593     if (unlikely (status))
594 	return status;
595 
596     if (! surface->base.finished) {
597 	cairo_surface_destroy (surface->recording_surface);
598 
599 	surface->recording_surface = _create_recording_surface_for_target (surface->target,
600 									   surface->content);
601 	status = surface->recording_surface->status;
602 	if (unlikely (status))
603 	    return status;
604 
605 	surface->page_num++;
606 	surface->base.is_clear = TRUE;
607     }
608 
609     return CAIRO_STATUS_SUCCESS;
610 }
611 
612 static cairo_bool_t
_cairo_paginated_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)613 _cairo_paginated_surface_get_extents (void	              *abstract_surface,
614 				      cairo_rectangle_int_t   *rectangle)
615 {
616     cairo_paginated_surface_t *surface = abstract_surface;
617 
618     return _cairo_surface_get_extents (surface->target, rectangle);
619 }
620 
621 static void
_cairo_paginated_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)622 _cairo_paginated_surface_get_font_options (void                  *abstract_surface,
623 					   cairo_font_options_t  *options)
624 {
625     cairo_paginated_surface_t *surface = abstract_surface;
626 
627     cairo_surface_get_font_options (surface->target, options);
628 }
629 
630 static cairo_int_status_t
_cairo_paginated_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_clip_t * clip)631 _cairo_paginated_surface_paint (void			*abstract_surface,
632 				cairo_operator_t	 op,
633 				const cairo_pattern_t	*source,
634 				const cairo_clip_t	*clip)
635 {
636     cairo_paginated_surface_t *surface = abstract_surface;
637 
638     return _cairo_surface_paint (surface->recording_surface, op, source, clip);
639 }
640 
641 static cairo_int_status_t
_cairo_paginated_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,const cairo_clip_t * clip)642 _cairo_paginated_surface_mask (void		*abstract_surface,
643 			       cairo_operator_t	 op,
644 			       const cairo_pattern_t	*source,
645 			       const cairo_pattern_t	*mask,
646 			       const cairo_clip_t		*clip)
647 {
648     cairo_paginated_surface_t *surface = abstract_surface;
649 
650     return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
651 }
652 
653 static cairo_int_status_t
_cairo_paginated_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const 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,const cairo_clip_t * clip)654 _cairo_paginated_surface_stroke (void			*abstract_surface,
655 				 cairo_operator_t	 op,
656 				 const cairo_pattern_t	*source,
657 				 const cairo_path_fixed_t	*path,
658 				 const cairo_stroke_style_t	*style,
659 				 const cairo_matrix_t		*ctm,
660 				 const cairo_matrix_t		*ctm_inverse,
661 				 double			 tolerance,
662 				 cairo_antialias_t	 antialias,
663 				 const cairo_clip_t		*clip)
664 {
665     cairo_paginated_surface_t *surface = abstract_surface;
666 
667     return _cairo_surface_stroke (surface->recording_surface, op, source,
668 				  path, style,
669 				  ctm, ctm_inverse,
670 				  tolerance, antialias,
671 				  clip);
672 }
673 
674 static cairo_int_status_t
_cairo_paginated_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,const cairo_clip_t * clip)675 _cairo_paginated_surface_fill (void			*abstract_surface,
676 			       cairo_operator_t		 op,
677 			       const cairo_pattern_t	*source,
678 			       const cairo_path_fixed_t	*path,
679 			       cairo_fill_rule_t	 fill_rule,
680 			       double			 tolerance,
681 			       cairo_antialias_t	 antialias,
682 			       const cairo_clip_t		*clip)
683 {
684     cairo_paginated_surface_t *surface = abstract_surface;
685 
686     return _cairo_surface_fill (surface->recording_surface, op, source,
687 				path, fill_rule,
688 				tolerance, antialias,
689 				clip);
690 }
691 
692 static cairo_bool_t
_cairo_paginated_surface_has_show_text_glyphs(void * abstract_surface)693 _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
694 {
695     cairo_paginated_surface_t *surface = abstract_surface;
696 
697     return cairo_surface_has_show_text_glyphs (surface->target);
698 }
699 
700 static cairo_int_status_t
_cairo_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,const cairo_clip_t * clip)701 _cairo_paginated_surface_show_text_glyphs (void			      *abstract_surface,
702 					   cairo_operator_t	       op,
703 					   const cairo_pattern_t      *source,
704 					   const char		      *utf8,
705 					   int			       utf8_len,
706 					   cairo_glyph_t	      *glyphs,
707 					   int			       num_glyphs,
708 					   const cairo_text_cluster_t *clusters,
709 					   int			       num_clusters,
710 					   cairo_text_cluster_flags_t  cluster_flags,
711 					   cairo_scaled_font_t	      *scaled_font,
712 					   const cairo_clip_t		      *clip)
713 {
714     cairo_paginated_surface_t *surface = abstract_surface;
715 
716     return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
717 					    utf8, utf8_len,
718 					    glyphs, num_glyphs,
719 					    clusters, num_clusters,
720 					    cluster_flags,
721 					    scaled_font,
722 					    clip);
723 }
724 
725 static const char **
_cairo_paginated_surface_get_supported_mime_types(void * abstract_surface)726 _cairo_paginated_surface_get_supported_mime_types (void *abstract_surface)
727 {
728     cairo_paginated_surface_t *surface = abstract_surface;
729 
730     if (surface->target->backend->get_supported_mime_types)
731 	return surface->target->backend->get_supported_mime_types (surface->target);
732 
733     return NULL;
734 }
735 
736 static cairo_int_status_t
_cairo_paginated_surface_tag(void * abstract_surface,cairo_bool_t begin,const char * tag_name,const char * attributes)737 _cairo_paginated_surface_tag (void			 *abstract_surface,
738 			      cairo_bool_t                begin,
739 			      const char                 *tag_name,
740 			      const char                 *attributes)
741 {
742     cairo_paginated_surface_t *surface = abstract_surface;
743 
744     return _cairo_surface_tag (surface->recording_surface,
745 			       begin, tag_name, attributes);
746 }
747 
748 static cairo_surface_t *
_cairo_paginated_surface_snapshot(void * abstract_other)749 _cairo_paginated_surface_snapshot (void *abstract_other)
750 {
751     cairo_paginated_surface_t *other = abstract_other;
752 
753     return other->recording_surface->backend->snapshot (other->recording_surface);
754 }
755 
756 static cairo_t *
_cairo_paginated_context_create(void * target)757 _cairo_paginated_context_create (void *target)
758 {
759     cairo_paginated_surface_t *surface = target;
760 
761     if (_cairo_surface_is_subsurface (&surface->base))
762 	surface = (cairo_paginated_surface_t *)
763 	    _cairo_surface_subsurface_get_target (&surface->base);
764 
765     return surface->recording_surface->backend->create_context (target);
766 }
767 
768 static const cairo_surface_backend_t cairo_paginated_surface_backend = {
769     CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
770     _cairo_paginated_surface_finish,
771 
772     _cairo_paginated_context_create,
773 
774     _cairo_paginated_surface_create_similar,
775     NULL, /* create similar image */
776     NULL, /* map to image */
777     NULL, /* unmap image */
778 
779     _cairo_paginated_surface_source,
780     _cairo_paginated_surface_acquire_source_image,
781     _cairo_paginated_surface_release_source_image,
782     _cairo_paginated_surface_snapshot,
783 
784     _cairo_paginated_surface_copy_page,
785     _cairo_paginated_surface_show_page,
786 
787     _cairo_paginated_surface_get_extents,
788     _cairo_paginated_surface_get_font_options,
789 
790     NULL, /* flush */
791     NULL, /* mark_dirty_rectangle */
792 
793     _cairo_paginated_surface_paint,
794     _cairo_paginated_surface_mask,
795     _cairo_paginated_surface_stroke,
796     _cairo_paginated_surface_fill,
797     NULL, /* fill_stroke */
798     NULL, /* show_glyphs */
799     _cairo_paginated_surface_has_show_text_glyphs,
800     _cairo_paginated_surface_show_text_glyphs,
801     _cairo_paginated_surface_get_supported_mime_types,
802     _cairo_paginated_surface_tag,
803 };
804