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 <chris@chris-wilson.co.uk>
36 : */
37 :
38 : #include "cairoint.h"
39 :
40 : #include "cairo-error-private.h"
41 : #include "cairo-surface-wrapper-private.h"
42 :
43 : /* A collection of routines to facilitate surface wrapping */
44 :
45 : static void
46 0 : _copy_transformed_pattern (cairo_pattern_t *pattern,
47 : const cairo_pattern_t *original,
48 : const cairo_matrix_t *ctm_inverse)
49 : {
50 0 : _cairo_pattern_init_static_copy (pattern, original);
51 :
52 : /* apply device_transform first so that it is transformed by ctm_inverse */
53 0 : if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
54 : cairo_surface_pattern_t *surface_pattern;
55 : cairo_surface_t *surface;
56 :
57 0 : surface_pattern = (cairo_surface_pattern_t *) original;
58 0 : surface = surface_pattern->surface;
59 :
60 0 : if (_cairo_surface_has_device_transform (surface))
61 0 : _cairo_pattern_transform (pattern, &surface->device_transform);
62 : }
63 :
64 0 : if (! _cairo_matrix_is_identity (ctm_inverse))
65 0 : _cairo_pattern_transform (pattern, ctm_inverse);
66 0 : }
67 :
68 : static inline cairo_bool_t
69 0 : _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
70 : {
71 0 : return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
72 : }
73 :
74 : static cairo_bool_t
75 0 : _cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
76 : {
77 0 : return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
78 : }
79 :
80 : cairo_status_t
81 0 : _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
82 : cairo_image_surface_t **image_out,
83 : void **image_extra)
84 : {
85 0 : if (unlikely (wrapper->target->status))
86 0 : return wrapper->target->status;
87 :
88 0 : return _cairo_surface_acquire_source_image (wrapper->target,
89 : image_out, image_extra);
90 : }
91 :
92 : void
93 0 : _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
94 : cairo_image_surface_t *image,
95 : void *image_extra)
96 : {
97 0 : _cairo_surface_release_source_image (wrapper->target, image, image_extra);
98 0 : }
99 :
100 : cairo_status_t
101 0 : _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
102 : cairo_operator_t op,
103 : const cairo_pattern_t *source,
104 : cairo_clip_t *clip)
105 : {
106 : cairo_status_t status;
107 0 : cairo_clip_t clip_copy, *dev_clip = clip;
108 : cairo_pattern_union_t source_copy;
109 : cairo_clip_t target_clip;
110 :
111 0 : if (unlikely (wrapper->target->status))
112 0 : return wrapper->target->status;
113 :
114 0 : if (wrapper->has_extents) {
115 0 : _cairo_clip_init_copy (&target_clip, clip);
116 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
117 0 : if (unlikely (status))
118 0 : goto FINISH;
119 :
120 0 : dev_clip = clip = &target_clip;
121 : }
122 :
123 0 : if (clip && clip->all_clipped) {
124 0 : status = CAIRO_STATUS_SUCCESS;
125 0 : goto FINISH;
126 : }
127 :
128 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
129 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
130 : {
131 : cairo_matrix_t m;
132 :
133 0 : cairo_matrix_init_identity (&m);
134 :
135 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
136 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
137 :
138 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
139 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
140 :
141 0 : if (clip != NULL) {
142 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
143 0 : if (unlikely (status))
144 0 : goto FINISH;
145 :
146 0 : dev_clip = &clip_copy;
147 : }
148 :
149 0 : status = cairo_matrix_invert (&m);
150 0 : assert (status == CAIRO_STATUS_SUCCESS);
151 :
152 0 : _copy_transformed_pattern (&source_copy.base, source, &m);
153 0 : source = &source_copy.base;
154 : }
155 :
156 0 : status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
157 :
158 : FINISH:
159 0 : if (wrapper->has_extents)
160 0 : _cairo_clip_reset (&target_clip);
161 0 : if (dev_clip != clip)
162 0 : _cairo_clip_reset (dev_clip);
163 0 : return status;
164 : }
165 :
166 : cairo_status_t
167 0 : _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
168 : cairo_operator_t op,
169 : const cairo_pattern_t *source,
170 : const cairo_pattern_t *mask,
171 : cairo_clip_t *clip)
172 : {
173 : cairo_status_t status;
174 0 : cairo_clip_t clip_copy, *dev_clip = clip;
175 : cairo_pattern_union_t source_copy;
176 : cairo_pattern_union_t mask_copy;
177 : cairo_clip_t target_clip;
178 :
179 0 : if (unlikely (wrapper->target->status))
180 0 : return wrapper->target->status;
181 :
182 0 : if (wrapper->has_extents) {
183 0 : _cairo_clip_init_copy (&target_clip, clip);
184 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
185 0 : if (unlikely (status))
186 0 : goto FINISH;
187 :
188 0 : dev_clip = clip = &target_clip;
189 : }
190 :
191 0 : if (clip && clip->all_clipped) {
192 0 : status = CAIRO_STATUS_SUCCESS;
193 0 : goto FINISH;
194 : }
195 :
196 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
197 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
198 : {
199 : cairo_matrix_t m;
200 :
201 0 : cairo_matrix_init_identity (&m);
202 :
203 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
204 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
205 :
206 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
207 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
208 :
209 0 : if (clip != NULL) {
210 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
211 0 : if (unlikely (status))
212 0 : goto FINISH;
213 :
214 0 : dev_clip = &clip_copy;
215 : }
216 :
217 0 : status = cairo_matrix_invert (&m);
218 0 : assert (status == CAIRO_STATUS_SUCCESS);
219 :
220 0 : _copy_transformed_pattern (&source_copy.base, source, &m);
221 0 : source = &source_copy.base;
222 :
223 0 : _copy_transformed_pattern (&mask_copy.base, mask, &m);
224 0 : mask = &mask_copy.base;
225 : }
226 :
227 0 : status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
228 :
229 : FINISH:
230 0 : if (wrapper->has_extents)
231 0 : _cairo_clip_reset (&target_clip);
232 0 : if (dev_clip != clip)
233 0 : _cairo_clip_reset (dev_clip);
234 0 : return status;
235 : }
236 :
237 : cairo_status_t
238 0 : _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
239 : cairo_operator_t op,
240 : const cairo_pattern_t *source,
241 : cairo_path_fixed_t *path,
242 : const cairo_stroke_style_t *stroke_style,
243 : const cairo_matrix_t *ctm,
244 : const cairo_matrix_t *ctm_inverse,
245 : double tolerance,
246 : cairo_antialias_t antialias,
247 : cairo_clip_t *clip)
248 : {
249 : cairo_status_t status;
250 0 : cairo_path_fixed_t path_copy, *dev_path = path;
251 0 : cairo_clip_t clip_copy, *dev_clip = clip;
252 0 : cairo_matrix_t dev_ctm = *ctm;
253 0 : cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
254 : cairo_pattern_union_t source_copy;
255 : cairo_clip_t target_clip;
256 :
257 0 : if (unlikely (wrapper->target->status))
258 0 : return wrapper->target->status;
259 :
260 0 : if (wrapper->has_extents) {
261 0 : _cairo_clip_init_copy (&target_clip, clip);
262 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
263 0 : if (unlikely (status))
264 0 : goto FINISH;
265 :
266 0 : dev_clip = clip = &target_clip;
267 : }
268 :
269 0 : if (clip && clip->all_clipped) {
270 0 : status = CAIRO_STATUS_SUCCESS;
271 0 : goto FINISH;
272 : }
273 :
274 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
275 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
276 0 : {
277 : cairo_matrix_t m;
278 :
279 0 : cairo_matrix_init_identity (&m);
280 :
281 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
282 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
283 :
284 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
285 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
286 :
287 0 : status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
288 0 : if (unlikely (status))
289 0 : goto FINISH;
290 :
291 0 : _cairo_path_fixed_transform (&path_copy, &m);
292 0 : dev_path = &path_copy;
293 :
294 0 : if (clip != NULL) {
295 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
296 0 : if (unlikely (status))
297 0 : goto FINISH;
298 :
299 0 : dev_clip = &clip_copy;
300 : }
301 :
302 0 : cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
303 :
304 0 : status = cairo_matrix_invert (&m);
305 0 : assert (status == CAIRO_STATUS_SUCCESS);
306 :
307 0 : cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
308 :
309 0 : _copy_transformed_pattern (&source_copy.base, source, &m);
310 0 : source = &source_copy.base;
311 : }
312 : else
313 : {
314 0 : if (clip != NULL) {
315 0 : dev_clip = &clip_copy;
316 0 : _cairo_clip_init_copy (&clip_copy, clip);
317 : }
318 : }
319 :
320 0 : status = _cairo_surface_stroke (wrapper->target, op, source,
321 : dev_path, stroke_style,
322 : &dev_ctm, &dev_ctm_inverse,
323 : tolerance, antialias,
324 : dev_clip);
325 :
326 : FINISH:
327 0 : if (dev_path != path)
328 0 : _cairo_path_fixed_fini (dev_path);
329 0 : if (wrapper->has_extents)
330 0 : _cairo_clip_reset (&target_clip);
331 0 : if (dev_clip != clip)
332 0 : _cairo_clip_reset (dev_clip);
333 0 : return status;
334 : }
335 :
336 : cairo_status_t
337 0 : _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
338 : cairo_operator_t fill_op,
339 : const cairo_pattern_t *fill_source,
340 : cairo_fill_rule_t fill_rule,
341 : double fill_tolerance,
342 : cairo_antialias_t fill_antialias,
343 : cairo_path_fixed_t *path,
344 : cairo_operator_t stroke_op,
345 : const cairo_pattern_t *stroke_source,
346 : const cairo_stroke_style_t *stroke_style,
347 : const cairo_matrix_t *stroke_ctm,
348 : const cairo_matrix_t *stroke_ctm_inverse,
349 : double stroke_tolerance,
350 : cairo_antialias_t stroke_antialias,
351 : cairo_clip_t *clip)
352 : {
353 : cairo_status_t status;
354 0 : cairo_path_fixed_t path_copy, *dev_path = path;
355 0 : cairo_clip_t clip_copy, *dev_clip = clip;
356 0 : cairo_matrix_t dev_ctm = *stroke_ctm;
357 0 : cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
358 : cairo_pattern_union_t stroke_source_copy;
359 : cairo_pattern_union_t fill_source_copy;
360 : cairo_clip_t target_clip;
361 :
362 0 : if (unlikely (wrapper->target->status))
363 0 : return wrapper->target->status;
364 :
365 0 : if (wrapper->has_extents) {
366 0 : _cairo_clip_init_copy (&target_clip, clip);
367 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
368 0 : if (unlikely (status))
369 0 : goto FINISH;
370 :
371 0 : dev_clip = clip = &target_clip;
372 : }
373 :
374 0 : if (clip && clip->all_clipped) {
375 0 : status = CAIRO_STATUS_SUCCESS;
376 0 : goto FINISH;
377 : }
378 :
379 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
380 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
381 0 : {
382 : cairo_matrix_t m;
383 :
384 0 : cairo_matrix_init_identity (&m);
385 :
386 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
387 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
388 :
389 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
390 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
391 :
392 0 : status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
393 0 : if (unlikely (status))
394 0 : goto FINISH;
395 :
396 0 : _cairo_path_fixed_transform (&path_copy, &m);
397 0 : dev_path = &path_copy;
398 :
399 0 : if (clip != NULL) {
400 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
401 0 : if (unlikely (status))
402 0 : goto FINISH;
403 :
404 0 : dev_clip = &clip_copy;
405 : }
406 :
407 0 : cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
408 :
409 0 : status = cairo_matrix_invert (&m);
410 0 : assert (status == CAIRO_STATUS_SUCCESS);
411 :
412 0 : cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
413 :
414 0 : _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
415 0 : stroke_source = &stroke_source_copy.base;
416 :
417 0 : _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
418 0 : fill_source = &fill_source_copy.base;
419 : }
420 : else
421 : {
422 0 : if (clip != NULL) {
423 0 : dev_clip = &clip_copy;
424 0 : _cairo_clip_init_copy (&clip_copy, clip);
425 : }
426 : }
427 :
428 0 : status = _cairo_surface_fill_stroke (wrapper->target,
429 : fill_op, fill_source, fill_rule,
430 : fill_tolerance, fill_antialias,
431 : dev_path,
432 : stroke_op, stroke_source,
433 : stroke_style,
434 : &dev_ctm, &dev_ctm_inverse,
435 : stroke_tolerance, stroke_antialias,
436 : dev_clip);
437 :
438 : FINISH:
439 0 : if (dev_path != path)
440 0 : _cairo_path_fixed_fini (dev_path);
441 0 : if (wrapper->has_extents)
442 0 : _cairo_clip_reset (&target_clip);
443 0 : if (dev_clip != clip)
444 0 : _cairo_clip_reset (dev_clip);
445 0 : return status;
446 : }
447 :
448 : cairo_status_t
449 0 : _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
450 : cairo_operator_t op,
451 : const cairo_pattern_t *source,
452 : cairo_path_fixed_t *path,
453 : cairo_fill_rule_t fill_rule,
454 : double tolerance,
455 : cairo_antialias_t antialias,
456 : cairo_clip_t *clip)
457 : {
458 : cairo_status_t status;
459 0 : cairo_path_fixed_t path_copy, *dev_path = path;
460 0 : cairo_clip_t clip_copy, *dev_clip = clip;
461 : cairo_pattern_union_t source_copy;
462 : cairo_clip_t target_clip;
463 :
464 0 : if (unlikely (wrapper->target->status))
465 0 : return wrapper->target->status;
466 :
467 0 : if (wrapper->has_extents) {
468 0 : _cairo_clip_init_copy (&target_clip, clip);
469 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
470 0 : if (unlikely (status))
471 0 : goto FINISH;
472 :
473 0 : dev_clip = clip = &target_clip;
474 : }
475 :
476 0 : if (clip && clip->all_clipped) {
477 0 : status = CAIRO_STATUS_SUCCESS;
478 0 : goto FINISH;
479 : }
480 :
481 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
482 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
483 0 : {
484 : cairo_matrix_t m;
485 :
486 0 : cairo_matrix_init_identity (&m);
487 :
488 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
489 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
490 :
491 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
492 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
493 :
494 0 : status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
495 0 : if (unlikely (status))
496 0 : goto FINISH;
497 :
498 0 : _cairo_path_fixed_transform (&path_copy, &m);
499 0 : dev_path = &path_copy;
500 :
501 0 : if (clip != NULL) {
502 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
503 0 : if (unlikely (status))
504 0 : goto FINISH;
505 :
506 0 : dev_clip = &clip_copy;
507 : }
508 :
509 0 : status = cairo_matrix_invert (&m);
510 0 : assert (status == CAIRO_STATUS_SUCCESS);
511 :
512 0 : _copy_transformed_pattern (&source_copy.base, source, &m);
513 0 : source = &source_copy.base;
514 : }
515 : else
516 : {
517 0 : if (clip != NULL) {
518 0 : dev_clip = &clip_copy;
519 0 : _cairo_clip_init_copy (&clip_copy, clip);
520 : }
521 : }
522 :
523 0 : status = _cairo_surface_fill (wrapper->target, op, source,
524 : dev_path, fill_rule,
525 : tolerance, antialias,
526 : dev_clip);
527 :
528 : FINISH:
529 0 : if (dev_path != path)
530 0 : _cairo_path_fixed_fini (dev_path);
531 0 : if (wrapper->has_extents)
532 0 : _cairo_clip_reset (&target_clip);
533 0 : if (dev_clip != clip)
534 0 : _cairo_clip_reset (dev_clip);
535 0 : return status;
536 : }
537 :
538 : cairo_status_t
539 0 : _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
540 : cairo_operator_t op,
541 : const cairo_pattern_t *source,
542 : const char *utf8,
543 : int utf8_len,
544 : cairo_glyph_t *glyphs,
545 : int num_glyphs,
546 : const cairo_text_cluster_t *clusters,
547 : int num_clusters,
548 : cairo_text_cluster_flags_t cluster_flags,
549 : cairo_scaled_font_t *scaled_font,
550 : cairo_clip_t *clip)
551 : {
552 : cairo_status_t status;
553 0 : cairo_clip_t clip_copy, *dev_clip = clip;
554 0 : cairo_glyph_t *dev_glyphs = glyphs;
555 : cairo_pattern_union_t source_copy;
556 : cairo_clip_t target_clip;
557 :
558 0 : if (unlikely (wrapper->target->status))
559 0 : return wrapper->target->status;
560 :
561 0 : if (glyphs == NULL || num_glyphs == 0)
562 0 : return CAIRO_STATUS_SUCCESS;
563 :
564 0 : if (wrapper->has_extents) {
565 0 : _cairo_clip_init_copy (&target_clip, clip);
566 0 : status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
567 0 : if (unlikely (status))
568 0 : goto FINISH;
569 :
570 0 : dev_clip = clip = &target_clip;
571 : }
572 :
573 0 : if (clip && clip->all_clipped) {
574 0 : status = CAIRO_STATUS_SUCCESS;
575 0 : goto FINISH;
576 : }
577 :
578 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
579 0 : _cairo_surface_wrapper_needs_extents_transform (wrapper))
580 0 : {
581 : cairo_matrix_t m;
582 : int i;
583 :
584 0 : cairo_matrix_init_identity (&m);
585 :
586 0 : if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
587 0 : cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
588 :
589 0 : if (_cairo_surface_wrapper_needs_device_transform (wrapper))
590 0 : cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
591 :
592 0 : if (clip != NULL) {
593 0 : status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
594 0 : if (unlikely (status))
595 0 : goto FINISH;
596 :
597 0 : dev_clip = &clip_copy;
598 : }
599 :
600 0 : dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
601 0 : if (dev_glyphs == NULL) {
602 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
603 0 : goto FINISH;
604 : }
605 :
606 0 : for (i = 0; i < num_glyphs; i++) {
607 0 : dev_glyphs[i] = glyphs[i];
608 0 : cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
609 : }
610 :
611 0 : status = cairo_matrix_invert (&m);
612 0 : assert (status == CAIRO_STATUS_SUCCESS);
613 :
614 0 : _copy_transformed_pattern (&source_copy.base, source, &m);
615 0 : source = &source_copy.base;
616 : }
617 : else
618 : {
619 0 : if (clip != NULL) {
620 0 : dev_clip = &clip_copy;
621 0 : _cairo_clip_init_copy (&clip_copy, clip);
622 : }
623 : }
624 :
625 0 : status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
626 : utf8, utf8_len,
627 : dev_glyphs, num_glyphs,
628 : clusters, num_clusters,
629 : cluster_flags,
630 : scaled_font,
631 : dev_clip);
632 :
633 : FINISH:
634 0 : if (dev_clip != clip)
635 0 : _cairo_clip_reset (dev_clip);
636 0 : if (wrapper->has_extents)
637 0 : _cairo_clip_reset (&target_clip);
638 0 : if (dev_glyphs != glyphs)
639 0 : free (dev_glyphs);
640 0 : return status;
641 : }
642 :
643 : cairo_surface_t *
644 0 : _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
645 : cairo_content_t content,
646 : int width,
647 : int height)
648 : {
649 0 : return _cairo_surface_create_similar_scratch (wrapper->target,
650 : content, width, height);
651 : }
652 :
653 : cairo_bool_t
654 0 : _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
655 : cairo_rectangle_int_t *extents)
656 : {
657 0 : if (wrapper->has_extents) {
658 0 : if (_cairo_surface_get_extents (wrapper->target, extents))
659 0 : _cairo_rectangle_intersect (extents, &wrapper->extents);
660 : else
661 0 : *extents = wrapper->extents;
662 :
663 0 : return TRUE;
664 : } else {
665 0 : return _cairo_surface_get_extents (wrapper->target, extents);
666 : }
667 : }
668 :
669 : void
670 0 : _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
671 : const cairo_rectangle_int_t *extents)
672 : {
673 0 : if (extents != NULL) {
674 0 : wrapper->extents = *extents;
675 0 : wrapper->has_extents = TRUE;
676 : } else {
677 0 : wrapper->has_extents = FALSE;
678 : }
679 0 : }
680 :
681 : void
682 0 : _cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper,
683 : cairo_font_options_t *options)
684 : {
685 0 : cairo_surface_get_font_options (wrapper->target, options);
686 0 : }
687 :
688 : cairo_surface_t *
689 0 : _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
690 : {
691 0 : return _cairo_surface_snapshot (wrapper->target);
692 : }
693 :
694 : cairo_bool_t
695 0 : _cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
696 : {
697 0 : return cairo_surface_has_show_text_glyphs (wrapper->target);
698 : }
699 :
700 : void
701 0 : _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
702 : cairo_surface_t *target)
703 : {
704 0 : wrapper->target = cairo_surface_reference (target);
705 0 : wrapper->has_extents = FALSE;
706 0 : }
707 :
708 : void
709 0 : _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
710 : {
711 0 : cairo_surface_destroy (wrapper->target);
712 0 : }
713 :
714 : cairo_status_t
715 0 : _cairo_surface_wrapper_flush (cairo_surface_wrapper_t *wrapper)
716 : {
717 0 : if (wrapper->target->backend->flush) {
718 0 : return wrapper->target->backend->flush(wrapper->target);
719 : }
720 0 : return CAIRO_STATUS_SUCCESS;
721 : }
|