Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 1 | /* |
2 | * Copyright © 2006 Keith Packard |
||
3 | * Copyright © 2007 Adrian Johnson |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it either under the terms of the GNU Lesser General Public |
||
7 | * License version 2.1 as published by the Free Software Foundation |
||
8 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
9 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
10 | * notice, a recipient may use your version of this file under either |
||
11 | * the MPL or the LGPL. |
||
12 | * |
||
13 | * You should have received a copy of the LGPL along with this library |
||
14 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
15 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
16 | * You should have received a copy of the MPL along with this library |
||
17 | * in the file COPYING-MPL-1.1 |
||
18 | * |
||
19 | * The contents of this file are subject to the Mozilla Public License |
||
20 | * Version 1.1 (the "License"); you may not use this file except in |
||
21 | * compliance with the License. You may obtain a copy of the License at |
||
22 | * http://www.mozilla.org/MPL/ |
||
23 | * |
||
24 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
25 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
26 | * the specific language governing rights and limitations. |
||
27 | * |
||
28 | * The Original Code is the cairo graphics library. |
||
29 | * |
||
30 | * The Initial Developer of the Original Code is Keith Packard |
||
31 | * |
||
32 | * Contributor(s): |
||
33 | * Keith Packard |
||
34 | * Adrian Johnson |
||
35 | */ |
||
36 | |||
37 | #include "cairoint.h" |
||
38 | |||
39 | #include "cairo-analysis-surface-private.h" |
||
3959 | Serge | 40 | #include "cairo-box-inline.h" |
41 | #include "cairo-default-context-private.h" |
||
1892 | serge | 42 | #include "cairo-error-private.h" |
43 | #include "cairo-paginated-private.h" |
||
3959 | Serge | 44 | #include "cairo-recording-surface-inline.h" |
45 | #include "cairo-surface-snapshot-inline.h" |
||
46 | #include "cairo-surface-subsurface-inline.h" |
||
1892 | serge | 47 | #include "cairo-region-private.h" |
48 | |||
49 | typedef struct { |
||
50 | cairo_surface_t base; |
||
51 | |||
52 | cairo_surface_t *target; |
||
53 | |||
54 | cairo_bool_t first_op; |
||
55 | cairo_bool_t has_supported; |
||
56 | cairo_bool_t has_unsupported; |
||
57 | |||
58 | cairo_region_t supported_region; |
||
59 | cairo_region_t fallback_region; |
||
60 | cairo_box_t page_bbox; |
||
61 | |||
62 | cairo_bool_t has_ctm; |
||
63 | cairo_matrix_t ctm; |
||
64 | |||
65 | } cairo_analysis_surface_t; |
||
66 | |||
67 | cairo_int_status_t |
||
68 | _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, |
||
69 | cairo_int_status_t status_b) |
||
70 | { |
||
71 | /* fatal errors should be checked and propagated at source */ |
||
3959 | Serge | 72 | assert (! _cairo_int_status_is_error (status_a)); |
73 | assert (! _cairo_int_status_is_error (status_b)); |
||
1892 | serge | 74 | |
75 | /* return the most important status */ |
||
76 | if (status_a == CAIRO_INT_STATUS_UNSUPPORTED || |
||
77 | status_b == CAIRO_INT_STATUS_UNSUPPORTED) |
||
78 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
79 | |||
80 | if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK || |
||
81 | status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK) |
||
82 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
||
83 | |||
84 | if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN || |
||
85 | status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
86 | return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; |
||
87 | |||
88 | if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
||
89 | status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) |
||
90 | return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; |
||
91 | |||
92 | /* at this point we have checked all the valid internal codes, so... */ |
||
3959 | Serge | 93 | assert (status_a == CAIRO_INT_STATUS_SUCCESS && |
94 | status_b == CAIRO_INT_STATUS_SUCCESS); |
||
1892 | serge | 95 | |
3959 | Serge | 96 | return CAIRO_INT_STATUS_SUCCESS; |
97 | } |
||
98 | |||
99 | struct proxy { |
||
100 | cairo_surface_t base; |
||
101 | cairo_surface_t *target; |
||
102 | }; |
||
103 | |||
104 | static cairo_status_t |
||
105 | proxy_finish (void *abstract_surface) |
||
106 | { |
||
1892 | serge | 107 | return CAIRO_STATUS_SUCCESS; |
108 | } |
||
109 | |||
3959 | Serge | 110 | static const cairo_surface_backend_t proxy_backend = { |
111 | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
||
112 | proxy_finish, |
||
113 | }; |
||
114 | |||
115 | static cairo_surface_t * |
||
116 | attach_proxy (cairo_surface_t *source, |
||
117 | cairo_surface_t *target) |
||
118 | { |
||
119 | struct proxy *proxy; |
||
120 | |||
121 | proxy = malloc (sizeof (*proxy)); |
||
122 | if (unlikely (proxy == NULL)) |
||
123 | return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); |
||
124 | |||
125 | _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content); |
||
126 | |||
127 | proxy->target = target; |
||
128 | _cairo_surface_attach_snapshot (source, &proxy->base, NULL); |
||
129 | |||
130 | return &proxy->base; |
||
131 | } |
||
132 | |||
133 | static void |
||
134 | detach_proxy (cairo_surface_t *proxy) |
||
135 | { |
||
136 | cairo_surface_finish (proxy); |
||
137 | cairo_surface_destroy (proxy); |
||
138 | } |
||
139 | |||
1892 | serge | 140 | static cairo_int_status_t |
141 | _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, |
||
142 | const cairo_pattern_t *pattern) |
||
143 | { |
||
144 | const cairo_surface_pattern_t *surface_pattern; |
||
3959 | Serge | 145 | cairo_analysis_surface_t *tmp; |
146 | cairo_surface_t *source, *proxy; |
||
147 | cairo_matrix_t p2d; |
||
148 | cairo_status_t status, analysis_status; |
||
1892 | serge | 149 | |
150 | assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); |
||
151 | surface_pattern = (const cairo_surface_pattern_t *) pattern; |
||
152 | assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); |
||
3959 | Serge | 153 | source = surface_pattern->surface; |
1892 | serge | 154 | |
3959 | Serge | 155 | proxy = _cairo_surface_has_snapshot (source, &proxy_backend); |
156 | if (proxy != NULL) { |
||
157 | /* nothing untoward found so far */ |
||
158 | return CAIRO_STATUS_SUCCESS; |
||
159 | } |
||
1892 | serge | 160 | |
3959 | Serge | 161 | tmp = (cairo_analysis_surface_t *) |
162 | _cairo_analysis_surface_create (surface->target); |
||
163 | if (unlikely (tmp->base.status)) |
||
164 | return tmp->base.status; |
||
165 | proxy = attach_proxy (source, &tmp->base); |
||
166 | |||
1892 | serge | 167 | p2d = pattern->matrix; |
168 | status = cairo_matrix_invert (&p2d); |
||
169 | assert (status == CAIRO_STATUS_SUCCESS); |
||
170 | |||
3959 | Serge | 171 | cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm); |
172 | tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm); |
||
1892 | serge | 173 | |
3959 | Serge | 174 | source = _cairo_surface_get_source (source, NULL); |
175 | status = _cairo_recording_surface_replay_and_create_regions (source, |
||
176 | &tmp->base); |
||
177 | analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; |
||
178 | detach_proxy (proxy); |
||
179 | cairo_surface_destroy (&tmp->base); |
||
1892 | serge | 180 | |
3959 | Serge | 181 | if (unlikely (status)) |
182 | return status; |
||
1892 | serge | 183 | |
3959 | Serge | 184 | return analysis_status; |
1892 | serge | 185 | } |
186 | |||
187 | static cairo_int_status_t |
||
188 | _add_operation (cairo_analysis_surface_t *surface, |
||
189 | cairo_rectangle_int_t *rect, |
||
190 | cairo_int_status_t backend_status) |
||
191 | { |
||
192 | cairo_int_status_t status; |
||
193 | cairo_box_t bbox; |
||
194 | |||
195 | if (rect->width == 0 || rect->height == 0) { |
||
196 | /* Even though the operation is not visible we must be careful |
||
197 | * to not allow unsupported operations to be replayed to the |
||
198 | * backend during CAIRO_PAGINATED_MODE_RENDER */ |
||
3959 | Serge | 199 | if (backend_status == CAIRO_INT_STATUS_SUCCESS || |
200 | backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
||
201 | backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
||
1892 | serge | 202 | { |
3959 | Serge | 203 | return CAIRO_INT_STATUS_SUCCESS; |
1892 | serge | 204 | } |
205 | else |
||
206 | { |
||
207 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
||
208 | } |
||
209 | } |
||
210 | |||
211 | _cairo_box_from_rectangle (&bbox, rect); |
||
212 | |||
213 | if (surface->has_ctm) { |
||
214 | int tx, ty; |
||
215 | |||
216 | if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) { |
||
217 | rect->x += tx; |
||
218 | rect->y += ty; |
||
3959 | Serge | 219 | |
220 | tx = _cairo_fixed_from_int (tx); |
||
221 | bbox.p1.x += tx; |
||
222 | bbox.p2.x += tx; |
||
223 | |||
224 | ty = _cairo_fixed_from_int (ty); |
||
225 | bbox.p1.y += ty; |
||
226 | bbox.p2.y += ty; |
||
1892 | serge | 227 | } else { |
228 | _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, |
||
229 | &bbox, NULL); |
||
230 | |||
231 | if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { |
||
232 | /* Even though the operation is not visible we must be |
||
233 | * careful to not allow unsupported operations to be |
||
234 | * replayed to the backend during |
||
235 | * CAIRO_PAGINATED_MODE_RENDER */ |
||
3959 | Serge | 236 | if (backend_status == CAIRO_INT_STATUS_SUCCESS || |
237 | backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || |
||
238 | backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) |
||
1892 | serge | 239 | { |
3959 | Serge | 240 | return CAIRO_INT_STATUS_SUCCESS; |
1892 | serge | 241 | } |
242 | else |
||
243 | { |
||
244 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
||
245 | } |
||
246 | } |
||
247 | |||
248 | _cairo_box_round_to_rectangle (&bbox, rect); |
||
249 | } |
||
250 | } |
||
251 | |||
252 | if (surface->first_op) { |
||
253 | surface->first_op = FALSE; |
||
254 | surface->page_bbox = bbox; |
||
3959 | Serge | 255 | } else |
256 | _cairo_box_add_box(&surface->page_bbox, &bbox); |
||
1892 | serge | 257 | |
258 | /* If the operation is completely enclosed within the fallback |
||
259 | * region there is no benefit in emitting a native operation as |
||
260 | * the fallback image will be painted on top. |
||
261 | */ |
||
262 | if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN) |
||
263 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
||
264 | |||
265 | if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { |
||
266 | /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates |
||
267 | * that the backend only supports this operation if the |
||
268 | * transparency removed. If the extents of this operation does |
||
269 | * not intersect any other native operation, the operation is |
||
270 | * natively supported and the backend will blend the |
||
271 | * transparency into the white background. |
||
272 | */ |
||
273 | if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT) |
||
3959 | Serge | 274 | backend_status = CAIRO_INT_STATUS_SUCCESS; |
1892 | serge | 275 | } |
276 | |||
3959 | Serge | 277 | if (backend_status == CAIRO_INT_STATUS_SUCCESS) { |
1892 | serge | 278 | /* Add the operation to the supported region. Operations in |
279 | * this region will be emitted as native operations. |
||
280 | */ |
||
281 | surface->has_supported = TRUE; |
||
282 | return cairo_region_union_rectangle (&surface->supported_region, rect); |
||
283 | } |
||
284 | |||
285 | /* Add the operation to the unsupported region. This region will |
||
286 | * be painted as an image after all native operations have been |
||
287 | * emitted. |
||
288 | */ |
||
289 | surface->has_unsupported = TRUE; |
||
290 | status = cairo_region_union_rectangle (&surface->fallback_region, rect); |
||
291 | |||
292 | /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate |
||
293 | * unsupported operations to the recording surface as using |
||
294 | * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to |
||
295 | * invoke the cairo-surface-fallback path then return |
||
296 | * CAIRO_STATUS_SUCCESS. |
||
297 | */ |
||
3959 | Serge | 298 | if (status == CAIRO_INT_STATUS_SUCCESS) |
1892 | serge | 299 | return CAIRO_INT_STATUS_IMAGE_FALLBACK; |
300 | else |
||
301 | return status; |
||
302 | } |
||
303 | |||
304 | static cairo_status_t |
||
305 | _cairo_analysis_surface_finish (void *abstract_surface) |
||
306 | { |
||
307 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
308 | |||
309 | _cairo_region_fini (&surface->supported_region); |
||
310 | _cairo_region_fini (&surface->fallback_region); |
||
311 | |||
312 | cairo_surface_destroy (surface->target); |
||
313 | |||
314 | return CAIRO_STATUS_SUCCESS; |
||
315 | } |
||
316 | |||
317 | static cairo_bool_t |
||
318 | _cairo_analysis_surface_get_extents (void *abstract_surface, |
||
319 | cairo_rectangle_int_t *rectangle) |
||
320 | { |
||
321 | cairo_analysis_surface_t *surface = abstract_surface; |
||
322 | |||
323 | return _cairo_surface_get_extents (surface->target, rectangle); |
||
324 | } |
||
325 | |||
326 | static void |
||
3959 | Serge | 327 | _rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip) |
1892 | serge | 328 | { |
329 | if (clip != NULL) |
||
3959 | Serge | 330 | _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip)); |
1892 | serge | 331 | } |
332 | |||
333 | static void |
||
334 | _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface, |
||
335 | cairo_operator_t op, |
||
336 | const cairo_pattern_t *source, |
||
3959 | Serge | 337 | const cairo_clip_t *clip, |
1892 | serge | 338 | cairo_rectangle_int_t *extents) |
339 | { |
||
340 | cairo_bool_t is_empty; |
||
341 | |||
342 | is_empty = _cairo_surface_get_extents (&surface->base, extents); |
||
343 | |||
344 | if (_cairo_operator_bounded_by_source (op)) { |
||
345 | cairo_rectangle_int_t source_extents; |
||
346 | |||
347 | _cairo_pattern_get_extents (source, &source_extents); |
||
3959 | Serge | 348 | _cairo_rectangle_intersect (extents, &source_extents); |
1892 | serge | 349 | } |
350 | |||
351 | _rectangle_intersect_clip (extents, clip); |
||
352 | } |
||
353 | |||
354 | static cairo_int_status_t |
||
355 | _cairo_analysis_surface_paint (void *abstract_surface, |
||
356 | cairo_operator_t op, |
||
357 | const cairo_pattern_t *source, |
||
3959 | Serge | 358 | const cairo_clip_t *clip) |
1892 | serge | 359 | { |
360 | cairo_analysis_surface_t *surface = abstract_surface; |
||
3959 | Serge | 361 | cairo_int_status_t backend_status; |
1892 | serge | 362 | cairo_rectangle_int_t extents; |
363 | |||
364 | if (surface->target->backend->paint == NULL) { |
||
365 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
366 | } else { |
||
367 | backend_status = |
||
368 | surface->target->backend->paint (surface->target, |
||
369 | op, source, clip); |
||
3959 | Serge | 370 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 371 | return backend_status; |
372 | } |
||
373 | |||
374 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
375 | backend_status = _analyze_recording_surface_pattern (surface, source); |
||
376 | |||
377 | _cairo_analysis_surface_operation_extents (surface, |
||
378 | op, source, clip, |
||
379 | &extents); |
||
380 | |||
381 | return _add_operation (surface, &extents, backend_status); |
||
382 | } |
||
383 | |||
384 | static cairo_int_status_t |
||
385 | _cairo_analysis_surface_mask (void *abstract_surface, |
||
386 | cairo_operator_t op, |
||
387 | const cairo_pattern_t *source, |
||
388 | const cairo_pattern_t *mask, |
||
3959 | Serge | 389 | const cairo_clip_t *clip) |
1892 | serge | 390 | { |
391 | cairo_analysis_surface_t *surface = abstract_surface; |
||
392 | cairo_int_status_t backend_status; |
||
393 | cairo_rectangle_int_t extents; |
||
394 | |||
395 | if (surface->target->backend->mask == NULL) { |
||
396 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
397 | } else { |
||
398 | backend_status = |
||
399 | surface->target->backend->mask (surface->target, |
||
400 | op, source, mask, clip); |
||
3959 | Serge | 401 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 402 | return backend_status; |
403 | } |
||
404 | |||
405 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { |
||
406 | cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; |
||
407 | cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS; |
||
408 | |||
409 | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
||
3959 | Serge | 410 | cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface; |
411 | src_surface = _cairo_surface_get_source (src_surface, NULL); |
||
412 | if (_cairo_surface_is_recording (src_surface)) { |
||
1892 | serge | 413 | backend_source_status = |
414 | _analyze_recording_surface_pattern (surface, source); |
||
3959 | Serge | 415 | if (_cairo_int_status_is_error (backend_source_status)) |
1892 | serge | 416 | return backend_source_status; |
417 | } |
||
418 | } |
||
419 | |||
420 | if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { |
||
3959 | Serge | 421 | cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface; |
422 | mask_surface = _cairo_surface_get_source (mask_surface, NULL); |
||
423 | if (_cairo_surface_is_recording (mask_surface)) { |
||
1892 | serge | 424 | backend_mask_status = |
425 | _analyze_recording_surface_pattern (surface, mask); |
||
3959 | Serge | 426 | if (_cairo_int_status_is_error (backend_mask_status)) |
1892 | serge | 427 | return backend_mask_status; |
428 | } |
||
429 | } |
||
430 | |||
431 | backend_status = |
||
432 | _cairo_analysis_surface_merge_status (backend_source_status, |
||
433 | backend_mask_status); |
||
434 | } |
||
435 | |||
436 | _cairo_analysis_surface_operation_extents (surface, |
||
437 | op, source, clip, |
||
438 | &extents); |
||
439 | |||
440 | if (_cairo_operator_bounded_by_mask (op)) { |
||
441 | cairo_rectangle_int_t mask_extents; |
||
442 | |||
443 | _cairo_pattern_get_extents (mask, &mask_extents); |
||
3959 | Serge | 444 | _cairo_rectangle_intersect (&extents, &mask_extents); |
1892 | serge | 445 | } |
446 | |||
447 | return _add_operation (surface, &extents, backend_status); |
||
448 | } |
||
449 | |||
450 | static cairo_int_status_t |
||
451 | _cairo_analysis_surface_stroke (void *abstract_surface, |
||
452 | cairo_operator_t op, |
||
453 | const cairo_pattern_t *source, |
||
3959 | Serge | 454 | const cairo_path_fixed_t *path, |
1892 | serge | 455 | const cairo_stroke_style_t *style, |
456 | const cairo_matrix_t *ctm, |
||
457 | const cairo_matrix_t *ctm_inverse, |
||
458 | double tolerance, |
||
459 | cairo_antialias_t antialias, |
||
3959 | Serge | 460 | const cairo_clip_t *clip) |
1892 | serge | 461 | { |
462 | cairo_analysis_surface_t *surface = abstract_surface; |
||
3959 | Serge | 463 | cairo_int_status_t backend_status; |
1892 | serge | 464 | cairo_rectangle_int_t extents; |
465 | |||
466 | if (surface->target->backend->stroke == NULL) { |
||
467 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
468 | } else { |
||
469 | backend_status = |
||
470 | surface->target->backend->stroke (surface->target, op, |
||
471 | source, path, style, |
||
472 | ctm, ctm_inverse, |
||
473 | tolerance, antialias, |
||
474 | clip); |
||
3959 | Serge | 475 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 476 | return backend_status; |
477 | } |
||
478 | |||
479 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
480 | backend_status = _analyze_recording_surface_pattern (surface, source); |
||
481 | |||
482 | _cairo_analysis_surface_operation_extents (surface, |
||
483 | op, source, clip, |
||
484 | &extents); |
||
485 | |||
486 | if (_cairo_operator_bounded_by_mask (op)) { |
||
487 | cairo_rectangle_int_t mask_extents; |
||
3959 | Serge | 488 | cairo_int_status_t status; |
1892 | serge | 489 | |
490 | status = _cairo_path_fixed_stroke_extents (path, style, |
||
491 | ctm, ctm_inverse, |
||
492 | tolerance, |
||
493 | &mask_extents); |
||
494 | if (unlikely (status)) |
||
495 | return status; |
||
496 | |||
3959 | Serge | 497 | _cairo_rectangle_intersect (&extents, &mask_extents); |
1892 | serge | 498 | } |
499 | |||
500 | return _add_operation (surface, &extents, backend_status); |
||
501 | } |
||
502 | |||
503 | static cairo_int_status_t |
||
504 | _cairo_analysis_surface_fill (void *abstract_surface, |
||
505 | cairo_operator_t op, |
||
506 | const cairo_pattern_t *source, |
||
3959 | Serge | 507 | const cairo_path_fixed_t *path, |
1892 | serge | 508 | cairo_fill_rule_t fill_rule, |
509 | double tolerance, |
||
510 | cairo_antialias_t antialias, |
||
3959 | Serge | 511 | const cairo_clip_t *clip) |
1892 | serge | 512 | { |
513 | cairo_analysis_surface_t *surface = abstract_surface; |
||
3959 | Serge | 514 | cairo_int_status_t backend_status; |
1892 | serge | 515 | cairo_rectangle_int_t extents; |
516 | |||
517 | if (surface->target->backend->fill == NULL) { |
||
518 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
519 | } else { |
||
520 | backend_status = |
||
521 | surface->target->backend->fill (surface->target, op, |
||
522 | source, path, fill_rule, |
||
523 | tolerance, antialias, |
||
524 | clip); |
||
3959 | Serge | 525 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 526 | return backend_status; |
527 | } |
||
528 | |||
529 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
530 | backend_status = _analyze_recording_surface_pattern (surface, source); |
||
531 | |||
532 | _cairo_analysis_surface_operation_extents (surface, |
||
533 | op, source, clip, |
||
534 | &extents); |
||
535 | |||
536 | if (_cairo_operator_bounded_by_mask (op)) { |
||
537 | cairo_rectangle_int_t mask_extents; |
||
538 | |||
539 | _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, |
||
540 | &mask_extents); |
||
541 | |||
3959 | Serge | 542 | _cairo_rectangle_intersect (&extents, &mask_extents); |
1892 | serge | 543 | } |
544 | |||
545 | return _add_operation (surface, &extents, backend_status); |
||
546 | } |
||
547 | |||
548 | static cairo_int_status_t |
||
549 | _cairo_analysis_surface_show_glyphs (void *abstract_surface, |
||
550 | cairo_operator_t op, |
||
551 | const cairo_pattern_t *source, |
||
552 | cairo_glyph_t *glyphs, |
||
553 | int num_glyphs, |
||
554 | cairo_scaled_font_t *scaled_font, |
||
3959 | Serge | 555 | const cairo_clip_t *clip) |
1892 | serge | 556 | { |
557 | cairo_analysis_surface_t *surface = abstract_surface; |
||
3959 | Serge | 558 | cairo_int_status_t status, backend_status; |
1892 | serge | 559 | cairo_rectangle_int_t extents, glyph_extents; |
560 | |||
561 | /* Adapted from _cairo_surface_show_glyphs */ |
||
562 | if (surface->target->backend->show_glyphs != NULL) { |
||
563 | backend_status = |
||
564 | surface->target->backend->show_glyphs (surface->target, op, |
||
565 | source, |
||
566 | glyphs, num_glyphs, |
||
567 | scaled_font, |
||
3959 | Serge | 568 | clip); |
569 | if (_cairo_int_status_is_error (backend_status)) |
||
1892 | serge | 570 | return backend_status; |
571 | } |
||
572 | else if (surface->target->backend->show_text_glyphs != NULL) |
||
573 | { |
||
574 | backend_status = |
||
575 | surface->target->backend->show_text_glyphs (surface->target, op, |
||
576 | source, |
||
577 | NULL, 0, |
||
578 | glyphs, num_glyphs, |
||
579 | NULL, 0, |
||
580 | FALSE, |
||
581 | scaled_font, |
||
582 | clip); |
||
3959 | Serge | 583 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 584 | return backend_status; |
585 | } |
||
586 | else |
||
587 | { |
||
588 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
589 | } |
||
590 | |||
591 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
592 | backend_status = _analyze_recording_surface_pattern (surface, source); |
||
593 | |||
594 | _cairo_analysis_surface_operation_extents (surface, |
||
595 | op, source, clip, |
||
596 | &extents); |
||
597 | |||
598 | if (_cairo_operator_bounded_by_mask (op)) { |
||
599 | status = _cairo_scaled_font_glyph_device_extents (scaled_font, |
||
600 | glyphs, |
||
601 | num_glyphs, |
||
602 | &glyph_extents, |
||
603 | NULL); |
||
604 | if (unlikely (status)) |
||
605 | return status; |
||
606 | |||
3959 | Serge | 607 | _cairo_rectangle_intersect (&extents, &glyph_extents); |
1892 | serge | 608 | } |
609 | |||
610 | return _add_operation (surface, &extents, backend_status); |
||
611 | } |
||
612 | |||
613 | static cairo_bool_t |
||
614 | _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface) |
||
615 | { |
||
616 | cairo_analysis_surface_t *surface = abstract_surface; |
||
617 | |||
618 | return cairo_surface_has_show_text_glyphs (surface->target); |
||
619 | } |
||
620 | |||
621 | static cairo_int_status_t |
||
622 | _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, |
||
623 | cairo_operator_t op, |
||
624 | const cairo_pattern_t *source, |
||
625 | const char *utf8, |
||
626 | int utf8_len, |
||
627 | cairo_glyph_t *glyphs, |
||
628 | int num_glyphs, |
||
629 | const cairo_text_cluster_t *clusters, |
||
630 | int num_clusters, |
||
631 | cairo_text_cluster_flags_t cluster_flags, |
||
632 | cairo_scaled_font_t *scaled_font, |
||
3959 | Serge | 633 | const cairo_clip_t *clip) |
1892 | serge | 634 | { |
635 | cairo_analysis_surface_t *surface = abstract_surface; |
||
3959 | Serge | 636 | cairo_int_status_t status, backend_status; |
1892 | serge | 637 | cairo_rectangle_int_t extents, glyph_extents; |
638 | |||
639 | /* Adapted from _cairo_surface_show_glyphs */ |
||
640 | backend_status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
641 | if (surface->target->backend->show_text_glyphs != NULL) { |
||
642 | backend_status = |
||
643 | surface->target->backend->show_text_glyphs (surface->target, op, |
||
644 | source, |
||
645 | utf8, utf8_len, |
||
646 | glyphs, num_glyphs, |
||
647 | clusters, num_clusters, |
||
648 | cluster_flags, |
||
649 | scaled_font, |
||
650 | clip); |
||
3959 | Serge | 651 | if (_cairo_int_status_is_error (backend_status)) |
1892 | serge | 652 | return backend_status; |
653 | } |
||
654 | if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && |
||
655 | surface->target->backend->show_glyphs != NULL) |
||
656 | { |
||
657 | backend_status = |
||
658 | surface->target->backend->show_glyphs (surface->target, op, |
||
659 | source, |
||
660 | glyphs, num_glyphs, |
||
661 | scaled_font, |
||
3959 | Serge | 662 | clip); |
663 | if (_cairo_int_status_is_error (backend_status)) |
||
1892 | serge | 664 | return backend_status; |
665 | } |
||
666 | |||
667 | if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) |
||
668 | backend_status = _analyze_recording_surface_pattern (surface, source); |
||
669 | |||
670 | _cairo_analysis_surface_operation_extents (surface, |
||
671 | op, source, clip, |
||
672 | &extents); |
||
673 | |||
674 | if (_cairo_operator_bounded_by_mask (op)) { |
||
675 | status = _cairo_scaled_font_glyph_device_extents (scaled_font, |
||
676 | glyphs, |
||
677 | num_glyphs, |
||
678 | &glyph_extents, |
||
679 | NULL); |
||
680 | if (unlikely (status)) |
||
681 | return status; |
||
682 | |||
3959 | Serge | 683 | _cairo_rectangle_intersect (&extents, &glyph_extents); |
1892 | serge | 684 | } |
685 | |||
686 | return _add_operation (surface, &extents, backend_status); |
||
687 | } |
||
688 | |||
689 | static const cairo_surface_backend_t cairo_analysis_surface_backend = { |
||
690 | CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, |
||
3959 | Serge | 691 | |
692 | _cairo_analysis_surface_finish, |
||
693 | NULL, |
||
694 | |||
1892 | serge | 695 | NULL, /* create_similar */ |
3959 | Serge | 696 | NULL, /* create_similar_image */ |
697 | NULL, /* map_to_image */ |
||
698 | NULL, /* unmap */ |
||
699 | |||
700 | NULL, /* source */ |
||
1892 | serge | 701 | NULL, /* acquire_source_image */ |
702 | NULL, /* release_source_image */ |
||
3959 | Serge | 703 | NULL, /* snapshot */ |
704 | |||
1892 | serge | 705 | NULL, /* copy_page */ |
706 | NULL, /* show_page */ |
||
3959 | Serge | 707 | |
1892 | serge | 708 | _cairo_analysis_surface_get_extents, |
709 | NULL, /* get_font_options */ |
||
3959 | Serge | 710 | |
1892 | serge | 711 | NULL, /* flush */ |
712 | NULL, /* mark_dirty_rectangle */ |
||
3959 | Serge | 713 | |
1892 | serge | 714 | _cairo_analysis_surface_paint, |
715 | _cairo_analysis_surface_mask, |
||
716 | _cairo_analysis_surface_stroke, |
||
717 | _cairo_analysis_surface_fill, |
||
3959 | Serge | 718 | NULL, /* fill_stroke */ |
1892 | serge | 719 | _cairo_analysis_surface_show_glyphs, |
720 | _cairo_analysis_surface_has_show_text_glyphs, |
||
721 | _cairo_analysis_surface_show_text_glyphs |
||
722 | }; |
||
723 | |||
724 | cairo_surface_t * |
||
725 | _cairo_analysis_surface_create (cairo_surface_t *target) |
||
726 | { |
||
727 | cairo_analysis_surface_t *surface; |
||
728 | cairo_status_t status; |
||
729 | |||
730 | status = target->status; |
||
731 | if (unlikely (status)) |
||
732 | return _cairo_surface_create_in_error (status); |
||
733 | |||
734 | surface = malloc (sizeof (cairo_analysis_surface_t)); |
||
735 | if (unlikely (surface == NULL)) |
||
736 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
737 | |||
738 | /* I believe the content type here is truly arbitrary. I'm quite |
||
739 | * sure nothing will ever use this value. */ |
||
740 | _cairo_surface_init (&surface->base, |
||
741 | &cairo_analysis_surface_backend, |
||
742 | NULL, /* device */ |
||
743 | CAIRO_CONTENT_COLOR_ALPHA); |
||
744 | |||
745 | cairo_matrix_init_identity (&surface->ctm); |
||
746 | surface->has_ctm = FALSE; |
||
747 | |||
748 | surface->target = cairo_surface_reference (target); |
||
749 | surface->first_op = TRUE; |
||
750 | surface->has_supported = FALSE; |
||
751 | surface->has_unsupported = FALSE; |
||
752 | |||
753 | _cairo_region_init (&surface->supported_region); |
||
754 | _cairo_region_init (&surface->fallback_region); |
||
755 | |||
756 | surface->page_bbox.p1.x = 0; |
||
757 | surface->page_bbox.p1.y = 0; |
||
758 | surface->page_bbox.p2.x = 0; |
||
759 | surface->page_bbox.p2.y = 0; |
||
760 | |||
761 | return &surface->base; |
||
762 | } |
||
763 | |||
764 | void |
||
765 | _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface, |
||
766 | const cairo_matrix_t *ctm) |
||
767 | { |
||
768 | cairo_analysis_surface_t *surface; |
||
769 | |||
770 | if (abstract_surface->status) |
||
771 | return; |
||
772 | |||
773 | surface = (cairo_analysis_surface_t *) abstract_surface; |
||
774 | |||
775 | surface->ctm = *ctm; |
||
776 | surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); |
||
777 | } |
||
778 | |||
779 | void |
||
780 | _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface, |
||
781 | cairo_matrix_t *ctm) |
||
782 | { |
||
783 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
784 | |||
785 | *ctm = surface->ctm; |
||
786 | } |
||
787 | |||
788 | |||
789 | cairo_region_t * |
||
790 | _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface) |
||
791 | { |
||
792 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
793 | |||
794 | return &surface->supported_region; |
||
795 | } |
||
796 | |||
797 | cairo_region_t * |
||
798 | _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface) |
||
799 | { |
||
800 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
801 | |||
802 | return &surface->fallback_region; |
||
803 | } |
||
804 | |||
805 | cairo_bool_t |
||
806 | _cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface) |
||
807 | { |
||
808 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
809 | |||
810 | return surface->has_supported; |
||
811 | } |
||
812 | |||
813 | cairo_bool_t |
||
814 | _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface) |
||
815 | { |
||
816 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
817 | |||
818 | return surface->has_unsupported; |
||
819 | } |
||
820 | |||
821 | void |
||
822 | _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface, |
||
823 | cairo_box_t *bbox) |
||
824 | { |
||
825 | cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; |
||
826 | |||
827 | *bbox = surface->page_bbox; |
||
828 | } |
||
829 | |||
830 | /* null surface type: a surface that does nothing (has no side effects, yay!) */ |
||
831 | |||
832 | static cairo_int_status_t |
||
833 | _return_success (void) |
||
834 | { |
||
835 | return CAIRO_STATUS_SUCCESS; |
||
836 | } |
||
837 | |||
838 | /* These typedefs are just to silence the compiler... */ |
||
839 | typedef cairo_int_status_t |
||
840 | (*_paint_func) (void *surface, |
||
841 | cairo_operator_t op, |
||
842 | const cairo_pattern_t *source, |
||
3959 | Serge | 843 | const cairo_clip_t *clip); |
1892 | serge | 844 | |
845 | typedef cairo_int_status_t |
||
846 | (*_mask_func) (void *surface, |
||
847 | cairo_operator_t op, |
||
848 | const cairo_pattern_t *source, |
||
849 | const cairo_pattern_t *mask, |
||
3959 | Serge | 850 | const cairo_clip_t *clip); |
1892 | serge | 851 | |
852 | typedef cairo_int_status_t |
||
853 | (*_stroke_func) (void *surface, |
||
854 | cairo_operator_t op, |
||
855 | const cairo_pattern_t *source, |
||
3959 | Serge | 856 | const cairo_path_fixed_t *path, |
1892 | serge | 857 | const cairo_stroke_style_t *style, |
858 | const cairo_matrix_t *ctm, |
||
859 | const cairo_matrix_t *ctm_inverse, |
||
860 | double tolerance, |
||
861 | cairo_antialias_t antialias, |
||
3959 | Serge | 862 | const cairo_clip_t *clip); |
1892 | serge | 863 | |
864 | typedef cairo_int_status_t |
||
865 | (*_fill_func) (void *surface, |
||
866 | cairo_operator_t op, |
||
867 | const cairo_pattern_t *source, |
||
3959 | Serge | 868 | const cairo_path_fixed_t *path, |
1892 | serge | 869 | cairo_fill_rule_t fill_rule, |
870 | double tolerance, |
||
871 | cairo_antialias_t antialias, |
||
3959 | Serge | 872 | const cairo_clip_t *clip); |
1892 | serge | 873 | |
874 | typedef cairo_int_status_t |
||
875 | (*_show_glyphs_func) (void *surface, |
||
876 | cairo_operator_t op, |
||
877 | const cairo_pattern_t *source, |
||
878 | cairo_glyph_t *glyphs, |
||
879 | int num_glyphs, |
||
880 | cairo_scaled_font_t *scaled_font, |
||
3959 | Serge | 881 | const cairo_clip_t *clip); |
1892 | serge | 882 | |
883 | static const cairo_surface_backend_t cairo_null_surface_backend = { |
||
884 | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
||
3959 | Serge | 885 | NULL, /* finish */ |
1892 | serge | 886 | |
3959 | Serge | 887 | NULL, /* only accessed through the surface functions */ |
888 | |||
1892 | serge | 889 | NULL, /* create_similar */ |
3959 | Serge | 890 | NULL, /* create similar image */ |
891 | NULL, /* map to image */ |
||
892 | NULL, /* unmap image*/ |
||
893 | |||
894 | NULL, /* source */ |
||
1892 | serge | 895 | NULL, /* acquire_source_image */ |
896 | NULL, /* release_source_image */ |
||
3959 | Serge | 897 | NULL, /* snapshot */ |
898 | |||
1892 | serge | 899 | NULL, /* copy_page */ |
900 | NULL, /* show_page */ |
||
3959 | Serge | 901 | |
1892 | serge | 902 | NULL, /* get_extents */ |
903 | NULL, /* get_font_options */ |
||
3959 | Serge | 904 | |
1892 | serge | 905 | NULL, /* flush */ |
906 | NULL, /* mark_dirty_rectangle */ |
||
3959 | Serge | 907 | |
1892 | serge | 908 | (_paint_func) _return_success, /* paint */ |
909 | (_mask_func) _return_success, /* mask */ |
||
910 | (_stroke_func) _return_success, /* stroke */ |
||
911 | (_fill_func) _return_success, /* fill */ |
||
3959 | Serge | 912 | NULL, /* fill_stroke */ |
1892 | serge | 913 | (_show_glyphs_func) _return_success, /* show_glyphs */ |
914 | NULL, /* has_show_text_glyphs */ |
||
915 | NULL /* show_text_glyphs */ |
||
916 | }; |
||
917 | |||
918 | cairo_surface_t * |
||
919 | _cairo_null_surface_create (cairo_content_t content) |
||
920 | { |
||
921 | cairo_surface_t *surface; |
||
922 | |||
923 | surface = malloc (sizeof (cairo_surface_t)); |
||
924 | if (unlikely (surface == NULL)) { |
||
925 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
926 | } |
||
927 | |||
928 | _cairo_surface_init (surface, |
||
929 | &cairo_null_surface_backend, |
||
930 | NULL, /* device */ |
||
931 | content); |
||
932 | |||
933 | return surface; |
||
934 | } |