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