/work/workdir/UnpackedTarball/cairo/src/cairo-paginated-surface.c
Line | Count | Source (jump to first uncovered line) |
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 * |
61 | | _cairo_paginated_surface_create_similar (void *abstract_surface, |
62 | | cairo_content_t content, |
63 | | int width, |
64 | | int height) |
65 | 0 | { |
66 | 0 | cairo_rectangle_t rect; |
67 | 0 | rect.x = rect.y = 0.; |
68 | 0 | rect.width = width; |
69 | 0 | rect.height = height; |
70 | 0 | return cairo_recording_surface_create (content, &rect); |
71 | 0 | } |
72 | | |
73 | | static cairo_surface_t * |
74 | | _create_recording_surface_for_target (cairo_surface_t *target, |
75 | | cairo_content_t content) |
76 | 4 | { |
77 | 4 | cairo_rectangle_int_t rect; |
78 | | |
79 | 4 | if (_cairo_surface_get_extents (target, &rect)) { |
80 | 4 | cairo_rectangle_t recording_extents; |
81 | | |
82 | 4 | recording_extents.x = rect.x; |
83 | 4 | recording_extents.y = rect.y; |
84 | 4 | recording_extents.width = rect.width; |
85 | 4 | recording_extents.height = rect.height; |
86 | | |
87 | 4 | return cairo_recording_surface_create (content, &recording_extents); |
88 | 4 | } else { |
89 | 0 | return cairo_recording_surface_create (content, NULL); |
90 | 0 | } |
91 | 4 | } |
92 | | |
93 | | cairo_surface_t * |
94 | | _cairo_paginated_surface_create (cairo_surface_t *target, |
95 | | cairo_content_t content, |
96 | | const cairo_paginated_surface_backend_t *backend) |
97 | 2 | { |
98 | 2 | cairo_paginated_surface_t *surface; |
99 | 2 | cairo_status_t status; |
100 | | |
101 | 2 | surface = _cairo_malloc (sizeof (cairo_paginated_surface_t)); |
102 | 2 | if (unlikely (surface == NULL)) { |
103 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
104 | 0 | goto FAIL; |
105 | 0 | } |
106 | | |
107 | 2 | _cairo_surface_init (&surface->base, |
108 | 2 | &cairo_paginated_surface_backend, |
109 | 2 | NULL, /* device */ |
110 | 2 | content, |
111 | 2 | 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 | 2 | surface->base.type = target->type; |
116 | | |
117 | 2 | surface->target = cairo_surface_reference (target); |
118 | | |
119 | 2 | surface->content = content; |
120 | 2 | surface->backend = backend; |
121 | | |
122 | 2 | surface->recording_surface = _create_recording_surface_for_target (target, content); |
123 | 2 | status = surface->recording_surface->status; |
124 | 2 | if (unlikely (status)) |
125 | 0 | goto FAIL_CLEANUP_SURFACE; |
126 | | |
127 | 2 | surface->page_num = 1; |
128 | 2 | surface->base.is_clear = TRUE; |
129 | | |
130 | 2 | return &surface->base; |
131 | | |
132 | 0 | FAIL_CLEANUP_SURFACE: |
133 | 0 | cairo_surface_destroy (target); |
134 | 0 | free (surface); |
135 | 0 | FAIL: |
136 | 0 | return _cairo_surface_create_in_error (status); |
137 | 0 | } |
138 | | |
139 | | cairo_bool_t |
140 | | _cairo_surface_is_paginated (cairo_surface_t *surface) |
141 | 0 | { |
142 | 0 | return surface->backend == &cairo_paginated_surface_backend; |
143 | 0 | } |
144 | | |
145 | | cairo_surface_t * |
146 | | _cairo_paginated_surface_get_target (cairo_surface_t *surface) |
147 | 0 | { |
148 | 0 | cairo_paginated_surface_t *paginated_surface; |
149 | |
|
150 | 0 | assert (_cairo_surface_is_paginated (surface)); |
151 | | |
152 | 0 | paginated_surface = (cairo_paginated_surface_t *) surface; |
153 | 0 | return paginated_surface->target; |
154 | 0 | } |
155 | | |
156 | | cairo_surface_t * |
157 | | _cairo_paginated_surface_get_recording (cairo_surface_t *surface) |
158 | 0 | { |
159 | 0 | cairo_paginated_surface_t *paginated_surface; |
160 | |
|
161 | 0 | assert (_cairo_surface_is_paginated (surface)); |
162 | | |
163 | 0 | paginated_surface = (cairo_paginated_surface_t *) surface; |
164 | 0 | return paginated_surface->recording_surface; |
165 | 0 | } |
166 | | |
167 | | cairo_status_t |
168 | | _cairo_paginated_surface_set_size (cairo_surface_t *surface, |
169 | | int width, |
170 | | int height) |
171 | 0 | { |
172 | 0 | cairo_paginated_surface_t *paginated_surface; |
173 | 0 | cairo_status_t status; |
174 | 0 | cairo_rectangle_t recording_extents; |
175 | |
|
176 | 0 | assert (_cairo_surface_is_paginated (surface)); |
177 | | |
178 | 0 | paginated_surface = (cairo_paginated_surface_t *) surface; |
179 | |
|
180 | 0 | recording_extents.x = 0; |
181 | 0 | recording_extents.y = 0; |
182 | 0 | recording_extents.width = width; |
183 | 0 | recording_extents.height = height; |
184 | |
|
185 | 0 | cairo_surface_destroy (paginated_surface->recording_surface); |
186 | 0 | paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content, |
187 | 0 | &recording_extents); |
188 | 0 | status = paginated_surface->recording_surface->status; |
189 | 0 | if (unlikely (status)) |
190 | 0 | return _cairo_surface_set_error (surface, status); |
191 | | |
192 | 0 | return CAIRO_STATUS_SUCCESS; |
193 | 0 | } |
194 | | |
195 | | static cairo_status_t |
196 | | _cairo_paginated_surface_finish (void *abstract_surface) |
197 | 2 | { |
198 | 2 | cairo_paginated_surface_t *surface = abstract_surface; |
199 | 2 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
200 | | |
201 | 2 | 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 | 2 | status = _cairo_paginated_surface_show_page (surface); |
206 | 2 | } |
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 | 2 | if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) |
214 | 2 | cairo_surface_finish (surface->target); |
215 | 2 | if (status == CAIRO_STATUS_SUCCESS) |
216 | 2 | status = cairo_surface_status (surface->target); |
217 | 2 | cairo_surface_destroy (surface->target); |
218 | | |
219 | 2 | cairo_surface_finish (surface->recording_surface); |
220 | 2 | if (status == CAIRO_STATUS_SUCCESS) |
221 | 2 | status = cairo_surface_status (surface->recording_surface); |
222 | 2 | cairo_surface_destroy (surface->recording_surface); |
223 | | |
224 | 2 | return status; |
225 | 2 | } |
226 | | |
227 | | static cairo_surface_t * |
228 | | _cairo_paginated_surface_create_image_surface (void *abstract_surface, |
229 | | int width, |
230 | | int height) |
231 | 0 | { |
232 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
233 | 0 | cairo_surface_t *image; |
234 | 0 | cairo_font_options_t options; |
235 | |
|
236 | 0 | image = _cairo_image_surface_create_with_content (surface->content, |
237 | 0 | width, |
238 | 0 | height); |
239 | |
|
240 | 0 | cairo_surface_get_font_options (&surface->base, &options); |
241 | 0 | _cairo_surface_set_font_options (image, &options); |
242 | |
|
243 | 0 | return image; |
244 | 0 | } |
245 | | |
246 | | static cairo_surface_t * |
247 | | _cairo_paginated_surface_source (void *abstract_surface, |
248 | | cairo_rectangle_int_t *extents) |
249 | 0 | { |
250 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
251 | 0 | return _cairo_surface_get_source (surface->target, extents); |
252 | 0 | } |
253 | | |
254 | | static cairo_status_t |
255 | | _cairo_paginated_surface_acquire_source_image (void *abstract_surface, |
256 | | cairo_image_surface_t **image_out, |
257 | | void **image_extra) |
258 | 0 | { |
259 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
260 | 0 | cairo_bool_t is_bounded; |
261 | 0 | cairo_surface_t *image; |
262 | 0 | cairo_status_t status; |
263 | 0 | cairo_rectangle_int_t extents; |
264 | |
|
265 | 0 | is_bounded = _cairo_surface_get_extents (surface->target, &extents); |
266 | 0 | if (! is_bounded) |
267 | 0 | return CAIRO_INT_STATUS_UNSUPPORTED; |
268 | | |
269 | 0 | image = _cairo_paginated_surface_create_image_surface (surface, |
270 | 0 | extents.width, |
271 | 0 | extents.height); |
272 | |
|
273 | 0 | status = _cairo_recording_surface_replay (surface->recording_surface, image); |
274 | 0 | if (unlikely (status)) { |
275 | 0 | cairo_surface_destroy (image); |
276 | 0 | return status; |
277 | 0 | } |
278 | | |
279 | 0 | *image_out = (cairo_image_surface_t*) image; |
280 | 0 | *image_extra = NULL; |
281 | |
|
282 | 0 | return CAIRO_STATUS_SUCCESS; |
283 | 0 | } |
284 | | |
285 | | static void |
286 | | _cairo_paginated_surface_release_source_image (void *abstract_surface, |
287 | | cairo_image_surface_t *image, |
288 | | void *image_extra) |
289 | 0 | { |
290 | 0 | cairo_surface_destroy (&image->base); |
291 | 0 | } |
292 | | |
293 | | static cairo_int_status_t |
294 | | _paint_thumbnail_image (cairo_paginated_surface_t *surface, |
295 | | int width, |
296 | | int height) |
297 | 0 | { |
298 | 0 | cairo_surface_pattern_t pattern; |
299 | 0 | cairo_rectangle_int_t extents; |
300 | 0 | double x_scale; |
301 | 0 | double y_scale; |
302 | 0 | cairo_surface_t *image = NULL; |
303 | 0 | cairo_surface_t *opaque = NULL; |
304 | 0 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
305 | |
|
306 | 0 | _cairo_surface_get_extents (surface->target, &extents); |
307 | 0 | x_scale = (double)width / extents.width; |
308 | 0 | y_scale = (double)height / extents.height; |
309 | |
|
310 | 0 | image = _cairo_paginated_surface_create_image_surface (surface, width, height); |
311 | 0 | cairo_surface_set_device_scale (image, x_scale, y_scale); |
312 | 0 | cairo_surface_set_device_offset (image, -extents.x*x_scale, -extents.y*y_scale); |
313 | 0 | status = _cairo_recording_surface_replay (surface->recording_surface, image); |
314 | 0 | if (unlikely (status)) |
315 | 0 | goto cleanup; |
316 | | |
317 | | /* flatten transparency */ |
318 | | |
319 | 0 | opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); |
320 | 0 | if (unlikely (opaque->status)) { |
321 | 0 | status = opaque->status; |
322 | 0 | goto cleanup; |
323 | 0 | } |
324 | | |
325 | 0 | status = _cairo_surface_paint (opaque, |
326 | 0 | CAIRO_OPERATOR_SOURCE, |
327 | 0 | &_cairo_pattern_white.base, |
328 | 0 | NULL); |
329 | 0 | if (unlikely (status)) |
330 | 0 | goto cleanup; |
331 | | |
332 | 0 | _cairo_pattern_init_for_surface (&pattern, image); |
333 | 0 | pattern.base.filter = CAIRO_FILTER_NEAREST; |
334 | 0 | status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL); |
335 | 0 | _cairo_pattern_fini (&pattern.base); |
336 | 0 | if (unlikely (status)) |
337 | 0 | goto cleanup; |
338 | | |
339 | 0 | status = surface->backend->set_thumbnail_image (surface->target, (cairo_image_surface_t *)opaque); |
340 | |
|
341 | 0 | cleanup: |
342 | 0 | if (image) |
343 | 0 | cairo_surface_destroy (image); |
344 | 0 | if (opaque) |
345 | 0 | cairo_surface_destroy (opaque); |
346 | |
|
347 | 0 | return status; |
348 | 0 | } |
349 | | |
350 | | static cairo_int_status_t |
351 | | _paint_fallback_image (cairo_paginated_surface_t *surface, |
352 | | cairo_rectangle_int_t *rect) |
353 | 0 | { |
354 | 0 | double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution; |
355 | 0 | double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution; |
356 | 0 | int x, y, width, height; |
357 | 0 | cairo_status_t status; |
358 | 0 | cairo_surface_t *image; |
359 | 0 | cairo_surface_pattern_t pattern; |
360 | 0 | cairo_clip_t *clip; |
361 | |
|
362 | 0 | x = rect->x; |
363 | 0 | y = rect->y; |
364 | 0 | width = rect->width; |
365 | 0 | height = rect->height; |
366 | 0 | image = _cairo_paginated_surface_create_image_surface (surface, |
367 | 0 | ceil (width * x_scale), |
368 | 0 | ceil (height * y_scale)); |
369 | 0 | 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 | 0 | cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale); |
373 | |
|
374 | 0 | status = _cairo_recording_surface_replay (surface->recording_surface, image); |
375 | 0 | if (unlikely (status)) |
376 | 0 | goto CLEANUP_IMAGE; |
377 | | |
378 | 0 | _cairo_pattern_init_for_surface (&pattern, image); |
379 | 0 | cairo_matrix_init (&pattern.base.matrix, |
380 | 0 | 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 | 0 | pattern.base.filter = CAIRO_FILTER_NEAREST; |
384 | |
|
385 | 0 | clip = _cairo_clip_intersect_rectangle (NULL, rect); |
386 | 0 | status = _cairo_surface_paint (surface->target, |
387 | 0 | CAIRO_OPERATOR_SOURCE, |
388 | 0 | &pattern.base, clip); |
389 | 0 | _cairo_clip_destroy (clip); |
390 | 0 | _cairo_pattern_fini (&pattern.base); |
391 | |
|
392 | 0 | CLEANUP_IMAGE: |
393 | 0 | cairo_surface_destroy (image); |
394 | |
|
395 | 0 | return status; |
396 | 0 | } |
397 | | |
398 | | static cairo_int_status_t |
399 | | _paint_page (cairo_paginated_surface_t *surface) |
400 | 2 | { |
401 | 2 | cairo_surface_t *analysis; |
402 | 2 | cairo_int_status_t status; |
403 | 2 | cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; |
404 | | |
405 | 2 | if (unlikely (surface->target->status)) |
406 | 0 | return surface->target->status; |
407 | | |
408 | 2 | analysis = _cairo_analysis_surface_create (surface->target); |
409 | 2 | if (unlikely (analysis->status)) |
410 | 0 | return _cairo_surface_set_error (surface->target, analysis->status); |
411 | | |
412 | 2 | status = surface->backend->set_paginated_mode (surface->target, |
413 | 2 | CAIRO_PAGINATED_MODE_ANALYZE); |
414 | 2 | if (unlikely (status)) |
415 | 0 | goto FAIL; |
416 | | |
417 | 2 | status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface, |
418 | 2 | NULL, analysis, FALSE); |
419 | 2 | if (status) |
420 | 0 | goto FAIL; |
421 | | |
422 | 2 | assert (analysis->status == CAIRO_STATUS_SUCCESS); |
423 | | |
424 | 2 | if (surface->backend->set_bounding_box) { |
425 | 0 | cairo_box_t bbox; |
426 | |
|
427 | 0 | _cairo_analysis_surface_get_bounding_box (analysis, &bbox); |
428 | 0 | status = surface->backend->set_bounding_box (surface->target, &bbox); |
429 | 0 | if (unlikely (status)) |
430 | 0 | goto FAIL; |
431 | 0 | } |
432 | | |
433 | 2 | if (surface->backend->set_fallback_images_required) { |
434 | 2 | cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis); |
435 | | |
436 | 2 | status = surface->backend->set_fallback_images_required (surface->target, |
437 | 2 | has_fallbacks); |
438 | 2 | if (unlikely (status)) |
439 | 0 | goto FAIL; |
440 | 2 | } |
441 | | |
442 | | /* Finer grained fallbacks are currently only supported for some |
443 | | * surface types */ |
444 | 2 | if (surface->backend->supports_fine_grained_fallbacks != NULL && |
445 | 2 | surface->backend->supports_fine_grained_fallbacks (surface->target)) |
446 | 2 | { |
447 | 2 | has_supported = _cairo_analysis_surface_has_supported (analysis); |
448 | 2 | has_page_fallback = FALSE; |
449 | 2 | has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); |
450 | 2 | } |
451 | 0 | else |
452 | 0 | { |
453 | 0 | if (_cairo_analysis_surface_has_unsupported (analysis)) { |
454 | 0 | has_supported = FALSE; |
455 | 0 | has_page_fallback = TRUE; |
456 | 0 | } else { |
457 | 0 | has_supported = TRUE; |
458 | 0 | has_page_fallback = FALSE; |
459 | 0 | } |
460 | 0 | has_finegrained_fallback = FALSE; |
461 | 0 | } |
462 | | |
463 | 2 | if (has_supported) { |
464 | 0 | status = surface->backend->set_paginated_mode (surface->target, |
465 | 0 | CAIRO_PAGINATED_MODE_RENDER); |
466 | 0 | if (unlikely (status)) |
467 | 0 | goto FAIL; |
468 | | |
469 | 0 | status = _cairo_recording_surface_replay_region (surface->recording_surface, |
470 | 0 | NULL, |
471 | 0 | surface->target, |
472 | 0 | CAIRO_RECORDING_REGION_NATIVE); |
473 | 0 | assert (status != CAIRO_INT_STATUS_UNSUPPORTED); |
474 | 0 | if (unlikely (status)) |
475 | 0 | goto FAIL; |
476 | 0 | } |
477 | | |
478 | 2 | if (has_page_fallback) { |
479 | 0 | cairo_rectangle_int_t extents; |
480 | 0 | cairo_bool_t is_bounded; |
481 | |
|
482 | 0 | status = surface->backend->set_paginated_mode (surface->target, |
483 | 0 | CAIRO_PAGINATED_MODE_FALLBACK); |
484 | 0 | if (unlikely (status)) |
485 | 0 | goto FAIL; |
486 | | |
487 | 0 | is_bounded = _cairo_surface_get_extents (surface->target, &extents); |
488 | 0 | if (! is_bounded) { |
489 | 0 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
490 | 0 | goto FAIL; |
491 | 0 | } |
492 | | |
493 | 0 | status = _paint_fallback_image (surface, &extents); |
494 | 0 | if (unlikely (status)) |
495 | 0 | goto FAIL; |
496 | 0 | } |
497 | | |
498 | 2 | if (has_finegrained_fallback) { |
499 | 0 | cairo_region_t *region; |
500 | 0 | int num_rects, i; |
501 | |
|
502 | 0 | status = surface->backend->set_paginated_mode (surface->target, |
503 | 0 | CAIRO_PAGINATED_MODE_FALLBACK); |
504 | 0 | if (unlikely (status)) |
505 | 0 | goto FAIL; |
506 | | |
507 | 0 | region = _cairo_analysis_surface_get_unsupported (analysis); |
508 | |
|
509 | 0 | num_rects = cairo_region_num_rectangles (region); |
510 | 0 | for (i = 0; i < num_rects; i++) { |
511 | 0 | cairo_rectangle_int_t rect; |
512 | |
|
513 | 0 | cairo_region_get_rectangle (region, i, &rect); |
514 | 0 | status = _paint_fallback_image (surface, &rect); |
515 | 0 | if (unlikely (status)) |
516 | 0 | goto FAIL; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | 2 | if (surface->backend->requires_thumbnail_image) { |
521 | 2 | int width, height; |
522 | | |
523 | 2 | if (surface->backend->requires_thumbnail_image (surface->target, &width, &height)) |
524 | 0 | _paint_thumbnail_image (surface, width, height); |
525 | 2 | } |
526 | | |
527 | 2 | FAIL: |
528 | 2 | cairo_surface_destroy (analysis); |
529 | | |
530 | 2 | return _cairo_surface_set_error (surface->target, status); |
531 | 2 | } |
532 | | |
533 | | static cairo_status_t |
534 | | _start_page (cairo_paginated_surface_t *surface) |
535 | 2 | { |
536 | 2 | if (surface->target->status) |
537 | 0 | return surface->target->status; |
538 | | |
539 | 2 | if (! surface->backend->start_page) |
540 | 0 | return CAIRO_STATUS_SUCCESS; |
541 | | |
542 | 2 | return _cairo_surface_set_error (surface->target, |
543 | 2 | surface->backend->start_page (surface->target)); |
544 | 2 | } |
545 | | |
546 | | static cairo_int_status_t |
547 | | _cairo_paginated_surface_copy_page (void *abstract_surface) |
548 | 0 | { |
549 | 0 | cairo_status_t status; |
550 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
551 | |
|
552 | 0 | status = _start_page (surface); |
553 | 0 | if (unlikely (status)) |
554 | 0 | return status; |
555 | | |
556 | 0 | status = _paint_page (surface); |
557 | 0 | if (unlikely (status)) |
558 | 0 | return status; |
559 | | |
560 | 0 | 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 | 0 | cairo_surface_show_page (surface->target); |
570 | 0 | return cairo_surface_status (surface->target); |
571 | 0 | } |
572 | | |
573 | | static cairo_int_status_t |
574 | | _cairo_paginated_surface_show_page (void *abstract_surface) |
575 | 2 | { |
576 | 2 | cairo_status_t status; |
577 | 2 | cairo_paginated_surface_t *surface = abstract_surface; |
578 | | |
579 | 2 | status = _start_page (surface); |
580 | 2 | if (unlikely (status)) |
581 | 0 | return status; |
582 | | |
583 | 2 | status = _paint_page (surface); |
584 | 2 | if (unlikely (status)) |
585 | 0 | return status; |
586 | | |
587 | 2 | cairo_surface_show_page (surface->target); |
588 | 2 | status = surface->target->status; |
589 | 2 | if (unlikely (status)) |
590 | 0 | return status; |
591 | | |
592 | 2 | status = surface->recording_surface->status; |
593 | 2 | if (unlikely (status)) |
594 | 0 | return status; |
595 | | |
596 | 2 | if (! surface->base.finished) { |
597 | 2 | cairo_surface_destroy (surface->recording_surface); |
598 | | |
599 | 2 | surface->recording_surface = _create_recording_surface_for_target (surface->target, |
600 | 2 | surface->content); |
601 | 2 | status = surface->recording_surface->status; |
602 | 2 | if (unlikely (status)) |
603 | 0 | return status; |
604 | | |
605 | 2 | surface->page_num++; |
606 | 2 | surface->base.is_clear = TRUE; |
607 | 2 | } |
608 | | |
609 | 2 | return CAIRO_STATUS_SUCCESS; |
610 | 2 | } |
611 | | |
612 | | static cairo_bool_t |
613 | | _cairo_paginated_surface_get_extents (void *abstract_surface, |
614 | | cairo_rectangle_int_t *rectangle) |
615 | 0 | { |
616 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
617 | |
|
618 | 0 | return _cairo_surface_get_extents (surface->target, rectangle); |
619 | 0 | } |
620 | | |
621 | | static void |
622 | | _cairo_paginated_surface_get_font_options (void *abstract_surface, |
623 | | cairo_font_options_t *options) |
624 | 2 | { |
625 | 2 | cairo_paginated_surface_t *surface = abstract_surface; |
626 | | |
627 | 2 | cairo_surface_get_font_options (surface->target, options); |
628 | 2 | } |
629 | | |
630 | | static cairo_int_status_t |
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 | 0 | { |
636 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
637 | |
|
638 | 0 | return _cairo_surface_paint (surface->recording_surface, op, source, clip); |
639 | 0 | } |
640 | | |
641 | | static cairo_int_status_t |
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 | 0 | { |
648 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
649 | |
|
650 | 0 | return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip); |
651 | 0 | } |
652 | | |
653 | | static cairo_int_status_t |
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 | 0 | { |
665 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
666 | |
|
667 | 0 | return _cairo_surface_stroke (surface->recording_surface, op, source, |
668 | 0 | path, style, |
669 | 0 | ctm, ctm_inverse, |
670 | 0 | tolerance, antialias, |
671 | 0 | clip); |
672 | 0 | } |
673 | | |
674 | | static cairo_int_status_t |
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 | 0 | { |
684 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
685 | |
|
686 | 0 | return _cairo_surface_fill (surface->recording_surface, op, source, |
687 | 0 | path, fill_rule, |
688 | 0 | tolerance, antialias, |
689 | 0 | clip); |
690 | 0 | } |
691 | | |
692 | | static cairo_bool_t |
693 | | _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface) |
694 | 0 | { |
695 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
696 | |
|
697 | 0 | return cairo_surface_has_show_text_glyphs (surface->target); |
698 | 0 | } |
699 | | |
700 | | static cairo_int_status_t |
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 | 0 | { |
714 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
715 | |
|
716 | 0 | return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source, |
717 | 0 | utf8, utf8_len, |
718 | 0 | glyphs, num_glyphs, |
719 | 0 | clusters, num_clusters, |
720 | 0 | cluster_flags, |
721 | 0 | scaled_font, |
722 | 0 | clip); |
723 | 0 | } |
724 | | |
725 | | static const char ** |
726 | | _cairo_paginated_surface_get_supported_mime_types (void *abstract_surface) |
727 | 0 | { |
728 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
729 | |
|
730 | 0 | if (surface->target->backend->get_supported_mime_types) |
731 | 0 | return surface->target->backend->get_supported_mime_types (surface->target); |
732 | | |
733 | 0 | return NULL; |
734 | 0 | } |
735 | | |
736 | | static cairo_int_status_t |
737 | | _cairo_paginated_surface_tag (void *abstract_surface, |
738 | | cairo_bool_t begin, |
739 | | const char *tag_name, |
740 | | const char *attributes) |
741 | 0 | { |
742 | 0 | cairo_paginated_surface_t *surface = abstract_surface; |
743 | |
|
744 | 0 | return _cairo_surface_tag (surface->recording_surface, |
745 | 0 | begin, tag_name, attributes); |
746 | 0 | } |
747 | | |
748 | | static cairo_surface_t * |
749 | | _cairo_paginated_surface_snapshot (void *abstract_other) |
750 | 0 | { |
751 | 0 | cairo_paginated_surface_t *other = abstract_other; |
752 | |
|
753 | 0 | return other->recording_surface->backend->snapshot (other->recording_surface); |
754 | 0 | } |
755 | | |
756 | | static cairo_t * |
757 | | _cairo_paginated_context_create (void *target) |
758 | 0 | { |
759 | 0 | cairo_paginated_surface_t *surface = target; |
760 | |
|
761 | 0 | if (_cairo_surface_is_subsurface (&surface->base)) |
762 | 0 | surface = (cairo_paginated_surface_t *) |
763 | 0 | _cairo_surface_subsurface_get_target (&surface->base); |
764 | |
|
765 | 0 | return surface->recording_surface->backend->create_context (target); |
766 | 0 | } |
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 | | }; |