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 © 2008 Chris Wilson
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Chris Wilson.
34 * Chris Wilson <chris@chris-wilson.co.uk>
37 /* The script surface is one that records all operations performed on
38 * it in the form of a procedural script, similar in fashion to
39 * PostScript but using Cairo's imaging model. In essence, this is
40 * equivalent to the recording-surface, but as there is no impedance mismatch
41 * between Cairo and CairoScript, we can generate output immediately
42 * without having to copy and hold the data in memory.
46 * SECTION:cairo-script
47 * @Title: Script Surfaces
48 * @Short_Description: Rendering to replayable scripts
49 * @See_Also: #cairo_surface_t
51 * The script surface provides the ability to render to a native
52 * script that matches the cairo drawing model. The scripts can
53 * be replayed using tools under the util/cairo-script directory,
54 * or with cairo-perf-trace.
58 * CAIRO_HAS_SCRIPT_SURFACE:
60 * Defined if the script surface backend is available.
61 * The script surface backend is always built in since 1.12.
69 #include "cairo-script.h"
70 #include "cairo-script-private.h"
72 #include "cairo-analysis-surface-private.h"
73 #include "cairo-default-context-private.h"
74 #include "cairo-device-private.h"
75 #include "cairo-error-private.h"
76 #include "cairo-list-inline.h"
77 #include "cairo-image-surface-private.h"
78 #include "cairo-output-stream-private.h"
79 #include "cairo-pattern-private.h"
80 #include "cairo-recording-surface-inline.h"
81 #include "cairo-scaled-font-private.h"
82 #include "cairo-surface-clipper-private.h"
83 #include "cairo-surface-snapshot-inline.h"
84 #include "cairo-surface-subsurface-private.h"
85 #include "cairo-surface-wrapper-private.h"
88 #include "cairo-ft-private.h"
93 #ifdef WORDS_BIGENDIAN
96 #define to_be32(x) bswap_32(x)
99 #define _cairo_output_stream_puts(S, STR) \
100 _cairo_output_stream_write ((S), (STR), strlen (STR))
102 #define static cairo_warn static
104 typedef struct _cairo_script_context cairo_script_context_t
;
105 typedef struct _cairo_script_surface cairo_script_surface_t
;
106 typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t
;
107 typedef struct _cairo_script_font cairo_script_font_t
;
109 typedef struct _operand
{
118 struct deferred_finish
{
123 struct _cairo_script_context
{
127 int attach_snapshots
;
129 cairo_bool_t owns_stream
;
130 cairo_output_stream_t
*stream
;
131 cairo_script_mode_t mode
;
136 unsigned int map
[64];
137 struct _bitmap
*next
;
138 } surface_id
, font_id
;
140 cairo_list_t operands
;
141 cairo_list_t deferred
;
144 cairo_list_t defines
;
147 struct _cairo_script_font
{
148 cairo_scaled_font_private_t base
;
150 cairo_bool_t has_sfnt
;
152 unsigned long subset_glyph_index
;
154 cairo_scaled_font_t
*parent
;
157 struct _cairo_script_implicit_context
{
158 cairo_operator_t current_operator
;
159 cairo_fill_rule_t current_fill_rule
;
160 double current_tolerance
;
161 cairo_antialias_t current_antialias
;
162 cairo_stroke_style_t current_style
;
163 cairo_pattern_union_t current_source
;
164 cairo_matrix_t current_ctm
;
165 cairo_matrix_t current_stroke_matrix
;
166 cairo_matrix_t current_font_matrix
;
167 cairo_font_options_t current_font_options
;
168 cairo_scaled_font_t
*current_scaled_font
;
169 cairo_path_fixed_t current_path
;
170 cairo_bool_t has_clip
;
173 struct _cairo_script_surface
{
174 cairo_surface_t base
;
176 cairo_surface_wrapper_t wrapper
;
178 cairo_surface_clipper_t clipper
;
181 cairo_bool_t emitted
;
182 cairo_bool_t defined
;
185 double width
, height
;
187 /* implicit flattened context */
188 cairo_script_implicit_context_t cr
;
191 static const cairo_surface_backend_t _cairo_script_surface_backend
;
193 static cairo_script_surface_t
*
194 _cairo_script_surface_create_internal (cairo_script_context_t
*ctx
,
195 cairo_content_t content
,
196 cairo_rectangle_t
*extents
,
197 cairo_surface_t
*passthrough
);
200 _cairo_script_scaled_font_fini (cairo_scaled_font_private_t
*abstract_private
,
201 cairo_scaled_font_t
*scaled_font
);
204 _cairo_script_implicit_context_init (cairo_script_implicit_context_t
*cr
);
207 _cairo_script_implicit_context_reset (cairo_script_implicit_context_t
*cr
);
210 _bitmap_release_id (struct _bitmap
*b
, unsigned long token
)
212 struct _bitmap
**prev
= NULL
;
215 if (token
< b
->min
+ sizeof (b
->map
) * CHAR_BIT
) {
216 unsigned int bit
, elem
;
219 elem
= token
/ (sizeof (b
->map
[0]) * CHAR_BIT
);
220 bit
= token
% (sizeof (b
->map
[0]) * CHAR_BIT
);
221 b
->map
[elem
] &= ~(1 << bit
);
222 if (! --b
->count
&& prev
) {
233 static cairo_status_t
234 _bitmap_next_id (struct _bitmap
*b
,
237 struct _bitmap
*bb
, **prev
= NULL
;
238 unsigned long min
= 0;
244 if (b
->count
< sizeof (b
->map
) * CHAR_BIT
) {
245 unsigned int n
, m
, bit
;
246 for (n
= 0; n
< ARRAY_LENGTH (b
->map
); n
++) {
247 if (b
->map
[n
] == (unsigned int) -1)
250 for (m
=0, bit
=1; m
<sizeof (b
->map
[0])*CHAR_BIT
; m
++, bit
<<=1) {
251 if ((b
->map
[n
] & bit
) == 0) {
254 *id
= n
* sizeof (b
->map
[0])*CHAR_BIT
+ m
+ b
->min
;
255 return CAIRO_STATUS_SUCCESS
;
260 min
+= sizeof (b
->map
) * CHAR_BIT
;
266 bb
= malloc (sizeof (struct _bitmap
));
267 if (unlikely (bb
== NULL
))
268 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
275 memset (bb
->map
+ 1, 0, sizeof (bb
->map
) - sizeof (bb
->map
[0]));
278 return CAIRO_STATUS_SUCCESS
;
282 _bitmap_fini (struct _bitmap
*b
)
285 struct _bitmap
*next
= b
->next
;
292 _direction_to_string (cairo_bool_t backward
)
294 static const char *names
[] = {
298 assert (backward
< ARRAY_LENGTH (names
));
299 return names
[backward
];
303 _operator_to_string (cairo_operator_t op
)
305 static const char *names
[] = {
306 "CLEAR", /* CAIRO_OPERATOR_CLEAR */
308 "SOURCE", /* CAIRO_OPERATOR_SOURCE */
309 "OVER", /* CAIRO_OPERATOR_OVER */
310 "IN", /* CAIRO_OPERATOR_IN */
311 "OUT", /* CAIRO_OPERATOR_OUT */
312 "ATOP", /* CAIRO_OPERATOR_ATOP */
314 "DEST", /* CAIRO_OPERATOR_DEST */
315 "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */
316 "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */
317 "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */
318 "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */
320 "XOR", /* CAIRO_OPERATOR_XOR */
321 "ADD", /* CAIRO_OPERATOR_ADD */
322 "SATURATE", /* CAIRO_OPERATOR_SATURATE */
324 "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */
325 "SCREEN", /* CAIRO_OPERATOR_SCREEN */
326 "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */
327 "DARKEN", /* CAIRO_OPERATOR_DARKEN */
328 "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */
329 "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */
330 "BURN", /* CAIRO_OPERATOR_COLOR_BURN */
331 "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */
332 "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */
333 "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */
334 "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */
335 "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */
336 "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
337 "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */
338 "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
340 assert (op
< ARRAY_LENGTH (names
));
345 _extend_to_string (cairo_extend_t extend
)
347 static const char *names
[] = {
348 "EXTEND_NONE", /* CAIRO_EXTEND_NONE */
349 "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */
350 "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */
351 "EXTEND_PAD" /* CAIRO_EXTEND_PAD */
353 assert (extend
< ARRAY_LENGTH (names
));
354 return names
[extend
];
358 _filter_to_string (cairo_filter_t filter
)
360 static const char *names
[] = {
361 "FILTER_FAST", /* CAIRO_FILTER_FAST */
362 "FILTER_GOOD", /* CAIRO_FILTER_GOOD */
363 "FILTER_BEST", /* CAIRO_FILTER_BEST */
364 "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */
365 "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */
366 "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */
368 assert (filter
< ARRAY_LENGTH (names
));
369 return names
[filter
];
373 _fill_rule_to_string (cairo_fill_rule_t rule
)
375 static const char *names
[] = {
376 "WINDING", /* CAIRO_FILL_RULE_WINDING */
377 "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */
379 assert (rule
< ARRAY_LENGTH (names
));
384 _antialias_to_string (cairo_antialias_t antialias
)
386 static const char *names
[] = {
387 "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */
388 "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */
389 "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */
390 "ANTIALIAS_SUBPIXEL", /* CAIRO_ANTIALIAS_SUBPIXEL */
391 "ANTIALIAS_FAST", /* CAIRO_ANTIALIAS_FAST */
392 "ANTIALIAS_GOOD", /* CAIRO_ANTIALIAS_GOOD */
393 "ANTIALIAS_BEST" /* CAIRO_ANTIALIAS_BEST */
395 assert (antialias
< ARRAY_LENGTH (names
));
396 return names
[antialias
];
400 _line_cap_to_string (cairo_line_cap_t line_cap
)
402 static const char *names
[] = {
403 "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */
404 "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */
405 "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */
407 assert (line_cap
< ARRAY_LENGTH (names
));
408 return names
[line_cap
];
412 _line_join_to_string (cairo_line_join_t line_join
)
414 static const char *names
[] = {
415 "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */
416 "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */
417 "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */
419 assert (line_join
< ARRAY_LENGTH (names
));
420 return names
[line_join
];
423 static inline cairo_script_context_t
*
424 to_context (cairo_script_surface_t
*surface
)
426 return (cairo_script_context_t
*) surface
->base
.device
;
430 target_is_active (cairo_script_surface_t
*surface
)
432 return cairo_list_is_first (&surface
->operand
.link
,
433 &to_context (surface
)->operands
);
437 target_push (cairo_script_surface_t
*surface
)
439 cairo_list_move (&surface
->operand
.link
, &to_context (surface
)->operands
);
443 target_depth (cairo_script_surface_t
*surface
)
448 cairo_list_foreach (link
, &to_context (surface
)->operands
) {
449 if (link
== &surface
->operand
.link
)
458 _get_target (cairo_script_surface_t
*surface
)
460 cairo_script_context_t
*ctx
= to_context (surface
);
462 if (target_is_active (surface
)) {
463 _cairo_output_stream_puts (ctx
->stream
, "dup ");
467 if (surface
->defined
) {
468 _cairo_output_stream_printf (ctx
->stream
, "s%u ",
469 surface
->base
.unique_id
);
471 int depth
= target_depth (surface
);
473 assert (! cairo_list_is_empty (&surface
->operand
.link
));
474 assert (! target_is_active (surface
));
477 _cairo_output_stream_printf (ctx
->stream
, "%d index ", depth
);
478 _cairo_output_stream_puts (ctx
->stream
, "/target get exch pop ");
481 _cairo_output_stream_puts (ctx
->stream
, "exch ");
483 _cairo_output_stream_printf (ctx
->stream
,
484 "%d -1 roll ", depth
);
486 target_push (surface
);
487 _cairo_output_stream_puts (ctx
->stream
, "dup ");
493 _content_to_string (cairo_content_t content
)
496 case CAIRO_CONTENT_ALPHA
: return "ALPHA";
497 case CAIRO_CONTENT_COLOR
: return "COLOR";
499 case CAIRO_CONTENT_COLOR_ALPHA
: return "COLOR_ALPHA";
503 static cairo_status_t
504 _emit_surface (cairo_script_surface_t
*surface
)
506 cairo_script_context_t
*ctx
= to_context (surface
);
508 _cairo_output_stream_printf (ctx
->stream
,
510 _content_to_string (surface
->base
.content
));
511 if (surface
->width
!= -1 && surface
->height
!= -1) {
512 _cairo_output_stream_printf (ctx
->stream
,
513 " /width %f /height %f",
518 if (surface
->base
.x_fallback_resolution
!=
519 CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT
||
520 surface
->base
.y_fallback_resolution
!=
521 CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT
)
523 _cairo_output_stream_printf (ctx
->stream
,
524 " /fallback-resolution [%f %f]",
525 surface
->base
.x_fallback_resolution
,
526 surface
->base
.y_fallback_resolution
);
529 if (surface
->base
.device_transform
.x0
!= 0. ||
530 surface
->base
.device_transform
.y0
!= 0.)
532 /* XXX device offset is encoded into the pattern matrices etc. */
534 _cairo_output_stream_printf (ctx
->stream
,
535 " /device-offset [%f %f]",
536 surface
->base
.device_transform
.x0
,
537 surface
->base
.device_transform
.y0
);
541 _cairo_output_stream_puts (ctx
->stream
, " >> surface context\n");
542 surface
->emitted
= TRUE
;
543 return CAIRO_STATUS_SUCCESS
;
546 static cairo_status_t
547 _emit_context (cairo_script_surface_t
*surface
)
549 cairo_script_context_t
*ctx
= to_context (surface
);
551 if (target_is_active (surface
))
552 return CAIRO_STATUS_SUCCESS
;
554 while (! cairo_list_is_empty (&ctx
->operands
)) {
556 cairo_script_surface_t
*old
;
558 op
= cairo_list_first_entry (&ctx
->operands
,
561 if (op
->type
== DEFERRED
)
564 old
= cairo_container_of (op
, cairo_script_surface_t
, operand
);
570 if (! old
->defined
) {
571 assert (old
->emitted
);
572 _cairo_output_stream_printf (ctx
->stream
,
573 "/target get /s%u exch def pop\n",
574 old
->base
.unique_id
);
577 _cairo_output_stream_puts (ctx
->stream
, "pop\n");
580 cairo_list_del (&old
->operand
.link
);
583 if (target_is_active (surface
))
584 return CAIRO_STATUS_SUCCESS
;
586 if (! surface
->emitted
) {
587 cairo_status_t status
;
589 status
= _emit_surface (surface
);
590 if (unlikely (status
))
592 } else if (cairo_list_is_empty (&surface
->operand
.link
)) {
593 assert (surface
->defined
);
594 _cairo_output_stream_printf (ctx
->stream
,
596 surface
->base
.unique_id
);
597 _cairo_script_implicit_context_reset (&surface
->cr
);
598 _cairo_surface_clipper_reset (&surface
->clipper
);
600 int depth
= target_depth (surface
);
602 _cairo_output_stream_puts (ctx
->stream
, "exch\n");
604 _cairo_output_stream_printf (ctx
->stream
,
609 target_push (surface
);
611 return CAIRO_STATUS_SUCCESS
;
614 static cairo_status_t
615 _emit_operator (cairo_script_surface_t
*surface
,
618 assert (target_is_active (surface
));
620 if (surface
->cr
.current_operator
== op
)
621 return CAIRO_STATUS_SUCCESS
;
623 surface
->cr
.current_operator
= op
;
625 _cairo_output_stream_printf (to_context (surface
)->stream
,
626 "//%s set-operator\n",
627 _operator_to_string (op
));
628 return CAIRO_STATUS_SUCCESS
;
631 static cairo_status_t
632 _emit_fill_rule (cairo_script_surface_t
*surface
,
633 cairo_fill_rule_t fill_rule
)
635 assert (target_is_active (surface
));
637 if (surface
->cr
.current_fill_rule
== fill_rule
)
638 return CAIRO_STATUS_SUCCESS
;
640 surface
->cr
.current_fill_rule
= fill_rule
;
642 _cairo_output_stream_printf (to_context (surface
)->stream
,
643 "//%s set-fill-rule\n",
644 _fill_rule_to_string (fill_rule
));
645 return CAIRO_STATUS_SUCCESS
;
648 static cairo_status_t
649 _emit_tolerance (cairo_script_surface_t
*surface
,
653 assert (target_is_active (surface
));
656 fabs (tolerance
- CAIRO_GSTATE_TOLERANCE_DEFAULT
) < 1e-5) &&
657 surface
->cr
.current_tolerance
== tolerance
)
659 return CAIRO_STATUS_SUCCESS
;
662 surface
->cr
.current_tolerance
= tolerance
;
664 _cairo_output_stream_printf (to_context (surface
)->stream
,
665 "%f set-tolerance\n",
667 return CAIRO_STATUS_SUCCESS
;
670 static cairo_status_t
671 _emit_antialias (cairo_script_surface_t
*surface
,
672 cairo_antialias_t antialias
)
674 assert (target_is_active (surface
));
676 if (surface
->cr
.current_antialias
== antialias
)
677 return CAIRO_STATUS_SUCCESS
;
679 surface
->cr
.current_antialias
= antialias
;
681 _cairo_output_stream_printf (to_context (surface
)->stream
,
682 "//%s set-antialias\n",
683 _antialias_to_string (antialias
));
685 return CAIRO_STATUS_SUCCESS
;
688 static cairo_status_t
689 _emit_line_width (cairo_script_surface_t
*surface
,
693 assert (target_is_active (surface
));
696 fabs (line_width
- CAIRO_GSTATE_LINE_WIDTH_DEFAULT
) < 1e-5) &&
697 surface
->cr
.current_style
.line_width
== line_width
)
699 return CAIRO_STATUS_SUCCESS
;
702 surface
->cr
.current_style
.line_width
= line_width
;
704 _cairo_output_stream_printf (to_context (surface
)->stream
,
705 "%f set-line-width\n",
707 return CAIRO_STATUS_SUCCESS
;
710 static cairo_status_t
711 _emit_line_cap (cairo_script_surface_t
*surface
,
712 cairo_line_cap_t line_cap
)
714 assert (target_is_active (surface
));
716 if (surface
->cr
.current_style
.line_cap
== line_cap
)
717 return CAIRO_STATUS_SUCCESS
;
719 surface
->cr
.current_style
.line_cap
= line_cap
;
721 _cairo_output_stream_printf (to_context (surface
)->stream
,
722 "//%s set-line-cap\n",
723 _line_cap_to_string (line_cap
));
724 return CAIRO_STATUS_SUCCESS
;
727 static cairo_status_t
728 _emit_line_join (cairo_script_surface_t
*surface
,
729 cairo_line_join_t line_join
)
731 assert (target_is_active (surface
));
733 if (surface
->cr
.current_style
.line_join
== line_join
)
734 return CAIRO_STATUS_SUCCESS
;
736 surface
->cr
.current_style
.line_join
= line_join
;
738 _cairo_output_stream_printf (to_context (surface
)->stream
,
739 "//%s set-line-join\n",
740 _line_join_to_string (line_join
));
741 return CAIRO_STATUS_SUCCESS
;
744 static cairo_status_t
745 _emit_miter_limit (cairo_script_surface_t
*surface
,
749 assert (target_is_active (surface
));
752 fabs (miter_limit
- CAIRO_GSTATE_MITER_LIMIT_DEFAULT
) < 1e-5) &&
753 surface
->cr
.current_style
.miter_limit
== miter_limit
)
755 return CAIRO_STATUS_SUCCESS
;
758 surface
->cr
.current_style
.miter_limit
= miter_limit
;
760 _cairo_output_stream_printf (to_context (surface
)->stream
,
761 "%f set-miter-limit\n",
763 return CAIRO_STATUS_SUCCESS
;
767 _dashes_equal (const double *a
, const double *b
, int num_dashes
)
769 while (num_dashes
--) {
770 if (fabs (*a
- *b
) > 1e-5)
778 static cairo_status_t
779 _emit_dash (cairo_script_surface_t
*surface
,
781 unsigned int num_dashes
,
787 assert (target_is_active (surface
));
791 surface
->cr
.current_style
.num_dashes
== 0)
793 return CAIRO_STATUS_SUCCESS
;
797 (surface
->cr
.current_style
.num_dashes
== num_dashes
&&
799 (fabs (surface
->cr
.current_style
.dash_offset
- offset
) < 1e-5 &&
800 _dashes_equal (surface
->cr
.current_style
.dash
, dash
, num_dashes
)))))
802 return CAIRO_STATUS_SUCCESS
;
807 surface
->cr
.current_style
.dash
= _cairo_realloc_ab
808 (surface
->cr
.current_style
.dash
, num_dashes
, sizeof (double));
809 if (unlikely (surface
->cr
.current_style
.dash
== NULL
))
810 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
812 memcpy (surface
->cr
.current_style
.dash
, dash
,
813 sizeof (double) * num_dashes
);
815 free (surface
->cr
.current_style
.dash
);
816 surface
->cr
.current_style
.dash
= NULL
;
819 surface
->cr
.current_style
.num_dashes
= num_dashes
;
820 surface
->cr
.current_style
.dash_offset
= offset
;
822 _cairo_output_stream_puts (to_context (surface
)->stream
, "[");
823 for (n
= 0; n
< num_dashes
; n
++) {
824 _cairo_output_stream_printf (to_context (surface
)->stream
, "%f", dash
[n
]);
825 if (n
< num_dashes
-1)
826 _cairo_output_stream_puts (to_context (surface
)->stream
, " ");
828 _cairo_output_stream_printf (to_context (surface
)->stream
,
832 return CAIRO_STATUS_SUCCESS
;
835 static cairo_status_t
836 _emit_stroke_style (cairo_script_surface_t
*surface
,
837 const cairo_stroke_style_t
*style
,
840 cairo_status_t status
;
842 assert (target_is_active (surface
));
844 status
= _emit_line_width (surface
, style
->line_width
, force
);
845 if (unlikely (status
))
848 status
= _emit_line_cap (surface
, style
->line_cap
);
849 if (unlikely (status
))
852 status
= _emit_line_join (surface
, style
->line_join
);
853 if (unlikely (status
))
856 status
= _emit_miter_limit (surface
, style
->miter_limit
, force
);
857 if (unlikely (status
))
860 status
= _emit_dash (surface
,
861 style
->dash
, style
->num_dashes
, style
->dash_offset
,
863 if (unlikely (status
))
866 return CAIRO_STATUS_SUCCESS
;
870 _format_to_string (cairo_format_t format
)
873 case CAIRO_FORMAT_ARGB32
: return "ARGB32";
874 case CAIRO_FORMAT_RGB30
: return "RGB30";
875 case CAIRO_FORMAT_RGB24
: return "RGB24";
876 case CAIRO_FORMAT_RGB16_565
: return "RGB16_565";
877 case CAIRO_FORMAT_A8
: return "A8";
878 case CAIRO_FORMAT_A1
: return "A1";
879 case CAIRO_FORMAT_INVALID
: return "INVALID";
885 static cairo_status_t
886 _emit_solid_pattern (cairo_script_surface_t
*surface
,
887 const cairo_pattern_t
*pattern
)
889 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) pattern
;
890 cairo_script_context_t
*ctx
= to_context (surface
);
892 if (! CAIRO_COLOR_IS_OPAQUE (&solid
->color
))
894 if (! (surface
->base
.content
& CAIRO_CONTENT_COLOR
) ||
895 ((solid
->color
.red_short
== 0 || solid
->color
.red_short
== 0xffff) &&
896 (solid
->color
.green_short
== 0 || solid
->color
.green_short
== 0xffff) &&
897 (solid
->color
.blue_short
== 0 || solid
->color
.blue_short
== 0xffff) ))
899 _cairo_output_stream_printf (ctx
->stream
,
905 _cairo_output_stream_printf (ctx
->stream
,
915 if (solid
->color
.red_short
== solid
->color
.green_short
&&
916 solid
->color
.red_short
== solid
->color
.blue_short
)
918 _cairo_output_stream_printf (ctx
->stream
,
924 _cairo_output_stream_printf (ctx
->stream
,
932 return CAIRO_STATUS_SUCCESS
;
936 static cairo_status_t
937 _emit_gradient_color_stops (cairo_gradient_pattern_t
*gradient
,
938 cairo_output_stream_t
*output
)
942 for (n
= 0; n
< gradient
->n_stops
; n
++) {
943 _cairo_output_stream_printf (output
,
944 "\n %f %f %f %f %f add-color-stop",
945 gradient
->stops
[n
].offset
,
946 gradient
->stops
[n
].color
.red
,
947 gradient
->stops
[n
].color
.green
,
948 gradient
->stops
[n
].color
.blue
,
949 gradient
->stops
[n
].color
.alpha
);
952 return CAIRO_STATUS_SUCCESS
;
955 static cairo_status_t
956 _emit_linear_pattern (cairo_script_surface_t
*surface
,
957 const cairo_pattern_t
*pattern
)
959 cairo_script_context_t
*ctx
= to_context (surface
);
960 cairo_linear_pattern_t
*linear
;
962 linear
= (cairo_linear_pattern_t
*) pattern
;
964 _cairo_output_stream_printf (ctx
->stream
,
965 "%f %f %f %f linear",
966 linear
->pd1
.x
, linear
->pd1
.y
,
967 linear
->pd2
.x
, linear
->pd2
.y
);
968 return _emit_gradient_color_stops (&linear
->base
, ctx
->stream
);
971 static cairo_status_t
972 _emit_radial_pattern (cairo_script_surface_t
*surface
,
973 const cairo_pattern_t
*pattern
)
975 cairo_script_context_t
*ctx
= to_context (surface
);
976 cairo_radial_pattern_t
*radial
;
978 radial
= (cairo_radial_pattern_t
*) pattern
;
980 _cairo_output_stream_printf (ctx
->stream
,
981 "%f %f %f %f %f %f radial",
982 radial
->cd1
.center
.x
,
983 radial
->cd1
.center
.y
,
985 radial
->cd2
.center
.x
,
986 radial
->cd2
.center
.y
,
988 return _emit_gradient_color_stops (&radial
->base
, ctx
->stream
);
991 static cairo_status_t
992 _emit_mesh_pattern (cairo_script_surface_t
*surface
,
993 const cairo_pattern_t
*pattern
)
995 cairo_script_context_t
*ctx
= to_context (surface
);
996 cairo_pattern_t
*mesh
;
997 cairo_status_t status
;
1000 mesh
= (cairo_pattern_t
*) pattern
;
1001 status
= cairo_mesh_pattern_get_patch_count (mesh
, &n
);
1002 if (unlikely (status
))
1005 _cairo_output_stream_printf (ctx
->stream
, "mesh");
1006 for (i
= 0; i
< n
; i
++) {
1008 cairo_path_data_t
*data
;
1011 _cairo_output_stream_printf (ctx
->stream
, "\n begin-patch");
1013 path
= cairo_mesh_pattern_get_path (mesh
, i
);
1014 if (unlikely (path
->status
))
1015 return path
->status
;
1017 for (j
= 0; j
< path
->num_data
; j
+=data
[0].header
.length
) {
1018 data
= &path
->data
[j
];
1019 switch (data
->header
.type
) {
1020 case CAIRO_PATH_MOVE_TO
:
1021 _cairo_output_stream_printf (ctx
->stream
,
1023 data
[1].point
.x
, data
[1].point
.y
);
1025 case CAIRO_PATH_LINE_TO
:
1026 _cairo_output_stream_printf (ctx
->stream
,
1028 data
[1].point
.x
, data
[1].point
.y
);
1030 case CAIRO_PATH_CURVE_TO
:
1031 _cairo_output_stream_printf (ctx
->stream
,
1032 "\n %f %f %f %f %f %f c",
1033 data
[1].point
.x
, data
[1].point
.y
,
1034 data
[2].point
.x
, data
[2].point
.y
,
1035 data
[3].point
.x
, data
[3].point
.y
);
1037 case CAIRO_PATH_CLOSE_PATH
:
1041 cairo_path_destroy (path
);
1043 for (j
= 0; j
< 4; j
++) {
1046 status
= cairo_mesh_pattern_get_control_point (mesh
, i
, j
, &x
, &y
);
1047 if (unlikely (status
))
1049 _cairo_output_stream_printf (ctx
->stream
,
1050 "\n %d %f %f set-control-point",
1054 for (j
= 0; j
< 4; j
++) {
1057 status
= cairo_mesh_pattern_get_corner_color_rgba (mesh
, i
, j
, &r
, &g
, &b
, &a
);
1058 if (unlikely (status
))
1061 _cairo_output_stream_printf (ctx
->stream
,
1062 "\n %d %f %f %f %f set-corner-color",
1066 _cairo_output_stream_printf (ctx
->stream
, "\n end-patch");
1069 return CAIRO_STATUS_SUCCESS
;
1072 struct script_snapshot
{
1073 cairo_surface_t base
;
1076 static cairo_status_t
1077 script_snapshot_finish (void *abstract_surface
)
1079 return CAIRO_STATUS_SUCCESS
;
1082 static const cairo_surface_backend_t script_snapshot_backend
= {
1083 CAIRO_SURFACE_TYPE_SCRIPT
,
1084 script_snapshot_finish
,
1088 detach_snapshot (cairo_surface_t
*abstract_surface
)
1090 cairo_script_surface_t
*surface
= (cairo_script_surface_t
*)abstract_surface
;
1091 cairo_script_context_t
*ctx
= to_context (surface
);
1093 _cairo_output_stream_printf (ctx
->stream
,
1095 surface
->base
.unique_id
);
1099 attach_snapshot (cairo_script_context_t
*ctx
,
1100 cairo_surface_t
*source
)
1102 struct script_snapshot
*surface
;
1104 if (! ctx
->attach_snapshots
)
1107 surface
= malloc (sizeof (*surface
));
1108 if (unlikely (surface
== NULL
))
1111 _cairo_surface_init (&surface
->base
,
1112 &script_snapshot_backend
,
1116 _cairo_output_stream_printf (ctx
->stream
,
1117 "dup /s%d exch def ",
1118 surface
->base
.unique_id
);
1120 _cairo_surface_attach_snapshot (source
, &surface
->base
, detach_snapshot
);
1121 cairo_surface_destroy (&surface
->base
);
1124 static cairo_status_t
1125 _emit_recording_surface_pattern (cairo_script_surface_t
*surface
,
1126 cairo_recording_surface_t
*source
)
1128 cairo_script_implicit_context_t old_cr
;
1129 cairo_script_context_t
*ctx
= to_context (surface
);
1130 cairo_script_surface_t
*similar
;
1131 cairo_surface_t
*snapshot
;
1132 cairo_rectangle_t r
, *extents
;
1133 cairo_status_t status
;
1135 snapshot
= _cairo_surface_has_snapshot (&source
->base
, &script_snapshot_backend
);
1137 _cairo_output_stream_printf (ctx
->stream
, "s%d", snapshot
->unique_id
);
1138 return CAIRO_INT_STATUS_SUCCESS
;
1142 if (_cairo_recording_surface_get_bounds (&source
->base
, &r
))
1145 similar
= _cairo_script_surface_create_internal (ctx
,
1146 source
->base
.content
,
1149 if (unlikely (similar
->base
.status
))
1150 return similar
->base
.status
;
1152 similar
->base
.is_clear
= TRUE
;
1154 _cairo_output_stream_printf (ctx
->stream
, "//%s ",
1155 _content_to_string (source
->base
.content
));
1157 _cairo_output_stream_printf (ctx
->stream
, "[%f %f %f %f]",
1158 extents
->x
, extents
->y
,
1159 extents
->width
, extents
->height
);
1161 _cairo_output_stream_puts (ctx
->stream
, "[]");
1162 _cairo_output_stream_puts (ctx
->stream
, " record\n");
1164 attach_snapshot (ctx
, &source
->base
);
1166 _cairo_output_stream_puts (ctx
->stream
, "dup context\n");
1168 target_push (similar
);
1169 similar
->emitted
= TRUE
;
1172 old_cr
= surface
->cr
;
1173 _cairo_script_implicit_context_init (&surface
->cr
);
1174 status
= _cairo_recording_surface_replay (&source
->base
, &similar
->base
);
1175 surface
->cr
= old_cr
;
1177 if (unlikely (status
)) {
1178 cairo_surface_destroy (&similar
->base
);
1182 cairo_list_del (&similar
->operand
.link
);
1183 assert (target_is_active (surface
));
1185 _cairo_output_stream_puts (ctx
->stream
, "pop ");
1186 cairo_surface_destroy (&similar
->base
);
1188 return CAIRO_STATUS_SUCCESS
;
1191 static cairo_status_t
1192 _emit_script_surface_pattern (cairo_script_surface_t
*surface
,
1193 cairo_script_surface_t
*source
)
1195 _get_target (source
);
1197 return CAIRO_STATUS_SUCCESS
;
1200 static cairo_status_t
1201 _write_image_surface (cairo_output_stream_t
*output
,
1202 const cairo_image_surface_t
*image
)
1204 int stride
, row
, width
;
1205 uint8_t row_stack
[CAIRO_STACK_BUFFER_SIZE
];
1209 stride
= image
->stride
;
1210 width
= image
->width
;
1213 switch (image
->format
) {
1214 case CAIRO_FORMAT_A1
:
1215 for (row
= image
->height
; row
--; ) {
1216 _cairo_output_stream_write (output
, data
, (width
+7)/8);
1220 case CAIRO_FORMAT_A8
:
1221 for (row
= image
->height
; row
--; ) {
1222 _cairo_output_stream_write (output
, data
, width
);
1226 case CAIRO_FORMAT_RGB16_565
:
1227 for (row
= image
->height
; row
--; ) {
1228 _cairo_output_stream_write (output
, data
, 2*width
);
1232 case CAIRO_FORMAT_RGB24
:
1233 for (row
= image
->height
; row
--; ) {
1236 for (col
= width
; col
--; ) {
1237 _cairo_output_stream_write (output
, rowdata
, 3);
1243 case CAIRO_FORMAT_ARGB32
:
1244 for (row
= image
->height
; row
--; ) {
1245 _cairo_output_stream_write (output
, data
, 4*width
);
1249 case CAIRO_FORMAT_INVALID
:
1255 if (stride
> ARRAY_LENGTH (row_stack
)) {
1256 rowdata
= malloc (stride
);
1257 if (unlikely (rowdata
== NULL
))
1258 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1260 rowdata
= row_stack
;
1262 switch (image
->format
) {
1263 case CAIRO_FORMAT_A1
:
1264 for (row
= image
->height
; row
--; ) {
1266 for (col
= 0; col
< (width
+ 7)/8; col
++)
1267 rowdata
[col
] = CAIRO_BITSWAP8 (data
[col
]);
1268 _cairo_output_stream_write (output
, rowdata
, (width
+7)/8);
1272 case CAIRO_FORMAT_A8
:
1273 for (row
= image
->height
; row
--; ) {
1274 _cairo_output_stream_write (output
, data
, width
);
1278 case CAIRO_FORMAT_RGB16_565
:
1279 for (row
= image
->height
; row
--; ) {
1280 uint16_t *src
= (uint16_t *) data
;
1281 uint16_t *dst
= (uint16_t *) rowdata
;
1283 for (col
= 0; col
< width
; col
++)
1284 dst
[col
] = bswap_16 (src
[col
]);
1285 _cairo_output_stream_write (output
, rowdata
, 2*width
);
1289 case CAIRO_FORMAT_RGB24
:
1290 for (row
= image
->height
; row
--; ) {
1291 uint8_t *src
= data
;
1293 for (col
= 0; col
< width
; col
++) {
1294 rowdata
[3*col
+2] = *src
++;
1295 rowdata
[3*col
+1] = *src
++;
1296 rowdata
[3*col
+0] = *src
++;
1299 _cairo_output_stream_write (output
, rowdata
, 3*width
);
1303 case CAIRO_FORMAT_RGB30
:
1304 case CAIRO_FORMAT_ARGB32
:
1305 for (row
= image
->height
; row
--; ) {
1306 uint32_t *src
= (uint32_t *) data
;
1307 uint32_t *dst
= (uint32_t *) rowdata
;
1309 for (col
= 0; col
< width
; col
++)
1310 dst
[col
] = bswap_32 (src
[col
]);
1311 _cairo_output_stream_write (output
, rowdata
, 4*width
);
1315 case CAIRO_FORMAT_INVALID
:
1320 if (rowdata
!= row_stack
)
1324 return CAIRO_STATUS_SUCCESS
;
1327 static cairo_int_status_t
1328 _emit_png_surface (cairo_script_surface_t
*surface
,
1329 cairo_image_surface_t
*image
)
1331 cairo_script_context_t
*ctx
= to_context (surface
);
1332 cairo_output_stream_t
*base85_stream
;
1333 cairo_status_t status
;
1334 const uint8_t *mime_data
;
1335 unsigned long mime_data_length
;
1337 cairo_surface_get_mime_data (&image
->base
, CAIRO_MIME_TYPE_PNG
,
1338 &mime_data
, &mime_data_length
);
1339 if (mime_data
== NULL
)
1340 return CAIRO_INT_STATUS_UNSUPPORTED
;
1342 _cairo_output_stream_printf (ctx
->stream
,
1347 "/mime-type (image/png) "
1349 image
->width
, image
->height
,
1350 _format_to_string (image
->format
));
1352 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
1353 _cairo_output_stream_write (base85_stream
, mime_data
, mime_data_length
);
1354 status
= _cairo_output_stream_destroy (base85_stream
);
1355 if (unlikely (status
))
1358 _cairo_output_stream_puts (ctx
->stream
, "~> >> image ");
1359 return CAIRO_STATUS_SUCCESS
;
1362 static cairo_int_status_t
1363 _emit_image_surface (cairo_script_surface_t
*surface
,
1364 cairo_image_surface_t
*image
)
1366 cairo_script_context_t
*ctx
= to_context (surface
);
1367 cairo_output_stream_t
*base85_stream
;
1368 cairo_output_stream_t
*zlib_stream
;
1369 cairo_int_status_t status
, status2
;
1370 cairo_surface_t
*snapshot
;
1371 const uint8_t *mime_data
;
1372 unsigned long mime_data_length
;
1374 snapshot
= _cairo_surface_has_snapshot (&image
->base
,
1375 &script_snapshot_backend
);
1377 _cairo_output_stream_printf (ctx
->stream
, "s%u ", snapshot
->unique_id
);
1378 return CAIRO_INT_STATUS_SUCCESS
;
1381 status
= _emit_png_surface (surface
, image
);
1382 if (_cairo_int_status_is_error (status
)) {
1384 } else if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
1385 cairo_image_surface_t
*clone
;
1388 if (image
->format
== CAIRO_FORMAT_INVALID
) {
1389 clone
= _cairo_image_surface_coerce (image
);
1391 clone
= (cairo_image_surface_t
*)
1392 cairo_surface_reference (&image
->base
);
1395 _cairo_output_stream_printf (ctx
->stream
,
1401 clone
->width
, clone
->height
,
1402 _format_to_string (clone
->format
));
1404 switch (clone
->format
) {
1405 case CAIRO_FORMAT_A1
:
1406 len
= (clone
->width
+ 7)/8;
1408 case CAIRO_FORMAT_A8
:
1411 case CAIRO_FORMAT_RGB16_565
:
1412 len
= clone
->width
* 2;
1414 case CAIRO_FORMAT_RGB24
:
1415 len
= clone
->width
* 3;
1417 case CAIRO_FORMAT_RGB30
:
1418 case CAIRO_FORMAT_ARGB32
:
1419 len
= clone
->width
* 4;
1421 case CAIRO_FORMAT_INVALID
:
1427 len
*= clone
->height
;
1430 _cairo_output_stream_puts (ctx
->stream
, "<|");
1432 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
1434 len
= to_be32 (len
);
1435 _cairo_output_stream_write (base85_stream
, &len
, sizeof (len
));
1437 zlib_stream
= _cairo_deflate_stream_create (base85_stream
);
1438 status
= _write_image_surface (zlib_stream
, clone
);
1440 status2
= _cairo_output_stream_destroy (zlib_stream
);
1441 if (status
== CAIRO_INT_STATUS_SUCCESS
)
1443 status2
= _cairo_output_stream_destroy (base85_stream
);
1444 if (status
== CAIRO_INT_STATUS_SUCCESS
)
1446 if (unlikely (status
))
1449 _cairo_output_stream_puts (ctx
->stream
, "<~");
1451 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
1452 status
= _write_image_surface (base85_stream
, clone
);
1453 status2
= _cairo_output_stream_destroy (base85_stream
);
1454 if (status
== CAIRO_INT_STATUS_SUCCESS
)
1456 if (unlikely (status
))
1459 _cairo_output_stream_puts (ctx
->stream
, "~> >> image ");
1461 cairo_surface_destroy (&clone
->base
);
1464 cairo_surface_get_mime_data (&image
->base
, CAIRO_MIME_TYPE_JPEG
,
1465 &mime_data
, &mime_data_length
);
1466 if (mime_data
!= NULL
) {
1467 _cairo_output_stream_printf (ctx
->stream
,
1469 CAIRO_MIME_TYPE_JPEG
);
1471 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
1472 _cairo_output_stream_write (base85_stream
, mime_data
, mime_data_length
);
1473 status
= _cairo_output_stream_destroy (base85_stream
);
1474 if (unlikely (status
))
1477 _cairo_output_stream_puts (ctx
->stream
, "~> set-mime-data\n");
1480 cairo_surface_get_mime_data (&image
->base
, CAIRO_MIME_TYPE_JP2
,
1481 &mime_data
, &mime_data_length
);
1482 if (mime_data
!= NULL
) {
1483 _cairo_output_stream_printf (ctx
->stream
,
1485 CAIRO_MIME_TYPE_JP2
);
1487 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
1488 _cairo_output_stream_write (base85_stream
, mime_data
, mime_data_length
);
1489 status
= _cairo_output_stream_destroy (base85_stream
);
1490 if (unlikely (status
))
1493 _cairo_output_stream_puts (ctx
->stream
, "~> set-mime-data\n");
1496 return CAIRO_INT_STATUS_SUCCESS
;
1499 static cairo_int_status_t
1500 _emit_image_surface_pattern (cairo_script_surface_t
*surface
,
1501 cairo_surface_t
*source
)
1503 cairo_image_surface_t
*image
;
1504 cairo_status_t status
;
1507 status
= _cairo_surface_acquire_source_image (source
, &image
, &extra
);
1508 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
1509 status
= _emit_image_surface (surface
, image
);
1510 _cairo_surface_release_source_image (source
, image
, extra
);
1516 static cairo_int_status_t
1517 _emit_subsurface_pattern (cairo_script_surface_t
*surface
,
1518 cairo_surface_subsurface_t
*sub
)
1520 cairo_surface_t
*source
= sub
->target
;
1521 cairo_int_status_t status
;
1523 switch ((int) source
->backend
->type
) {
1524 case CAIRO_SURFACE_TYPE_RECORDING
:
1525 status
= _emit_recording_surface_pattern (surface
, (cairo_recording_surface_t
*) source
);
1527 case CAIRO_SURFACE_TYPE_SCRIPT
:
1528 status
= _emit_script_surface_pattern (surface
, (cairo_script_surface_t
*) source
);
1531 status
= _emit_image_surface_pattern (surface
, source
);
1534 if (unlikely (status
))
1537 _cairo_output_stream_printf (to_context (surface
)->stream
,
1538 "%d %d %d %d subsurface ",
1542 sub
->extents
.height
);
1543 return CAIRO_INT_STATUS_SUCCESS
;
1546 static cairo_int_status_t
1547 _emit_surface_pattern (cairo_script_surface_t
*surface
,
1548 const cairo_pattern_t
*pattern
)
1550 cairo_script_context_t
*ctx
= to_context (surface
);
1551 cairo_surface_pattern_t
*surface_pattern
;
1552 cairo_surface_t
*source
, *snapshot
, *free_me
= NULL
;
1553 cairo_surface_t
*take_snapshot
= NULL
;
1554 cairo_int_status_t status
;
1556 surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
1557 source
= surface_pattern
->surface
;
1559 if (_cairo_surface_is_snapshot (source
)) {
1560 snapshot
= _cairo_surface_has_snapshot (source
, &script_snapshot_backend
);
1562 _cairo_output_stream_printf (ctx
->stream
,
1564 snapshot
->unique_id
);
1565 return CAIRO_INT_STATUS_SUCCESS
;
1568 if (_cairo_surface_snapshot_is_reused (source
))
1569 take_snapshot
= source
;
1571 free_me
= source
= _cairo_surface_snapshot_get_target (source
);
1574 switch ((int) source
->backend
->type
) {
1575 case CAIRO_SURFACE_TYPE_RECORDING
:
1576 status
= _emit_recording_surface_pattern (surface
, (cairo_recording_surface_t
*) source
);
1578 case CAIRO_SURFACE_TYPE_SCRIPT
:
1579 status
= _emit_script_surface_pattern (surface
, (cairo_script_surface_t
*) source
);
1581 case CAIRO_SURFACE_TYPE_SUBSURFACE
:
1582 status
= _emit_subsurface_pattern (surface
, (cairo_surface_subsurface_t
*) source
);
1585 status
= _emit_image_surface_pattern (surface
, source
);
1588 cairo_surface_destroy (free_me
);
1589 if (unlikely (status
))
1593 attach_snapshot (ctx
, take_snapshot
);
1595 _cairo_output_stream_puts (ctx
->stream
, "pattern");
1596 return CAIRO_INT_STATUS_SUCCESS
;
1599 static cairo_int_status_t
1600 _emit_raster_pattern (cairo_script_surface_t
*surface
,
1601 const cairo_pattern_t
*pattern
)
1603 cairo_surface_t
*source
;
1604 cairo_int_status_t status
;
1606 source
= _cairo_raster_source_pattern_acquire (pattern
, &surface
->base
, NULL
);
1607 if (unlikely (source
== NULL
)) {
1609 return CAIRO_INT_STATUS_UNSUPPORTED
;
1611 if (unlikely (source
->status
))
1612 return source
->status
;
1614 status
= _emit_image_surface_pattern (surface
, source
);
1615 _cairo_raster_source_pattern_release (pattern
, source
);
1616 if (unlikely (status
))
1619 _cairo_output_stream_puts (to_context(surface
)->stream
, "pattern");
1620 return CAIRO_INT_STATUS_SUCCESS
;
1623 static cairo_int_status_t
1624 _emit_pattern (cairo_script_surface_t
*surface
,
1625 const cairo_pattern_t
*pattern
)
1627 cairo_script_context_t
*ctx
= to_context (surface
);
1628 cairo_int_status_t status
;
1629 cairo_bool_t is_default_extend
;
1630 cairo_bool_t need_newline
= TRUE
;
1632 switch (pattern
->type
) {
1633 case CAIRO_PATTERN_TYPE_SOLID
:
1634 /* solid colors do not need filter/extend/matrix */
1635 return _emit_solid_pattern (surface
, pattern
);
1637 case CAIRO_PATTERN_TYPE_LINEAR
:
1638 status
= _emit_linear_pattern (surface
, pattern
);
1639 is_default_extend
= pattern
->extend
== CAIRO_EXTEND_GRADIENT_DEFAULT
;
1641 case CAIRO_PATTERN_TYPE_RADIAL
:
1642 status
= _emit_radial_pattern (surface
, pattern
);
1643 is_default_extend
= pattern
->extend
== CAIRO_EXTEND_GRADIENT_DEFAULT
;
1645 case CAIRO_PATTERN_TYPE_MESH
:
1646 status
= _emit_mesh_pattern (surface
, pattern
);
1647 is_default_extend
= TRUE
;
1649 case CAIRO_PATTERN_TYPE_SURFACE
:
1650 status
= _emit_surface_pattern (surface
, pattern
);
1651 is_default_extend
= pattern
->extend
== CAIRO_EXTEND_SURFACE_DEFAULT
;
1653 case CAIRO_PATTERN_TYPE_RASTER_SOURCE
:
1654 status
= _emit_raster_pattern (surface
, pattern
);
1655 is_default_extend
= pattern
->extend
== CAIRO_EXTEND_SURFACE_DEFAULT
;
1660 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1662 if (unlikely (status
))
1665 if (! _cairo_matrix_is_identity (&pattern
->matrix
)) {
1667 _cairo_output_stream_puts (ctx
->stream
, "\n ");
1668 need_newline
= FALSE
;
1671 _cairo_output_stream_printf (ctx
->stream
,
1672 " [%f %f %f %f %f %f] set-matrix\n ",
1673 pattern
->matrix
.xx
, pattern
->matrix
.yx
,
1674 pattern
->matrix
.xy
, pattern
->matrix
.yy
,
1675 pattern
->matrix
.x0
, pattern
->matrix
.y0
);
1678 /* XXX need to discriminate the user explicitly setting the default */
1679 if (pattern
->filter
!= CAIRO_FILTER_DEFAULT
) {
1681 _cairo_output_stream_puts (ctx
->stream
, "\n ");
1682 need_newline
= FALSE
;
1685 _cairo_output_stream_printf (ctx
->stream
,
1686 " //%s set-filter\n ",
1687 _filter_to_string (pattern
->filter
));
1689 if (! is_default_extend
){
1691 _cairo_output_stream_puts (ctx
->stream
, "\n ");
1692 need_newline
= FALSE
;
1695 _cairo_output_stream_printf (ctx
->stream
,
1696 " //%s set-extend\n ",
1697 _extend_to_string (pattern
->extend
));
1701 _cairo_output_stream_puts (ctx
->stream
, "\n ");
1703 return CAIRO_INT_STATUS_SUCCESS
;
1706 static cairo_int_status_t
1707 _emit_identity (cairo_script_surface_t
*surface
,
1708 cairo_bool_t
*matrix_updated
)
1710 assert (target_is_active (surface
));
1712 if (_cairo_matrix_is_identity (&surface
->cr
.current_ctm
))
1713 return CAIRO_INT_STATUS_SUCCESS
;
1715 _cairo_output_stream_puts (to_context (surface
)->stream
,
1716 "identity set-matrix\n");
1718 *matrix_updated
= TRUE
;
1719 cairo_matrix_init_identity (&surface
->cr
.current_ctm
);
1721 return CAIRO_INT_STATUS_SUCCESS
;
1724 static cairo_int_status_t
1725 _emit_source (cairo_script_surface_t
*surface
,
1726 cairo_operator_t op
,
1727 const cairo_pattern_t
*source
)
1729 cairo_bool_t matrix_updated
= FALSE
;
1730 cairo_int_status_t status
;
1732 assert (target_is_active (surface
));
1734 if (op
== CAIRO_OPERATOR_CLEAR
) {
1735 /* the source is ignored, so don't change it */
1736 return CAIRO_INT_STATUS_SUCCESS
;
1739 if (_cairo_pattern_equal (&surface
->cr
.current_source
.base
, source
))
1740 return CAIRO_INT_STATUS_SUCCESS
;
1742 _cairo_pattern_fini (&surface
->cr
.current_source
.base
);
1743 status
= _cairo_pattern_init_copy (&surface
->cr
.current_source
.base
,
1745 if (unlikely (status
))
1748 status
= _emit_identity (surface
, &matrix_updated
);
1749 if (unlikely (status
))
1752 status
= _emit_pattern (surface
, source
);
1753 if (unlikely (status
))
1756 assert (target_is_active (surface
));
1757 _cairo_output_stream_puts (to_context (surface
)->stream
,
1759 return CAIRO_INT_STATUS_SUCCESS
;
1762 static cairo_status_t
1763 _path_move_to (void *closure
,
1764 const cairo_point_t
*point
)
1766 _cairo_output_stream_printf (closure
,
1768 _cairo_fixed_to_double (point
->x
),
1769 _cairo_fixed_to_double (point
->y
));
1771 return CAIRO_STATUS_SUCCESS
;
1774 static cairo_status_t
1775 _path_line_to (void *closure
,
1776 const cairo_point_t
*point
)
1778 _cairo_output_stream_printf (closure
,
1780 _cairo_fixed_to_double (point
->x
),
1781 _cairo_fixed_to_double (point
->y
));
1783 return CAIRO_STATUS_SUCCESS
;
1786 static cairo_status_t
1787 _path_curve_to (void *closure
,
1788 const cairo_point_t
*p1
,
1789 const cairo_point_t
*p2
,
1790 const cairo_point_t
*p3
)
1792 _cairo_output_stream_printf (closure
,
1793 " %f %f %f %f %f %f c",
1794 _cairo_fixed_to_double (p1
->x
),
1795 _cairo_fixed_to_double (p1
->y
),
1796 _cairo_fixed_to_double (p2
->x
),
1797 _cairo_fixed_to_double (p2
->y
),
1798 _cairo_fixed_to_double (p3
->x
),
1799 _cairo_fixed_to_double (p3
->y
));
1801 return CAIRO_STATUS_SUCCESS
;
1804 static cairo_status_t
1805 _path_close (void *closure
)
1807 _cairo_output_stream_printf (closure
,
1810 return CAIRO_STATUS_SUCCESS
;
1813 static cairo_status_t
1814 _emit_path_boxes (cairo_script_surface_t
*surface
,
1815 const cairo_path_fixed_t
*path
)
1817 cairo_script_context_t
*ctx
= to_context (surface
);
1818 cairo_path_fixed_iter_t iter
;
1819 cairo_status_t status
;
1820 struct _cairo_boxes_chunk
*chunk
;
1821 cairo_boxes_t boxes
;
1825 _cairo_boxes_init (&boxes
);
1826 _cairo_path_fixed_iter_init (&iter
, path
);
1827 while (_cairo_path_fixed_iter_is_fill_box (&iter
, &box
)) {
1828 if (box
.p1
.y
== box
.p2
.y
|| box
.p1
.x
== box
.p2
.x
)
1831 status
= _cairo_boxes_add (&boxes
, CAIRO_ANTIALIAS_DEFAULT
, &box
);
1832 if (unlikely (status
)) {
1833 _cairo_boxes_fini (&boxes
);
1838 if (! _cairo_path_fixed_iter_at_end (&iter
)) {
1839 _cairo_boxes_fini (&boxes
);
1840 return CAIRO_STATUS_INVALID_PATH_DATA
;
1843 for (chunk
= &boxes
.chunks
; chunk
; chunk
= chunk
->next
) {
1844 for (i
= 0; i
< chunk
->count
; i
++) {
1845 const cairo_box_t
*b
= &chunk
->base
[i
];
1846 double x1
= _cairo_fixed_to_double (b
->p1
.x
);
1847 double y1
= _cairo_fixed_to_double (b
->p1
.y
);
1848 double x2
= _cairo_fixed_to_double (b
->p2
.x
);
1849 double y2
= _cairo_fixed_to_double (b
->p2
.y
);
1851 _cairo_output_stream_printf (ctx
->stream
,
1852 "\n %f %f %f %f rectangle",
1853 x1
, y1
, x2
- x1
, y2
- y1
);
1857 _cairo_boxes_fini (&boxes
);
1861 static cairo_status_t
1862 _emit_path (cairo_script_surface_t
*surface
,
1863 const cairo_path_fixed_t
*path
,
1864 cairo_bool_t is_fill
)
1866 cairo_script_context_t
*ctx
= to_context (surface
);
1868 cairo_int_status_t status
;
1870 assert (target_is_active (surface
));
1871 assert (_cairo_matrix_is_identity (&surface
->cr
.current_ctm
));
1873 if (_cairo_path_fixed_equal (&surface
->cr
.current_path
, path
))
1874 return CAIRO_STATUS_SUCCESS
;
1876 _cairo_path_fixed_fini (&surface
->cr
.current_path
);
1878 _cairo_output_stream_puts (ctx
->stream
, "n");
1881 _cairo_path_fixed_init (&surface
->cr
.current_path
);
1882 _cairo_output_stream_puts (ctx
->stream
, "\n");
1883 return CAIRO_STATUS_SUCCESS
;
1886 status
= _cairo_path_fixed_init_copy (&surface
->cr
.current_path
, path
);
1887 if (unlikely (status
))
1890 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1891 if (_cairo_path_fixed_is_rectangle (path
, &box
)) {
1892 double x1
= _cairo_fixed_to_double (box
.p1
.x
);
1893 double y1
= _cairo_fixed_to_double (box
.p1
.y
);
1894 double x2
= _cairo_fixed_to_double (box
.p2
.x
);
1895 double y2
= _cairo_fixed_to_double (box
.p2
.y
);
1897 assert (x1
> -9999);
1899 _cairo_output_stream_printf (ctx
->stream
,
1900 " %f %f %f %f rectangle",
1901 x1
, y1
, x2
- x1
, y2
- y1
);
1902 status
= CAIRO_INT_STATUS_SUCCESS
;
1903 } else if (is_fill
&& _cairo_path_fixed_fill_is_rectilinear (path
)) {
1904 status
= _emit_path_boxes (surface
, path
);
1907 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
1908 status
= _cairo_path_fixed_interpret (path
,
1916 _cairo_output_stream_puts (ctx
->stream
, "\n");
1921 _scaling_matrix_equal (const cairo_matrix_t
*a
,
1922 const cairo_matrix_t
*b
)
1924 return fabs (a
->xx
- b
->xx
) < 1e-5 &&
1925 fabs (a
->xy
- b
->xy
) < 1e-5 &&
1926 fabs (a
->yx
- b
->yx
) < 1e-5 &&
1927 fabs (a
->yy
- b
->yy
) < 1e-5;
1930 static cairo_status_t
1931 _emit_scaling_matrix (cairo_script_surface_t
*surface
,
1932 const cairo_matrix_t
*ctm
,
1933 cairo_bool_t
*matrix_updated
)
1935 cairo_script_context_t
*ctx
= to_context (surface
);
1936 cairo_bool_t was_identity
;
1937 assert (target_is_active (surface
));
1939 if (_scaling_matrix_equal (&surface
->cr
.current_ctm
, ctm
))
1940 return CAIRO_STATUS_SUCCESS
;
1942 was_identity
= _cairo_matrix_is_identity (&surface
->cr
.current_ctm
);
1944 *matrix_updated
= TRUE
;
1945 surface
->cr
.current_ctm
= *ctm
;
1946 surface
->cr
.current_ctm
.x0
= 0.;
1947 surface
->cr
.current_ctm
.y0
= 0.;
1949 if (_cairo_matrix_is_identity (&surface
->cr
.current_ctm
)) {
1950 _cairo_output_stream_puts (ctx
->stream
,
1951 "identity set-matrix\n");
1952 } else if (was_identity
&& fabs (ctm
->yx
) < 1e-5 && fabs (ctm
->xy
) < 1e-5) {
1953 _cairo_output_stream_printf (ctx
->stream
,
1957 _cairo_output_stream_printf (ctx
->stream
,
1958 "[%f %f %f %f 0 0] set-matrix\n",
1963 return CAIRO_STATUS_SUCCESS
;
1966 static cairo_status_t
1967 _emit_font_matrix (cairo_script_surface_t
*surface
,
1968 const cairo_matrix_t
*font_matrix
)
1970 cairo_script_context_t
*ctx
= to_context (surface
);
1971 assert (target_is_active (surface
));
1973 if (memcmp (&surface
->cr
.current_font_matrix
,
1975 sizeof (cairo_matrix_t
)) == 0)
1977 return CAIRO_STATUS_SUCCESS
;
1980 surface
->cr
.current_font_matrix
= *font_matrix
;
1982 if (_cairo_matrix_is_identity (font_matrix
)) {
1983 _cairo_output_stream_puts (ctx
->stream
,
1984 "identity set-font-matrix\n");
1986 _cairo_output_stream_printf (ctx
->stream
,
1987 "[%f %f %f %f %f %f] set-font-matrix\n",
1988 font_matrix
->xx
, font_matrix
->yx
,
1989 font_matrix
->xy
, font_matrix
->yy
,
1990 font_matrix
->x0
, font_matrix
->y0
);
1993 return CAIRO_STATUS_SUCCESS
;
1996 static cairo_surface_t
*
1997 _cairo_script_surface_create_similar (void *abstract_surface
,
1998 cairo_content_t content
,
2002 cairo_script_surface_t
*surface
, *other
= abstract_surface
;
2003 cairo_surface_t
*passthrough
= NULL
;
2004 cairo_script_context_t
*ctx
;
2005 cairo_rectangle_t extents
;
2006 cairo_status_t status
;
2008 ctx
= to_context (other
);
2010 status
= cairo_device_acquire (&ctx
->base
);
2011 if (unlikely (status
))
2012 return _cairo_surface_create_in_error (status
);
2014 if (! other
->emitted
) {
2015 status
= _emit_surface (other
);
2016 if (unlikely (status
)) {
2017 cairo_device_release (&ctx
->base
);
2018 return _cairo_surface_create_in_error (status
);
2021 target_push (other
);
2024 if (_cairo_surface_wrapper_is_active (&other
->wrapper
)) {
2026 _cairo_surface_wrapper_create_similar (&other
->wrapper
,
2027 content
, width
, height
);
2028 if (unlikely (passthrough
->status
)) {
2029 cairo_device_release (&ctx
->base
);
2034 extents
.x
= extents
.y
= 0;
2035 extents
.width
= width
;
2036 extents
.height
= height
;
2037 surface
= _cairo_script_surface_create_internal (ctx
, content
,
2038 &extents
, passthrough
);
2039 cairo_surface_destroy (passthrough
);
2041 if (unlikely (surface
->base
.status
)) {
2042 cairo_device_release (&ctx
->base
);
2043 return &surface
->base
;
2046 _get_target (other
);
2047 _cairo_output_stream_printf (ctx
->stream
,
2048 "%u %u //%s similar dup /s%u exch def context\n",
2050 _content_to_string (content
),
2051 surface
->base
.unique_id
);
2053 surface
->emitted
= TRUE
;
2054 surface
->defined
= TRUE
;
2055 surface
->base
.is_clear
= TRUE
;
2056 target_push (surface
);
2058 cairo_device_release (&ctx
->base
);
2059 return &surface
->base
;
2062 static cairo_status_t
2063 _device_flush (void *abstract_device
)
2065 cairo_script_context_t
*ctx
= abstract_device
;
2067 return _cairo_output_stream_flush (ctx
->stream
);
2071 _device_destroy (void *abstract_device
)
2073 cairo_script_context_t
*ctx
= abstract_device
;
2074 cairo_status_t status
;
2076 while (! cairo_list_is_empty (&ctx
->fonts
)) {
2077 cairo_script_font_t
*font
;
2079 font
= cairo_list_first_entry (&ctx
->fonts
, cairo_script_font_t
, link
);
2080 cairo_list_del (&font
->base
.link
);
2081 cairo_list_del (&font
->link
);
2085 _bitmap_fini (ctx
->surface_id
.next
);
2086 _bitmap_fini (ctx
->font_id
.next
);
2088 if (ctx
->owns_stream
)
2089 status
= _cairo_output_stream_destroy (ctx
->stream
);
2094 static cairo_surface_t
*
2095 _cairo_script_surface_source (void *abstract_surface
,
2096 cairo_rectangle_int_t
*extents
)
2098 cairo_script_surface_t
*surface
= abstract_surface
;
2101 extents
->x
= extents
->y
= 0;
2102 extents
->width
= surface
->width
;
2103 extents
->height
= surface
->height
;
2106 return &surface
->base
;
2109 static cairo_status_t
2110 _cairo_script_surface_acquire_source_image (void *abstract_surface
,
2111 cairo_image_surface_t
**image_out
,
2114 cairo_script_surface_t
*surface
= abstract_surface
;
2116 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
2117 return _cairo_surface_wrapper_acquire_source_image (&surface
->wrapper
,
2122 return CAIRO_INT_STATUS_UNSUPPORTED
;
2126 _cairo_script_surface_release_source_image (void *abstract_surface
,
2127 cairo_image_surface_t
*image
,
2130 cairo_script_surface_t
*surface
= abstract_surface
;
2132 assert (_cairo_surface_wrapper_is_active (&surface
->wrapper
));
2133 _cairo_surface_wrapper_release_source_image (&surface
->wrapper
,
2138 static cairo_status_t
2139 _cairo_script_surface_finish (void *abstract_surface
)
2141 cairo_script_surface_t
*surface
= abstract_surface
;
2142 cairo_script_context_t
*ctx
= to_context (surface
);
2143 cairo_status_t status
= CAIRO_STATUS_SUCCESS
, status2
;
2145 _cairo_surface_wrapper_fini (&surface
->wrapper
);
2147 free (surface
->cr
.current_style
.dash
);
2148 surface
->cr
.current_style
.dash
= NULL
;
2150 _cairo_pattern_fini (&surface
->cr
.current_source
.base
);
2151 _cairo_path_fixed_fini (&surface
->cr
.current_path
);
2152 _cairo_surface_clipper_reset (&surface
->clipper
);
2154 status
= cairo_device_acquire (&ctx
->base
);
2155 if (unlikely (status
))
2158 if (surface
->emitted
) {
2159 assert (! surface
->active
);
2161 if (! cairo_list_is_empty (&surface
->operand
.link
)) {
2162 if (! ctx
->active
) {
2163 if (target_is_active (surface
)) {
2164 _cairo_output_stream_printf (ctx
->stream
,
2167 int depth
= target_depth (surface
);
2169 _cairo_output_stream_printf (ctx
->stream
,
2172 _cairo_output_stream_printf (ctx
->stream
,
2177 cairo_list_del (&surface
->operand
.link
);
2179 struct deferred_finish
*link
= malloc (sizeof (*link
));
2181 status2
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2182 if (status
== CAIRO_STATUS_SUCCESS
)
2184 cairo_list_del (&surface
->operand
.link
);
2186 link
->operand
.type
= DEFERRED
;
2187 cairo_list_swap (&link
->operand
.link
,
2188 &surface
->operand
.link
);
2189 cairo_list_add (&link
->link
, &ctx
->deferred
);
2194 if (surface
->defined
) {
2195 _cairo_output_stream_printf (ctx
->stream
,
2197 surface
->base
.unique_id
);
2201 if (status
== CAIRO_STATUS_SUCCESS
)
2202 status
= _cairo_output_stream_flush (to_context (surface
)->stream
);
2204 cairo_device_release (&ctx
->base
);
2209 static cairo_int_status_t
2210 _cairo_script_surface_copy_page (void *abstract_surface
)
2212 cairo_script_surface_t
*surface
= abstract_surface
;
2213 cairo_status_t status
;
2215 status
= cairo_device_acquire (surface
->base
.device
);
2216 if (unlikely (status
))
2219 status
= _emit_context (surface
);
2220 if (unlikely (status
))
2223 _cairo_output_stream_puts (to_context (surface
)->stream
, "copy-page\n");
2226 cairo_device_release (surface
->base
.device
);
2230 static cairo_int_status_t
2231 _cairo_script_surface_show_page (void *abstract_surface
)
2233 cairo_script_surface_t
*surface
= abstract_surface
;
2234 cairo_status_t status
;
2236 status
= cairo_device_acquire (surface
->base
.device
);
2237 if (unlikely (status
))
2240 status
= _emit_context (surface
);
2241 if (unlikely (status
))
2244 _cairo_output_stream_puts (to_context (surface
)->stream
, "show-page\n");
2247 cairo_device_release (surface
->base
.device
);
2251 static cairo_status_t
2252 _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t
*clipper
,
2253 cairo_path_fixed_t
*path
,
2254 cairo_fill_rule_t fill_rule
,
2256 cairo_antialias_t antialias
)
2258 cairo_script_surface_t
*surface
= cairo_container_of (clipper
,
2259 cairo_script_surface_t
,
2261 cairo_script_context_t
*ctx
= to_context (surface
);
2262 cairo_bool_t matrix_updated
= FALSE
;
2263 cairo_status_t status
;
2266 status
= _emit_context (surface
);
2267 if (unlikely (status
))
2271 if (surface
->cr
.has_clip
) {
2272 _cairo_output_stream_puts (ctx
->stream
, "reset-clip\n");
2273 surface
->cr
.has_clip
= FALSE
;
2275 return CAIRO_STATUS_SUCCESS
;
2278 /* skip the trivial clip covering the surface extents */
2279 if (surface
->width
>= 0 && surface
->height
>= 0 &&
2280 _cairo_path_fixed_is_box (path
, &box
))
2282 if (box
.p1
.x
<= 0 && box
.p1
.y
<= 0 &&
2283 box
.p2
.x
>= _cairo_fixed_from_double (surface
->width
) &&
2284 box
.p2
.y
>= _cairo_fixed_from_double (surface
->height
))
2286 return CAIRO_STATUS_SUCCESS
;
2290 status
= _emit_identity (surface
, &matrix_updated
);
2291 if (unlikely (status
))
2294 status
= _emit_fill_rule (surface
, fill_rule
);
2295 if (unlikely (status
))
2298 if (path
->has_curve_to
) {
2299 status
= _emit_tolerance (surface
, tolerance
, matrix_updated
);
2300 if (unlikely (status
))
2304 if (! _cairo_path_fixed_fill_maybe_region (path
)) {
2305 status
= _emit_antialias (surface
, antialias
);
2306 if (unlikely (status
))
2310 status
= _emit_path (surface
, path
, TRUE
);
2311 if (unlikely (status
))
2314 _cairo_output_stream_puts (ctx
->stream
, "clip+\n");
2315 surface
->cr
.has_clip
= TRUE
;
2317 return CAIRO_STATUS_SUCCESS
;
2320 static cairo_status_t
2321 active (cairo_script_surface_t
*surface
)
2323 cairo_status_t status
;
2325 status
= cairo_device_acquire (surface
->base
.device
);
2326 if (unlikely (status
))
2329 if (surface
->active
++ == 0)
2330 to_context (surface
)->active
++;
2332 return CAIRO_STATUS_SUCCESS
;
2336 inactive (cairo_script_surface_t
*surface
)
2338 cairo_script_context_t
*ctx
= to_context (surface
);
2339 cairo_list_t sorted
;
2341 assert (surface
->active
> 0);
2342 if (--surface
->active
)
2345 assert (ctx
->active
> 0);
2349 cairo_list_init (&sorted
);
2350 while (! cairo_list_is_empty (&ctx
->deferred
)) {
2351 struct deferred_finish
*df
;
2352 cairo_list_t
*operand
;
2355 df
= cairo_list_first_entry (&ctx
->deferred
,
2356 struct deferred_finish
,
2360 cairo_list_foreach (operand
, &ctx
->operands
) {
2361 if (operand
== &df
->operand
.link
)
2366 df
->operand
.type
= depth
;
2368 if (cairo_list_is_empty (&sorted
)) {
2369 cairo_list_move (&df
->link
, &sorted
);
2371 struct deferred_finish
*pos
;
2373 cairo_list_foreach_entry (pos
, struct deferred_finish
,
2377 if (df
->operand
.type
< pos
->operand
.type
)
2380 cairo_list_move_tail (&df
->link
, &pos
->link
);
2384 while (! cairo_list_is_empty (&sorted
)) {
2385 struct deferred_finish
*df
;
2386 cairo_list_t
*operand
;
2389 df
= cairo_list_first_entry (&sorted
,
2390 struct deferred_finish
,
2394 cairo_list_foreach (operand
, &ctx
->operands
) {
2395 if (operand
== &df
->operand
.link
)
2401 _cairo_output_stream_printf (ctx
->stream
,
2403 } else if (depth
== 1) {
2404 _cairo_output_stream_printf (ctx
->stream
,
2407 _cairo_output_stream_printf (ctx
->stream
,
2412 cairo_list_del (&df
->operand
.link
);
2413 cairo_list_del (&df
->link
);
2418 cairo_device_release (surface
->base
.device
);
2421 static cairo_int_status_t
2422 _cairo_script_surface_paint (void *abstract_surface
,
2423 cairo_operator_t op
,
2424 const cairo_pattern_t
*source
,
2425 const cairo_clip_t
*clip
)
2427 cairo_script_surface_t
*surface
= abstract_surface
;
2428 cairo_status_t status
;
2430 status
= active (surface
);
2431 if (unlikely (status
))
2434 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
2435 if (unlikely (status
))
2438 status
= _emit_context (surface
);
2439 if (unlikely (status
))
2442 status
= _emit_source (surface
, op
, source
);
2443 if (unlikely (status
))
2446 status
= _emit_operator (surface
, op
);
2447 if (unlikely (status
))
2450 _cairo_output_stream_puts (to_context (surface
)->stream
,
2455 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
2456 return _cairo_surface_wrapper_paint (&surface
->wrapper
,
2460 return CAIRO_STATUS_SUCCESS
;
2467 static cairo_int_status_t
2468 _cairo_script_surface_mask (void *abstract_surface
,
2469 cairo_operator_t op
,
2470 const cairo_pattern_t
*source
,
2471 const cairo_pattern_t
*mask
,
2472 const cairo_clip_t
*clip
)
2474 cairo_script_surface_t
*surface
= abstract_surface
;
2475 cairo_status_t status
;
2477 status
= active (surface
);
2478 if (unlikely (status
))
2481 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
2482 if (unlikely (status
))
2485 status
= _emit_context (surface
);
2486 if (unlikely (status
))
2489 status
= _emit_source (surface
, op
, source
);
2490 if (unlikely (status
))
2493 status
= _emit_operator (surface
, op
);
2494 if (unlikely (status
))
2497 if (_cairo_pattern_equal (source
, mask
)) {
2498 _cairo_output_stream_puts (to_context (surface
)->stream
, "/source get");
2500 status
= _emit_pattern (surface
, mask
);
2501 if (unlikely (status
))
2505 assert (surface
->cr
.current_operator
== op
);
2507 _cairo_output_stream_puts (to_context (surface
)->stream
,
2512 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
2513 return _cairo_surface_wrapper_mask (&surface
->wrapper
,
2514 op
, source
, mask
, clip
);
2517 return CAIRO_STATUS_SUCCESS
;
2524 static cairo_int_status_t
2525 _cairo_script_surface_stroke (void *abstract_surface
,
2526 cairo_operator_t op
,
2527 const cairo_pattern_t
*source
,
2528 const cairo_path_fixed_t
*path
,
2529 const cairo_stroke_style_t
*style
,
2530 const cairo_matrix_t
*ctm
,
2531 const cairo_matrix_t
*ctm_inverse
,
2533 cairo_antialias_t antialias
,
2534 const cairo_clip_t
*clip
)
2536 cairo_script_surface_t
*surface
= abstract_surface
;
2537 cairo_bool_t matrix_updated
= FALSE
;
2538 cairo_status_t status
;
2540 status
= active (surface
);
2541 if (unlikely (status
))
2544 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
2545 if (unlikely (status
))
2548 status
= _emit_context (surface
);
2549 if (unlikely (status
))
2552 status
= _emit_identity (surface
, &matrix_updated
);
2553 if (unlikely (status
))
2556 status
= _emit_path (surface
, path
, FALSE
);
2557 if (unlikely (status
))
2560 status
= _emit_source (surface
, op
, source
);
2561 if (unlikely (status
))
2564 status
= _emit_scaling_matrix (surface
, ctm
, &matrix_updated
);
2565 if (unlikely (status
))
2568 status
= _emit_operator (surface
, op
);
2569 if (unlikely (status
))
2572 if (_scaling_matrix_equal (&surface
->cr
.current_ctm
,
2573 &surface
->cr
.current_stroke_matrix
))
2575 matrix_updated
= FALSE
;
2579 matrix_updated
= TRUE
;
2580 surface
->cr
.current_stroke_matrix
= surface
->cr
.current_ctm
;
2583 status
= _emit_stroke_style (surface
, style
, matrix_updated
);
2584 if (unlikely (status
))
2587 status
= _emit_tolerance (surface
, tolerance
, matrix_updated
);
2588 if (unlikely (status
))
2591 status
= _emit_antialias (surface
, antialias
);
2592 if (unlikely (status
))
2595 _cairo_output_stream_puts (to_context (surface
)->stream
, "stroke+\n");
2599 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
2600 return _cairo_surface_wrapper_stroke (&surface
->wrapper
,
2604 tolerance
, antialias
,
2608 return CAIRO_STATUS_SUCCESS
;
2615 static cairo_int_status_t
2616 _cairo_script_surface_fill (void *abstract_surface
,
2617 cairo_operator_t op
,
2618 const cairo_pattern_t
*source
,
2619 const cairo_path_fixed_t
*path
,
2620 cairo_fill_rule_t fill_rule
,
2622 cairo_antialias_t antialias
,
2623 const cairo_clip_t
*clip
)
2625 cairo_script_surface_t
*surface
= abstract_surface
;
2626 cairo_bool_t matrix_updated
= FALSE
;
2627 cairo_status_t status
;
2630 status
= active (surface
);
2631 if (unlikely (status
))
2634 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
2635 if (unlikely (status
))
2638 status
= _emit_context (surface
);
2639 if (unlikely (status
))
2642 status
= _emit_identity (surface
, &matrix_updated
);
2643 if (unlikely (status
))
2646 status
= _emit_source (surface
, op
, source
);
2647 if (unlikely (status
))
2650 if (! _cairo_path_fixed_is_box (path
, &box
)) {
2651 status
= _emit_fill_rule (surface
, fill_rule
);
2652 if (unlikely (status
))
2656 if (path
->has_curve_to
) {
2657 status
= _emit_tolerance (surface
, tolerance
, matrix_updated
);
2658 if (unlikely (status
))
2662 if (! _cairo_path_fixed_fill_maybe_region (path
)) {
2663 status
= _emit_antialias (surface
, antialias
);
2664 if (unlikely (status
))
2668 status
= _emit_path (surface
, path
, TRUE
);
2669 if (unlikely (status
))
2672 status
= _emit_operator (surface
, op
);
2673 if (unlikely (status
))
2676 _cairo_output_stream_puts (to_context (surface
)->stream
, "fill+\n");
2680 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
2681 return _cairo_surface_wrapper_fill (&surface
->wrapper
,
2689 return CAIRO_STATUS_SUCCESS
;
2696 static cairo_surface_t
*
2697 _cairo_script_surface_snapshot (void *abstract_surface
)
2699 cairo_script_surface_t
*surface
= abstract_surface
;
2701 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
))
2702 return _cairo_surface_wrapper_snapshot (&surface
->wrapper
);
2708 _cairo_script_surface_has_show_text_glyphs (void *abstract_surface
)
2714 _subpixel_order_to_string (cairo_subpixel_order_t subpixel_order
)
2716 static const char *names
[] = {
2717 "SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */
2718 "SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */
2719 "SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */
2720 "SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */
2721 "SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */
2723 return names
[subpixel_order
];
2726 _hint_style_to_string (cairo_hint_style_t hint_style
)
2728 static const char *names
[] = {
2729 "HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */
2730 "HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */
2731 "HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */
2732 "HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */
2733 "HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */
2735 return names
[hint_style
];
2738 _hint_metrics_to_string (cairo_hint_metrics_t hint_metrics
)
2740 static const char *names
[] = {
2741 "HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */
2742 "HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */
2743 "HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */
2745 return names
[hint_metrics
];
2748 static cairo_status_t
2749 _emit_font_options (cairo_script_surface_t
*surface
,
2750 cairo_font_options_t
*font_options
)
2752 cairo_script_context_t
*ctx
= to_context (surface
);
2754 if (cairo_font_options_equal (&surface
->cr
.current_font_options
,
2757 return CAIRO_STATUS_SUCCESS
;
2760 _cairo_output_stream_printf (ctx
->stream
, "<<");
2762 if (font_options
->antialias
!= surface
->cr
.current_font_options
.antialias
) {
2763 _cairo_output_stream_printf (ctx
->stream
,
2765 _antialias_to_string (font_options
->antialias
));
2768 if (font_options
->subpixel_order
!=
2769 surface
->cr
.current_font_options
.subpixel_order
)
2771 _cairo_output_stream_printf (ctx
->stream
,
2772 " /subpixel-order //%s",
2773 _subpixel_order_to_string (font_options
->subpixel_order
));
2776 if (font_options
->hint_style
!=
2777 surface
->cr
.current_font_options
.hint_style
)
2779 _cairo_output_stream_printf (ctx
->stream
,
2780 " /hint-style //%s",
2781 _hint_style_to_string (font_options
->hint_style
));
2784 if (font_options
->hint_metrics
!=
2785 surface
->cr
.current_font_options
.hint_metrics
)
2787 _cairo_output_stream_printf (ctx
->stream
,
2788 " /hint-metrics //%s",
2789 _hint_metrics_to_string (font_options
->hint_metrics
));
2792 _cairo_output_stream_printf (ctx
->stream
,
2793 " >> set-font-options\n");
2795 surface
->cr
.current_font_options
= *font_options
;
2796 return CAIRO_STATUS_SUCCESS
;
2800 _cairo_script_scaled_font_fini (cairo_scaled_font_private_t
*abstract_private
,
2801 cairo_scaled_font_t
*scaled_font
)
2803 cairo_script_font_t
*priv
= (cairo_script_font_t
*)abstract_private
;
2804 cairo_script_context_t
*ctx
= (cairo_script_context_t
*)abstract_private
->key
;
2805 cairo_status_t status
;
2807 status
= cairo_device_acquire (&ctx
->base
);
2808 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
2809 _cairo_output_stream_printf (ctx
->stream
,
2810 "/f%lu undef /sf%lu undef\n",
2814 _bitmap_release_id (&ctx
->font_id
, priv
->id
);
2815 cairo_device_release (&ctx
->base
);
2818 cairo_list_del (&priv
->link
);
2819 cairo_list_del (&priv
->base
.link
);
2823 static cairo_script_font_t
*
2824 _cairo_script_font_get (cairo_script_context_t
*ctx
, cairo_scaled_font_t
*font
)
2826 return (cairo_script_font_t
*) _cairo_scaled_font_find_private (font
, ctx
);
2829 static long unsigned
2830 _cairo_script_font_id (cairo_script_context_t
*ctx
, cairo_scaled_font_t
*font
)
2832 return _cairo_script_font_get (ctx
, font
)->id
;
2835 static cairo_status_t
2836 _emit_type42_font (cairo_script_surface_t
*surface
,
2837 cairo_scaled_font_t
*scaled_font
)
2839 cairo_script_context_t
*ctx
= to_context (surface
);
2840 const cairo_scaled_font_backend_t
*backend
;
2841 cairo_output_stream_t
*base85_stream
;
2842 cairo_output_stream_t
*zlib_stream
;
2843 cairo_status_t status
, status2
;
2845 unsigned int load_flags
;
2849 backend
= scaled_font
->backend
;
2850 if (backend
->load_truetype_table
== NULL
)
2851 return CAIRO_INT_STATUS_UNSUPPORTED
;
2854 status
= backend
->load_truetype_table (scaled_font
, 0, 0, NULL
, &size
);
2855 if (unlikely (status
))
2858 buf
= malloc (size
);
2859 if (unlikely (buf
== NULL
))
2860 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2862 status
= backend
->load_truetype_table (scaled_font
, 0, 0, buf
, &size
);
2863 if (unlikely (status
)) {
2868 #if CAIRO_HAS_FT_FONT
2869 load_flags
= _cairo_ft_scaled_font_get_load_flags (scaled_font
);
2873 _cairo_output_stream_printf (ctx
->stream
,
2881 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
2882 len
= to_be32 (size
);
2883 _cairo_output_stream_write (base85_stream
, &len
, sizeof (len
));
2885 zlib_stream
= _cairo_deflate_stream_create (base85_stream
);
2887 _cairo_output_stream_write (zlib_stream
, buf
, size
);
2890 status2
= _cairo_output_stream_destroy (zlib_stream
);
2891 if (status
== CAIRO_STATUS_SUCCESS
)
2894 status2
= _cairo_output_stream_destroy (base85_stream
);
2895 if (status
== CAIRO_STATUS_SUCCESS
)
2898 _cairo_output_stream_printf (ctx
->stream
,
2899 "~> >> font dup /f%lu exch def set-font-face",
2900 _cairo_script_font_id (ctx
, scaled_font
));
2905 static cairo_status_t
2906 _emit_scaled_font_init (cairo_script_surface_t
*surface
,
2907 cairo_scaled_font_t
*scaled_font
,
2908 cairo_script_font_t
**font_out
)
2910 cairo_script_context_t
*ctx
= to_context (surface
);
2911 cairo_script_font_t
*font_private
;
2912 cairo_int_status_t status
;
2914 font_private
= malloc (sizeof (cairo_script_font_t
));
2915 if (unlikely (font_private
== NULL
))
2916 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
2918 _cairo_scaled_font_attach_private (scaled_font
, &font_private
->base
, ctx
,
2919 _cairo_script_scaled_font_fini
);
2921 font_private
->parent
= scaled_font
;
2922 font_private
->subset_glyph_index
= 0;
2923 font_private
->has_sfnt
= TRUE
;
2925 cairo_list_add (&font_private
->link
, &ctx
->fonts
);
2927 status
= _bitmap_next_id (&ctx
->font_id
,
2929 if (unlikely (status
)) {
2930 free (font_private
);
2934 status
= _emit_context (surface
);
2935 if (unlikely (status
)) {
2936 free (font_private
);
2940 status
= _emit_type42_font (surface
, scaled_font
);
2941 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
) {
2942 *font_out
= font_private
;
2946 font_private
->has_sfnt
= FALSE
;
2947 _cairo_output_stream_printf (ctx
->stream
,
2950 " /metrics [%f %f %f %f %f] set\n"
2951 " /glyphs array set\n"
2952 " font dup /f%lu exch def set-font-face",
2953 scaled_font
->fs_extents
.ascent
,
2954 scaled_font
->fs_extents
.descent
,
2955 scaled_font
->fs_extents
.height
,
2956 scaled_font
->fs_extents
.max_x_advance
,
2957 scaled_font
->fs_extents
.max_y_advance
,
2960 *font_out
= font_private
;
2961 return CAIRO_STATUS_SUCCESS
;
2964 static cairo_status_t
2965 _emit_scaled_font (cairo_script_surface_t
*surface
,
2966 cairo_scaled_font_t
*scaled_font
)
2968 cairo_script_context_t
*ctx
= to_context (surface
);
2969 cairo_matrix_t matrix
;
2970 cairo_font_options_t options
;
2971 cairo_bool_t matrix_updated
= FALSE
;
2972 cairo_status_t status
;
2973 cairo_script_font_t
*font_private
;
2975 cairo_scaled_font_get_ctm (scaled_font
, &matrix
);
2976 status
= _emit_scaling_matrix (surface
, &matrix
, &matrix_updated
);
2977 if (unlikely (status
))
2980 if (! matrix_updated
&& surface
->cr
.current_scaled_font
== scaled_font
)
2981 return CAIRO_STATUS_SUCCESS
;
2983 surface
->cr
.current_scaled_font
= scaled_font
;
2985 font_private
= _cairo_script_font_get (ctx
, scaled_font
);
2986 if (font_private
== NULL
) {
2987 cairo_scaled_font_get_font_matrix (scaled_font
, &matrix
);
2988 status
= _emit_font_matrix (surface
, &matrix
);
2989 if (unlikely (status
))
2992 cairo_scaled_font_get_font_options (scaled_font
, &options
);
2993 status
= _emit_font_options (surface
, &options
);
2994 if (unlikely (status
))
2997 status
= _emit_scaled_font_init (surface
, scaled_font
, &font_private
);
2998 if (unlikely (status
))
3001 assert (target_is_active (surface
));
3002 _cairo_output_stream_printf (ctx
->stream
,
3003 " /scaled-font get /sf%lu exch def\n",
3006 _cairo_output_stream_printf (ctx
->stream
,
3007 "sf%lu set-scaled-font\n",
3011 return CAIRO_STATUS_SUCCESS
;
3014 static cairo_status_t
3015 _emit_scaled_glyph_vector (cairo_script_surface_t
*surface
,
3016 cairo_scaled_font_t
*scaled_font
,
3017 cairo_script_font_t
*font_private
,
3018 cairo_scaled_glyph_t
*scaled_glyph
)
3020 cairo_script_context_t
*ctx
= to_context (surface
);
3021 cairo_script_implicit_context_t old_cr
;
3022 cairo_status_t status
;
3023 unsigned long index
;
3025 index
= ++font_private
->subset_glyph_index
;
3026 scaled_glyph
->dev_private_key
= ctx
;
3027 scaled_glyph
->dev_private
= (void *) index
;
3029 _cairo_output_stream_printf (ctx
->stream
,
3031 " /metrics [%f %f %f %f %f %f]\n"
3034 scaled_glyph
->fs_metrics
.x_bearing
,
3035 scaled_glyph
->fs_metrics
.y_bearing
,
3036 scaled_glyph
->fs_metrics
.width
,
3037 scaled_glyph
->fs_metrics
.height
,
3038 scaled_glyph
->fs_metrics
.x_advance
,
3039 scaled_glyph
->fs_metrics
.y_advance
);
3041 if (! _cairo_matrix_is_identity (&scaled_font
->scale_inverse
)) {
3042 _cairo_output_stream_printf (ctx
->stream
,
3043 "[%f %f %f %f %f %f] transform\n",
3044 scaled_font
->scale_inverse
.xx
,
3045 scaled_font
->scale_inverse
.yx
,
3046 scaled_font
->scale_inverse
.xy
,
3047 scaled_font
->scale_inverse
.yy
,
3048 scaled_font
->scale_inverse
.x0
,
3049 scaled_font
->scale_inverse
.y0
);
3052 old_cr
= surface
->cr
;
3053 _cairo_script_implicit_context_init (&surface
->cr
);
3054 status
= _cairo_recording_surface_replay (scaled_glyph
->recording_surface
,
3056 surface
->cr
= old_cr
;
3058 _cairo_output_stream_puts (ctx
->stream
, "} >> set\n");
3063 static cairo_status_t
3064 _emit_scaled_glyph_bitmap (cairo_script_surface_t
*surface
,
3065 cairo_scaled_font_t
*scaled_font
,
3066 cairo_script_font_t
*font_private
,
3067 cairo_scaled_glyph_t
*scaled_glyph
)
3069 cairo_script_context_t
*ctx
= to_context (surface
);
3070 cairo_status_t status
;
3071 unsigned long index
;
3073 index
= ++font_private
->subset_glyph_index
;
3074 scaled_glyph
->dev_private_key
= ctx
;
3075 scaled_glyph
->dev_private
= (void *) index
;
3077 _cairo_output_stream_printf (ctx
->stream
,
3079 " /metrics [%f %f %f %f %f %f]\n"
3081 "%f %f translate\n",
3083 scaled_glyph
->fs_metrics
.x_bearing
,
3084 scaled_glyph
->fs_metrics
.y_bearing
,
3085 scaled_glyph
->fs_metrics
.width
,
3086 scaled_glyph
->fs_metrics
.height
,
3087 scaled_glyph
->fs_metrics
.x_advance
,
3088 scaled_glyph
->fs_metrics
.y_advance
,
3089 scaled_glyph
->fs_metrics
.x_bearing
,
3090 scaled_glyph
->fs_metrics
.y_bearing
);
3092 status
= _emit_image_surface (surface
, scaled_glyph
->surface
);
3093 if (unlikely (status
))
3096 _cairo_output_stream_puts (ctx
->stream
, "pattern ");
3098 if (! _cairo_matrix_is_identity (&scaled_font
->font_matrix
)) {
3099 _cairo_output_stream_printf (ctx
->stream
,
3100 "\n [%f %f %f %f %f %f] set-matrix\n",
3101 scaled_font
->font_matrix
.xx
,
3102 scaled_font
->font_matrix
.yx
,
3103 scaled_font
->font_matrix
.xy
,
3104 scaled_font
->font_matrix
.yy
,
3105 scaled_font
->font_matrix
.x0
,
3106 scaled_font
->font_matrix
.y0
);
3108 _cairo_output_stream_puts (ctx
->stream
,
3109 "mask\n} >> set\n");
3111 return CAIRO_STATUS_SUCCESS
;
3114 static cairo_status_t
3115 _emit_scaled_glyph_prologue (cairo_script_surface_t
*surface
,
3116 cairo_scaled_font_t
*scaled_font
)
3118 cairo_script_context_t
*ctx
= to_context (surface
);
3120 _cairo_output_stream_printf (ctx
->stream
, "f%lu /glyphs get\n",
3121 _cairo_script_font_id (ctx
, scaled_font
));
3123 return CAIRO_STATUS_SUCCESS
;
3126 static cairo_status_t
3127 _emit_scaled_glyphs (cairo_script_surface_t
*surface
,
3128 cairo_scaled_font_t
*scaled_font
,
3129 cairo_glyph_t
*glyphs
,
3130 unsigned int num_glyphs
)
3132 cairo_script_context_t
*ctx
= to_context (surface
);
3133 cairo_script_font_t
*font_private
;
3134 cairo_status_t status
;
3136 cairo_bool_t have_glyph_prologue
= FALSE
;
3138 if (num_glyphs
== 0)
3139 return CAIRO_STATUS_SUCCESS
;
3141 font_private
= _cairo_script_font_get (ctx
, scaled_font
);
3142 if (font_private
->has_sfnt
)
3143 return CAIRO_STATUS_SUCCESS
;
3145 _cairo_scaled_font_freeze_cache (scaled_font
);
3146 for (n
= 0; n
< num_glyphs
; n
++) {
3147 cairo_scaled_glyph_t
*scaled_glyph
;
3149 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3151 CAIRO_SCALED_GLYPH_INFO_METRICS
,
3153 if (unlikely (status
))
3156 if (scaled_glyph
->dev_private_key
== ctx
)
3159 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3161 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE
,
3163 if (_cairo_status_is_error (status
))
3166 if (status
== CAIRO_STATUS_SUCCESS
) {
3167 if (! have_glyph_prologue
) {
3168 status
= _emit_scaled_glyph_prologue (surface
, scaled_font
);
3169 if (unlikely (status
))
3172 have_glyph_prologue
= TRUE
;
3175 status
= _emit_scaled_glyph_vector (surface
,
3176 scaled_font
, font_private
,
3178 if (unlikely (status
))
3184 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3186 CAIRO_SCALED_GLYPH_INFO_SURFACE
,
3188 if (_cairo_status_is_error (status
))
3191 if (status
== CAIRO_STATUS_SUCCESS
) {
3192 if (! have_glyph_prologue
) {
3193 status
= _emit_scaled_glyph_prologue (surface
, scaled_font
);
3194 if (unlikely (status
))
3197 have_glyph_prologue
= TRUE
;
3200 status
= _emit_scaled_glyph_bitmap (surface
,
3204 if (unlikely (status
))
3210 _cairo_scaled_font_thaw_cache (scaled_font
);
3212 if (have_glyph_prologue
) {
3213 _cairo_output_stream_puts (to_context (surface
)->stream
, "pop pop\n");
3220 to_octal (int value
, char *buf
, size_t size
)
3223 buf
[--size
] = '0' + (value
& 7);
3229 _emit_string_literal (cairo_script_surface_t
*surface
,
3230 const char *utf8
, int len
)
3232 cairo_script_context_t
*ctx
= to_context (surface
);
3236 _cairo_output_stream_puts (ctx
->stream
, "(");
3242 len
= strlen (utf8
);
3246 while (utf8
< end
) {
3247 switch ((c
= *utf8
++)) {
3267 _cairo_output_stream_printf (ctx
->stream
, "\\%c", c
);
3270 if (isprint (c
) || isspace (c
)) {
3271 _cairo_output_stream_printf (ctx
->stream
, "%c", c
);
3273 char buf
[4] = { '\\' };
3275 to_octal (c
, buf
+1, 3);
3276 _cairo_output_stream_write (ctx
->stream
, buf
, 4);
3281 _cairo_output_stream_puts (ctx
->stream
, ")");
3284 static cairo_int_status_t
3285 _cairo_script_surface_show_text_glyphs (void *abstract_surface
,
3286 cairo_operator_t op
,
3287 const cairo_pattern_t
*source
,
3290 cairo_glyph_t
*glyphs
,
3292 const cairo_text_cluster_t
*clusters
,
3294 cairo_text_cluster_flags_t backward
,
3295 cairo_scaled_font_t
*scaled_font
,
3296 const cairo_clip_t
*clip
)
3298 cairo_script_surface_t
*surface
= abstract_surface
;
3299 cairo_script_context_t
*ctx
= to_context (surface
);
3300 cairo_script_font_t
*font_private
;
3301 cairo_scaled_glyph_t
*scaled_glyph
;
3302 cairo_matrix_t matrix
;
3303 cairo_status_t status
;
3304 double x
, y
, ix
, iy
;
3306 cairo_output_stream_t
*base85_stream
= NULL
;
3308 status
= active (surface
);
3309 if (unlikely (status
))
3312 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
3313 if (unlikely (status
))
3316 status
= _emit_context (surface
);
3317 if (unlikely (status
))
3320 status
= _emit_source (surface
, op
, source
);
3321 if (unlikely (status
))
3324 status
= _emit_scaled_font (surface
, scaled_font
);
3325 if (unlikely (status
))
3328 status
= _emit_operator (surface
, op
);
3329 if (unlikely (status
))
3332 status
= _emit_scaled_glyphs (surface
, scaled_font
, glyphs
, num_glyphs
);
3333 if (unlikely (status
))
3336 /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */
3337 /* [cx cy [glyphs]] show_glyphs */
3339 if (utf8
!= NULL
&& clusters
!= NULL
) {
3340 _emit_string_literal (surface
, utf8
, utf8_len
);
3341 _cairo_output_stream_puts (ctx
->stream
, " ");
3344 matrix
= surface
->cr
.current_ctm
;
3345 status
= cairo_matrix_invert (&matrix
);
3346 assert (status
== CAIRO_STATUS_SUCCESS
);
3348 ix
= x
= glyphs
[0].x
;
3349 iy
= y
= glyphs
[0].y
;
3350 cairo_matrix_transform_point (&matrix
, &ix
, &iy
);
3351 ix
-= scaled_font
->font_matrix
.x0
;
3352 iy
-= scaled_font
->font_matrix
.y0
;
3354 _cairo_scaled_font_freeze_cache (scaled_font
);
3355 font_private
= _cairo_script_font_get (ctx
, scaled_font
);
3357 _cairo_output_stream_printf (ctx
->stream
,
3361 for (n
= 0; n
< num_glyphs
; n
++) {
3362 if (font_private
->has_sfnt
) {
3363 if (glyphs
[n
].index
> 256)
3366 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3368 CAIRO_SCALED_GLYPH_INFO_METRICS
,
3370 if (unlikely (status
)) {
3371 _cairo_scaled_font_thaw_cache (scaled_font
);
3375 if ((long unsigned) scaled_glyph
->dev_private
> 256)
3380 if (n
== num_glyphs
) {
3381 _cairo_output_stream_puts (ctx
->stream
, "<~");
3382 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
3384 _cairo_output_stream_puts (ctx
->stream
, "[");
3386 for (n
= 0; n
< num_glyphs
; n
++) {
3389 status
= _cairo_scaled_glyph_lookup (scaled_font
,
3391 CAIRO_SCALED_GLYPH_INFO_METRICS
,
3393 if (unlikely (status
)) {
3394 _cairo_scaled_font_thaw_cache (scaled_font
);
3398 if (fabs (glyphs
[n
].x
- x
) > 1e-5 || fabs (glyphs
[n
].y
- y
) > 1e-5) {
3399 if (fabs (glyphs
[n
].y
- y
) < 1e-5) {
3400 if (base85_stream
!= NULL
) {
3401 status
= _cairo_output_stream_destroy (base85_stream
);
3402 if (unlikely (status
)) {
3403 base85_stream
= NULL
;
3407 _cairo_output_stream_printf (ctx
->stream
,
3408 "~> %f <~", glyphs
[n
].x
- x
);
3409 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
3411 _cairo_output_stream_printf (ctx
->stream
,
3412 " ] %f [ ", glyphs
[n
].x
- x
);
3417 ix
= x
= glyphs
[n
].x
;
3418 iy
= y
= glyphs
[n
].y
;
3419 cairo_matrix_transform_point (&matrix
, &ix
, &iy
);
3420 ix
-= scaled_font
->font_matrix
.x0
;
3421 iy
-= scaled_font
->font_matrix
.y0
;
3422 if (base85_stream
!= NULL
) {
3423 status
= _cairo_output_stream_destroy (base85_stream
);
3424 if (unlikely (status
)) {
3425 base85_stream
= NULL
;
3429 _cairo_output_stream_printf (ctx
->stream
,
3432 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
3434 _cairo_output_stream_printf (ctx
->stream
,
3440 if (base85_stream
!= NULL
) {
3443 if (font_private
->has_sfnt
)
3444 c
= glyphs
[n
].index
;
3446 c
= (uint8_t) (long unsigned) scaled_glyph
->dev_private
;
3448 _cairo_output_stream_write (base85_stream
, &c
, 1);
3450 if (font_private
->has_sfnt
)
3451 _cairo_output_stream_printf (ctx
->stream
, " %lu",
3454 _cairo_output_stream_printf (ctx
->stream
, " %lu",
3455 (long unsigned) scaled_glyph
->dev_private
);
3458 dx
= scaled_glyph
->metrics
.x_advance
;
3459 dy
= scaled_glyph
->metrics
.y_advance
;
3460 cairo_matrix_transform_distance (&scaled_font
->ctm
, &dx
, &dy
);
3464 _cairo_scaled_font_thaw_cache (scaled_font
);
3466 if (base85_stream
!= NULL
) {
3467 cairo_status_t status2
;
3469 status2
= _cairo_output_stream_destroy (base85_stream
);
3470 if (status
== CAIRO_STATUS_SUCCESS
)
3473 _cairo_output_stream_printf (ctx
->stream
, "~>");
3475 _cairo_output_stream_puts (ctx
->stream
, " ]");
3477 if (unlikely (status
))
3480 if (utf8
!= NULL
&& clusters
!= NULL
) {
3481 for (n
= 0; n
< num_clusters
; n
++) {
3482 if (clusters
[n
].num_bytes
> UCHAR_MAX
||
3483 clusters
[n
].num_glyphs
> UCHAR_MAX
)
3489 if (n
< num_clusters
) {
3490 _cairo_output_stream_puts (ctx
->stream
, "] [ ");
3491 for (n
= 0; n
< num_clusters
; n
++) {
3492 _cairo_output_stream_printf (ctx
->stream
,
3494 clusters
[n
].num_bytes
,
3495 clusters
[n
].num_glyphs
);
3497 _cairo_output_stream_puts (ctx
->stream
, "]");
3501 _cairo_output_stream_puts (ctx
->stream
, "] <~");
3502 base85_stream
= _cairo_base85_stream_create (ctx
->stream
);
3503 for (n
= 0; n
< num_clusters
; n
++) {
3505 c
[0] = clusters
[n
].num_bytes
;
3506 c
[1] = clusters
[n
].num_glyphs
;
3507 _cairo_output_stream_write (base85_stream
, c
, 2);
3509 status
= _cairo_output_stream_destroy (base85_stream
);
3510 if (unlikely (status
))
3513 _cairo_output_stream_puts (ctx
->stream
, "~>");
3516 _cairo_output_stream_printf (ctx
->stream
,
3517 " //%s show-text-glyphs\n",
3518 _direction_to_string (backward
));
3520 _cairo_output_stream_puts (ctx
->stream
,
3526 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)){
3527 return _cairo_surface_wrapper_show_text_glyphs (&surface
->wrapper
,
3531 clusters
, num_clusters
,
3537 return CAIRO_STATUS_SUCCESS
;
3545 _cairo_script_surface_get_extents (void *abstract_surface
,
3546 cairo_rectangle_int_t
*rectangle
)
3548 cairo_script_surface_t
*surface
= abstract_surface
;
3550 if (_cairo_surface_wrapper_is_active (&surface
->wrapper
)) {
3551 return _cairo_surface_wrapper_get_extents (&surface
->wrapper
,
3555 if (surface
->width
< 0 || surface
->height
< 0)
3560 rectangle
->width
= surface
->width
;
3561 rectangle
->height
= surface
->height
;
3566 static const cairo_surface_backend_t
3567 _cairo_script_surface_backend
= {
3568 CAIRO_SURFACE_TYPE_SCRIPT
,
3569 _cairo_script_surface_finish
,
3571 _cairo_default_context_create
,
3573 _cairo_script_surface_create_similar
,
3574 NULL
, /* create similar image */
3575 NULL
, /* map to image */
3576 NULL
, /* unmap image */
3578 _cairo_script_surface_source
,
3579 _cairo_script_surface_acquire_source_image
,
3580 _cairo_script_surface_release_source_image
,
3581 _cairo_script_surface_snapshot
,
3583 _cairo_script_surface_copy_page
,
3584 _cairo_script_surface_show_page
,
3586 _cairo_script_surface_get_extents
,
3587 NULL
, /* get_font_options */
3590 NULL
, /* mark_dirty_rectangle */
3592 _cairo_script_surface_paint
,
3593 _cairo_script_surface_mask
,
3594 _cairo_script_surface_stroke
,
3595 _cairo_script_surface_fill
,
3596 NULL
, /* fill/stroke */
3598 _cairo_script_surface_has_show_text_glyphs
,
3599 _cairo_script_surface_show_text_glyphs
3603 _cairo_script_implicit_context_init (cairo_script_implicit_context_t
*cr
)
3605 cr
->current_operator
= CAIRO_GSTATE_OPERATOR_DEFAULT
;
3606 cr
->current_fill_rule
= CAIRO_GSTATE_FILL_RULE_DEFAULT
;
3607 cr
->current_tolerance
= CAIRO_GSTATE_TOLERANCE_DEFAULT
;
3608 cr
->current_antialias
= CAIRO_ANTIALIAS_DEFAULT
;
3609 _cairo_stroke_style_init (&cr
->current_style
);
3610 _cairo_pattern_init_solid (&cr
->current_source
.solid
,
3612 _cairo_path_fixed_init (&cr
->current_path
);
3613 cairo_matrix_init_identity (&cr
->current_ctm
);
3614 cairo_matrix_init_identity (&cr
->current_stroke_matrix
);
3615 cairo_matrix_init_identity (&cr
->current_font_matrix
);
3616 _cairo_font_options_init_default (&cr
->current_font_options
);
3617 cr
->current_scaled_font
= NULL
;
3618 cr
->has_clip
= FALSE
;
3622 _cairo_script_implicit_context_reset (cairo_script_implicit_context_t
*cr
)
3624 free (cr
->current_style
.dash
);
3625 cr
->current_style
.dash
= NULL
;
3627 _cairo_pattern_fini (&cr
->current_source
.base
);
3628 _cairo_path_fixed_fini (&cr
->current_path
);
3630 _cairo_script_implicit_context_init (cr
);
3633 static cairo_script_surface_t
*
3634 _cairo_script_surface_create_internal (cairo_script_context_t
*ctx
,
3635 cairo_content_t content
,
3636 cairo_rectangle_t
*extents
,
3637 cairo_surface_t
*passthrough
)
3639 cairo_script_surface_t
*surface
;
3641 if (unlikely (ctx
== NULL
))
3642 return (cairo_script_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER
));
3644 surface
= malloc (sizeof (cairo_script_surface_t
));
3645 if (unlikely (surface
== NULL
))
3646 return (cairo_script_surface_t
*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
3648 _cairo_surface_init (&surface
->base
,
3649 &_cairo_script_surface_backend
,
3653 _cairo_surface_wrapper_init (&surface
->wrapper
, passthrough
);
3655 _cairo_surface_clipper_init (&surface
->clipper
,
3656 _cairo_script_surface_clipper_intersect_clip_path
);
3658 surface
->width
= surface
->height
= -1;
3660 surface
->width
= extents
->width
;
3661 surface
->height
= extents
->height
;
3662 cairo_surface_set_device_offset (&surface
->base
,
3663 -extents
->x
, -extents
->y
);
3666 surface
->emitted
= FALSE
;
3667 surface
->defined
= FALSE
;
3668 surface
->active
= FALSE
;
3669 surface
->operand
.type
= SURFACE
;
3670 cairo_list_init (&surface
->operand
.link
);
3672 _cairo_script_implicit_context_init (&surface
->cr
);
3677 static const cairo_device_backend_t _cairo_script_device_backend
= {
3678 CAIRO_DEVICE_TYPE_SCRIPT
,
3680 NULL
, NULL
, /* lock, unlock */
3682 _device_flush
, /* flush */
3688 _cairo_script_context_create_internal (cairo_output_stream_t
*stream
)
3690 cairo_script_context_t
*ctx
;
3692 ctx
= malloc (sizeof (cairo_script_context_t
));
3693 if (unlikely (ctx
== NULL
))
3694 return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
3696 memset (ctx
, 0, sizeof (cairo_script_context_t
));
3698 _cairo_device_init (&ctx
->base
, &_cairo_script_device_backend
);
3700 cairo_list_init (&ctx
->operands
);
3701 cairo_list_init (&ctx
->deferred
);
3702 ctx
->stream
= stream
;
3703 ctx
->mode
= CAIRO_SCRIPT_MODE_ASCII
;
3705 cairo_list_init (&ctx
->fonts
);
3706 cairo_list_init (&ctx
->defines
);
3708 ctx
->attach_snapshots
= TRUE
;
3714 _cairo_script_context_attach_snapshots (cairo_device_t
*device
,
3715 cairo_bool_t enable
)
3717 cairo_script_context_t
*ctx
;
3719 ctx
= (cairo_script_context_t
*) device
;
3720 ctx
->attach_snapshots
= enable
;
3723 static cairo_device_t
*
3724 _cairo_script_context_create (cairo_output_stream_t
*stream
)
3726 cairo_script_context_t
*ctx
;
3728 ctx
= (cairo_script_context_t
*)
3729 _cairo_script_context_create_internal (stream
);
3730 if (unlikely (ctx
->base
.status
))
3733 ctx
->owns_stream
= TRUE
;
3734 _cairo_output_stream_puts (ctx
->stream
, "%!CairoScript\n");
3739 * cairo_script_create:
3740 * @filename: the name (path) of the file to write the script to
3742 * Creates a output device for emitting the script, used when
3743 * creating the individual surfaces.
3745 * Return value: a pointer to the newly created device. The caller
3746 * owns the surface and should call cairo_device_destroy() when done
3749 * This function always returns a valid pointer, but it will return a
3750 * pointer to a "nil" device if an error such as out of memory
3751 * occurs. You can use cairo_device_status() to check for this.
3756 cairo_script_create (const char *filename
)
3758 cairo_output_stream_t
*stream
;
3759 cairo_status_t status
;
3761 stream
= _cairo_output_stream_create_for_filename (filename
);
3762 if ((status
= _cairo_output_stream_get_status (stream
)))
3763 return _cairo_device_create_in_error (status
);
3765 return _cairo_script_context_create (stream
);
3769 * cairo_script_create_for_stream:
3770 * @write_func: callback function passed the bytes written to the script
3771 * @closure: user data to be passed to the callback
3773 * Creates a output device for emitting the script, used when
3774 * creating the individual surfaces.
3776 * Return value: a pointer to the newly created device. The caller
3777 * owns the surface and should call cairo_device_destroy() when done
3780 * This function always returns a valid pointer, but it will return a
3781 * pointer to a "nil" device if an error such as out of memory
3782 * occurs. You can use cairo_device_status() to check for this.
3787 cairo_script_create_for_stream (cairo_write_func_t write_func
,
3790 cairo_output_stream_t
*stream
;
3791 cairo_status_t status
;
3793 stream
= _cairo_output_stream_create (write_func
, NULL
, closure
);
3794 if ((status
= _cairo_output_stream_get_status (stream
)))
3795 return _cairo_device_create_in_error (status
);
3797 return _cairo_script_context_create (stream
);
3801 * cairo_script_write_comment:
3802 * @script: the script (output device)
3803 * @comment: the string to emit
3804 * @len:the length of the sting to write, or -1 to use strlen()
3806 * Emit a string verbatim into the script.
3811 cairo_script_write_comment (cairo_device_t
*script
,
3812 const char *comment
,
3815 cairo_script_context_t
*context
= (cairo_script_context_t
*) script
;
3818 len
= strlen (comment
);
3820 _cairo_output_stream_puts (context
->stream
, "% ");
3821 _cairo_output_stream_write (context
->stream
, comment
, len
);
3822 _cairo_output_stream_puts (context
->stream
, "\n");
3826 * cairo_script_set_mode:
3827 * @script: The script (output device)
3828 * @mode: the new mode
3830 * Change the output mode of the script
3835 cairo_script_set_mode (cairo_device_t
*script
,
3836 cairo_script_mode_t mode
)
3838 cairo_script_context_t
*context
= (cairo_script_context_t
*) script
;
3840 context
->mode
= mode
;
3844 * cairo_script_get_mode:
3845 * @script: The script (output device) to query
3847 * Queries the script for its current output mode.
3849 * Return value: the current output mode of the script
3854 cairo_script_get_mode (cairo_device_t
*script
)
3856 cairo_script_context_t
*context
= (cairo_script_context_t
*) script
;
3858 return context
->mode
;
3862 * cairo_script_surface_create:
3863 * @script: the script (output device)
3864 * @content: the content of the surface
3865 * @width: width in pixels
3866 * @height: height in pixels
3868 * Create a new surface that will emit its rendering through @script
3870 * Return value: a pointer to the newly created surface. The caller
3871 * owns the surface and should call cairo_surface_destroy() when done
3874 * This function always returns a valid pointer, but it will return a
3875 * pointer to a "nil" surface if an error such as out of memory
3876 * occurs. You can use cairo_surface_status() to check for this.
3881 cairo_script_surface_create (cairo_device_t
*script
,
3882 cairo_content_t content
,
3886 cairo_rectangle_t
*extents
, r
;
3888 if (unlikely (script
->backend
->type
!= CAIRO_DEVICE_TYPE_SCRIPT
))
3889 return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
3891 if (unlikely (script
->status
))
3892 return _cairo_surface_create_in_error (script
->status
);
3895 if (width
> 0 && height
> 0) {
3901 return &_cairo_script_surface_create_internal ((cairo_script_context_t
*) script
,
3905 slim_hidden_def (cairo_script_surface_create
);
3908 * cairo_script_surface_create_for_target:
3909 * @script: the script (output device)
3910 * @target: a target surface to wrap
3912 * Create a pxoy surface that will render to @target and record
3913 * the operations to @device.
3915 * Return value: a pointer to the newly created surface. The caller
3916 * owns the surface and should call cairo_surface_destroy() when done
3919 * This function always returns a valid pointer, but it will return a
3920 * pointer to a "nil" surface if an error such as out of memory
3921 * occurs. You can use cairo_surface_status() to check for this.
3926 cairo_script_surface_create_for_target (cairo_device_t
*script
,
3927 cairo_surface_t
*target
)
3929 cairo_rectangle_int_t extents
;
3930 cairo_rectangle_t rect
, *r
;
3932 if (unlikely (script
->backend
->type
!= CAIRO_DEVICE_TYPE_SCRIPT
))
3933 return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
3935 if (unlikely (script
->status
))
3936 return _cairo_surface_create_in_error (script
->status
);
3938 if (unlikely (target
->status
))
3939 return _cairo_surface_create_in_error (target
->status
);
3942 if (_cairo_surface_get_extents (target
, &extents
)) {
3943 rect
.x
= rect
.y
= 0;
3944 rect
.width
= extents
.width
;
3945 rect
.height
= extents
.height
;
3948 return &_cairo_script_surface_create_internal ((cairo_script_context_t
*) script
,
3954 * cairo_script_from_recording_surface:
3955 * @script: the script (output device)
3956 * @recording_surface: the recording surface to replay
3958 * Converts the record operations in @recording_surface into a script.
3960 * Return value: #CAIRO_STATUS_SUCCESS on successful completion or an error code.
3965 cairo_script_from_recording_surface (cairo_device_t
*script
,
3966 cairo_surface_t
*recording_surface
)
3968 cairo_rectangle_t r
, *extents
;
3969 cairo_surface_t
*surface
;
3970 cairo_status_t status
;
3972 if (unlikely (script
->backend
->type
!= CAIRO_DEVICE_TYPE_SCRIPT
))
3973 return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
3975 if (unlikely (script
->status
))
3976 return _cairo_error (script
->status
);
3978 if (unlikely (recording_surface
->status
))
3979 return recording_surface
->status
;
3981 if (unlikely (! _cairo_surface_is_recording (recording_surface
)))
3982 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
3985 if (_cairo_recording_surface_get_bounds (recording_surface
, &r
))
3988 surface
= &_cairo_script_surface_create_internal ((cairo_script_context_t
*) script
,
3989 recording_surface
->content
,
3992 if (unlikely (surface
->status
))
3993 return surface
->status
;
3995 status
= _cairo_recording_surface_replay (recording_surface
, surface
);
3996 cairo_surface_destroy (surface
);