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