Line data Source code
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 :
53 : static const cairo_surface_backend_t cairo_paginated_surface_backend;
54 :
55 : static cairo_int_status_t
56 : _cairo_paginated_surface_show_page (void *abstract_surface);
57 :
58 : static cairo_surface_t *
59 0 : _cairo_paginated_surface_create_similar (void *abstract_surface,
60 : cairo_content_t content,
61 : int width,
62 : int height)
63 : {
64 : cairo_rectangle_t rect;
65 0 : rect.x = rect.y = 0.;
66 0 : rect.width = width;
67 0 : rect.height = height;
68 0 : return cairo_recording_surface_create (content, &rect);
69 : }
70 :
71 : static cairo_surface_t *
72 0 : _create_recording_surface_for_target (cairo_surface_t *target,
73 : cairo_content_t content)
74 : {
75 : cairo_rectangle_int_t rect;
76 :
77 0 : if (_cairo_surface_get_extents (target, &rect)) {
78 : cairo_rectangle_t recording_extents;
79 :
80 0 : recording_extents.x = rect.x;
81 0 : recording_extents.y = rect.y;
82 0 : recording_extents.width = rect.width;
83 0 : recording_extents.height = rect.height;
84 :
85 0 : return cairo_recording_surface_create (content, &recording_extents);
86 : } else {
87 0 : return cairo_recording_surface_create (content, NULL);
88 : }
89 : }
90 :
91 : cairo_surface_t *
92 0 : _cairo_paginated_surface_create (cairo_surface_t *target,
93 : cairo_content_t content,
94 : const cairo_paginated_surface_backend_t *backend)
95 : {
96 : cairo_paginated_surface_t *surface;
97 : cairo_status_t status;
98 :
99 0 : surface = malloc (sizeof (cairo_paginated_surface_t));
100 0 : if (unlikely (surface == NULL)) {
101 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
102 0 : goto FAIL;
103 : }
104 :
105 0 : _cairo_surface_init (&surface->base,
106 : &cairo_paginated_surface_backend,
107 : NULL, /* device */
108 : content);
109 :
110 : /* Override surface->base.type with target's type so we don't leak
111 : * evidence of the paginated wrapper out to the user. */
112 0 : surface->base.type = target->type;
113 :
114 0 : surface->target = cairo_surface_reference (target);
115 :
116 0 : surface->content = content;
117 0 : surface->backend = backend;
118 :
119 0 : surface->recording_surface = _create_recording_surface_for_target (target, content);
120 0 : status = surface->recording_surface->status;
121 0 : if (unlikely (status))
122 0 : goto FAIL_CLEANUP_SURFACE;
123 :
124 0 : surface->page_num = 1;
125 0 : surface->base.is_clear = TRUE;
126 :
127 0 : return &surface->base;
128 :
129 : FAIL_CLEANUP_SURFACE:
130 0 : cairo_surface_destroy (target);
131 0 : free (surface);
132 : FAIL:
133 0 : return _cairo_surface_create_in_error (status);
134 : }
135 :
136 : cairo_bool_t
137 0 : _cairo_surface_is_paginated (cairo_surface_t *surface)
138 : {
139 0 : return surface->backend == &cairo_paginated_surface_backend;
140 : }
141 :
142 : cairo_surface_t *
143 0 : _cairo_paginated_surface_get_target (cairo_surface_t *surface)
144 : {
145 : cairo_paginated_surface_t *paginated_surface;
146 :
147 0 : assert (_cairo_surface_is_paginated (surface));
148 :
149 0 : paginated_surface = (cairo_paginated_surface_t *) surface;
150 :
151 0 : return paginated_surface->target;
152 : }
153 :
154 : static cairo_status_t
155 0 : _cairo_paginated_surface_finish (void *abstract_surface)
156 : {
157 0 : cairo_paginated_surface_t *surface = abstract_surface;
158 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
159 :
160 0 : if (! surface->base.is_clear || surface->page_num == 1) {
161 : /* Bypass some of the sanity checking in cairo-surface.c, as we
162 : * know that the surface is finished...
163 : */
164 0 : status = _cairo_paginated_surface_show_page (surface);
165 : }
166 :
167 : /* XXX We want to propagate any errors from destroy(), but those are not
168 : * returned via the api. So we need to explicitly finish the target,
169 : * and check the status afterwards. However, we can only call finish()
170 : * on the target, if we own it.
171 : */
172 0 : if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
173 0 : cairo_surface_finish (surface->target);
174 0 : if (status == CAIRO_STATUS_SUCCESS)
175 0 : status = cairo_surface_status (surface->target);
176 0 : cairo_surface_destroy (surface->target);
177 :
178 0 : cairo_surface_finish (surface->recording_surface);
179 0 : if (status == CAIRO_STATUS_SUCCESS)
180 0 : status = cairo_surface_status (surface->recording_surface);
181 0 : cairo_surface_destroy (surface->recording_surface);
182 :
183 0 : return status;
184 : }
185 :
186 : static cairo_surface_t *
187 0 : _cairo_paginated_surface_create_image_surface (void *abstract_surface,
188 : int width,
189 : int height)
190 : {
191 0 : cairo_paginated_surface_t *surface = abstract_surface;
192 : cairo_surface_t *image;
193 : cairo_font_options_t options;
194 :
195 0 : image = _cairo_image_surface_create_with_content (surface->content,
196 : width,
197 : height);
198 :
199 0 : cairo_surface_get_font_options (&surface->base, &options);
200 0 : _cairo_surface_set_font_options (image, &options);
201 :
202 0 : return image;
203 : }
204 :
205 : static cairo_status_t
206 0 : _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
207 : cairo_image_surface_t **image_out,
208 : void **image_extra)
209 : {
210 0 : cairo_paginated_surface_t *surface = abstract_surface;
211 : cairo_bool_t is_bounded;
212 : cairo_surface_t *image;
213 : cairo_status_t status;
214 : cairo_rectangle_int_t extents;
215 :
216 0 : is_bounded = _cairo_surface_get_extents (surface->target, &extents);
217 0 : if (! is_bounded)
218 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
219 :
220 0 : image = _cairo_paginated_surface_create_image_surface (surface,
221 : extents.width,
222 : extents.height);
223 :
224 0 : status = _cairo_recording_surface_replay (surface->recording_surface, image);
225 0 : if (unlikely (status)) {
226 0 : cairo_surface_destroy (image);
227 0 : return status;
228 : }
229 :
230 0 : *image_out = (cairo_image_surface_t*) image;
231 0 : *image_extra = NULL;
232 :
233 0 : return CAIRO_STATUS_SUCCESS;
234 : }
235 :
236 : static void
237 0 : _cairo_paginated_surface_release_source_image (void *abstract_surface,
238 : cairo_image_surface_t *image,
239 : void *image_extra)
240 : {
241 0 : cairo_surface_destroy (&image->base);
242 0 : }
243 :
244 : static cairo_int_status_t
245 0 : _paint_fallback_image (cairo_paginated_surface_t *surface,
246 : cairo_rectangle_int_t *rect)
247 : {
248 0 : double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
249 0 : double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
250 : int x, y, width, height;
251 : cairo_status_t status;
252 : cairo_surface_t *image;
253 : cairo_surface_pattern_t pattern;
254 : cairo_clip_t clip;
255 :
256 0 : x = rect->x;
257 0 : y = rect->y;
258 0 : width = rect->width;
259 0 : height = rect->height;
260 0 : image = _cairo_paginated_surface_create_image_surface (surface,
261 0 : ceil (width * x_scale),
262 0 : ceil (height * y_scale));
263 0 : _cairo_surface_set_device_scale (image, x_scale, y_scale);
264 : /* set_device_offset just sets the x0/y0 components of the matrix;
265 : * so we have to do the scaling manually. */
266 0 : cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
267 :
268 0 : status = _cairo_recording_surface_replay (surface->recording_surface, image);
269 0 : if (unlikely (status))
270 0 : goto CLEANUP_IMAGE;
271 :
272 0 : _cairo_pattern_init_for_surface (&pattern, image);
273 0 : cairo_matrix_init (&pattern.base.matrix,
274 0 : x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
275 : /* the fallback should be rendered at native resolution, so disable
276 : * filtering (if possible) to avoid introducing potential artifacts. */
277 0 : pattern.base.filter = CAIRO_FILTER_NEAREST;
278 :
279 0 : _cairo_clip_init (&clip);
280 0 : status = _cairo_clip_rectangle (&clip, rect);
281 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
282 0 : status = _cairo_surface_paint (surface->target,
283 : CAIRO_OPERATOR_SOURCE,
284 : &pattern.base, &clip);
285 : }
286 :
287 0 : _cairo_clip_fini (&clip);
288 0 : _cairo_pattern_fini (&pattern.base);
289 :
290 : CLEANUP_IMAGE:
291 0 : cairo_surface_destroy (image);
292 :
293 0 : return status;
294 : }
295 :
296 : static cairo_int_status_t
297 0 : _paint_page (cairo_paginated_surface_t *surface)
298 : {
299 : cairo_surface_t *analysis;
300 : cairo_status_t status;
301 : cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
302 :
303 0 : if (unlikely (surface->target->status))
304 0 : return surface->target->status;
305 :
306 0 : analysis = _cairo_analysis_surface_create (surface->target);
307 0 : if (unlikely (analysis->status))
308 0 : return _cairo_surface_set_error (surface->target, analysis->status);
309 :
310 0 : surface->backend->set_paginated_mode (surface->target,
311 : CAIRO_PAGINATED_MODE_ANALYZE);
312 0 : status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
313 : analysis);
314 0 : if (status || analysis->status) {
315 0 : if (status == CAIRO_STATUS_SUCCESS)
316 0 : status = analysis->status;
317 0 : goto FAIL;
318 : }
319 :
320 0 : if (surface->backend->set_bounding_box) {
321 : cairo_box_t bbox;
322 :
323 0 : _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
324 0 : status = surface->backend->set_bounding_box (surface->target, &bbox);
325 0 : if (unlikely (status))
326 0 : goto FAIL;
327 : }
328 :
329 0 : if (surface->backend->set_fallback_images_required) {
330 0 : cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
331 :
332 0 : status = surface->backend->set_fallback_images_required (surface->target,
333 : has_fallbacks);
334 0 : if (unlikely (status))
335 0 : goto FAIL;
336 : }
337 :
338 : /* Finer grained fallbacks are currently only supported for some
339 : * surface types */
340 0 : if (surface->backend->supports_fine_grained_fallbacks != NULL &&
341 0 : surface->backend->supports_fine_grained_fallbacks (surface->target))
342 : {
343 0 : has_supported = _cairo_analysis_surface_has_supported (analysis);
344 0 : has_page_fallback = FALSE;
345 0 : has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
346 : }
347 : else
348 : {
349 0 : if (_cairo_analysis_surface_has_unsupported (analysis)) {
350 0 : has_supported = FALSE;
351 0 : has_page_fallback = TRUE;
352 : } else {
353 0 : has_supported = TRUE;
354 0 : has_page_fallback = FALSE;
355 : }
356 0 : has_finegrained_fallback = FALSE;
357 : }
358 :
359 0 : if (has_supported) {
360 0 : surface->backend->set_paginated_mode (surface->target,
361 : CAIRO_PAGINATED_MODE_RENDER);
362 :
363 0 : status = _cairo_recording_surface_replay_region (surface->recording_surface,
364 : NULL,
365 : surface->target,
366 : CAIRO_RECORDING_REGION_NATIVE);
367 0 : assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
368 0 : if (unlikely (status))
369 0 : goto FAIL;
370 : }
371 :
372 0 : if (has_page_fallback) {
373 : cairo_rectangle_int_t extents;
374 : cairo_bool_t is_bounded;
375 :
376 0 : surface->backend->set_paginated_mode (surface->target,
377 : CAIRO_PAGINATED_MODE_FALLBACK);
378 :
379 0 : is_bounded = _cairo_surface_get_extents (surface->target, &extents);
380 0 : if (! is_bounded) {
381 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
382 0 : goto FAIL;
383 : }
384 :
385 0 : status = _paint_fallback_image (surface, &extents);
386 0 : if (unlikely (status))
387 0 : goto FAIL;
388 : }
389 :
390 0 : if (has_finegrained_fallback) {
391 : cairo_region_t *region;
392 : int num_rects, i;
393 :
394 0 : surface->backend->set_paginated_mode (surface->target,
395 : CAIRO_PAGINATED_MODE_FALLBACK);
396 :
397 0 : region = _cairo_analysis_surface_get_unsupported (analysis);
398 :
399 0 : num_rects = cairo_region_num_rectangles (region);
400 0 : for (i = 0; i < num_rects; i++) {
401 : cairo_rectangle_int_t rect;
402 :
403 0 : cairo_region_get_rectangle (region, i, &rect);
404 0 : status = _paint_fallback_image (surface, &rect);
405 0 : if (unlikely (status))
406 0 : goto FAIL;
407 : }
408 : }
409 :
410 : FAIL:
411 0 : cairo_surface_destroy (analysis);
412 :
413 0 : return _cairo_surface_set_error (surface->target, status);
414 : }
415 :
416 : static cairo_status_t
417 0 : _start_page (cairo_paginated_surface_t *surface)
418 : {
419 0 : if (surface->target->status)
420 0 : return surface->target->status;
421 :
422 0 : if (! surface->backend->start_page)
423 0 : return CAIRO_STATUS_SUCCESS;
424 :
425 0 : return _cairo_surface_set_error (surface->target,
426 0 : surface->backend->start_page (surface->target));
427 : }
428 :
429 : static cairo_int_status_t
430 0 : _cairo_paginated_surface_copy_page (void *abstract_surface)
431 : {
432 : cairo_status_t status;
433 0 : cairo_paginated_surface_t *surface = abstract_surface;
434 :
435 0 : status = _start_page (surface);
436 0 : if (unlikely (status))
437 0 : return status;
438 :
439 0 : status = _paint_page (surface);
440 0 : if (unlikely (status))
441 0 : return status;
442 :
443 0 : surface->page_num++;
444 :
445 : /* XXX: It might make sense to add some support here for calling
446 : * cairo_surface_copy_page on the target surface. It would be an
447 : * optimization for the output, but the interaction with image
448 : * fallbacks gets tricky. For now, we just let the target see a
449 : * show_page and we implement the copying by simply not destroying
450 : * the recording-surface. */
451 :
452 0 : cairo_surface_show_page (surface->target);
453 0 : return cairo_surface_status (surface->target);
454 : }
455 :
456 : static cairo_int_status_t
457 0 : _cairo_paginated_surface_show_page (void *abstract_surface)
458 : {
459 : cairo_status_t status;
460 0 : cairo_paginated_surface_t *surface = abstract_surface;
461 :
462 0 : status = _start_page (surface);
463 0 : if (unlikely (status))
464 0 : return status;
465 :
466 0 : status = _paint_page (surface);
467 0 : if (unlikely (status))
468 0 : return status;
469 :
470 0 : cairo_surface_show_page (surface->target);
471 0 : status = surface->target->status;
472 0 : if (unlikely (status))
473 0 : return status;
474 :
475 0 : status = surface->recording_surface->status;
476 0 : if (unlikely (status))
477 0 : return status;
478 :
479 0 : if (! surface->base.finished) {
480 0 : cairo_surface_destroy (surface->recording_surface);
481 :
482 0 : surface->recording_surface = _create_recording_surface_for_target (surface->target,
483 : surface->content);
484 0 : status = surface->recording_surface->status;
485 0 : if (unlikely (status))
486 0 : return status;
487 :
488 0 : surface->page_num++;
489 0 : surface->base.is_clear = TRUE;
490 : }
491 :
492 0 : return CAIRO_STATUS_SUCCESS;
493 : }
494 :
495 : static cairo_bool_t
496 0 : _cairo_paginated_surface_get_extents (void *abstract_surface,
497 : cairo_rectangle_int_t *rectangle)
498 : {
499 0 : cairo_paginated_surface_t *surface = abstract_surface;
500 :
501 0 : return _cairo_surface_get_extents (surface->target, rectangle);
502 : }
503 :
504 : static void
505 0 : _cairo_paginated_surface_get_font_options (void *abstract_surface,
506 : cairo_font_options_t *options)
507 : {
508 0 : cairo_paginated_surface_t *surface = abstract_surface;
509 :
510 0 : cairo_surface_get_font_options (surface->target, options);
511 0 : }
512 :
513 : static cairo_int_status_t
514 0 : _cairo_paginated_surface_paint (void *abstract_surface,
515 : cairo_operator_t op,
516 : const cairo_pattern_t *source,
517 : cairo_clip_t *clip)
518 : {
519 0 : cairo_paginated_surface_t *surface = abstract_surface;
520 :
521 0 : return _cairo_surface_paint (surface->recording_surface, op, source, clip);
522 : }
523 :
524 : static cairo_int_status_t
525 0 : _cairo_paginated_surface_mask (void *abstract_surface,
526 : cairo_operator_t op,
527 : const cairo_pattern_t *source,
528 : const cairo_pattern_t *mask,
529 : cairo_clip_t *clip)
530 : {
531 0 : cairo_paginated_surface_t *surface = abstract_surface;
532 :
533 0 : return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
534 : }
535 :
536 : static cairo_int_status_t
537 0 : _cairo_paginated_surface_stroke (void *abstract_surface,
538 : cairo_operator_t op,
539 : const cairo_pattern_t *source,
540 : cairo_path_fixed_t *path,
541 : const cairo_stroke_style_t *style,
542 : const cairo_matrix_t *ctm,
543 : const cairo_matrix_t *ctm_inverse,
544 : double tolerance,
545 : cairo_antialias_t antialias,
546 : cairo_clip_t *clip)
547 : {
548 0 : cairo_paginated_surface_t *surface = abstract_surface;
549 :
550 0 : return _cairo_surface_stroke (surface->recording_surface, op, source,
551 : path, style,
552 : ctm, ctm_inverse,
553 : tolerance, antialias,
554 : clip);
555 : }
556 :
557 : static cairo_int_status_t
558 0 : _cairo_paginated_surface_fill (void *abstract_surface,
559 : cairo_operator_t op,
560 : const cairo_pattern_t *source,
561 : cairo_path_fixed_t *path,
562 : cairo_fill_rule_t fill_rule,
563 : double tolerance,
564 : cairo_antialias_t antialias,
565 : cairo_clip_t *clip)
566 : {
567 0 : cairo_paginated_surface_t *surface = abstract_surface;
568 :
569 0 : return _cairo_surface_fill (surface->recording_surface, op, source,
570 : path, fill_rule,
571 : tolerance, antialias,
572 : clip);
573 : }
574 :
575 : static cairo_bool_t
576 0 : _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
577 : {
578 0 : cairo_paginated_surface_t *surface = abstract_surface;
579 :
580 0 : return cairo_surface_has_show_text_glyphs (surface->target);
581 : }
582 :
583 : static cairo_int_status_t
584 0 : _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
585 : cairo_operator_t op,
586 : const cairo_pattern_t *source,
587 : const char *utf8,
588 : int utf8_len,
589 : cairo_glyph_t *glyphs,
590 : int num_glyphs,
591 : const cairo_text_cluster_t *clusters,
592 : int num_clusters,
593 : cairo_text_cluster_flags_t cluster_flags,
594 : cairo_scaled_font_t *scaled_font,
595 : cairo_clip_t *clip)
596 : {
597 0 : cairo_paginated_surface_t *surface = abstract_surface;
598 :
599 0 : return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
600 : utf8, utf8_len,
601 : glyphs, num_glyphs,
602 : clusters, num_clusters,
603 : cluster_flags,
604 : scaled_font,
605 : clip);
606 : }
607 :
608 : static cairo_surface_t *
609 0 : _cairo_paginated_surface_snapshot (void *abstract_other)
610 : {
611 0 : cairo_paginated_surface_t *other = abstract_other;
612 :
613 0 : return _cairo_surface_snapshot (other->recording_surface);
614 : }
615 :
616 : static const cairo_surface_backend_t cairo_paginated_surface_backend = {
617 : CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
618 : _cairo_paginated_surface_create_similar,
619 : _cairo_paginated_surface_finish,
620 : _cairo_paginated_surface_acquire_source_image,
621 : _cairo_paginated_surface_release_source_image,
622 : NULL, /* acquire_dest_image */
623 : NULL, /* release_dest_image */
624 : NULL, /* clone_similar */
625 : NULL, /* composite */
626 : NULL, /* fill_rectangles */
627 : NULL, /* composite_trapezoids */
628 : NULL, /* create_span_renderer */
629 : NULL, /* check_span_renderer */
630 : _cairo_paginated_surface_copy_page,
631 : _cairo_paginated_surface_show_page,
632 : _cairo_paginated_surface_get_extents,
633 : NULL, /* old_show_glyphs */
634 : _cairo_paginated_surface_get_font_options,
635 : NULL, /* flush */
636 : NULL, /* mark_dirty_rectangle */
637 : NULL, /* scaled_font_fini */
638 : NULL, /* scaled_glyph_fini */
639 : _cairo_paginated_surface_paint,
640 : _cairo_paginated_surface_mask,
641 : _cairo_paginated_surface_stroke,
642 : _cairo_paginated_surface_fill,
643 : NULL, /* show_glyphs */
644 : _cairo_paginated_surface_snapshot,
645 : NULL, /* is_similar */
646 : NULL, /* fill_stroke */
647 : NULL, /* create_solid_pattern_surface */
648 : NULL, /* can_repaint_solid_pattern_surface */
649 : _cairo_paginated_surface_has_show_text_glyphs,
650 : _cairo_paginated_surface_show_text_glyphs
651 : };
|