1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2005 Red Hat, Inc
4 * Copyright © 2007 Adrian Johnson
5 * Copyright © 2009 Chris Wilson
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.
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
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/
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.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is Red Hat, Inc.
35 * Chris Wilson <chris@chris-wilson.co.uk>
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"
45 /* A collection of routines to facilitate surface wrapping */
48 _copy_transformed_pattern (cairo_pattern_t
*pattern
,
49 const cairo_pattern_t
*original
,
50 const cairo_matrix_t
*ctm_inverse
)
52 _cairo_pattern_init_static_copy (pattern
, original
);
54 if (! _cairo_matrix_is_identity (ctm_inverse
))
55 _cairo_pattern_transform (pattern
, ctm_inverse
);
59 _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t
*wrapper
,
60 cairo_image_surface_t
**image_out
,
63 if (unlikely (wrapper
->target
->status
))
64 return wrapper
->target
->status
;
66 return _cairo_surface_acquire_source_image (wrapper
->target
,
67 image_out
, image_extra
);
71 _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t
*wrapper
,
72 cairo_image_surface_t
*image
,
75 _cairo_surface_release_source_image (wrapper
->target
, image
, image_extra
);
79 _cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t
*wrapper
,
82 cairo_matrix_init_identity (m
);
84 if (wrapper
->has_extents
&& (wrapper
->extents
.x
|| wrapper
->extents
.y
))
85 cairo_matrix_translate (m
, -wrapper
->extents
.x
, -wrapper
->extents
.y
);
87 if (! _cairo_matrix_is_identity (&wrapper
->transform
))
88 cairo_matrix_multiply (m
, &wrapper
->transform
, m
);
90 if (! _cairo_matrix_is_identity (&wrapper
->target
->device_transform
))
91 cairo_matrix_multiply (m
, &wrapper
->target
->device_transform
, m
);
95 _cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t
*wrapper
,
98 cairo_matrix_init_identity (m
);
100 if (! _cairo_matrix_is_identity (&wrapper
->target
->device_transform_inverse
))
101 cairo_matrix_multiply (m
, &wrapper
->target
->device_transform_inverse
, m
);
103 if (! _cairo_matrix_is_identity (&wrapper
->transform
)) {
105 cairo_status_t status
;
107 inv
= wrapper
->transform
;
108 status
= cairo_matrix_invert (&inv
);
109 assert (status
== CAIRO_STATUS_SUCCESS
);
110 cairo_matrix_multiply (m
, &inv
, m
);
113 if (wrapper
->has_extents
&& (wrapper
->extents
.x
|| wrapper
->extents
.y
))
114 cairo_matrix_translate (m
, wrapper
->extents
.x
, wrapper
->extents
.y
);
117 static cairo_clip_t
*
118 _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t
*wrapper
,
119 const cairo_clip_t
*clip
)
123 copy
= _cairo_clip_copy (clip
);
124 if (wrapper
->has_extents
) {
125 copy
= _cairo_clip_intersect_rectangle (copy
, &wrapper
->extents
);
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
);
131 copy
= _cairo_clip_intersect_clip (copy
, wrapper
->clip
);
137 _cairo_surface_wrapper_paint (cairo_surface_wrapper_t
*wrapper
,
139 const cairo_pattern_t
*source
,
140 const cairo_clip_t
*clip
)
142 cairo_status_t status
;
143 cairo_clip_t
*dev_clip
;
144 cairo_pattern_union_t source_copy
;
146 if (unlikely (wrapper
->target
->status
))
147 return wrapper
->target
->status
;
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
;
153 if (wrapper
->needs_transform
) {
156 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
158 status
= cairo_matrix_invert (&m
);
159 assert (status
== CAIRO_STATUS_SUCCESS
);
161 _copy_transformed_pattern (&source_copy
.base
, source
, &m
);
162 source
= &source_copy
.base
;
165 status
= _cairo_surface_paint (wrapper
->target
, op
, source
, dev_clip
);
167 _cairo_clip_destroy (dev_clip
);
173 _cairo_surface_wrapper_mask (cairo_surface_wrapper_t
*wrapper
,
175 const cairo_pattern_t
*source
,
176 const cairo_pattern_t
*mask
,
177 const cairo_clip_t
*clip
)
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
;
184 if (unlikely (wrapper
->target
->status
))
185 return wrapper
->target
->status
;
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
;
191 if (wrapper
->needs_transform
) {
194 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
196 status
= cairo_matrix_invert (&m
);
197 assert (status
== CAIRO_STATUS_SUCCESS
);
199 _copy_transformed_pattern (&source_copy
.base
, source
, &m
);
200 source
= &source_copy
.base
;
202 _copy_transformed_pattern (&mask_copy
.base
, mask
, &m
);
203 mask
= &mask_copy
.base
;
206 status
= _cairo_surface_mask (wrapper
->target
, op
, source
, mask
, dev_clip
);
208 _cairo_clip_destroy (dev_clip
);
213 _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t
*wrapper
,
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
,
221 cairo_antialias_t antialias
,
222 const cairo_clip_t
*clip
)
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
;
231 if (unlikely (wrapper
->target
->status
))
232 return wrapper
->target
->status
;
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
;
238 if (wrapper
->needs_transform
) {
241 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
243 status
= _cairo_path_fixed_init_copy (&path_copy
, dev_path
);
244 if (unlikely (status
))
247 _cairo_path_fixed_transform (&path_copy
, &m
);
248 dev_path
= &path_copy
;
250 cairo_matrix_multiply (&dev_ctm
, &dev_ctm
, &m
);
252 status
= cairo_matrix_invert (&m
);
253 assert (status
== CAIRO_STATUS_SUCCESS
);
255 cairo_matrix_multiply (&dev_ctm_inverse
, &m
, &dev_ctm_inverse
);
257 _copy_transformed_pattern (&source_copy
.base
, source
, &m
);
258 source
= &source_copy
.base
;
261 status
= _cairo_surface_stroke (wrapper
->target
, op
, source
,
262 dev_path
, stroke_style
,
263 &dev_ctm
, &dev_ctm_inverse
,
264 tolerance
, antialias
,
268 if (dev_path
!= path
)
269 _cairo_path_fixed_fini (dev_path
);
270 _cairo_clip_destroy (dev_clip
);
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
)
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
;
299 if (unlikely (wrapper
->target
->status
))
300 return wrapper
->target
->status
;
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
;
306 if (wrapper
->needs_transform
) {
309 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
311 status
= _cairo_path_fixed_init_copy (&path_copy
, dev_path
);
312 if (unlikely (status
))
315 _cairo_path_fixed_transform (&path_copy
, &m
);
316 dev_path
= &path_copy
;
318 cairo_matrix_multiply (&dev_ctm
, &dev_ctm
, &m
);
320 status
= cairo_matrix_invert (&m
);
321 assert (status
== CAIRO_STATUS_SUCCESS
);
323 cairo_matrix_multiply (&dev_ctm_inverse
, &m
, &dev_ctm_inverse
);
325 _copy_transformed_pattern (&stroke_source_copy
.base
, stroke_source
, &m
);
326 stroke_source
= &stroke_source_copy
.base
;
328 _copy_transformed_pattern (&fill_source_copy
.base
, fill_source
, &m
);
329 fill_source
= &fill_source_copy
.base
;
332 status
= _cairo_surface_fill_stroke (wrapper
->target
,
333 fill_op
, fill_source
, fill_rule
,
334 fill_tolerance
, fill_antialias
,
336 stroke_op
, stroke_source
,
338 &dev_ctm
, &dev_ctm_inverse
,
339 stroke_tolerance
, stroke_antialias
,
343 if (dev_path
!= path
)
344 _cairo_path_fixed_fini (dev_path
);
345 _cairo_clip_destroy (dev_clip
);
350 _cairo_surface_wrapper_fill (cairo_surface_wrapper_t
*wrapper
,
352 const cairo_pattern_t
*source
,
353 const cairo_path_fixed_t
*path
,
354 cairo_fill_rule_t fill_rule
,
356 cairo_antialias_t antialias
,
357 const cairo_clip_t
*clip
)
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
;
364 if (unlikely (wrapper
->target
->status
))
365 return wrapper
->target
->status
;
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
;
371 if (wrapper
->needs_transform
) {
374 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
376 status
= _cairo_path_fixed_init_copy (&path_copy
, dev_path
);
377 if (unlikely (status
))
380 _cairo_path_fixed_transform (&path_copy
, &m
);
381 dev_path
= &path_copy
;
383 status
= cairo_matrix_invert (&m
);
384 assert (status
== CAIRO_STATUS_SUCCESS
);
386 _copy_transformed_pattern (&source_copy
.base
, source
, &m
);
387 source
= &source_copy
.base
;
390 status
= _cairo_surface_fill (wrapper
->target
, op
, source
,
392 tolerance
, antialias
,
396 if (dev_path
!= path
)
397 _cairo_path_fixed_fini (dev_path
);
398 _cairo_clip_destroy (dev_clip
);
403 _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t
*wrapper
,
405 const cairo_pattern_t
*source
,
408 const cairo_glyph_t
*glyphs
,
410 const cairo_text_cluster_t
*clusters
,
412 cairo_text_cluster_flags_t cluster_flags
,
413 cairo_scaled_font_t
*scaled_font
,
414 const cairo_clip_t
*clip
)
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
;
424 if (unlikely (wrapper
->target
->status
))
425 return wrapper
->target
->status
;
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
;
431 cairo_surface_get_font_options (wrapper
->target
, &options
);
432 cairo_font_options_merge (&options
, &scaled_font
->options
);
434 if (wrapper
->needs_transform
) {
438 _cairo_surface_wrapper_get_transform (wrapper
, &m
);
440 if (! _cairo_matrix_is_translation (&m
)) {
443 _cairo_matrix_multiply (&ctm
,
446 dev_scaled_font
= cairo_scaled_font_create (scaled_font
->font_face
,
447 &scaled_font
->font_matrix
,
451 if (num_glyphs
> ARRAY_LENGTH (stack_glyphs
)) {
452 dev_glyphs
= _cairo_malloc_ab (num_glyphs
, sizeof (cairo_glyph_t
));
453 if (unlikely (dev_glyphs
== NULL
)) {
454 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
459 for (i
= 0; i
< num_glyphs
; i
++) {
460 dev_glyphs
[i
] = glyphs
[i
];
461 cairo_matrix_transform_point (&m
,
466 status
= cairo_matrix_invert (&m
);
467 assert (status
== CAIRO_STATUS_SUCCESS
);
469 _copy_transformed_pattern (&source_copy
.base
, source
, &m
);
470 source
= &source_copy
.base
;
472 if (! cairo_font_options_equal (&options
, &scaled_font
->options
)) {
473 dev_scaled_font
= cairo_scaled_font_create (scaled_font
->font_face
,
474 &scaled_font
->font_matrix
,
479 /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
480 * to modify the glyph array that's passed in. We must always
481 * copy the array before handing it to the backend.
483 if (num_glyphs
> ARRAY_LENGTH (stack_glyphs
)) {
484 dev_glyphs
= _cairo_malloc_ab (num_glyphs
, sizeof (cairo_glyph_t
));
485 if (unlikely (dev_glyphs
== NULL
)) {
486 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
491 memcpy (dev_glyphs
, glyphs
, sizeof (cairo_glyph_t
) * num_glyphs
);
494 status
= _cairo_surface_show_text_glyphs (wrapper
->target
, op
, source
,
496 dev_glyphs
, num_glyphs
,
497 clusters
, num_clusters
,
502 _cairo_clip_destroy (dev_clip
);
503 if (dev_glyphs
!= stack_glyphs
)
505 if (dev_scaled_font
!= scaled_font
)
506 cairo_scaled_font_destroy (dev_scaled_font
);
511 _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t
*wrapper
,
512 cairo_content_t content
,
516 return _cairo_surface_create_scratch (wrapper
->target
,
517 content
, width
, height
, NULL
);
521 _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t
*wrapper
,
522 cairo_rectangle_int_t
*extents
)
524 if (wrapper
->has_extents
) {
525 if (_cairo_surface_get_extents (wrapper
->target
, extents
))
526 _cairo_rectangle_intersect (extents
, &wrapper
->extents
);
528 *extents
= wrapper
->extents
;
532 return _cairo_surface_get_extents (wrapper
->target
, extents
);
537 _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t
*wrapper
)
540 (wrapper
->has_extents
&& (wrapper
->extents
.x
| wrapper
->extents
.y
)) ||
541 ! _cairo_matrix_is_identity (&wrapper
->transform
) ||
542 ! _cairo_matrix_is_identity (&wrapper
->target
->device_transform
);
546 _cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t
*wrapper
,
547 const cairo_rectangle_int_t
*extents
)
549 if (! wrapper
->has_extents
) {
550 wrapper
->extents
= *extents
;
551 wrapper
->has_extents
= TRUE
;
553 _cairo_rectangle_intersect (&wrapper
->extents
, extents
);
555 wrapper
->needs_transform
=
556 _cairo_surface_wrapper_needs_device_transform (wrapper
);
560 _cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t
*wrapper
,
561 const cairo_matrix_t
*transform
)
563 cairo_status_t status
;
565 if (transform
== NULL
|| _cairo_matrix_is_identity (transform
)) {
566 cairo_matrix_init_identity (&wrapper
->transform
);
568 wrapper
->needs_transform
=
569 _cairo_surface_wrapper_needs_device_transform (wrapper
);
571 wrapper
->transform
= *transform
;
572 status
= cairo_matrix_invert (&wrapper
->transform
);
573 /* should always be invertible unless given pathological input */
574 assert (status
== CAIRO_STATUS_SUCCESS
);
576 wrapper
->needs_transform
= TRUE
;
581 _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t
*wrapper
,
582 const cairo_clip_t
*clip
)
584 wrapper
->clip
= clip
;
588 _cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t
*wrapper
,
589 cairo_font_options_t
*options
)
591 cairo_surface_get_font_options (wrapper
->target
, options
);
595 _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t
*wrapper
)
597 if (wrapper
->target
->backend
->snapshot
)
598 return wrapper
->target
->backend
->snapshot (wrapper
->target
);
604 _cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t
*wrapper
)
606 return cairo_surface_has_show_text_glyphs (wrapper
->target
);
610 _cairo_surface_wrapper_init (cairo_surface_wrapper_t
*wrapper
,
611 cairo_surface_t
*target
)
613 wrapper
->target
= cairo_surface_reference (target
);
614 cairo_matrix_init_identity (&wrapper
->transform
);
615 wrapper
->has_extents
= FALSE
;
616 wrapper
->extents
.x
= wrapper
->extents
.y
= 0;
617 wrapper
->clip
= NULL
;
619 wrapper
->needs_transform
= FALSE
;
621 wrapper
->needs_transform
=
622 ! _cairo_matrix_is_identity (&target
->device_transform
);
627 _cairo_surface_wrapper_fini (cairo_surface_wrapper_t
*wrapper
)
629 cairo_surface_destroy (wrapper
->target
);
633 _cairo_surface_wrapper_get_target_extents (cairo_surface_wrapper_t
*wrapper
,
634 cairo_rectangle_int_t
*extents
)
636 cairo_rectangle_int_t clip
;
637 cairo_bool_t has_clip
;
639 has_clip
= _cairo_surface_get_extents (wrapper
->target
, &clip
);
642 if (! _cairo_rectangle_intersect (&clip
,
643 _cairo_clip_get_extents (wrapper
->clip
)))
647 clip
= *_cairo_clip_get_extents (wrapper
->clip
);
651 if (has_clip
&& wrapper
->needs_transform
) {
653 double x1
, y1
, x2
, y2
;
655 _cairo_surface_wrapper_get_inverse_transform (wrapper
, &m
);
659 x2
= clip
.x
+ clip
.width
;
660 y2
= clip
.y
+ clip
.height
;
662 _cairo_matrix_transform_bounding_box (&m
, &x1
, &y1
, &x2
, &y2
, NULL
);
666 clip
.width
= ceil (x2
) - clip
.x
;
667 clip
.height
= ceil (y2
) - clip
.y
;
671 if (wrapper
->has_extents
) {
672 *extents
= wrapper
->extents
;
673 return _cairo_rectangle_intersect (extents
, &clip
);
678 } else if (wrapper
->has_extents
) {
679 *extents
= wrapper
->extents
;
682 _cairo_unbounded_rectangle_init (extents
);