beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-surface-wrapper.c
blob9236c8bf42e546325dbfbf99d834962aa08f6e64
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.
34 * Contributor(s):
35 * Chris Wilson <chris@chris-wilson.co.uk>
38 #include "cairoint.h"
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 */
47 static void
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);
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)
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);
70 void
71 _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
72 cairo_image_surface_t *image,
73 void *image_extra)
75 _cairo_surface_release_source_image (wrapper->target, image, image_extra);
78 static void
79 _cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
80 cairo_matrix_t *m)
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);
94 static void
95 _cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
96 cairo_matrix_t *m)
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)) {
104 cairo_matrix_t inv;
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)
121 cairo_clip_t *copy;
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);
130 if (wrapper->clip)
131 copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
133 return copy;
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)
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) {
154 cairo_matrix_t m;
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);
168 return status;
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)
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) {
192 cairo_matrix_t m;
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);
209 return status;
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)
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) {
239 cairo_matrix_t m;
241 _cairo_surface_wrapper_get_transform (wrapper, &m);
243 status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
244 if (unlikely (status))
245 goto FINISH;
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,
265 dev_clip);
267 FINISH:
268 if (dev_path != path)
269 _cairo_path_fixed_fini (dev_path);
270 _cairo_clip_destroy (dev_clip);
271 return status;
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)
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) {
307 cairo_matrix_t m;
309 _cairo_surface_wrapper_get_transform (wrapper, &m);
311 status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
312 if (unlikely (status))
313 goto FINISH;
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,
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);
342 FINISH:
343 if (dev_path != path)
344 _cairo_path_fixed_fini (dev_path);
345 _cairo_clip_destroy (dev_clip);
346 return status;
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)
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) {
372 cairo_matrix_t m;
374 _cairo_surface_wrapper_get_transform (wrapper, &m);
376 status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
377 if (unlikely (status))
378 goto FINISH;
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,
391 dev_path, fill_rule,
392 tolerance, antialias,
393 dev_clip);
395 FINISH:
396 if (dev_path != path)
397 _cairo_path_fixed_fini (dev_path);
398 _cairo_clip_destroy (dev_clip);
399 return status;
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)
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) {
435 cairo_matrix_t m;
436 int i;
438 _cairo_surface_wrapper_get_transform (wrapper, &m);
440 if (! _cairo_matrix_is_translation (&m)) {
441 cairo_matrix_t ctm;
443 _cairo_matrix_multiply (&ctm,
445 &scaled_font->ctm);
446 dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
447 &scaled_font->font_matrix,
448 &ctm, &options);
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);
455 goto FINISH;
459 for (i = 0; i < num_glyphs; i++) {
460 dev_glyphs[i] = glyphs[i];
461 cairo_matrix_transform_point (&m,
462 &dev_glyphs[i].x,
463 &dev_glyphs[i].y);
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;
471 } else {
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,
475 &scaled_font->ctm,
476 &options);
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);
487 goto FINISH;
491 memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
494 status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
495 utf8, utf8_len,
496 dev_glyphs, num_glyphs,
497 clusters, num_clusters,
498 cluster_flags,
499 dev_scaled_font,
500 dev_clip);
501 FINISH:
502 _cairo_clip_destroy (dev_clip);
503 if (dev_glyphs != stack_glyphs)
504 free (dev_glyphs);
505 if (dev_scaled_font != scaled_font)
506 cairo_scaled_font_destroy (dev_scaled_font);
507 return status;
510 cairo_surface_t *
511 _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
512 cairo_content_t content,
513 int width,
514 int height)
516 return _cairo_surface_create_scratch (wrapper->target,
517 content, width, height, NULL);
520 cairo_bool_t
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);
527 else
528 *extents = wrapper->extents;
530 return TRUE;
531 } else {
532 return _cairo_surface_get_extents (wrapper->target, extents);
536 static cairo_bool_t
537 _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
539 return
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);
545 void
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;
552 } else
553 _cairo_rectangle_intersect (&wrapper->extents, extents);
555 wrapper->needs_transform =
556 _cairo_surface_wrapper_needs_device_transform (wrapper);
559 void
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);
570 } else {
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;
580 void
581 _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
582 const cairo_clip_t *clip)
584 wrapper->clip = clip;
587 void
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);
594 cairo_surface_t *
595 _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
597 if (wrapper->target->backend->snapshot)
598 return wrapper->target->backend->snapshot (wrapper->target);
600 return NULL;
603 cairo_bool_t
604 _cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
606 return cairo_surface_has_show_text_glyphs (wrapper->target);
609 void
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;
620 if (target) {
621 wrapper->needs_transform =
622 ! _cairo_matrix_is_identity (&target->device_transform);
626 void
627 _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
629 cairo_surface_destroy (wrapper->target);
632 cairo_bool_t
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);
640 if (wrapper->clip) {
641 if (has_clip) {
642 if (! _cairo_rectangle_intersect (&clip,
643 _cairo_clip_get_extents (wrapper->clip)))
644 return FALSE;
645 } else {
646 has_clip = TRUE;
647 clip = *_cairo_clip_get_extents (wrapper->clip);
651 if (has_clip && wrapper->needs_transform) {
652 cairo_matrix_t m;
653 double x1, y1, x2, y2;
655 _cairo_surface_wrapper_get_inverse_transform (wrapper, &m);
657 x1 = clip.x;
658 y1 = clip.y;
659 x2 = clip.x + clip.width;
660 y2 = clip.y + clip.height;
662 _cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL);
664 clip.x = floor (x1);
665 clip.y = floor (y1);
666 clip.width = ceil (x2) - clip.x;
667 clip.height = ceil (y2) - clip.y;
670 if (has_clip) {
671 if (wrapper->has_extents) {
672 *extents = wrapper->extents;
673 return _cairo_rectangle_intersect (extents, &clip);
674 } else {
675 *extents = clip;
676 return TRUE;
678 } else if (wrapper->has_extents) {
679 *extents = wrapper->extents;
680 return TRUE;
681 } else {
682 _cairo_unbounded_rectangle_init (extents);
683 return TRUE;