Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* cairo - a vector graphics library with display and print output |
2 | * |
||
3 | * Copyright © 2005 Red Hat, Inc |
||
4 | * Copyright © 2007 Adrian Johnson |
||
5 | * Copyright © 2009 Chris Wilson |
||
6 | * |
||
7 | * This library is free software; you can redistribute it and/or |
||
8 | * modify it either under the terms of the GNU Lesser General Public |
||
9 | * License version 2.1 as published by the Free Software Foundation |
||
10 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
11 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
12 | * notice, a recipient may use your version of this file under either |
||
13 | * the MPL or the LGPL. |
||
14 | * |
||
15 | * You should have received a copy of the LGPL along with this library |
||
16 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
18 | * You should have received a copy of the MPL along with this library |
||
19 | * in the file COPYING-MPL-1.1 |
||
20 | * |
||
21 | * The contents of this file are subject to the Mozilla Public License |
||
22 | * Version 1.1 (the "License"); you may not use this file except in |
||
23 | * compliance with the License. You may obtain a copy of the License at |
||
24 | * http://www.mozilla.org/MPL/ |
||
25 | * |
||
26 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
27 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
28 | * the specific language governing rights and limitations. |
||
29 | * |
||
30 | * The Original Code is the cairo graphics library. |
||
31 | * |
||
32 | * The Initial Developer of the Original Code is Red Hat, Inc. |
||
33 | * |
||
34 | * Contributor(s): |
||
35 | * Chris Wilson |
||
36 | */ |
||
37 | |||
38 | #include "cairoint.h" |
||
39 | |||
40 | #include "cairo-clip-inline.h" |
||
41 | #include "cairo-error-private.h" |
||
42 | #include "cairo-pattern-private.h" |
||
43 | #include "cairo-surface-wrapper-private.h" |
||
44 | |||
45 | /* A collection of routines to facilitate surface wrapping */ |
||
46 | |||
47 | static void |
||
48 | _copy_transformed_pattern (cairo_pattern_t *pattern, |
||
49 | const cairo_pattern_t *original, |
||
50 | const cairo_matrix_t *ctm_inverse) |
||
51 | { |
||
52 | _cairo_pattern_init_static_copy (pattern, original); |
||
53 | |||
54 | if (! _cairo_matrix_is_identity (ctm_inverse)) |
||
55 | _cairo_pattern_transform (pattern, ctm_inverse); |
||
56 | } |
||
57 | |||
58 | cairo_status_t |
||
59 | _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, |
||
60 | cairo_image_surface_t **image_out, |
||
61 | void **image_extra) |
||
62 | { |
||
63 | if (unlikely (wrapper->target->status)) |
||
64 | return wrapper->target->status; |
||
65 | |||
66 | return _cairo_surface_acquire_source_image (wrapper->target, |
||
67 | image_out, image_extra); |
||
68 | } |
||
69 | |||
70 | void |
||
71 | _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, |
||
72 | cairo_image_surface_t *image, |
||
73 | void *image_extra) |
||
74 | { |
||
75 | _cairo_surface_release_source_image (wrapper->target, image, image_extra); |
||
76 | } |
||
77 | |||
78 | static void |
||
79 | _cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper, |
||
80 | cairo_matrix_t *m) |
||
81 | { |
||
82 | cairo_matrix_init_identity (m); |
||
83 | |||
84 | if (wrapper->has_extents && (wrapper->extents.x || wrapper->extents.y)) |
||
85 | cairo_matrix_translate (m, -wrapper->extents.x, -wrapper->extents.y); |
||
86 | |||
87 | if (! _cairo_matrix_is_identity (&wrapper->transform)) |
||
88 | cairo_matrix_multiply (m, &wrapper->transform, m); |
||
89 | |||
90 | if (! _cairo_matrix_is_identity (&wrapper->target->device_transform)) |
||
91 | cairo_matrix_multiply (m, &wrapper->target->device_transform, m); |
||
92 | } |
||
93 | |||
94 | static void |
||
95 | _cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper, |
||
96 | cairo_matrix_t *m) |
||
97 | { |
||
98 | cairo_matrix_init_identity (m); |
||
99 | |||
100 | if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse)) |
||
101 | cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m); |
||
102 | |||
103 | if (! _cairo_matrix_is_identity (&wrapper->transform)) { |
||
104 | cairo_matrix_t inv; |
||
105 | cairo_status_t status; |
||
106 | |||
107 | inv = wrapper->transform; |
||
108 | status = cairo_matrix_invert (&inv); |
||
109 | assert (status == CAIRO_STATUS_SUCCESS); |
||
110 | cairo_matrix_multiply (m, &inv, m); |
||
111 | } |
||
112 | |||
113 | if (wrapper->has_extents && (wrapper->extents.x || wrapper->extents.y)) |
||
114 | cairo_matrix_translate (m, wrapper->extents.x, wrapper->extents.y); |
||
115 | } |
||
116 | |||
117 | static cairo_clip_t * |
||
118 | _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper, |
||
119 | const cairo_clip_t *clip) |
||
120 | { |
||
121 | cairo_clip_t *copy; |
||
122 | |||
123 | copy = _cairo_clip_copy (clip); |
||
124 | if (wrapper->has_extents) { |
||
125 | copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents); |
||
126 | } |
||
127 | copy = _cairo_clip_transform (copy, &wrapper->transform); |
||
128 | if (! _cairo_matrix_is_identity (&wrapper->target->device_transform)) |
||
129 | copy = _cairo_clip_transform (copy, &wrapper->target->device_transform); |
||
130 | if (wrapper->clip) |
||
131 | copy = _cairo_clip_intersect_clip (copy, wrapper->clip); |
||
132 | |||
133 | return copy; |
||
134 | } |
||
135 | |||
136 | cairo_status_t |
||
137 | _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, |
||
138 | cairo_operator_t op, |
||
139 | const cairo_pattern_t *source, |
||
140 | const cairo_clip_t *clip) |
||
141 | { |
||
142 | cairo_status_t status; |
||
143 | cairo_clip_t *dev_clip; |
||
144 | cairo_pattern_union_t source_copy; |
||
145 | |||
146 | if (unlikely (wrapper->target->status)) |
||
147 | return wrapper->target->status; |
||
148 | |||
149 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
150 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
151 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
152 | |||
153 | if (wrapper->needs_transform) { |
||
154 | cairo_matrix_t m; |
||
155 | |||
156 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
157 | |||
158 | status = cairo_matrix_invert (&m); |
||
159 | assert (status == CAIRO_STATUS_SUCCESS); |
||
160 | |||
161 | _copy_transformed_pattern (&source_copy.base, source, &m); |
||
162 | source = &source_copy.base; |
||
163 | } |
||
164 | |||
165 | status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); |
||
166 | |||
167 | _cairo_clip_destroy (dev_clip); |
||
168 | return status; |
||
169 | } |
||
170 | |||
171 | |||
172 | cairo_status_t |
||
173 | _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, |
||
174 | cairo_operator_t op, |
||
175 | const cairo_pattern_t *source, |
||
176 | const cairo_pattern_t *mask, |
||
177 | const cairo_clip_t *clip) |
||
178 | { |
||
179 | cairo_status_t status; |
||
180 | cairo_clip_t *dev_clip; |
||
181 | cairo_pattern_union_t source_copy; |
||
182 | cairo_pattern_union_t mask_copy; |
||
183 | |||
184 | if (unlikely (wrapper->target->status)) |
||
185 | return wrapper->target->status; |
||
186 | |||
187 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
188 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
189 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
190 | |||
191 | if (wrapper->needs_transform) { |
||
192 | cairo_matrix_t m; |
||
193 | |||
194 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
195 | |||
196 | status = cairo_matrix_invert (&m); |
||
197 | assert (status == CAIRO_STATUS_SUCCESS); |
||
198 | |||
199 | _copy_transformed_pattern (&source_copy.base, source, &m); |
||
200 | source = &source_copy.base; |
||
201 | |||
202 | _copy_transformed_pattern (&mask_copy.base, mask, &m); |
||
203 | mask = &mask_copy.base; |
||
204 | } |
||
205 | |||
206 | status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); |
||
207 | |||
208 | _cairo_clip_destroy (dev_clip); |
||
209 | return status; |
||
210 | } |
||
211 | |||
212 | cairo_status_t |
||
213 | _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, |
||
214 | cairo_operator_t op, |
||
215 | const cairo_pattern_t *source, |
||
216 | const cairo_path_fixed_t *path, |
||
217 | const cairo_stroke_style_t *stroke_style, |
||
218 | const cairo_matrix_t *ctm, |
||
219 | const cairo_matrix_t *ctm_inverse, |
||
220 | double tolerance, |
||
221 | cairo_antialias_t antialias, |
||
222 | const cairo_clip_t *clip) |
||
223 | { |
||
224 | cairo_status_t status; |
||
225 | cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; |
||
226 | cairo_clip_t *dev_clip; |
||
227 | cairo_matrix_t dev_ctm = *ctm; |
||
228 | cairo_matrix_t dev_ctm_inverse = *ctm_inverse; |
||
229 | cairo_pattern_union_t source_copy; |
||
230 | |||
231 | if (unlikely (wrapper->target->status)) |
||
232 | return wrapper->target->status; |
||
233 | |||
234 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
235 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
236 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
237 | |||
238 | if (wrapper->needs_transform) { |
||
239 | cairo_matrix_t m; |
||
240 | |||
241 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
242 | |||
243 | status = _cairo_path_fixed_init_copy (&path_copy, dev_path); |
||
244 | if (unlikely (status)) |
||
245 | goto FINISH; |
||
246 | |||
247 | _cairo_path_fixed_transform (&path_copy, &m); |
||
248 | dev_path = &path_copy; |
||
249 | |||
250 | cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); |
||
251 | |||
252 | status = cairo_matrix_invert (&m); |
||
253 | assert (status == CAIRO_STATUS_SUCCESS); |
||
254 | |||
255 | cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); |
||
256 | |||
257 | _copy_transformed_pattern (&source_copy.base, source, &m); |
||
258 | source = &source_copy.base; |
||
259 | } |
||
260 | |||
261 | status = _cairo_surface_stroke (wrapper->target, op, source, |
||
262 | dev_path, stroke_style, |
||
263 | &dev_ctm, &dev_ctm_inverse, |
||
264 | tolerance, antialias, |
||
265 | dev_clip); |
||
266 | |||
267 | FINISH: |
||
268 | if (dev_path != path) |
||
269 | _cairo_path_fixed_fini (dev_path); |
||
270 | _cairo_clip_destroy (dev_clip); |
||
271 | return status; |
||
272 | } |
||
273 | |||
274 | cairo_status_t |
||
275 | _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, |
||
276 | cairo_operator_t fill_op, |
||
277 | const cairo_pattern_t *fill_source, |
||
278 | cairo_fill_rule_t fill_rule, |
||
279 | double fill_tolerance, |
||
280 | cairo_antialias_t fill_antialias, |
||
281 | const cairo_path_fixed_t*path, |
||
282 | cairo_operator_t stroke_op, |
||
283 | const cairo_pattern_t *stroke_source, |
||
284 | const cairo_stroke_style_t *stroke_style, |
||
285 | const cairo_matrix_t *stroke_ctm, |
||
286 | const cairo_matrix_t *stroke_ctm_inverse, |
||
287 | double stroke_tolerance, |
||
288 | cairo_antialias_t stroke_antialias, |
||
289 | const cairo_clip_t *clip) |
||
290 | { |
||
291 | cairo_status_t status; |
||
292 | cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path; |
||
293 | cairo_matrix_t dev_ctm = *stroke_ctm; |
||
294 | cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; |
||
295 | cairo_clip_t *dev_clip; |
||
296 | cairo_pattern_union_t stroke_source_copy; |
||
297 | cairo_pattern_union_t fill_source_copy; |
||
298 | |||
299 | if (unlikely (wrapper->target->status)) |
||
300 | return wrapper->target->status; |
||
301 | |||
302 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
303 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
304 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
305 | |||
306 | if (wrapper->needs_transform) { |
||
307 | cairo_matrix_t m; |
||
308 | |||
309 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
310 | |||
311 | status = _cairo_path_fixed_init_copy (&path_copy, dev_path); |
||
312 | if (unlikely (status)) |
||
313 | goto FINISH; |
||
314 | |||
315 | _cairo_path_fixed_transform (&path_copy, &m); |
||
316 | dev_path = &path_copy; |
||
317 | |||
318 | cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); |
||
319 | |||
320 | status = cairo_matrix_invert (&m); |
||
321 | assert (status == CAIRO_STATUS_SUCCESS); |
||
322 | |||
323 | cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); |
||
324 | |||
325 | _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m); |
||
326 | stroke_source = &stroke_source_copy.base; |
||
327 | |||
328 | _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m); |
||
329 | fill_source = &fill_source_copy.base; |
||
330 | } |
||
331 | |||
332 | status = _cairo_surface_fill_stroke (wrapper->target, |
||
333 | fill_op, fill_source, fill_rule, |
||
334 | fill_tolerance, fill_antialias, |
||
335 | dev_path, |
||
336 | stroke_op, stroke_source, |
||
337 | stroke_style, |
||
338 | &dev_ctm, &dev_ctm_inverse, |
||
339 | stroke_tolerance, stroke_antialias, |
||
340 | dev_clip); |
||
341 | |||
342 | FINISH: |
||
343 | if (dev_path != path) |
||
344 | _cairo_path_fixed_fini (dev_path); |
||
345 | _cairo_clip_destroy (dev_clip); |
||
346 | return status; |
||
347 | } |
||
348 | |||
349 | cairo_status_t |
||
350 | _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, |
||
351 | cairo_operator_t op, |
||
352 | const cairo_pattern_t *source, |
||
353 | const cairo_path_fixed_t *path, |
||
354 | cairo_fill_rule_t fill_rule, |
||
355 | double tolerance, |
||
356 | cairo_antialias_t antialias, |
||
357 | const cairo_clip_t *clip) |
||
358 | { |
||
359 | cairo_status_t status; |
||
360 | cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; |
||
361 | cairo_pattern_union_t source_copy; |
||
362 | cairo_clip_t *dev_clip; |
||
363 | |||
364 | if (unlikely (wrapper->target->status)) |
||
365 | return wrapper->target->status; |
||
366 | |||
367 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
368 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
369 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
370 | |||
371 | if (wrapper->needs_transform) { |
||
372 | cairo_matrix_t m; |
||
373 | |||
374 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
375 | |||
376 | status = _cairo_path_fixed_init_copy (&path_copy, dev_path); |
||
377 | if (unlikely (status)) |
||
378 | goto FINISH; |
||
379 | |||
380 | _cairo_path_fixed_transform (&path_copy, &m); |
||
381 | dev_path = &path_copy; |
||
382 | |||
383 | status = cairo_matrix_invert (&m); |
||
384 | assert (status == CAIRO_STATUS_SUCCESS); |
||
385 | |||
386 | _copy_transformed_pattern (&source_copy.base, source, &m); |
||
387 | source = &source_copy.base; |
||
388 | } |
||
389 | |||
390 | status = _cairo_surface_fill (wrapper->target, op, source, |
||
391 | dev_path, fill_rule, |
||
392 | tolerance, antialias, |
||
393 | dev_clip); |
||
394 | |||
395 | FINISH: |
||
396 | if (dev_path != path) |
||
397 | _cairo_path_fixed_fini (dev_path); |
||
398 | _cairo_clip_destroy (dev_clip); |
||
399 | return status; |
||
400 | } |
||
401 | |||
402 | cairo_status_t |
||
403 | _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, |
||
404 | cairo_operator_t op, |
||
405 | const cairo_pattern_t *source, |
||
406 | const char *utf8, |
||
407 | int utf8_len, |
||
408 | const cairo_glyph_t *glyphs, |
||
409 | int num_glyphs, |
||
410 | const cairo_text_cluster_t *clusters, |
||
411 | int num_clusters, |
||
412 | cairo_text_cluster_flags_t cluster_flags, |
||
413 | cairo_scaled_font_t *scaled_font, |
||
414 | const cairo_clip_t *clip) |
||
415 | { |
||
416 | cairo_status_t status; |
||
417 | cairo_clip_t *dev_clip; |
||
418 | cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)]; |
||
419 | cairo_glyph_t *dev_glyphs = stack_glyphs; |
||
420 | cairo_scaled_font_t *dev_scaled_font = scaled_font; |
||
421 | cairo_pattern_union_t source_copy; |
||
422 | cairo_font_options_t options; |
||
423 | |||
424 | if (unlikely (wrapper->target->status)) |
||
425 | return wrapper->target->status; |
||
426 | |||
427 | dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); |
||
428 | if (_cairo_clip_is_all_clipped (dev_clip)) |
||
429 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
430 | |||
431 | cairo_surface_get_font_options (wrapper->target, &options); |
||
432 | cairo_font_options_merge (&options, &scaled_font->options); |
||
433 | |||
434 | if (wrapper->needs_transform) { |
||
435 | cairo_matrix_t m; |
||
436 | int i; |
||
437 | |||
438 | _cairo_surface_wrapper_get_transform (wrapper, &m); |
||
439 | |||
440 | if (! _cairo_matrix_is_translation (&wrapper->transform)) { |
||
441 | cairo_matrix_t ctm; |
||
442 | |||
443 | /* XXX No device-transform? A bug in the tangle of layers? */ |
||
444 | _cairo_matrix_multiply (&ctm, |
||
445 | &wrapper->transform, |
||
446 | &scaled_font->ctm); |
||
447 | dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, |
||
448 | &scaled_font->font_matrix, |
||
449 | &ctm, &options); |
||
450 | } |
||
451 | |||
452 | if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { |
||
453 | dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); |
||
454 | if (unlikely (dev_glyphs == NULL)) { |
||
455 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
456 | goto FINISH; |
||
457 | } |
||
458 | } |
||
459 | |||
460 | for (i = 0; i < num_glyphs; i++) { |
||
461 | dev_glyphs[i] = glyphs[i]; |
||
462 | cairo_matrix_transform_point (&m, |
||
463 | &dev_glyphs[i].x, |
||
464 | &dev_glyphs[i].y); |
||
465 | } |
||
466 | |||
467 | status = cairo_matrix_invert (&m); |
||
468 | assert (status == CAIRO_STATUS_SUCCESS); |
||
469 | |||
470 | _copy_transformed_pattern (&source_copy.base, source, &m); |
||
471 | source = &source_copy.base; |
||
472 | } else { |
||
473 | if (! cairo_font_options_equal (&options, &scaled_font->options)) { |
||
474 | dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, |
||
475 | &scaled_font->font_matrix, |
||
476 | &scaled_font->ctm, |
||
477 | &options); |
||
478 | } |
||
479 | |||
480 | /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed |
||
481 | * to modify the glyph array that's passed in. We must always |
||
482 | * copy the array before handing it to the backend. |
||
483 | */ |
||
484 | if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { |
||
485 | dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); |
||
486 | if (unlikely (dev_glyphs == NULL)) { |
||
487 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
488 | goto FINISH; |
||
489 | } |
||
490 | } |
||
491 | |||
492 | memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); |
||
493 | } |
||
494 | |||
495 | status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, |
||
496 | utf8, utf8_len, |
||
497 | dev_glyphs, num_glyphs, |
||
498 | clusters, num_clusters, |
||
499 | cluster_flags, |
||
500 | dev_scaled_font, |
||
501 | dev_clip); |
||
502 | FINISH: |
||
503 | _cairo_clip_destroy (dev_clip); |
||
504 | if (dev_glyphs != stack_glyphs) |
||
505 | free (dev_glyphs); |
||
506 | if (dev_scaled_font != scaled_font) |
||
507 | cairo_scaled_font_destroy (dev_scaled_font); |
||
508 | return status; |
||
509 | } |
||
510 | |||
511 | cairo_surface_t * |
||
512 | _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, |
||
513 | cairo_content_t content, |
||
514 | int width, |
||
515 | int height) |
||
516 | { |
||
517 | return _cairo_surface_create_similar_scratch (wrapper->target, |
||
518 | content, width, height); |
||
519 | } |
||
520 | |||
521 | cairo_bool_t |
||
522 | _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, |
||
523 | cairo_rectangle_int_t *extents) |
||
524 | { |
||
525 | if (wrapper->has_extents) { |
||
526 | if (_cairo_surface_get_extents (wrapper->target, extents)) |
||
527 | _cairo_rectangle_intersect (extents, &wrapper->extents); |
||
528 | else |
||
529 | *extents = wrapper->extents; |
||
530 | |||
531 | return TRUE; |
||
532 | } else { |
||
533 | return _cairo_surface_get_extents (wrapper->target, extents); |
||
534 | } |
||
535 | } |
||
536 | |||
537 | static cairo_bool_t |
||
538 | _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper) |
||
539 | { |
||
540 | return |
||
541 | (wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) || |
||
542 | ! _cairo_matrix_is_identity (&wrapper->transform) || |
||
543 | ! _cairo_matrix_is_identity (&wrapper->target->device_transform); |
||
544 | } |
||
545 | |||
546 | void |
||
547 | _cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper, |
||
548 | const cairo_rectangle_int_t *extents) |
||
549 | { |
||
550 | if (! wrapper->has_extents) { |
||
551 | wrapper->extents = *extents; |
||
552 | wrapper->has_extents = TRUE; |
||
553 | } else |
||
554 | _cairo_rectangle_intersect (&wrapper->extents, extents); |
||
555 | |||
556 | wrapper->needs_transform = |
||
557 | _cairo_surface_wrapper_needs_device_transform (wrapper); |
||
558 | } |
||
559 | |||
560 | void |
||
561 | _cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper, |
||
562 | const cairo_matrix_t *transform) |
||
563 | { |
||
564 | cairo_status_t status; |
||
565 | |||
566 | if (transform == NULL || _cairo_matrix_is_identity (transform)) { |
||
567 | cairo_matrix_init_identity (&wrapper->transform); |
||
568 | |||
569 | wrapper->needs_transform = |
||
570 | _cairo_surface_wrapper_needs_device_transform (wrapper); |
||
571 | } else { |
||
572 | wrapper->transform = *transform; |
||
573 | status = cairo_matrix_invert (&wrapper->transform); |
||
574 | /* should always be invertible unless given pathological input */ |
||
575 | assert (status == CAIRO_STATUS_SUCCESS); |
||
576 | |||
577 | wrapper->needs_transform = TRUE; |
||
578 | } |
||
579 | } |
||
580 | |||
581 | void |
||
582 | _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper, |
||
583 | const cairo_clip_t *clip) |
||
584 | { |
||
585 | wrapper->clip = clip; |
||
586 | } |
||
587 | |||
588 | void |
||
589 | _cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper, |
||
590 | cairo_font_options_t *options) |
||
591 | { |
||
592 | cairo_surface_get_font_options (wrapper->target, options); |
||
593 | } |
||
594 | |||
595 | cairo_surface_t * |
||
596 | _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper) |
||
597 | { |
||
598 | if (wrapper->target->backend->snapshot) |
||
599 | return wrapper->target->backend->snapshot (wrapper->target); |
||
600 | |||
601 | return NULL; |
||
602 | } |
||
603 | |||
604 | cairo_bool_t |
||
605 | _cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper) |
||
606 | { |
||
607 | return cairo_surface_has_show_text_glyphs (wrapper->target); |
||
608 | } |
||
609 | |||
610 | void |
||
611 | _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, |
||
612 | cairo_surface_t *target) |
||
613 | { |
||
614 | wrapper->target = cairo_surface_reference (target); |
||
615 | cairo_matrix_init_identity (&wrapper->transform); |
||
616 | wrapper->has_extents = FALSE; |
||
617 | wrapper->extents.x = wrapper->extents.y = 0; |
||
618 | wrapper->clip = NULL; |
||
619 | |||
620 | wrapper->needs_transform = FALSE; |
||
621 | if (target) { |
||
622 | wrapper->needs_transform = |
||
623 | ! _cairo_matrix_is_identity (&target->device_transform); |
||
624 | } |
||
625 | } |
||
626 | |||
627 | void |
||
628 | _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper) |
||
629 | { |
||
630 | cairo_surface_destroy (wrapper->target); |
||
631 | } |
||
632 | |||
633 | cairo_bool_t |
||
634 | _cairo_surface_wrapper_get_target_extents (cairo_surface_wrapper_t *wrapper, |
||
635 | cairo_rectangle_int_t *extents) |
||
636 | { |
||
637 | cairo_rectangle_int_t clip; |
||
638 | cairo_bool_t has_clip; |
||
639 | |||
640 | has_clip = _cairo_surface_get_extents (wrapper->target, &clip); |
||
641 | if (wrapper->clip) { |
||
642 | if (has_clip) { |
||
643 | if (! _cairo_rectangle_intersect (&clip, |
||
644 | _cairo_clip_get_extents (wrapper->clip))) |
||
645 | return FALSE; |
||
646 | } else { |
||
647 | has_clip = TRUE; |
||
648 | clip = *_cairo_clip_get_extents (wrapper->clip); |
||
649 | } |
||
650 | } |
||
651 | |||
652 | if (has_clip && wrapper->needs_transform) { |
||
653 | cairo_matrix_t m; |
||
654 | double x1, y1, x2, y2; |
||
655 | |||
656 | _cairo_surface_wrapper_get_inverse_transform (wrapper, &m); |
||
657 | |||
658 | x1 = clip.x; |
||
659 | y1 = clip.y; |
||
660 | x2 = clip.x + clip.width; |
||
661 | y2 = clip.y + clip.height; |
||
662 | |||
663 | _cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL); |
||
664 | |||
665 | clip.x = floor (x1); |
||
666 | clip.y = floor (y1); |
||
667 | clip.width = ceil (x2) - clip.x; |
||
668 | clip.height = ceil (y2) - clip.y; |
||
669 | } |
||
670 | |||
671 | if (has_clip) { |
||
672 | if (wrapper->has_extents) { |
||
673 | *extents = wrapper->extents; |
||
674 | return _cairo_rectangle_intersect (extents, &clip); |
||
675 | } else { |
||
676 | *extents = clip; |
||
677 | return TRUE; |
||
678 | } |
||
679 | } else if (wrapper->has_extents) { |
||
680 | *extents = wrapper->extents; |
||
681 | return TRUE; |
||
682 | } else { |
||
683 | _cairo_unbounded_rectangle_init (extents); |
||
684 | return TRUE; |
||
685 | } |
||
686 | }> |