/src/cairo/src/cairo-analysis-surface.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* |
3 | | * Copyright © 2006 Keith Packard |
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 Keith Packard |
32 | | * |
33 | | * Contributor(s): |
34 | | * Keith Packard <keithp@keithp.com> |
35 | | * Adrian Johnson <ajohnson@redneon.com> |
36 | | */ |
37 | | |
38 | | #include "cairoint.h" |
39 | | |
40 | | #include "cairo-analysis-surface-private.h" |
41 | | #include "cairo-box-inline.h" |
42 | | #include "cairo-default-context-private.h" |
43 | | #include "cairo-error-private.h" |
44 | | #include "cairo-paginated-private.h" |
45 | | #include "cairo-recording-surface-inline.h" |
46 | | #include "cairo-surface-snapshot-inline.h" |
47 | | #include "cairo-surface-subsurface-inline.h" |
48 | | #include "cairo-region-private.h" |
49 | | |
50 | | typedef struct { |
51 | | cairo_surface_t base; |
52 | | |
53 | | cairo_surface_t *target; |
54 | | |
55 | | cairo_bool_t first_op; |
56 | | cairo_bool_t has_supported; |
57 | | cairo_bool_t has_unsupported; |
58 | | |
59 | | cairo_region_t supported_region; |
60 | | cairo_region_t fallback_region; |
61 | | cairo_box_t page_bbox; |
62 | | |
63 | | cairo_bool_t create_region_ids; |
64 | | unsigned source_region_id; |
65 | | unsigned mask_region_id; |
66 | | |
67 | | cairo_bool_t has_ctm; |
68 | | cairo_matrix_t ctm; |
69 | | |
70 | | } cairo_analysis_surface_t; |
71 | | |
72 | | cairo_int_status_t |
73 | | _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, |
74 | | cairo_int_status_t status_b) |
75 | 1.19k | { |
76 | | /* fatal errors should be checked and propagated at source */ |
77 | 1.19k | assert (! _cairo_int_status_is_error (status_a)); |
78 | 1.19k | assert (! _cairo_int_status_is_error (status_b)); |
79 | | |
80 | | /* return the most important status */ |
81 | 1.19k | if (status_a == CAIRO_INT_STATUS_UNSUPPORTED || |
82 | 1.19k | status_b == CAIRO_INT_STATUS_UNSUPPORTED) |
83 | 0 | return CAIRO_INT_STATUS_UNSUPPORTED; |
84 | | |
85 | 1.19k | if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK || |
86 | 1.19k | status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK) |
87 | 0 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
88 | | |
89 | 1.19k | if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN || |
90 | 1.19k | status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
91 | 23 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
92 | | |
93 | 1.17k | if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
94 | 1.17k | status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) |
95 | 0 | return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; |
96 | | |
97 | | /* at this point we have checked all the valid internal codes, so... */ |
98 | 1.17k | assert (status_a == CAIRO_INT_STATUS_SUCCESS && |
99 | 1.17k | status_b == CAIRO_INT_STATUS_SUCCESS); |
100 | | |
101 | 1.17k | return CAIRO_INT_STATUS_SUCCESS; |
102 | 1.17k | } |
103 | | |
104 | | struct proxy { |
105 | | cairo_surface_t base; |
106 | | cairo_surface_t *target; |
107 | | }; |
108 | | |
109 | | static cairo_status_t |
110 | | proxy_finish (void *abstract_surface) |
111 | 548 | { |
112 | 548 | return CAIRO_STATUS_SUCCESS; |
113 | 548 | } |
114 | | |
115 | | static const cairo_surface_backend_t proxy_backend = { |
116 | | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
117 | | proxy_finish, |
118 | | }; |
119 | | |
120 | | static cairo_surface_t * |
121 | | attach_proxy (cairo_surface_t *source, |
122 | | cairo_surface_t *target) |
123 | 548 | { |
124 | 548 | struct proxy *proxy; |
125 | | |
126 | 548 | proxy = _cairo_calloc (sizeof (*proxy)); |
127 | 548 | if (unlikely (proxy == NULL)) |
128 | 0 | return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); |
129 | | |
130 | 548 | _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content, target->is_vector); |
131 | | |
132 | 548 | proxy->target = target; |
133 | 548 | _cairo_surface_attach_snapshot (source, &proxy->base, NULL); |
134 | | |
135 | 548 | return &proxy->base; |
136 | 548 | } |
137 | | |
138 | | static void |
139 | | detach_proxy (cairo_surface_t *proxy) |
140 | 548 | { |
141 | 548 | cairo_surface_finish (proxy); |
142 | 548 | cairo_surface_destroy (proxy); |
143 | 548 | } |
144 | | |
145 | | static cairo_int_status_t |
146 | | _add_operation (cairo_analysis_surface_t *surface, |
147 | | cairo_rectangle_int_t *rect, |
148 | | cairo_int_status_t backend_status) |
149 | 499k | { |
150 | 499k | cairo_int_status_t status; |
151 | 499k | cairo_box_t bbox; |
152 | | |
153 | 499k | if (rect->width == 0 || rect->height == 0) { |
154 | | /* Even though the operation is not visible we must be careful |
155 | | * to not allow unsupported operations to be replayed to the |
156 | | * backend during CAIRO_PAGINATED_MODE_RENDER */ |
157 | 13 | if (backend_status == CAIRO_INT_STATUS_SUCCESS || |
158 | 13 | backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
159 | 13 | backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
160 | 13 | { |
161 | 13 | return CAIRO_INT_STATUS_SUCCESS; |
162 | 13 | } |
163 | 0 | else |
164 | 0 | { |
165 | 0 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
166 | 0 | } |
167 | 13 | } |
168 | | |
169 | 499k | _cairo_box_from_rectangle (&bbox, rect); |
170 | | |
171 | 499k | if (surface->has_ctm) { |
172 | 1.22k | int tx, ty; |
173 | | |
174 | 1.22k | if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) { |
175 | 706 | rect->x += tx; |
176 | 706 | rect->y += ty; |
177 | | |
178 | 706 | tx = _cairo_fixed_from_int (tx); |
179 | 706 | bbox.p1.x += tx; |
180 | 706 | bbox.p2.x += tx; |
181 | | |
182 | 706 | ty = _cairo_fixed_from_int (ty); |
183 | 706 | bbox.p1.y += ty; |
184 | 706 | bbox.p2.y += ty; |
185 | 706 | } else { |
186 | 518 | _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, |
187 | 518 | &bbox, NULL); |
188 | | |
189 | 518 | if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { |
190 | | /* Even though the operation is not visible we must be |
191 | | * careful to not allow unsupported operations to be |
192 | | * replayed to the backend during |
193 | | * CAIRO_PAGINATED_MODE_RENDER */ |
194 | 0 | if (backend_status == CAIRO_INT_STATUS_SUCCESS || |
195 | 0 | backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
196 | 0 | backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
197 | 0 | { |
198 | 0 | return CAIRO_INT_STATUS_SUCCESS; |
199 | 0 | } |
200 | 0 | else |
201 | 0 | { |
202 | 0 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 518 | _cairo_box_round_to_rectangle (&bbox, rect); |
207 | 518 | } |
208 | 1.22k | } |
209 | | |
210 | 499k | if (surface->first_op) { |
211 | 1.09k | surface->first_op = FALSE; |
212 | 1.09k | surface->page_bbox = bbox; |
213 | 1.09k | } else |
214 | 498k | _cairo_box_add_box(&surface->page_bbox, &bbox); |
215 | | |
216 | | /* If the operation is completely enclosed within the fallback |
217 | | * region there is no benefit in emitting a native operation as |
218 | | * the fallback image will be painted on top. |
219 | | */ |
220 | 499k | if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN) |
221 | 0 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
222 | | |
223 | 499k | if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { |
224 | | /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates |
225 | | * that the backend only supports this operation if the |
226 | | * transparency removed. If the extents of this operation does |
227 | | * not intersect any other native operation, the operation is |
228 | | * natively supported and the backend will blend the |
229 | | * transparency into the white background. |
230 | | */ |
231 | 0 | if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT) |
232 | 0 | backend_status = CAIRO_INT_STATUS_SUCCESS; |
233 | 0 | } |
234 | | |
235 | 499k | if (backend_status == CAIRO_INT_STATUS_SUCCESS) { |
236 | | /* Add the operation to the supported region. Operations in |
237 | | * this region will be emitted as native operations. |
238 | | */ |
239 | 499k | surface->has_supported = TRUE; |
240 | 499k | return cairo_region_union_rectangle (&surface->supported_region, rect); |
241 | 499k | } |
242 | | |
243 | | /* Add the operation to the unsupported region. This region will |
244 | | * be painted as an image after all native operations have been |
245 | | * emitted. |
246 | | */ |
247 | 0 | surface->has_unsupported = TRUE; |
248 | 0 | status = cairo_region_union_rectangle (&surface->fallback_region, rect); |
249 | | |
250 | | /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate |
251 | | * unsupported operations to the recording surface as using |
252 | | * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to |
253 | | * invoke the cairo-surface-fallback path then return |
254 | | * CAIRO_STATUS_SUCCESS. |
255 | | */ |
256 | 0 | if (status == CAIRO_INT_STATUS_SUCCESS) |
257 | 0 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
258 | 0 | else |
259 | 0 | return status; |
260 | 0 | } |
261 | | |
262 | | static cairo_int_status_t |
263 | | _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, |
264 | | const cairo_pattern_t *pattern, |
265 | | cairo_rectangle_int_t *extents, |
266 | | unsigned int *regions_id, |
267 | | cairo_analysis_source_t source_type) |
268 | 548 | { |
269 | 548 | const cairo_surface_pattern_t *surface_pattern; |
270 | 548 | cairo_analysis_surface_t *tmp; |
271 | 548 | cairo_surface_t *source, *proxy; |
272 | 548 | cairo_matrix_t p2d; |
273 | 548 | cairo_int_status_t status; |
274 | 548 | cairo_int_status_t analysis_status = CAIRO_INT_STATUS_SUCCESS; |
275 | 548 | cairo_bool_t surface_is_unbounded; |
276 | 548 | cairo_bool_t unused; |
277 | 548 | cairo_bool_t replay_all; |
278 | | |
279 | 548 | assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); |
280 | 548 | surface_pattern = (const cairo_surface_pattern_t *) pattern; |
281 | 548 | assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); |
282 | 548 | source = surface_pattern->surface; |
283 | | |
284 | 548 | proxy = _cairo_surface_has_snapshot (source, &proxy_backend); |
285 | 548 | if (proxy != NULL) { |
286 | | /* nothing untoward found so far */ |
287 | 0 | return CAIRO_STATUS_SUCCESS; |
288 | 0 | } |
289 | | |
290 | 548 | tmp = (cairo_analysis_surface_t *) |
291 | 548 | _cairo_analysis_surface_create (surface->target, surface->create_region_ids); |
292 | 548 | if (unlikely (tmp->base.status)) { |
293 | 0 | status = tmp->base.status; |
294 | 0 | goto cleanup1; |
295 | 0 | } |
296 | 548 | proxy = attach_proxy (source, &tmp->base); |
297 | | |
298 | 548 | p2d = pattern->matrix; |
299 | 548 | status = cairo_matrix_invert (&p2d); |
300 | 548 | assert (status == CAIRO_INT_STATUS_SUCCESS); |
301 | 548 | _cairo_analysis_surface_set_ctm (&tmp->base, &p2d); |
302 | | |
303 | 548 | source = _cairo_surface_get_source (source, NULL); |
304 | 548 | surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT |
305 | 548 | || pattern->extend == CAIRO_EXTEND_REFLECT); |
306 | | |
307 | 548 | if (surface->create_region_ids) { |
308 | 548 | status = _cairo_recording_surface_region_array_attach (source, regions_id); |
309 | 548 | if (unlikely (status)) |
310 | 0 | goto cleanup2; |
311 | 548 | } |
312 | | |
313 | 548 | replay_all = FALSE; |
314 | 548 | if (surface->target->backend->analyze_recording_surface) { |
315 | 548 | status = surface->target->backend->analyze_recording_surface ( |
316 | 548 | surface->target, |
317 | 548 | surface_pattern, |
318 | 548 | surface->create_region_ids ? *regions_id : 0, |
319 | 548 | source_type, |
320 | 548 | TRUE); |
321 | 548 | if (status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
322 | | /* Ensure all commands are replayed even if previously |
323 | | * replayed and assigned to a region.*/ |
324 | 0 | replay_all = TRUE; |
325 | 0 | status = CAIRO_INT_STATUS_SUCCESS; |
326 | 0 | } |
327 | 548 | if (unlikely (status)) |
328 | 0 | goto cleanup3; |
329 | 548 | } |
330 | | |
331 | 548 | if (surface->create_region_ids) { |
332 | 548 | status = _cairo_recording_surface_replay_and_create_regions (source, |
333 | 548 | *regions_id, |
334 | 548 | &pattern->matrix, |
335 | 548 | &tmp->base, |
336 | 548 | surface_is_unbounded, |
337 | 548 | replay_all); |
338 | 548 | if (unlikely (status)) |
339 | 0 | goto cleanup3; |
340 | 548 | } else { |
341 | 0 | status = _cairo_recording_surface_replay_with_transform (source, |
342 | 0 | &pattern->matrix, |
343 | 0 | &tmp->base, |
344 | 0 | surface_is_unbounded, |
345 | 0 | replay_all); |
346 | 0 | if (unlikely (status)) |
347 | 0 | goto cleanup3; |
348 | 0 | } |
349 | | |
350 | 548 | if (surface->target->backend->analyze_recording_surface) { |
351 | 548 | status = surface->target->backend->analyze_recording_surface ( |
352 | 548 | surface->target, |
353 | 548 | surface_pattern, |
354 | 548 | surface->create_region_ids ? *regions_id : 0, |
355 | 548 | source_type, |
356 | 548 | FALSE); |
357 | 548 | if (unlikely (status)) |
358 | 0 | goto cleanup3; |
359 | 548 | } |
360 | | |
361 | | /* black background or mime data fills entire extents */ |
362 | 548 | if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) { |
363 | 0 | cairo_rectangle_int_t rect; |
364 | |
|
365 | 0 | if (_cairo_surface_get_extents (source, &rect)) { |
366 | 0 | cairo_box_t bbox; |
367 | |
|
368 | 0 | _cairo_box_from_rectangle (&bbox, &rect); |
369 | 0 | _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL); |
370 | 0 | _cairo_box_round_to_rectangle (&bbox, &rect); |
371 | 0 | status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS); |
372 | 0 | if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) |
373 | 0 | status = CAIRO_INT_STATUS_SUCCESS; |
374 | 0 | if (unlikely (status)) |
375 | 0 | goto cleanup3; |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | 548 | if (tmp->has_supported) { |
380 | 548 | surface->has_supported = TRUE; |
381 | 548 | unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); |
382 | 548 | } |
383 | | |
384 | 548 | if (tmp->has_unsupported) { |
385 | 0 | surface->has_unsupported = TRUE; |
386 | 0 | unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); |
387 | 0 | } |
388 | | |
389 | 548 | analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; |
390 | 548 | if (pattern->extend != CAIRO_EXTEND_NONE) { |
391 | 518 | _cairo_unbounded_rectangle_init (extents); |
392 | 518 | } else { |
393 | 30 | status = cairo_matrix_invert (&tmp->ctm); |
394 | 30 | _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm, |
395 | 30 | &tmp->page_bbox, NULL); |
396 | 30 | _cairo_box_round_to_rectangle (&tmp->page_bbox, extents); |
397 | 30 | } |
398 | | |
399 | 548 | cleanup3: |
400 | 548 | if (surface->create_region_ids && unlikely (status)) { |
401 | 0 | _cairo_recording_surface_region_array_remove (source, *regions_id); |
402 | 0 | } |
403 | 548 | cleanup2: |
404 | 548 | detach_proxy (proxy); |
405 | 548 | cleanup1: |
406 | 548 | cairo_surface_destroy (&tmp->base); |
407 | | |
408 | 548 | if (unlikely (status)) |
409 | 0 | return status; |
410 | 548 | else |
411 | 548 | return analysis_status; |
412 | 548 | } |
413 | | |
414 | | static cairo_status_t |
415 | | _cairo_analysis_surface_finish (void *abstract_surface) |
416 | 2.57k | { |
417 | 2.57k | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
418 | | |
419 | 2.57k | _cairo_region_fini (&surface->supported_region); |
420 | 2.57k | _cairo_region_fini (&surface->fallback_region); |
421 | | |
422 | 2.57k | cairo_surface_destroy (surface->target); |
423 | | |
424 | 2.57k | return CAIRO_STATUS_SUCCESS; |
425 | 2.57k | } |
426 | | |
427 | | static cairo_bool_t |
428 | | _cairo_analysis_surface_get_extents (void *abstract_surface, |
429 | | cairo_rectangle_int_t *rectangle) |
430 | 499k | { |
431 | 499k | cairo_analysis_surface_t *surface = abstract_surface; |
432 | | |
433 | 499k | return _cairo_surface_get_extents (surface->target, rectangle); |
434 | 499k | } |
435 | | |
436 | | static void |
437 | | _rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip) |
438 | 499k | { |
439 | 499k | if (clip != NULL) |
440 | 498k | _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip)); |
441 | 499k | } |
442 | | |
443 | | static void |
444 | | _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface, |
445 | | cairo_operator_t op, |
446 | | const cairo_pattern_t *source, |
447 | | const cairo_clip_t *clip, |
448 | | cairo_rectangle_int_t *extents) |
449 | 499k | { |
450 | 499k | cairo_bool_t is_empty; |
451 | | |
452 | 499k | is_empty = _cairo_surface_get_extents (&surface->base, extents); |
453 | | |
454 | 499k | if (_cairo_operator_bounded_by_source (op)) { |
455 | 498k | cairo_rectangle_int_t source_extents; |
456 | | |
457 | 498k | _cairo_pattern_get_extents (source, &source_extents, surface->target->is_vector); |
458 | 498k | _cairo_rectangle_intersect (extents, &source_extents); |
459 | 498k | } |
460 | | |
461 | 499k | _rectangle_intersect_clip (extents, clip); |
462 | 499k | } |
463 | | |
464 | | static cairo_int_status_t |
465 | | _cairo_analysis_surface_paint (void *abstract_surface, |
466 | | cairo_operator_t op, |
467 | | const cairo_pattern_t *source, |
468 | | const cairo_clip_t *clip) |
469 | 333 | { |
470 | 333 | cairo_analysis_surface_t *surface = abstract_surface; |
471 | 333 | cairo_int_status_t backend_status; |
472 | 333 | cairo_rectangle_int_t extents; |
473 | | |
474 | 333 | surface->source_region_id = 0; |
475 | 333 | surface->mask_region_id = 0; |
476 | 333 | if (surface->target->backend->paint == NULL) { |
477 | 0 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
478 | 333 | } else { |
479 | 333 | backend_status = |
480 | 333 | surface->target->backend->paint (surface->target, |
481 | 333 | op, source, clip); |
482 | 333 | if (_cairo_int_status_is_error (backend_status)) |
483 | 0 | return backend_status; |
484 | 333 | } |
485 | | |
486 | 333 | _cairo_analysis_surface_operation_extents (surface, |
487 | 333 | op, source, clip, |
488 | 333 | &extents); |
489 | 333 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
490 | 7 | cairo_rectangle_int_t rec_extents; |
491 | 7 | backend_status = _analyze_recording_surface_pattern (surface, |
492 | 7 | source, |
493 | 7 | &rec_extents, |
494 | 7 | &surface->source_region_id, |
495 | 7 | CAIRO_ANALYSIS_SOURCE_PAINT); |
496 | 7 | _cairo_rectangle_intersect (&extents, &rec_extents); |
497 | 7 | } |
498 | | |
499 | 333 | return _add_operation (surface, &extents, backend_status); |
500 | 333 | } |
501 | | |
502 | | static cairo_int_status_t |
503 | | _cairo_analysis_surface_mask (void *abstract_surface, |
504 | | cairo_operator_t op, |
505 | | const cairo_pattern_t *source, |
506 | | const cairo_pattern_t *mask, |
507 | | const cairo_clip_t *clip) |
508 | 1.17k | { |
509 | 1.17k | cairo_analysis_surface_t *surface = abstract_surface; |
510 | 1.17k | cairo_int_status_t backend_status; |
511 | 1.17k | cairo_rectangle_int_t extents; |
512 | | |
513 | 1.17k | surface->source_region_id = 0; |
514 | 1.17k | surface->mask_region_id = 0; |
515 | 1.17k | if (surface->target->backend->mask == NULL) { |
516 | 0 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
517 | 1.17k | } else { |
518 | 1.17k | backend_status = |
519 | 1.17k | surface->target->backend->mask (surface->target, |
520 | 1.17k | op, source, mask, clip); |
521 | 1.17k | if (_cairo_int_status_is_error (backend_status)) |
522 | 0 | return backend_status; |
523 | 1.17k | } |
524 | | |
525 | 1.17k | _cairo_analysis_surface_operation_extents (surface, |
526 | 1.17k | op, source, clip, |
527 | 1.17k | &extents); |
528 | 1.17k | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
529 | 23 | cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; |
530 | 23 | cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS; |
531 | 23 | cairo_rectangle_int_t rec_extents; |
532 | | |
533 | 23 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
534 | 23 | cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface; |
535 | 23 | src_surface = _cairo_surface_get_source (src_surface, NULL); |
536 | 23 | if (_cairo_surface_is_recording (src_surface)) { |
537 | 23 | backend_source_status = |
538 | 23 | _analyze_recording_surface_pattern (surface, |
539 | 23 | source, |
540 | 23 | &rec_extents, |
541 | 23 | &surface->source_region_id, |
542 | 23 | CAIRO_ANALYSIS_SOURCE_MASK); |
543 | 23 | if (_cairo_int_status_is_error (backend_source_status)) |
544 | 0 | return backend_source_status; |
545 | | |
546 | 23 | _cairo_rectangle_intersect (&extents, &rec_extents); |
547 | 23 | } |
548 | 23 | } |
549 | | |
550 | 23 | if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { |
551 | 0 | cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface; |
552 | 0 | mask_surface = _cairo_surface_get_source (mask_surface, NULL); |
553 | 0 | if (_cairo_surface_is_recording (mask_surface)) { |
554 | 0 | backend_mask_status = |
555 | 0 | _analyze_recording_surface_pattern (surface, |
556 | 0 | mask, |
557 | 0 | &rec_extents, |
558 | 0 | &surface->mask_region_id, |
559 | 0 | CAIRO_ANALYSIS_MASK_MASK); |
560 | 0 | if (_cairo_int_status_is_error (backend_mask_status)) |
561 | 0 | return backend_mask_status; |
562 | | |
563 | 0 | _cairo_rectangle_intersect (&extents, &rec_extents); |
564 | 0 | } |
565 | 0 | } |
566 | | |
567 | 23 | backend_status = |
568 | 23 | _cairo_analysis_surface_merge_status (backend_source_status, |
569 | 23 | backend_mask_status); |
570 | 23 | } |
571 | | |
572 | 1.17k | if (_cairo_operator_bounded_by_mask (op)) { |
573 | 1.17k | cairo_rectangle_int_t mask_extents; |
574 | | |
575 | 1.17k | _cairo_pattern_get_extents (mask, &mask_extents, surface->target->is_vector); |
576 | 1.17k | _cairo_rectangle_intersect (&extents, &mask_extents); |
577 | 1.17k | } |
578 | | |
579 | 1.17k | return _add_operation (surface, &extents, backend_status); |
580 | 1.17k | } |
581 | | |
582 | | static cairo_int_status_t |
583 | | _cairo_analysis_surface_stroke (void *abstract_surface, |
584 | | cairo_operator_t op, |
585 | | const cairo_pattern_t *source, |
586 | | const cairo_path_fixed_t *path, |
587 | | const cairo_stroke_style_t *style, |
588 | | const cairo_matrix_t *ctm, |
589 | | const cairo_matrix_t *ctm_inverse, |
590 | | double tolerance, |
591 | | cairo_antialias_t antialias, |
592 | | const cairo_clip_t *clip) |
593 | 7.23k | { |
594 | 7.23k | cairo_analysis_surface_t *surface = abstract_surface; |
595 | 7.23k | cairo_int_status_t backend_status; |
596 | 7.23k | cairo_rectangle_int_t extents; |
597 | | |
598 | 7.23k | surface->source_region_id = 0; |
599 | 7.23k | surface->mask_region_id = 0; |
600 | 7.23k | if (surface->target->backend->stroke == NULL) { |
601 | 0 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
602 | 7.23k | } else { |
603 | 7.23k | backend_status = |
604 | 7.23k | surface->target->backend->stroke (surface->target, op, |
605 | 7.23k | source, path, style, |
606 | 7.23k | ctm, ctm_inverse, |
607 | 7.23k | tolerance, antialias, |
608 | 7.23k | clip); |
609 | 7.23k | if (_cairo_int_status_is_error (backend_status)) |
610 | 0 | return backend_status; |
611 | 7.23k | } |
612 | | |
613 | 7.23k | _cairo_analysis_surface_operation_extents (surface, |
614 | 7.23k | op, source, clip, |
615 | 7.23k | &extents); |
616 | 7.23k | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
617 | 0 | cairo_rectangle_int_t rec_extents; |
618 | 0 | backend_status = _analyze_recording_surface_pattern (surface, |
619 | 0 | source, |
620 | 0 | &rec_extents, |
621 | 0 | &surface->source_region_id, |
622 | 0 | CAIRO_ANALYSIS_SOURCE_STROKE); |
623 | 0 | _cairo_rectangle_intersect (&extents, &rec_extents); |
624 | 0 | } |
625 | | |
626 | 7.23k | if (_cairo_operator_bounded_by_mask (op)) { |
627 | 7.23k | cairo_rectangle_int_t mask_extents; |
628 | 7.23k | cairo_int_status_t status; |
629 | | |
630 | 7.23k | status = _cairo_path_fixed_stroke_extents (path, style, |
631 | 7.23k | ctm, ctm_inverse, |
632 | 7.23k | tolerance, |
633 | 7.23k | &mask_extents); |
634 | 7.23k | if (unlikely (status)) |
635 | 0 | return status; |
636 | | |
637 | 7.23k | _cairo_rectangle_intersect (&extents, &mask_extents); |
638 | 7.23k | } |
639 | | |
640 | 7.23k | return _add_operation (surface, &extents, backend_status); |
641 | 7.23k | } |
642 | | |
643 | | static cairo_int_status_t |
644 | | _cairo_analysis_surface_fill (void *abstract_surface, |
645 | | cairo_operator_t op, |
646 | | const cairo_pattern_t *source, |
647 | | const cairo_path_fixed_t *path, |
648 | | cairo_fill_rule_t fill_rule, |
649 | | double tolerance, |
650 | | cairo_antialias_t antialias, |
651 | | const cairo_clip_t *clip) |
652 | 5.82k | { |
653 | 5.82k | cairo_analysis_surface_t *surface = abstract_surface; |
654 | 5.82k | cairo_int_status_t backend_status; |
655 | 5.82k | cairo_rectangle_int_t extents; |
656 | | |
657 | 5.82k | if (surface->target->backend->fill == NULL) { |
658 | 0 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
659 | 5.82k | } else { |
660 | 5.82k | backend_status = |
661 | 5.82k | surface->target->backend->fill (surface->target, op, |
662 | 5.82k | source, path, fill_rule, |
663 | 5.82k | tolerance, antialias, |
664 | 5.82k | clip); |
665 | 5.82k | if (_cairo_int_status_is_error (backend_status)) |
666 | 0 | return backend_status; |
667 | 5.82k | } |
668 | | |
669 | 5.82k | _cairo_analysis_surface_operation_extents (surface, |
670 | 5.82k | op, source, clip, |
671 | 5.82k | &extents); |
672 | 5.82k | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
673 | 518 | cairo_rectangle_int_t rec_extents; |
674 | 518 | backend_status = _analyze_recording_surface_pattern (surface, |
675 | 518 | source, |
676 | 518 | &rec_extents, |
677 | 518 | &surface->source_region_id, |
678 | 518 | CAIRO_ANALYSIS_SOURCE_FILL); |
679 | 518 | _cairo_rectangle_intersect (&extents, &rec_extents); |
680 | 518 | } |
681 | | |
682 | 5.82k | if (_cairo_operator_bounded_by_mask (op)) { |
683 | 5.82k | cairo_rectangle_int_t mask_extents; |
684 | | |
685 | 5.82k | _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, |
686 | 5.82k | &mask_extents); |
687 | | |
688 | 5.82k | _cairo_rectangle_intersect (&extents, &mask_extents); |
689 | 5.82k | } |
690 | | |
691 | 5.82k | return _add_operation (surface, &extents, backend_status); |
692 | 5.82k | } |
693 | | |
694 | | static cairo_int_status_t |
695 | | _cairo_analysis_surface_show_glyphs (void *abstract_surface, |
696 | | cairo_operator_t op, |
697 | | const cairo_pattern_t *source, |
698 | | cairo_glyph_t *glyphs, |
699 | | int num_glyphs, |
700 | | cairo_scaled_font_t *scaled_font, |
701 | | const cairo_clip_t *clip) |
702 | 354k | { |
703 | 354k | cairo_analysis_surface_t *surface = abstract_surface; |
704 | 354k | cairo_int_status_t status, backend_status; |
705 | 354k | cairo_rectangle_int_t extents, glyph_extents; |
706 | | |
707 | 354k | surface->source_region_id = 0; |
708 | 354k | surface->mask_region_id = 0; |
709 | | |
710 | | /* Adapted from _cairo_surface_show_glyphs */ |
711 | 354k | if (surface->target->backend->show_glyphs != NULL) { |
712 | 0 | backend_status = |
713 | 0 | surface->target->backend->show_glyphs (surface->target, op, |
714 | 0 | source, |
715 | 0 | glyphs, num_glyphs, |
716 | 0 | scaled_font, |
717 | 0 | clip); |
718 | 0 | if (_cairo_int_status_is_error (backend_status)) |
719 | 0 | return backend_status; |
720 | 0 | } |
721 | 354k | else if (surface->target->backend->show_text_glyphs != NULL) |
722 | 354k | { |
723 | 354k | backend_status = |
724 | 354k | surface->target->backend->show_text_glyphs (surface->target, op, |
725 | 354k | source, |
726 | 354k | NULL, 0, |
727 | 354k | glyphs, num_glyphs, |
728 | 354k | NULL, 0, |
729 | 354k | FALSE, |
730 | 354k | scaled_font, |
731 | 354k | clip); |
732 | 354k | if (_cairo_int_status_is_error (backend_status)) |
733 | 0 | return backend_status; |
734 | 354k | } |
735 | 0 | else |
736 | 0 | { |
737 | 0 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
738 | 0 | } |
739 | | |
740 | 354k | _cairo_analysis_surface_operation_extents (surface, |
741 | 354k | op, source, clip, |
742 | 354k | &extents); |
743 | 354k | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
744 | 0 | cairo_rectangle_int_t rec_extents; |
745 | 0 | backend_status = _analyze_recording_surface_pattern (surface, |
746 | 0 | source, |
747 | 0 | &rec_extents, |
748 | 0 | &surface->source_region_id, |
749 | 0 | CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS); |
750 | 0 | _cairo_rectangle_intersect (&extents, &rec_extents); |
751 | 0 | } |
752 | | |
753 | 354k | if (_cairo_operator_bounded_by_mask (op)) { |
754 | 354k | status = _cairo_scaled_font_glyph_device_extents (scaled_font, |
755 | 354k | glyphs, |
756 | 354k | num_glyphs, |
757 | 354k | &glyph_extents, |
758 | 354k | NULL); |
759 | 354k | if (unlikely (status)) |
760 | 0 | return status; |
761 | | |
762 | 354k | _cairo_rectangle_intersect (&extents, &glyph_extents); |
763 | 354k | } |
764 | | |
765 | 354k | return _add_operation (surface, &extents, backend_status); |
766 | 354k | } |
767 | | |
768 | | static cairo_bool_t |
769 | | _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface) |
770 | 0 | { |
771 | 0 | cairo_analysis_surface_t *surface = abstract_surface; |
772 | |
|
773 | 0 | return cairo_surface_has_show_text_glyphs (surface->target); |
774 | 0 | } |
775 | | |
776 | | static cairo_int_status_t |
777 | | _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, |
778 | | cairo_operator_t op, |
779 | | const cairo_pattern_t *source, |
780 | | const char *utf8, |
781 | | int utf8_len, |
782 | | cairo_glyph_t *glyphs, |
783 | | int num_glyphs, |
784 | | const cairo_text_cluster_t *clusters, |
785 | | int num_clusters, |
786 | | cairo_text_cluster_flags_t cluster_flags, |
787 | | cairo_scaled_font_t *scaled_font, |
788 | | const cairo_clip_t *clip) |
789 | 130k | { |
790 | 130k | cairo_analysis_surface_t *surface = abstract_surface; |
791 | 130k | cairo_int_status_t status, backend_status; |
792 | 130k | cairo_rectangle_int_t extents, glyph_extents; |
793 | | |
794 | 130k | surface->source_region_id = 0; |
795 | 130k | surface->mask_region_id = 0; |
796 | | |
797 | | /* Adapted from _cairo_surface_show_glyphs */ |
798 | 130k | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
799 | 130k | if (surface->target->backend->show_text_glyphs != NULL) { |
800 | 130k | backend_status = |
801 | 130k | surface->target->backend->show_text_glyphs (surface->target, op, |
802 | 130k | source, |
803 | 130k | utf8, utf8_len, |
804 | 130k | glyphs, num_glyphs, |
805 | 130k | clusters, num_clusters, |
806 | 130k | cluster_flags, |
807 | 130k | scaled_font, |
808 | 130k | clip); |
809 | 130k | if (_cairo_int_status_is_error (backend_status)) |
810 | 0 | return backend_status; |
811 | 130k | } |
812 | 130k | if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && |
813 | 130k | surface->target->backend->show_glyphs != NULL) |
814 | 0 | { |
815 | 0 | backend_status = |
816 | 0 | surface->target->backend->show_glyphs (surface->target, op, |
817 | 0 | source, |
818 | 0 | glyphs, num_glyphs, |
819 | 0 | scaled_font, |
820 | 0 | clip); |
821 | 0 | if (_cairo_int_status_is_error (backend_status)) |
822 | 0 | return backend_status; |
823 | 0 | } |
824 | | |
825 | 130k | _cairo_analysis_surface_operation_extents (surface, |
826 | 130k | op, source, clip, |
827 | 130k | &extents); |
828 | 130k | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
829 | 0 | cairo_rectangle_int_t rec_extents; |
830 | 0 | _analyze_recording_surface_pattern (surface, |
831 | 0 | source, |
832 | 0 | &rec_extents, |
833 | 0 | &surface->source_region_id, |
834 | 0 | CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS); |
835 | 0 | _cairo_rectangle_intersect (&extents, &rec_extents); |
836 | 0 | } |
837 | | |
838 | 130k | if (_cairo_operator_bounded_by_mask (op)) { |
839 | 130k | status = _cairo_scaled_font_glyph_device_extents (scaled_font, |
840 | 130k | glyphs, |
841 | 130k | num_glyphs, |
842 | 130k | &glyph_extents, |
843 | 130k | NULL); |
844 | 130k | if (unlikely (status)) |
845 | 0 | return status; |
846 | | |
847 | 130k | _cairo_rectangle_intersect (&extents, &glyph_extents); |
848 | 130k | } |
849 | | |
850 | 130k | return _add_operation (surface, &extents, backend_status); |
851 | 130k | } |
852 | | |
853 | | static cairo_int_status_t |
854 | | _cairo_analysis_surface_tag (void *abstract_surface, |
855 | | cairo_bool_t begin, |
856 | | const char *tag_name, |
857 | | const char *attributes) |
858 | 0 | { |
859 | 0 | cairo_analysis_surface_t *surface = abstract_surface; |
860 | 0 | cairo_int_status_t backend_status; |
861 | |
|
862 | 0 | surface->source_region_id = 0; |
863 | 0 | surface->mask_region_id = 0; |
864 | 0 | backend_status = CAIRO_INT_STATUS_SUCCESS; |
865 | 0 | if (surface->target->backend->tag != NULL) { |
866 | 0 | backend_status = |
867 | 0 | surface->target->backend->tag (surface->target, |
868 | 0 | begin, |
869 | 0 | tag_name, |
870 | 0 | attributes); |
871 | 0 | if (backend_status == CAIRO_INT_STATUS_SUCCESS) |
872 | 0 | surface->has_supported = TRUE; |
873 | 0 | } |
874 | |
|
875 | 0 | return backend_status; |
876 | 0 | } |
877 | | |
878 | | static cairo_bool_t |
879 | | _cairo_analysis_surface_supports_color_glyph (void *abstract_surface, |
880 | | cairo_scaled_font_t *scaled_font, |
881 | | unsigned long glyph_index) |
882 | 0 | { |
883 | 0 | return TRUE; |
884 | 0 | } |
885 | | |
886 | | static cairo_int_status_t |
887 | | _cairo_analysis_surface_command_id (void *abstract_surface, |
888 | | unsigned int recording_id, |
889 | | unsigned int command_id) |
890 | 499k | { |
891 | 499k | cairo_analysis_surface_t *surface = abstract_surface; |
892 | 499k | cairo_int_status_t backend_status; |
893 | | |
894 | 499k | backend_status = CAIRO_INT_STATUS_SUCCESS; |
895 | 499k | if (surface->target->backend->command_id != NULL) { |
896 | 499k | backend_status = |
897 | 499k | surface->target->backend->command_id (surface->target, |
898 | 499k | recording_id, |
899 | 499k | command_id); |
900 | 499k | } |
901 | | |
902 | 499k | return backend_status; |
903 | 499k | } |
904 | | |
905 | | static const cairo_surface_backend_t cairo_analysis_surface_backend = { |
906 | | CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, |
907 | | |
908 | | _cairo_analysis_surface_finish, |
909 | | NULL, |
910 | | |
911 | | NULL, /* create_similar */ |
912 | | NULL, /* create_similar_image */ |
913 | | NULL, /* map_to_image */ |
914 | | NULL, /* unmap */ |
915 | | |
916 | | NULL, /* source */ |
917 | | NULL, /* acquire_source_image */ |
918 | | NULL, /* release_source_image */ |
919 | | NULL, /* snapshot */ |
920 | | |
921 | | NULL, /* copy_page */ |
922 | | NULL, /* show_page */ |
923 | | |
924 | | _cairo_analysis_surface_get_extents, |
925 | | NULL, /* get_font_options */ |
926 | | |
927 | | NULL, /* flush */ |
928 | | NULL, /* mark_dirty_rectangle */ |
929 | | |
930 | | _cairo_analysis_surface_paint, |
931 | | _cairo_analysis_surface_mask, |
932 | | _cairo_analysis_surface_stroke, |
933 | | _cairo_analysis_surface_fill, |
934 | | NULL, /* fill_stroke */ |
935 | | _cairo_analysis_surface_show_glyphs, |
936 | | _cairo_analysis_surface_has_show_text_glyphs, |
937 | | _cairo_analysis_surface_show_text_glyphs, |
938 | | NULL, /* get_supported_mime_types */ |
939 | | _cairo_analysis_surface_tag, |
940 | | _cairo_analysis_surface_supports_color_glyph, |
941 | | NULL, /* analyze_recording_surface */ |
942 | | _cairo_analysis_surface_command_id, |
943 | | }; |
944 | | |
945 | | cairo_surface_t * |
946 | | _cairo_analysis_surface_create (cairo_surface_t *target, |
947 | | cairo_bool_t create_region_ids) |
948 | 2.57k | { |
949 | 2.57k | cairo_analysis_surface_t *surface; |
950 | 2.57k | cairo_status_t status; |
951 | | |
952 | 2.57k | status = target->status; |
953 | 2.57k | if (unlikely (status)) |
954 | 0 | return _cairo_surface_create_in_error (status); |
955 | | |
956 | 2.57k | surface = _cairo_calloc (sizeof (cairo_analysis_surface_t)); |
957 | 2.57k | if (unlikely (surface == NULL)) |
958 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
959 | | |
960 | | /* I believe the content type here is truly arbitrary. I'm quite |
961 | | * sure nothing will ever use this value. */ |
962 | 2.57k | _cairo_surface_init (&surface->base, |
963 | 2.57k | &cairo_analysis_surface_backend, |
964 | 2.57k | NULL, /* device */ |
965 | 2.57k | CAIRO_CONTENT_COLOR_ALPHA, |
966 | 2.57k | target->is_vector); |
967 | | |
968 | 2.57k | cairo_matrix_init_identity (&surface->ctm); |
969 | 2.57k | surface->has_ctm = FALSE; |
970 | | |
971 | 2.57k | surface->target = cairo_surface_reference (target); |
972 | 2.57k | surface->first_op = TRUE; |
973 | 2.57k | surface->has_supported = FALSE; |
974 | 2.57k | surface->has_unsupported = FALSE; |
975 | | |
976 | 2.57k | surface->create_region_ids = create_region_ids; |
977 | 2.57k | surface->source_region_id = 0; |
978 | 2.57k | surface->mask_region_id = 0; |
979 | | |
980 | 2.57k | _cairo_region_init (&surface->supported_region); |
981 | 2.57k | _cairo_region_init (&surface->fallback_region); |
982 | | |
983 | 2.57k | surface->page_bbox.p1.x = 0; |
984 | 2.57k | surface->page_bbox.p1.y = 0; |
985 | 2.57k | surface->page_bbox.p2.x = 0; |
986 | 2.57k | surface->page_bbox.p2.y = 0; |
987 | | |
988 | 2.57k | return &surface->base; |
989 | 2.57k | } |
990 | | |
991 | | void |
992 | | _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface, |
993 | | const cairo_matrix_t *ctm) |
994 | 571 | { |
995 | 571 | cairo_analysis_surface_t *surface; |
996 | | |
997 | 571 | if (abstract_surface->status) |
998 | 0 | return; |
999 | | |
1000 | 571 | surface = (cairo_analysis_surface_t *) abstract_surface; |
1001 | | |
1002 | 571 | surface->ctm = *ctm; |
1003 | 571 | surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); |
1004 | 571 | } |
1005 | | |
1006 | | void |
1007 | | _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface, |
1008 | | cairo_matrix_t *ctm) |
1009 | 0 | { |
1010 | 0 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1011 | |
|
1012 | 0 | *ctm = surface->ctm; |
1013 | 0 | } |
1014 | | |
1015 | | |
1016 | | cairo_region_t * |
1017 | | _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface) |
1018 | 0 | { |
1019 | 0 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1020 | |
|
1021 | 0 | return &surface->supported_region; |
1022 | 0 | } |
1023 | | |
1024 | | cairo_region_t * |
1025 | | _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface) |
1026 | 0 | { |
1027 | 0 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1028 | |
|
1029 | 0 | return &surface->fallback_region; |
1030 | 0 | } |
1031 | | |
1032 | | cairo_bool_t |
1033 | | _cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface) |
1034 | 2.00k | { |
1035 | 2.00k | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1036 | | |
1037 | 2.00k | return surface->has_supported; |
1038 | 2.00k | } |
1039 | | |
1040 | | cairo_bool_t |
1041 | | _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface) |
1042 | 4.00k | { |
1043 | 4.00k | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1044 | | |
1045 | 4.00k | return surface->has_unsupported; |
1046 | 4.00k | } |
1047 | | |
1048 | | void |
1049 | | _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface, |
1050 | | cairo_box_t *bbox) |
1051 | 23 | { |
1052 | 23 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1053 | | |
1054 | 23 | *bbox = surface->page_bbox; |
1055 | 23 | } |
1056 | | |
1057 | | unsigned int |
1058 | | _cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface) |
1059 | 499k | { |
1060 | 499k | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1061 | | |
1062 | 499k | return surface->source_region_id; |
1063 | 499k | } |
1064 | | |
1065 | | unsigned int |
1066 | | _cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface) |
1067 | 1.17k | { |
1068 | 1.17k | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
1069 | | |
1070 | 1.17k | return surface->mask_region_id; |
1071 | 1.17k | } |
1072 | | |
1073 | | |
1074 | | /* null surface type: a surface that does nothing (has no side effects, yay!) */ |
1075 | | |
1076 | | static cairo_int_status_t |
1077 | | _paint_return_success (void *surface, |
1078 | | cairo_operator_t op, |
1079 | | const cairo_pattern_t *source, |
1080 | | const cairo_clip_t *clip) |
1081 | 0 | { |
1082 | 0 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1083 | 0 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; |
1084 | 0 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1085 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1086 | 0 | } |
1087 | | |
1088 | 0 | return CAIRO_INT_STATUS_SUCCESS; |
1089 | 0 | } |
1090 | | |
1091 | | static cairo_int_status_t |
1092 | | _mask_return_success (void *surface, |
1093 | | cairo_operator_t op, |
1094 | | const cairo_pattern_t *source, |
1095 | | const cairo_pattern_t *mask, |
1096 | | const cairo_clip_t *clip) |
1097 | 2 | { |
1098 | 2 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1099 | 0 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; |
1100 | 0 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1101 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1102 | 0 | } |
1103 | | |
1104 | 2 | if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1105 | 2 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask; |
1106 | 2 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1107 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1108 | 2 | } |
1109 | | |
1110 | 2 | return CAIRO_INT_STATUS_SUCCESS; |
1111 | 2 | } |
1112 | | |
1113 | | static cairo_int_status_t |
1114 | | _stroke_return_success (void *surface, |
1115 | | cairo_operator_t op, |
1116 | | const cairo_pattern_t *source, |
1117 | | const cairo_path_fixed_t *path, |
1118 | | const cairo_stroke_style_t *style, |
1119 | | const cairo_matrix_t *ctm, |
1120 | | const cairo_matrix_t *ctm_inverse, |
1121 | | double tolerance, |
1122 | | cairo_antialias_t antialias, |
1123 | | const cairo_clip_t *clip) |
1124 | 2 | { |
1125 | 2 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1126 | 0 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; |
1127 | 0 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1128 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1129 | 0 | } |
1130 | | |
1131 | 2 | return CAIRO_INT_STATUS_SUCCESS; |
1132 | 2 | } |
1133 | | |
1134 | | static cairo_int_status_t |
1135 | | _fill_return_success (void *surface, |
1136 | | cairo_operator_t op, |
1137 | | const cairo_pattern_t *source, |
1138 | | const cairo_path_fixed_t *path, |
1139 | | cairo_fill_rule_t fill_rule, |
1140 | | double tolerance, |
1141 | | cairo_antialias_t antialias, |
1142 | | const cairo_clip_t *clip) |
1143 | 340 | { |
1144 | 340 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1145 | 0 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; |
1146 | 0 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1147 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1148 | 0 | } |
1149 | | |
1150 | 340 | return CAIRO_INT_STATUS_SUCCESS; |
1151 | 340 | } |
1152 | | |
1153 | | static cairo_int_status_t |
1154 | | _show_glyphs_return_success (void *surface, |
1155 | | cairo_operator_t op, |
1156 | | const cairo_pattern_t *source, |
1157 | | cairo_glyph_t *glyphs, |
1158 | | int num_glyphs, |
1159 | | cairo_scaled_font_t *scaled_font, |
1160 | | const cairo_clip_t *clip) |
1161 | 0 | { |
1162 | 0 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1163 | 0 | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; |
1164 | 0 | if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) |
1165 | 0 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
1166 | 0 | } |
1167 | | |
1168 | 0 | return CAIRO_INT_STATUS_SUCCESS; |
1169 | 0 | } |
1170 | | |
1171 | | static const cairo_surface_backend_t cairo_null_surface_backend = { |
1172 | | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
1173 | | NULL, /* finish */ |
1174 | | |
1175 | | NULL, /* only accessed through the surface functions */ |
1176 | | |
1177 | | NULL, /* create_similar */ |
1178 | | NULL, /* create similar image */ |
1179 | | NULL, /* map to image */ |
1180 | | NULL, /* unmap image*/ |
1181 | | |
1182 | | NULL, /* source */ |
1183 | | NULL, /* acquire_source_image */ |
1184 | | NULL, /* release_source_image */ |
1185 | | NULL, /* snapshot */ |
1186 | | |
1187 | | NULL, /* copy_page */ |
1188 | | NULL, /* show_page */ |
1189 | | |
1190 | | NULL, /* get_extents */ |
1191 | | NULL, /* get_font_options */ |
1192 | | |
1193 | | NULL, /* flush */ |
1194 | | NULL, /* mark_dirty_rectangle */ |
1195 | | |
1196 | | _paint_return_success, /* paint */ |
1197 | | _mask_return_success, /* mask */ |
1198 | | _stroke_return_success, /* stroke */ |
1199 | | _fill_return_success, /* fill */ |
1200 | | NULL, /* fill_stroke */ |
1201 | | _show_glyphs_return_success, /* show_glyphs */ |
1202 | | NULL, /* has_show_text_glyphs */ |
1203 | | NULL, /* show_text_glyphs */ |
1204 | | NULL, /* get_supported_mime_types */ |
1205 | | NULL, /* tag */ |
1206 | | NULL, /* supports_color_glyph */ |
1207 | | NULL, /* analyze_recording_surface */ |
1208 | | NULL, /* command_id*/ |
1209 | | }; |
1210 | | |
1211 | | cairo_surface_t * |
1212 | | _cairo_null_surface_create (cairo_content_t content) |
1213 | 23 | { |
1214 | 23 | cairo_surface_t *surface; |
1215 | | |
1216 | 23 | surface = _cairo_calloc (sizeof (cairo_surface_t)); |
1217 | 23 | if (unlikely (surface == NULL)) { |
1218 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
1219 | 0 | } |
1220 | | |
1221 | 23 | _cairo_surface_init (surface, |
1222 | 23 | &cairo_null_surface_backend, |
1223 | 23 | NULL, /* device */ |
1224 | 23 | content, |
1225 | 23 | TRUE); /* is_vector */ |
1226 | | |
1227 | 23 | return surface; |
1228 | 23 | } |