1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2005 Red Hat, Inc
5 * Copyright © 2007 Adrian Johnson
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 * Kristian Høgsberg <krh@redhat.com>
36 * Carl Worth <cworth@cworth.org>
37 * Adrian Johnson <ajohnson@redneon.com>
40 /* A meta surface is a surface that records all drawing operations at
41 * the highest level of the surface backend interface, (that is, the
42 * level of paint, mask, stroke, fill, and show_text_glyphs). The meta
43 * surface can then be "replayed" against any target surface with:
45 * _cairo_meta_surface_replay (meta, target);
47 * after which the results in target will be identical to the results
48 * that would have been obtained if the original operations applied to
49 * the meta surface had instead been applied to the target surface.
51 * The recording phase of the meta surface is careful to snapshot all
52 * necessary objects (paths, patterns, etc.), in order to achieve
53 * accurate replay. The efficiency of the meta surface could be
54 * improved by improving the implementation of snapshot for the
55 * various objects. For example, it would be nice to have a
56 * copy-on-write implementation for _cairo_surface_snapshot.
60 #include "cairo-meta-surface-private.h"
61 #include "cairo-clip-private.h"
65 CAIRO_META_CREATE_REGIONS
66 } cairo_meta_replay_type_t
;
68 static const cairo_surface_backend_t cairo_meta_surface_backend
;
70 /* Currently all meta surfaces do have a size which should be passed
71 * in as the maximum size of any target surface against which the
72 * meta-surface will ever be replayed.
74 * XXX: The naming of "pixels" in the size here is a misnomer. It's
75 * actually a size in whatever device-space units are desired (again,
76 * according to the intended replay target). This should likely also
77 * be changed to use doubles not ints.
80 _cairo_meta_surface_create (cairo_content_t content
,
84 cairo_meta_surface_t
*meta
;
86 meta
= malloc (sizeof (cairo_meta_surface_t
));
87 if (unlikely (meta
== NULL
))
88 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
90 _cairo_surface_init (&meta
->base
, &cairo_meta_surface_backend
,
93 meta
->content
= content
;
94 meta
->width_pixels
= width_pixels
;
95 meta
->height_pixels
= height_pixels
;
97 _cairo_array_init (&meta
->commands
, sizeof (cairo_command_t
*));
98 meta
->commands_owner
= NULL
;
100 meta
->is_clipped
= FALSE
;
101 meta
->replay_start_idx
= 0;
106 static cairo_surface_t
*
107 _cairo_meta_surface_create_similar (void *abstract_surface
,
108 cairo_content_t content
,
112 return _cairo_meta_surface_create (content
, width
, height
);
115 static cairo_status_t
116 _cairo_meta_surface_finish (void *abstract_surface
)
118 cairo_meta_surface_t
*meta
= abstract_surface
;
119 cairo_command_t
*command
;
120 cairo_command_t
**elements
;
123 if (meta
->commands_owner
) {
124 cairo_surface_destroy (meta
->commands_owner
);
125 return CAIRO_STATUS_SUCCESS
;
128 num_elements
= meta
->commands
.num_elements
;
129 elements
= _cairo_array_index (&meta
->commands
, 0);
130 for (i
= 0; i
< num_elements
; i
++) {
131 command
= elements
[i
];
132 switch (command
->header
.type
) {
134 /* 5 basic drawing operations */
136 case CAIRO_COMMAND_PAINT
:
137 _cairo_pattern_fini_snapshot (&command
->paint
.source
.base
);
141 case CAIRO_COMMAND_MASK
:
142 _cairo_pattern_fini_snapshot (&command
->mask
.source
.base
);
143 _cairo_pattern_fini_snapshot (&command
->mask
.mask
.base
);
147 case CAIRO_COMMAND_STROKE
:
148 _cairo_pattern_fini_snapshot (&command
->stroke
.source
.base
);
149 _cairo_path_fixed_fini (&command
->stroke
.path
);
150 _cairo_stroke_style_fini (&command
->stroke
.style
);
154 case CAIRO_COMMAND_FILL
:
155 _cairo_pattern_fini_snapshot (&command
->fill
.source
.base
);
156 _cairo_path_fixed_fini (&command
->fill
.path
);
160 case CAIRO_COMMAND_SHOW_TEXT_GLYPHS
:
161 _cairo_pattern_fini_snapshot (&command
->show_text_glyphs
.source
.base
);
162 free (command
->show_text_glyphs
.utf8
);
163 free (command
->show_text_glyphs
.glyphs
);
164 free (command
->show_text_glyphs
.clusters
);
165 cairo_scaled_font_destroy (command
->show_text_glyphs
.scaled_font
);
170 case CAIRO_COMMAND_INTERSECT_CLIP_PATH
:
171 if (command
->intersect_clip_path
.path_pointer
)
172 _cairo_path_fixed_fini (&command
->intersect_clip_path
.path
);
181 _cairo_array_fini (&meta
->commands
);
183 return CAIRO_STATUS_SUCCESS
;
186 static cairo_status_t
187 _cairo_meta_surface_acquire_source_image (void *abstract_surface
,
188 cairo_image_surface_t
**image_out
,
191 cairo_status_t status
;
192 cairo_meta_surface_t
*surface
= abstract_surface
;
193 cairo_surface_t
*image
;
195 image
= _cairo_image_surface_create_with_content (surface
->content
,
196 surface
->width_pixels
,
197 surface
->height_pixels
);
199 status
= _cairo_meta_surface_replay (&surface
->base
, image
);
200 if (unlikely (status
)) {
201 cairo_surface_destroy (image
);
205 *image_out
= (cairo_image_surface_t
*) image
;
212 _cairo_meta_surface_release_source_image (void *abstract_surface
,
213 cairo_image_surface_t
*image
,
216 cairo_surface_destroy (&image
->base
);
219 static cairo_int_status_t
220 _cairo_meta_surface_paint (void *abstract_surface
,
222 const cairo_pattern_t
*source
,
223 cairo_rectangle_int_t
*extents
)
225 cairo_status_t status
;
226 cairo_meta_surface_t
*meta
= abstract_surface
;
227 cairo_command_paint_t
*command
;
229 command
= malloc (sizeof (cairo_command_paint_t
));
230 if (unlikely (command
== NULL
))
231 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
233 command
->header
.type
= CAIRO_COMMAND_PAINT
;
234 command
->header
.region
= CAIRO_META_REGION_ALL
;
235 command
->header
.extents
.x
= 0;
236 command
->header
.extents
.y
= 0;
237 command
->header
.extents
.width
= meta
->width_pixels
;
238 command
->header
.extents
.height
= meta
->height_pixels
;
241 status
= _cairo_pattern_init_snapshot (&command
->source
.base
, source
);
242 if (unlikely (status
))
243 goto CLEANUP_COMMAND
;
245 status
= _cairo_array_append (&meta
->commands
, &command
);
246 if (unlikely (status
))
249 /* An optimisation that takes care to not replay what was done
250 * before surface is cleared. We don't erase recorded commands
251 * since we may have earlier snapshots of this surface. */
252 if (op
== CAIRO_OPERATOR_CLEAR
&& !meta
->is_clipped
)
253 meta
->replay_start_idx
= meta
->commands
.num_elements
;
255 return CAIRO_STATUS_SUCCESS
;
258 _cairo_pattern_fini_snapshot (&command
->source
.base
);
264 static cairo_int_status_t
265 _cairo_meta_surface_mask (void *abstract_surface
,
267 const cairo_pattern_t
*source
,
268 const cairo_pattern_t
*mask
,
269 cairo_rectangle_int_t
*extents
)
271 cairo_status_t status
;
272 cairo_meta_surface_t
*meta
= abstract_surface
;
273 cairo_command_mask_t
*command
;
275 command
= malloc (sizeof (cairo_command_mask_t
));
276 if (unlikely (command
== NULL
))
277 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
279 command
->header
.type
= CAIRO_COMMAND_MASK
;
280 command
->header
.region
= CAIRO_META_REGION_ALL
;
281 command
->header
.extents
.x
= 0;
282 command
->header
.extents
.y
= 0;
283 command
->header
.extents
.width
= meta
->width_pixels
;
284 command
->header
.extents
.height
= meta
->height_pixels
;
287 status
= _cairo_pattern_init_snapshot (&command
->source
.base
, source
);
288 if (unlikely (status
))
289 goto CLEANUP_COMMAND
;
291 status
= _cairo_pattern_init_snapshot (&command
->mask
.base
, mask
);
292 if (unlikely (status
))
295 status
= _cairo_array_append (&meta
->commands
, &command
);
296 if (unlikely (status
))
299 return CAIRO_STATUS_SUCCESS
;
302 _cairo_pattern_fini_snapshot (&command
->mask
.base
);
304 _cairo_pattern_fini_snapshot (&command
->source
.base
);
310 static cairo_int_status_t
311 _cairo_meta_surface_stroke (void *abstract_surface
,
313 const cairo_pattern_t
*source
,
314 cairo_path_fixed_t
*path
,
315 cairo_stroke_style_t
*style
,
317 cairo_matrix_t
*ctm_inverse
,
319 cairo_antialias_t antialias
,
320 cairo_rectangle_int_t
*extents
)
322 cairo_status_t status
;
323 cairo_meta_surface_t
*meta
= abstract_surface
;
324 cairo_command_stroke_t
*command
;
326 command
= malloc (sizeof (cairo_command_stroke_t
));
327 if (unlikely (command
== NULL
))
328 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
330 command
->header
.type
= CAIRO_COMMAND_STROKE
;
331 command
->header
.region
= CAIRO_META_REGION_ALL
;
332 command
->header
.extents
.x
= 0;
333 command
->header
.extents
.y
= 0;
334 command
->header
.extents
.width
= meta
->width_pixels
;
335 command
->header
.extents
.height
= meta
->height_pixels
;
338 status
= _cairo_pattern_init_snapshot (&command
->source
.base
, source
);
339 if (unlikely (status
))
340 goto CLEANUP_COMMAND
;
342 status
= _cairo_path_fixed_init_copy (&command
->path
, path
);
343 if (unlikely (status
))
346 status
= _cairo_stroke_style_init_copy (&command
->style
, style
);
347 if (unlikely (status
))
351 command
->ctm_inverse
= *ctm_inverse
;
352 command
->tolerance
= tolerance
;
353 command
->antialias
= antialias
;
355 status
= _cairo_array_append (&meta
->commands
, &command
);
356 if (unlikely (status
))
359 return CAIRO_STATUS_SUCCESS
;
362 _cairo_stroke_style_fini (&command
->style
);
364 _cairo_path_fixed_fini (&command
->path
);
366 _cairo_pattern_fini_snapshot (&command
->source
.base
);
372 static cairo_int_status_t
373 _cairo_meta_surface_fill (void *abstract_surface
,
375 const cairo_pattern_t
*source
,
376 cairo_path_fixed_t
*path
,
377 cairo_fill_rule_t fill_rule
,
379 cairo_antialias_t antialias
,
380 cairo_rectangle_int_t
*extents
)
382 cairo_status_t status
;
383 cairo_meta_surface_t
*meta
= abstract_surface
;
384 cairo_command_fill_t
*command
;
386 command
= malloc (sizeof (cairo_command_fill_t
));
387 if (unlikely (command
== NULL
))
388 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
390 command
->header
.type
= CAIRO_COMMAND_FILL
;
391 command
->header
.region
= CAIRO_META_REGION_ALL
;
392 command
->header
.extents
.x
= 0;
393 command
->header
.extents
.y
= 0;
394 command
->header
.extents
.width
= meta
->width_pixels
;
395 command
->header
.extents
.height
= meta
->height_pixels
;
398 status
= _cairo_pattern_init_snapshot (&command
->source
.base
, source
);
399 if (unlikely (status
))
400 goto CLEANUP_COMMAND
;
402 status
= _cairo_path_fixed_init_copy (&command
->path
, path
);
403 if (unlikely (status
))
406 command
->fill_rule
= fill_rule
;
407 command
->tolerance
= tolerance
;
408 command
->antialias
= antialias
;
410 status
= _cairo_array_append (&meta
->commands
, &command
);
411 if (unlikely (status
))
414 return CAIRO_STATUS_SUCCESS
;
417 _cairo_path_fixed_fini (&command
->path
);
419 _cairo_pattern_fini_snapshot (&command
->source
.base
);
426 _cairo_meta_surface_has_show_text_glyphs (void *abstract_surface
)
431 static cairo_int_status_t
432 _cairo_meta_surface_show_text_glyphs (void *abstract_surface
,
434 const cairo_pattern_t
*source
,
437 cairo_glyph_t
*glyphs
,
439 const cairo_text_cluster_t
*clusters
,
441 cairo_text_cluster_flags_t cluster_flags
,
442 cairo_scaled_font_t
*scaled_font
,
443 cairo_rectangle_int_t
*extents
)
445 cairo_status_t status
;
446 cairo_meta_surface_t
*meta
= abstract_surface
;
447 cairo_command_show_text_glyphs_t
*command
;
449 command
= malloc (sizeof (cairo_command_show_text_glyphs_t
));
450 if (unlikely (command
== NULL
))
451 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
453 command
->header
.type
= CAIRO_COMMAND_SHOW_TEXT_GLYPHS
;
454 command
->header
.region
= CAIRO_META_REGION_ALL
;
455 command
->header
.extents
.x
= 0;
456 command
->header
.extents
.y
= 0;
457 command
->header
.extents
.width
= meta
->width_pixels
;
458 command
->header
.extents
.height
= meta
->height_pixels
;
461 status
= _cairo_pattern_init_snapshot (&command
->source
.base
, source
);
462 if (unlikely (status
))
463 goto CLEANUP_COMMAND
;
465 command
->utf8
= NULL
;
466 command
->utf8_len
= utf8_len
;
467 command
->glyphs
= NULL
;
468 command
->num_glyphs
= num_glyphs
;
469 command
->clusters
= NULL
;
470 command
->num_clusters
= num_clusters
;
473 command
->utf8
= malloc (utf8_len
);
474 if (unlikely (command
->utf8
== NULL
)) {
475 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
478 memcpy (command
->utf8
, utf8
, utf8_len
);
481 command
->glyphs
= _cairo_malloc_ab (num_glyphs
, sizeof (glyphs
[0]));
482 if (unlikely (command
->glyphs
== NULL
)) {
483 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
486 memcpy (command
->glyphs
, glyphs
, sizeof (glyphs
[0]) * num_glyphs
);
489 command
->clusters
= _cairo_malloc_ab (num_clusters
, sizeof (clusters
[0]));
490 if (unlikely (command
->clusters
== NULL
)) {
491 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
494 memcpy (command
->clusters
, clusters
, sizeof (clusters
[0]) * num_clusters
);
497 command
->cluster_flags
= cluster_flags
;
499 command
->scaled_font
= cairo_scaled_font_reference (scaled_font
);
501 status
= _cairo_array_append (&meta
->commands
, &command
);
502 if (unlikely (status
))
503 goto CLEANUP_SCALED_FONT
;
505 return CAIRO_STATUS_SUCCESS
;
508 cairo_scaled_font_destroy (command
->scaled_font
);
510 free (command
->utf8
);
511 free (command
->glyphs
);
512 free (command
->clusters
);
514 _cairo_pattern_fini_snapshot (&command
->source
.base
);
521 * _cairo_meta_surface_snapshot
522 * @surface: a #cairo_surface_t which must be a meta surface
524 * Make an immutable copy of @surface. It is an error to call a
525 * surface-modifying function on the result of this function.
527 * The caller owns the return value and should call
528 * cairo_surface_destroy() when finished with it. This function will not
529 * return %NULL, but will return a nil surface instead.
531 * Return value: The snapshot surface.
533 static cairo_surface_t
*
534 _cairo_meta_surface_snapshot (void *abstract_other
)
536 cairo_meta_surface_t
*other
= abstract_other
;
537 cairo_meta_surface_t
*meta
;
539 meta
= malloc (sizeof (cairo_meta_surface_t
));
540 if (unlikely (meta
== NULL
))
541 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
543 _cairo_surface_init (&meta
->base
, &cairo_meta_surface_backend
,
544 other
->base
.content
);
546 meta
->width_pixels
= other
->width_pixels
;
547 meta
->height_pixels
= other
->height_pixels
;
548 meta
->replay_start_idx
= other
->replay_start_idx
;
549 meta
->content
= other
->content
;
551 _cairo_array_init_snapshot (&meta
->commands
, &other
->commands
);
552 meta
->commands_owner
= cairo_surface_reference (&other
->base
);
557 static cairo_int_status_t
558 _cairo_meta_surface_intersect_clip_path (void *dst
,
559 cairo_path_fixed_t
*path
,
560 cairo_fill_rule_t fill_rule
,
562 cairo_antialias_t antialias
)
564 cairo_meta_surface_t
*meta
= dst
;
565 cairo_command_intersect_clip_path_t
*command
;
566 cairo_status_t status
;
568 command
= malloc (sizeof (cairo_command_intersect_clip_path_t
));
569 if (unlikely (command
== NULL
))
570 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
572 command
->header
.type
= CAIRO_COMMAND_INTERSECT_CLIP_PATH
;
573 command
->header
.region
= CAIRO_META_REGION_ALL
;
576 status
= _cairo_path_fixed_init_copy (&command
->path
, path
);
577 if (unlikely (status
)) {
581 command
->path_pointer
= &command
->path
;
582 meta
->is_clipped
= TRUE
;
584 command
->path_pointer
= NULL
;
585 meta
->is_clipped
= FALSE
;
587 command
->fill_rule
= fill_rule
;
588 command
->tolerance
= tolerance
;
589 command
->antialias
= antialias
;
591 status
= _cairo_array_append (&meta
->commands
, &command
);
592 if (unlikely (status
)) {
594 _cairo_path_fixed_fini (&command
->path
);
599 return CAIRO_STATUS_SUCCESS
;
602 /* Currently, we're using as the "size" of a meta surface the largest
603 * surface size against which the meta-surface is expected to be
604 * replayed, (as passed in to _cairo_meta_surface_create).
606 static cairo_int_status_t
607 _cairo_meta_surface_get_extents (void *abstract_surface
,
608 cairo_rectangle_int_t
*rectangle
)
610 cairo_meta_surface_t
*surface
= abstract_surface
;
612 if (surface
->width_pixels
== -1 && surface
->height_pixels
== -1)
613 return CAIRO_INT_STATUS_UNSUPPORTED
;
617 rectangle
->width
= surface
->width_pixels
;
618 rectangle
->height
= surface
->height_pixels
;
620 return CAIRO_STATUS_SUCCESS
;
624 * _cairo_surface_is_meta:
625 * @surface: a #cairo_surface_t
627 * Checks if a surface is a #cairo_meta_surface_t
629 * Return value: %TRUE if the surface is a meta surface
632 _cairo_surface_is_meta (const cairo_surface_t
*surface
)
634 return surface
->backend
== &cairo_meta_surface_backend
;
637 static const cairo_surface_backend_t cairo_meta_surface_backend
= {
638 CAIRO_INTERNAL_SURFACE_TYPE_META
,
639 _cairo_meta_surface_create_similar
,
640 _cairo_meta_surface_finish
,
641 _cairo_meta_surface_acquire_source_image
,
642 _cairo_meta_surface_release_source_image
,
643 NULL
, /* acquire_dest_image */
644 NULL
, /* release_dest_image */
645 NULL
, /* clone_similar */
646 NULL
, /* composite */
647 NULL
, /* fill_rectangles */
648 NULL
, /* composite_trapezoids */
649 NULL
, /* create_span_renderer */
650 NULL
, /* check_span_renderer */
651 NULL
, /* copy_page */
652 NULL
, /* show_page */
653 NULL
, /* set_clip_region */
654 _cairo_meta_surface_intersect_clip_path
,
655 _cairo_meta_surface_get_extents
,
656 NULL
, /* old_show_glyphs */
657 NULL
, /* get_font_options */
659 NULL
, /* mark_dirty_rectangle */
660 NULL
, /* scaled_font_fini */
661 NULL
, /* scaled_glyph_fini */
663 /* Here are the 5 basic drawing operations, (which are in some
664 * sense the only things that cairo_meta_surface should need to
665 * implement). However, we implement the more generic show_text_glyphs
666 * instead of show_glyphs. One or the other is eough. */
668 _cairo_meta_surface_paint
,
669 _cairo_meta_surface_mask
,
670 _cairo_meta_surface_stroke
,
671 _cairo_meta_surface_fill
,
674 _cairo_meta_surface_snapshot
,
676 NULL
, /* is_similar */
678 NULL
, /* fill_stroke */
679 NULL
, /* create_solid_pattern_surface */
680 NULL
, /* can_repaint_solid_pattern_surface */
682 _cairo_meta_surface_has_show_text_glyphs
,
683 _cairo_meta_surface_show_text_glyphs
686 static cairo_path_fixed_t
*
687 _cairo_command_get_path (cairo_command_t
*command
)
689 switch (command
->header
.type
) {
690 case CAIRO_COMMAND_PAINT
:
691 case CAIRO_COMMAND_MASK
:
692 case CAIRO_COMMAND_SHOW_TEXT_GLYPHS
:
694 case CAIRO_COMMAND_STROKE
:
695 return &command
->stroke
.path
;
696 case CAIRO_COMMAND_FILL
:
697 return &command
->fill
.path
;
698 case CAIRO_COMMAND_INTERSECT_CLIP_PATH
:
699 return command
->intersect_clip_path
.path_pointer
;
707 _cairo_meta_surface_get_path (cairo_surface_t
*surface
,
708 cairo_path_fixed_t
*path
)
710 cairo_meta_surface_t
*meta
;
711 cairo_command_t
*command
, **elements
;
713 cairo_int_status_t status
;
716 return surface
->status
;
718 meta
= (cairo_meta_surface_t
*) surface
;
719 status
= CAIRO_STATUS_SUCCESS
;
721 num_elements
= meta
->commands
.num_elements
;
722 elements
= _cairo_array_index (&meta
->commands
, 0);
723 for (i
= meta
->replay_start_idx
; i
< num_elements
; i
++) {
724 command
= elements
[i
];
726 switch (command
->header
.type
) {
727 case CAIRO_COMMAND_PAINT
:
728 case CAIRO_COMMAND_MASK
:
729 case CAIRO_COMMAND_INTERSECT_CLIP_PATH
:
730 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
733 case CAIRO_COMMAND_STROKE
:
737 _cairo_traps_init (&traps
);
739 /* XXX call cairo_stroke_to_path() when that is implemented */
740 status
= _cairo_path_fixed_stroke_to_traps (&command
->stroke
.path
,
741 &command
->stroke
.style
,
742 &command
->stroke
.ctm
,
743 &command
->stroke
.ctm_inverse
,
744 command
->stroke
.tolerance
,
747 if (status
== CAIRO_STATUS_SUCCESS
)
748 status
= _cairo_traps_path (&traps
, path
);
750 _cairo_traps_fini (&traps
);
753 case CAIRO_COMMAND_FILL
:
755 status
= _cairo_path_fixed_append (path
, &command
->fill
.path
, CAIRO_DIRECTION_FORWARD
);
758 case CAIRO_COMMAND_SHOW_TEXT_GLYPHS
:
760 status
= _cairo_scaled_font_glyph_path (command
->show_text_glyphs
.scaled_font
,
761 command
->show_text_glyphs
.glyphs
,
762 command
->show_text_glyphs
.num_glyphs
,
771 if (unlikely (status
))
775 return _cairo_surface_set_error (surface
, status
);
778 static cairo_status_t
779 _cairo_meta_surface_replay_internal (cairo_surface_t
*surface
,
780 cairo_surface_t
*target
,
781 cairo_meta_replay_type_t type
,
782 cairo_meta_region_type_t region
)
784 cairo_meta_surface_t
*meta
;
785 cairo_command_t
*command
, **elements
;
787 cairo_int_status_t status
, status2
;
788 cairo_clip_t clip
, *old_clip
;
789 cairo_bool_t has_device_transform
= _cairo_surface_has_device_transform (target
);
790 cairo_matrix_t
*device_transform
= &target
->device_transform
;
791 cairo_path_fixed_t path_copy
, *dev_path
;
794 return surface
->status
;
797 return _cairo_surface_set_error (surface
, target
->status
);
799 meta
= (cairo_meta_surface_t
*) surface
;
800 status
= CAIRO_STATUS_SUCCESS
;
802 _cairo_clip_init (&clip
, target
);
803 old_clip
= _cairo_surface_get_clip (target
);
805 num_elements
= meta
->commands
.num_elements
;
806 elements
= _cairo_array_index (&meta
->commands
, 0);
807 for (i
= meta
->replay_start_idx
; i
< num_elements
; i
++) {
808 command
= elements
[i
];
810 if (type
== CAIRO_META_REPLAY
&& region
!= CAIRO_META_REGION_ALL
) {
811 if (command
->header
.region
!= region
)
815 /* For all commands except intersect_clip_path, we have to
816 * ensure the current clip gets set on the surface. */
817 if (command
->header
.type
!= CAIRO_COMMAND_INTERSECT_CLIP_PATH
) {
818 status
= _cairo_surface_set_clip (target
, &clip
);
819 if (unlikely (status
))
823 dev_path
= _cairo_command_get_path (command
);
824 if (dev_path
&& has_device_transform
) {
825 status
= _cairo_path_fixed_init_copy (&path_copy
, dev_path
);
826 if (unlikely (status
))
828 _cairo_path_fixed_transform (&path_copy
, device_transform
);
829 dev_path
= &path_copy
;
832 switch (command
->header
.type
) {
833 case CAIRO_COMMAND_PAINT
:
834 status
= _cairo_surface_paint (target
,
836 &command
->paint
.source
.base
, &command
->header
.extents
);
838 case CAIRO_COMMAND_MASK
:
839 status
= _cairo_surface_mask (target
,
841 &command
->mask
.source
.base
,
842 &command
->mask
.mask
.base
, &command
->header
.extents
);
844 case CAIRO_COMMAND_STROKE
:
846 cairo_matrix_t dev_ctm
= command
->stroke
.ctm
;
847 cairo_matrix_t dev_ctm_inverse
= command
->stroke
.ctm_inverse
;
849 if (has_device_transform
) {
850 cairo_matrix_multiply (&dev_ctm
, &dev_ctm
, device_transform
);
851 cairo_matrix_multiply (&dev_ctm_inverse
,
852 &target
->device_transform_inverse
,
856 status
= _cairo_surface_stroke (target
,
858 &command
->stroke
.source
.base
,
860 &command
->stroke
.style
,
863 command
->stroke
.tolerance
,
864 command
->stroke
.antialias
, &command
->header
.extents
);
867 case CAIRO_COMMAND_FILL
:
869 cairo_command_t
*stroke_command
;
871 if (type
!= CAIRO_META_CREATE_REGIONS
)
872 stroke_command
= (i
< num_elements
- 1) ? elements
[i
+ 1] : NULL
;
874 stroke_command
= NULL
;
876 if (stroke_command
!= NULL
&&
877 type
== CAIRO_META_REPLAY
&& region
!= CAIRO_META_REGION_ALL
)
879 if (stroke_command
->header
.region
!= region
)
880 stroke_command
= NULL
;
882 if (stroke_command
!= NULL
&&
883 stroke_command
->header
.type
== CAIRO_COMMAND_STROKE
&&
884 _cairo_path_fixed_is_equal (dev_path
, _cairo_command_get_path (stroke_command
))) {
885 cairo_matrix_t dev_ctm
;
886 cairo_matrix_t dev_ctm_inverse
;
888 dev_ctm
= stroke_command
->stroke
.ctm
;
889 dev_ctm_inverse
= stroke_command
->stroke
.ctm_inverse
;
891 if (has_device_transform
) {
892 cairo_matrix_multiply (&dev_ctm
, &dev_ctm
, device_transform
);
893 cairo_matrix_multiply (&dev_ctm_inverse
,
894 &surface
->device_transform_inverse
,
898 status
= _cairo_surface_fill_stroke (target
,
900 &command
->fill
.source
.base
,
901 command
->fill
.fill_rule
,
902 command
->fill
.tolerance
,
903 command
->fill
.antialias
,
905 stroke_command
->stroke
.op
,
906 &stroke_command
->stroke
.source
.base
,
907 &stroke_command
->stroke
.style
,
910 stroke_command
->stroke
.tolerance
,
911 stroke_command
->stroke
.antialias
,
912 &stroke_command
->header
.extents
);
915 status
= _cairo_surface_fill (target
,
917 &command
->fill
.source
.base
,
919 command
->fill
.fill_rule
,
920 command
->fill
.tolerance
,
921 command
->fill
.antialias
, &command
->header
.extents
);
924 case CAIRO_COMMAND_SHOW_TEXT_GLYPHS
:
926 cairo_glyph_t
*glyphs
= command
->show_text_glyphs
.glyphs
;
927 cairo_glyph_t
*dev_glyphs
;
928 int i
, num_glyphs
= command
->show_text_glyphs
.num_glyphs
;
930 /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
931 * to modify the glyph array that's passed in. We must always
932 * copy the array before handing it to the backend.
934 dev_glyphs
= _cairo_malloc_ab (num_glyphs
, sizeof (cairo_glyph_t
));
935 if (unlikely (dev_glyphs
== NULL
)) {
936 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
940 if (has_device_transform
) {
941 for (i
= 0; i
< num_glyphs
; i
++) {
942 dev_glyphs
[i
] = glyphs
[i
];
943 cairo_matrix_transform_point (device_transform
,
948 memcpy (dev_glyphs
, glyphs
, sizeof (cairo_glyph_t
) * num_glyphs
);
951 status
= _cairo_surface_show_text_glyphs (target
,
952 command
->show_text_glyphs
.op
,
953 &command
->show_text_glyphs
.source
.base
,
954 command
->show_text_glyphs
.utf8
, command
->show_text_glyphs
.utf8_len
,
955 dev_glyphs
, num_glyphs
,
956 command
->show_text_glyphs
.clusters
, command
->show_text_glyphs
.num_clusters
,
957 command
->show_text_glyphs
.cluster_flags
,
958 command
->show_text_glyphs
.scaled_font
, &command
->header
.extents
);
963 case CAIRO_COMMAND_INTERSECT_CLIP_PATH
:
964 /* XXX Meta surface clipping is broken and requires some
965 * cairo-gstate.c rewriting. Work around it for now. */
966 if (dev_path
== NULL
)
967 _cairo_clip_reset (&clip
);
969 status
= _cairo_clip_clip (&clip
, dev_path
,
970 command
->intersect_clip_path
.fill_rule
,
971 command
->intersect_clip_path
.tolerance
,
972 command
->intersect_clip_path
.antialias
,
979 if (dev_path
== &path_copy
)
980 _cairo_path_fixed_fini (&path_copy
);
982 if (type
== CAIRO_META_CREATE_REGIONS
) {
983 if (status
== CAIRO_STATUS_SUCCESS
) {
984 command
->header
.region
= CAIRO_META_REGION_NATIVE
;
985 } else if (status
== CAIRO_INT_STATUS_IMAGE_FALLBACK
) {
986 command
->header
.region
= CAIRO_META_REGION_IMAGE_FALLBACK
;
987 status
= CAIRO_STATUS_SUCCESS
;
991 if (unlikely (status
))
995 _cairo_clip_reset (&clip
);
996 status2
= _cairo_surface_set_clip (target
, old_clip
);
997 if (status
== CAIRO_STATUS_SUCCESS
)
1000 return _cairo_surface_set_error (surface
, status
);
1004 _cairo_meta_surface_replay (cairo_surface_t
*surface
,
1005 cairo_surface_t
*target
)
1007 return _cairo_meta_surface_replay_internal (surface
,
1010 CAIRO_META_REGION_ALL
);
1013 /* Replay meta to surface. When the return status of each operation is
1014 * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
1015 * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
1016 * will be stored in the meta surface. Any other status will abort the
1017 * replay and return the status.
1020 _cairo_meta_surface_replay_and_create_regions (cairo_surface_t
*surface
,
1021 cairo_surface_t
*target
)
1023 return _cairo_meta_surface_replay_internal (surface
,
1025 CAIRO_META_CREATE_REGIONS
,
1026 CAIRO_META_REGION_ALL
);
1030 _cairo_meta_surface_replay_region (cairo_surface_t
*surface
,
1031 cairo_surface_t
*target
,
1032 cairo_meta_region_type_t region
)
1034 return _cairo_meta_surface_replay_internal (surface
,