sync with experimental
[luatex.git] / source / libs / cairo / cairo-1.14.6 / src / cairo-script-surface.c
bloba4cefdebb4be5d85fe2130ce00e34c086114c6ca
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.
33 * Contributor(s):
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.
45 /**
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.
55 **/
57 /**
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.
63 * Since: 1.12
64 **/
67 #include "cairoint.h"
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"
87 #if CAIRO_HAS_FT_FONT
88 #include "cairo-ft-private.h"
89 #endif
91 #include <ctype.h>
93 #ifdef WORDS_BIGENDIAN
94 #define to_be32(x) x
95 #else
96 #define to_be32(x) bswap_32(x)
97 #endif
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 {
110 enum {
111 SURFACE,
112 DEFERRED,
113 } type;
114 cairo_list_t link;
115 } operand_t;
118 struct deferred_finish {
119 cairo_list_t link;
120 operand_t operand;
123 struct _cairo_script_context {
124 cairo_device_t base;
126 int active;
127 int attach_snapshots;
129 cairo_bool_t owns_stream;
130 cairo_output_stream_t *stream;
131 cairo_script_mode_t mode;
133 struct _bitmap {
134 unsigned long min;
135 unsigned long count;
136 unsigned int map[64];
137 struct _bitmap *next;
138 } surface_id, font_id;
140 cairo_list_t operands;
141 cairo_list_t deferred;
143 cairo_list_t fonts;
144 cairo_list_t defines;
147 struct _cairo_script_font {
148 cairo_scaled_font_private_t base;
150 cairo_bool_t has_sfnt;
151 unsigned long id;
152 unsigned long subset_glyph_index;
153 cairo_list_t link;
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;
180 operand_t operand;
181 cairo_bool_t emitted;
182 cairo_bool_t defined;
183 cairo_bool_t active;
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);
199 static void
200 _cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
201 cairo_scaled_font_t *scaled_font);
203 static void
204 _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
206 static void
207 _cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr);
209 static void
210 _bitmap_release_id (struct _bitmap *b, unsigned long token)
212 struct _bitmap **prev = NULL;
214 do {
215 if (token < b->min + sizeof (b->map) * CHAR_BIT) {
216 unsigned int bit, elem;
218 token -= b->min;
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) {
223 *prev = b->next;
224 free (b);
226 return;
228 prev = &b->next;
229 b = b->next;
230 } while (b != NULL);
233 static cairo_status_t
234 _bitmap_next_id (struct _bitmap *b,
235 unsigned long *id)
237 struct _bitmap *bb, **prev = NULL;
238 unsigned long min = 0;
240 do {
241 if (b->min != min)
242 break;
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)
248 continue;
250 for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) {
251 if ((b->map[n] & bit) == 0) {
252 b->map[n] |= bit;
253 b->count++;
254 *id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min;
255 return CAIRO_STATUS_SUCCESS;
260 min += sizeof (b->map) * CHAR_BIT;
262 prev = &b->next;
263 b = b->next;
264 } while (b != NULL);
266 bb = malloc (sizeof (struct _bitmap));
267 if (unlikely (bb == NULL))
268 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
270 *prev = bb;
271 bb->next = b;
272 bb->min = min;
273 bb->count = 1;
274 bb->map[0] = 0x1;
275 memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0]));
276 *id = min;
278 return CAIRO_STATUS_SUCCESS;
281 static void
282 _bitmap_fini (struct _bitmap *b)
284 while (b != NULL) {
285 struct _bitmap *next = b->next;
286 free (b);
287 b = next;
291 static const char *
292 _direction_to_string (cairo_bool_t backward)
294 static const char *names[] = {
295 "FORWARD",
296 "BACKWARD"
298 assert (backward < ARRAY_LENGTH (names));
299 return names[backward];
302 static const char *
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));
341 return names[op];
344 static const char *
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];
357 static const char *
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];
372 static const char *
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));
380 return names[rule];
383 static const char *
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];
399 static const char *
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];
411 static const char *
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;
429 static cairo_bool_t
430 target_is_active (cairo_script_surface_t *surface)
432 return cairo_list_is_first (&surface->operand.link,
433 &to_context (surface)->operands);
436 static void
437 target_push (cairo_script_surface_t *surface)
439 cairo_list_move (&surface->operand.link, &to_context (surface)->operands);
442 static int
443 target_depth (cairo_script_surface_t *surface)
445 cairo_list_t *link;
446 int depth = 0;
448 cairo_list_foreach (link, &to_context (surface)->operands) {
449 if (link == &surface->operand.link)
450 break;
451 depth++;
454 return depth;
457 static void
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 ");
464 return;
467 if (surface->defined) {
468 _cairo_output_stream_printf (ctx->stream, "s%u ",
469 surface->base.unique_id);
470 } else {
471 int depth = target_depth (surface);
473 assert (! cairo_list_is_empty (&surface->operand.link));
474 assert (! target_is_active (surface));
476 if (ctx->active) {
477 _cairo_output_stream_printf (ctx->stream, "%d index ", depth);
478 _cairo_output_stream_puts (ctx->stream, "/target get exch pop ");
479 } else {
480 if (depth == 1) {
481 _cairo_output_stream_puts (ctx->stream, "exch ");
482 } else {
483 _cairo_output_stream_printf (ctx->stream,
484 "%d -1 roll ", depth);
486 target_push (surface);
487 _cairo_output_stream_puts (ctx->stream, "dup ");
492 static const char *
493 _content_to_string (cairo_content_t content)
495 switch (content) {
496 case CAIRO_CONTENT_ALPHA: return "ALPHA";
497 case CAIRO_CONTENT_COLOR: return "COLOR";
498 default:
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,
509 "<< /content //%s",
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",
514 surface->width,
515 surface->height);
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. */
533 if (0) {
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)) {
555 operand_t *op;
556 cairo_script_surface_t *old;
558 op = cairo_list_first_entry (&ctx->operands,
559 operand_t,
560 link);
561 if (op->type == DEFERRED)
562 break;
564 old = cairo_container_of (op, cairo_script_surface_t, operand);
565 if (old == surface)
566 break;
567 if (old->active)
568 break;
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);
575 old->defined = TRUE;
576 } else {
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))
591 return status;
592 } else if (cairo_list_is_empty (&surface->operand.link)) {
593 assert (surface->defined);
594 _cairo_output_stream_printf (ctx->stream,
595 "s%u context\n",
596 surface->base.unique_id);
597 _cairo_script_implicit_context_reset (&surface->cr);
598 _cairo_surface_clipper_reset (&surface->clipper);
599 } else {
600 int depth = target_depth (surface);
601 if (depth == 1) {
602 _cairo_output_stream_puts (ctx->stream, "exch\n");
603 } else {
604 _cairo_output_stream_printf (ctx->stream,
605 "%d -1 roll\n",
606 depth);
609 target_push (surface);
611 return CAIRO_STATUS_SUCCESS;
614 static cairo_status_t
615 _emit_operator (cairo_script_surface_t *surface,
616 cairo_operator_t op)
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,
650 double tolerance,
651 cairo_bool_t force)
653 assert (target_is_active (surface));
655 if ((! force ||
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",
666 tolerance);
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,
690 double line_width,
691 cairo_bool_t force)
693 assert (target_is_active (surface));
695 if ((! force ||
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",
706 line_width);
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,
746 double miter_limit,
747 cairo_bool_t force)
749 assert (target_is_active (surface));
751 if ((! force ||
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",
762 miter_limit);
763 return CAIRO_STATUS_SUCCESS;
766 static cairo_bool_t
767 _dashes_equal (const double *a, const double *b, int num_dashes)
769 while (num_dashes--) {
770 if (fabs (*a - *b) > 1e-5)
771 return FALSE;
772 a++, b++;
775 return TRUE;
778 static cairo_status_t
779 _emit_dash (cairo_script_surface_t *surface,
780 const double *dash,
781 unsigned int num_dashes,
782 double offset,
783 cairo_bool_t force)
785 unsigned int n;
787 assert (target_is_active (surface));
789 if (force &&
790 num_dashes == 0 &&
791 surface->cr.current_style.num_dashes == 0)
793 return CAIRO_STATUS_SUCCESS;
796 if (! force &&
797 (surface->cr.current_style.num_dashes == num_dashes &&
798 (num_dashes == 0 ||
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;
806 if (num_dashes) {
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);
814 } else {
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,
829 "] %f set-dash\n",
830 offset);
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,
838 cairo_bool_t force)
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))
846 return status;
848 status = _emit_line_cap (surface, style->line_cap);
849 if (unlikely (status))
850 return status;
852 status = _emit_line_join (surface, style->line_join);
853 if (unlikely (status))
854 return status;
856 status = _emit_miter_limit (surface, style->miter_limit, force);
857 if (unlikely (status))
858 return status;
860 status = _emit_dash (surface,
861 style->dash, style->num_dashes, style->dash_offset,
862 force);
863 if (unlikely (status))
864 return status;
866 return CAIRO_STATUS_SUCCESS;
869 static const char *
870 _format_to_string (cairo_format_t format)
872 switch (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";
881 ASSERT_NOT_REACHED;
882 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,
900 "%f a",
901 solid->color.alpha);
903 else
905 _cairo_output_stream_printf (ctx->stream,
906 "%f %f %f %f rgba",
907 solid->color.red,
908 solid->color.green,
909 solid->color.blue,
910 solid->color.alpha);
913 else
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,
919 "%f g",
920 solid->color.red);
922 else
924 _cairo_output_stream_printf (ctx->stream,
925 "%f %f %f rgb",
926 solid->color.red,
927 solid->color.green,
928 solid->color.blue);
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)
940 unsigned int n;
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,
984 radial->cd1.radius,
985 radial->cd2.center.x,
986 radial->cd2.center.y,
987 radial->cd2.radius);
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;
998 unsigned int i, n;
1000 mesh = (cairo_pattern_t *) pattern;
1001 status = cairo_mesh_pattern_get_patch_count (mesh, &n);
1002 if (unlikely (status))
1003 return status;
1005 _cairo_output_stream_printf (ctx->stream, "mesh");
1006 for (i = 0; i < n; i++) {
1007 cairo_path_t *path;
1008 cairo_path_data_t *data;
1009 int j;
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,
1022 "\n %f %f m",
1023 data[1].point.x, data[1].point.y);
1024 break;
1025 case CAIRO_PATH_LINE_TO:
1026 _cairo_output_stream_printf (ctx->stream,
1027 "\n %f %f l",
1028 data[1].point.x, data[1].point.y);
1029 break;
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);
1036 break;
1037 case CAIRO_PATH_CLOSE_PATH:
1038 break;
1041 cairo_path_destroy (path);
1043 for (j = 0; j < 4; j++) {
1044 double x, y;
1046 status = cairo_mesh_pattern_get_control_point (mesh, i, j, &x, &y);
1047 if (unlikely (status))
1048 return status;
1049 _cairo_output_stream_printf (ctx->stream,
1050 "\n %d %f %f set-control-point",
1051 j, x, y);
1054 for (j = 0; j < 4; j++) {
1055 double r, g, b, a;
1057 status = cairo_mesh_pattern_get_corner_color_rgba (mesh, i, j, &r, &g, &b, &a);
1058 if (unlikely (status))
1059 return status;
1061 _cairo_output_stream_printf (ctx->stream,
1062 "\n %d %f %f %f %f set-corner-color",
1063 j, r, g, b, a);
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,
1087 static void
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,
1094 "/s%d undef\n",
1095 surface->base.unique_id);
1098 static void
1099 attach_snapshot (cairo_script_context_t *ctx,
1100 cairo_surface_t *source)
1102 struct script_snapshot *surface;
1104 if (! ctx->attach_snapshots)
1105 return;
1107 surface = malloc (sizeof (*surface));
1108 if (unlikely (surface == NULL))
1109 return;
1111 _cairo_surface_init (&surface->base,
1112 &script_snapshot_backend,
1113 &ctx->base,
1114 source->content);
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);
1136 if (snapshot) {
1137 _cairo_output_stream_printf (ctx->stream, "s%d", snapshot->unique_id);
1138 return CAIRO_INT_STATUS_SUCCESS;
1141 extents = NULL;
1142 if (_cairo_recording_surface_get_bounds (&source->base, &r))
1143 extents = &r;
1145 similar = _cairo_script_surface_create_internal (ctx,
1146 source->base.content,
1147 extents,
1148 NULL);
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));
1156 if (extents) {
1157 _cairo_output_stream_printf (ctx->stream, "[%f %f %f %f]",
1158 extents->x, extents->y,
1159 extents->width, extents->height);
1160 } else
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);
1179 return status;
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];
1206 uint8_t *rowdata;
1207 uint8_t *data;
1209 stride = image->stride;
1210 width = image->width;
1211 data = image->data;
1212 #if WORDS_BIGENDIAN
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);
1217 data += stride;
1219 break;
1220 case CAIRO_FORMAT_A8:
1221 for (row = image->height; row--; ) {
1222 _cairo_output_stream_write (output, data, width);
1223 data += stride;
1225 break;
1226 case CAIRO_FORMAT_RGB16_565:
1227 for (row = image->height; row--; ) {
1228 _cairo_output_stream_write (output, data, 2*width);
1229 data += stride;
1231 break;
1232 case CAIRO_FORMAT_RGB24:
1233 for (row = image->height; row--; ) {
1234 int col;
1235 rowdata = data;
1236 for (col = width; col--; ) {
1237 _cairo_output_stream_write (output, rowdata, 3);
1238 rowdata+=4;
1240 data += stride;
1242 break;
1243 case CAIRO_FORMAT_ARGB32:
1244 for (row = image->height; row--; ) {
1245 _cairo_output_stream_write (output, data, 4*width);
1246 data += stride;
1248 break;
1249 case CAIRO_FORMAT_INVALID:
1250 default:
1251 ASSERT_NOT_REACHED;
1252 break;
1254 #else
1255 if (stride > ARRAY_LENGTH (row_stack)) {
1256 rowdata = malloc (stride);
1257 if (unlikely (rowdata == NULL))
1258 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1259 } else
1260 rowdata = row_stack;
1262 switch (image->format) {
1263 case CAIRO_FORMAT_A1:
1264 for (row = image->height; row--; ) {
1265 int col;
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);
1269 data += stride;
1271 break;
1272 case CAIRO_FORMAT_A8:
1273 for (row = image->height; row--; ) {
1274 _cairo_output_stream_write (output, data, width);
1275 data += stride;
1277 break;
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;
1282 int col;
1283 for (col = 0; col < width; col++)
1284 dst[col] = bswap_16 (src[col]);
1285 _cairo_output_stream_write (output, rowdata, 2*width);
1286 data += stride;
1288 break;
1289 case CAIRO_FORMAT_RGB24:
1290 for (row = image->height; row--; ) {
1291 uint8_t *src = data;
1292 int col;
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++;
1297 src++;
1299 _cairo_output_stream_write (output, rowdata, 3*width);
1300 data += stride;
1302 break;
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;
1308 int col;
1309 for (col = 0; col < width; col++)
1310 dst[col] = bswap_32 (src[col]);
1311 _cairo_output_stream_write (output, rowdata, 4*width);
1312 data += stride;
1314 break;
1315 case CAIRO_FORMAT_INVALID:
1316 default:
1317 ASSERT_NOT_REACHED;
1318 break;
1320 if (rowdata != row_stack)
1321 free (rowdata);
1322 #endif
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,
1343 "<< "
1344 "/width %d "
1345 "/height %d "
1346 "/format //%s "
1347 "/mime-type (image/png) "
1348 "/source <~",
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))
1356 return 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);
1376 if (snapshot) {
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)) {
1383 return status;
1384 } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1385 cairo_image_surface_t *clone;
1386 uint32_t len;
1388 if (image->format == CAIRO_FORMAT_INVALID) {
1389 clone = _cairo_image_surface_coerce (image);
1390 } else {
1391 clone = (cairo_image_surface_t *)
1392 cairo_surface_reference (&image->base);
1395 _cairo_output_stream_printf (ctx->stream,
1396 "<< "
1397 "/width %d "
1398 "/height %d "
1399 "/format //%s "
1400 "/source ",
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;
1407 break;
1408 case CAIRO_FORMAT_A8:
1409 len = clone->width;
1410 break;
1411 case CAIRO_FORMAT_RGB16_565:
1412 len = clone->width * 2;
1413 break;
1414 case CAIRO_FORMAT_RGB24:
1415 len = clone->width * 3;
1416 break;
1417 case CAIRO_FORMAT_RGB30:
1418 case CAIRO_FORMAT_ARGB32:
1419 len = clone->width * 4;
1420 break;
1421 case CAIRO_FORMAT_INVALID:
1422 default:
1423 ASSERT_NOT_REACHED;
1424 len = 0;
1425 break;
1427 len *= clone->height;
1429 if (len > 24) {
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)
1442 status = status2;
1443 status2 = _cairo_output_stream_destroy (base85_stream);
1444 if (status == CAIRO_INT_STATUS_SUCCESS)
1445 status = status2;
1446 if (unlikely (status))
1447 return status;
1448 } else {
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)
1455 status = status2;
1456 if (unlikely (status))
1457 return 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,
1468 "\n (%s) <~",
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))
1475 return 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,
1484 "\n (%s) <~",
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))
1491 return 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;
1505 void *extra;
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);
1513 return status;
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);
1526 break;
1527 case CAIRO_SURFACE_TYPE_SCRIPT:
1528 status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source);
1529 break;
1530 default:
1531 status = _emit_image_surface_pattern (surface, source);
1532 break;
1534 if (unlikely (status))
1535 return status;
1537 _cairo_output_stream_printf (to_context (surface)->stream,
1538 "%d %d %d %d subsurface ",
1539 sub->extents.x,
1540 sub->extents.y,
1541 sub->extents.width,
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);
1561 if (snapshot) {
1562 _cairo_output_stream_printf (ctx->stream,
1563 "s%d pattern ",
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);
1577 break;
1578 case CAIRO_SURFACE_TYPE_SCRIPT:
1579 status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source);
1580 break;
1581 case CAIRO_SURFACE_TYPE_SUBSURFACE:
1582 status = _emit_subsurface_pattern (surface, (cairo_surface_subsurface_t *) source);
1583 break;
1584 default:
1585 status = _emit_image_surface_pattern (surface, source);
1586 break;
1588 cairo_surface_destroy (free_me);
1589 if (unlikely (status))
1590 return status;
1592 if (take_snapshot)
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)) {
1608 ASSERT_NOT_REACHED;
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))
1617 return 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;
1640 break;
1641 case CAIRO_PATTERN_TYPE_RADIAL:
1642 status = _emit_radial_pattern (surface, pattern);
1643 is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT;
1644 break;
1645 case CAIRO_PATTERN_TYPE_MESH:
1646 status = _emit_mesh_pattern (surface, pattern);
1647 is_default_extend = TRUE;
1648 break;
1649 case CAIRO_PATTERN_TYPE_SURFACE:
1650 status = _emit_surface_pattern (surface, pattern);
1651 is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
1652 break;
1653 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
1654 status = _emit_raster_pattern (surface, pattern);
1655 is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
1656 break;
1658 default:
1659 ASSERT_NOT_REACHED;
1660 status = CAIRO_INT_STATUS_UNSUPPORTED;
1662 if (unlikely (status))
1663 return status;
1665 if (! _cairo_matrix_is_identity (&pattern->matrix)) {
1666 if (need_newline) {
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) {
1680 if (need_newline) {
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 ){
1690 if (need_newline) {
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));
1700 if (need_newline)
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,
1744 source);
1745 if (unlikely (status))
1746 return status;
1748 status = _emit_identity (surface, &matrix_updated);
1749 if (unlikely (status))
1750 return status;
1752 status = _emit_pattern (surface, source);
1753 if (unlikely (status))
1754 return status;
1756 assert (target_is_active (surface));
1757 _cairo_output_stream_puts (to_context (surface)->stream,
1758 " set-source\n");
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,
1767 " %f %f m",
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,
1779 " %f %f l",
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,
1808 " h");
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;
1822 cairo_box_t box;
1823 int i;
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)
1829 continue;
1831 status = _cairo_boxes_add (&boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
1832 if (unlikely (status)) {
1833 _cairo_boxes_fini (&boxes);
1834 return status;
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);
1858 return status;
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);
1867 cairo_box_t box;
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");
1880 if (path == NULL) {
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))
1888 return 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,
1909 _path_move_to,
1910 _path_line_to,
1911 _path_curve_to,
1912 _path_close,
1913 ctx->stream);
1916 _cairo_output_stream_puts (ctx->stream, "\n");
1918 return status;
1920 static cairo_bool_t
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,
1954 "%f %f scale\n",
1955 ctm->xx, ctm->yy);
1956 } else {
1957 _cairo_output_stream_printf (ctx->stream,
1958 "[%f %f %f %f 0 0] set-matrix\n",
1959 ctm->xx, ctm->yx,
1960 ctm->xy, ctm->yy);
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,
1974 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");
1985 } else {
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,
1999 int width,
2000 int height)
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)) {
2025 passthrough =
2026 _cairo_surface_wrapper_create_similar (&other->wrapper,
2027 content, width, height);
2028 if (unlikely (passthrough->status)) {
2029 cairo_device_release (&ctx->base);
2030 return passthrough;
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",
2049 width, height,
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);
2070 static void
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);
2082 free (font);
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);
2091 free (ctx);
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;
2100 if (extents) {
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,
2112 void **image_extra)
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,
2118 image_out,
2119 image_extra);
2122 return CAIRO_INT_STATUS_UNSUPPORTED;
2125 static void
2126 _cairo_script_surface_release_source_image (void *abstract_surface,
2127 cairo_image_surface_t *image,
2128 void *image_extra)
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,
2134 image,
2135 image_extra);
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))
2156 return 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,
2165 "pop\n");
2166 } else {
2167 int depth = target_depth (surface);
2168 if (depth == 1) {
2169 _cairo_output_stream_printf (ctx->stream,
2170 "exch pop\n");
2171 } else {
2172 _cairo_output_stream_printf (ctx->stream,
2173 "%d -1 roll pop\n",
2174 depth);
2177 cairo_list_del (&surface->operand.link);
2178 } else {
2179 struct deferred_finish *link = malloc (sizeof (*link));
2180 if (link == NULL) {
2181 status2 = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2182 if (status == CAIRO_STATUS_SUCCESS)
2183 status = status2;
2184 cairo_list_del (&surface->operand.link);
2185 } else {
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,
2196 "/s%u undef\n",
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);
2206 return status;
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))
2217 return status;
2219 status = _emit_context (surface);
2220 if (unlikely (status))
2221 goto BAIL;
2223 _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n");
2225 BAIL:
2226 cairo_device_release (surface->base.device);
2227 return status;
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))
2238 return status;
2240 status = _emit_context (surface);
2241 if (unlikely (status))
2242 goto BAIL;
2244 _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n");
2246 BAIL:
2247 cairo_device_release (surface->base.device);
2248 return status;
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,
2255 double tolerance,
2256 cairo_antialias_t antialias)
2258 cairo_script_surface_t *surface = cairo_container_of (clipper,
2259 cairo_script_surface_t,
2260 clipper);
2261 cairo_script_context_t *ctx = to_context (surface);
2262 cairo_bool_t matrix_updated = FALSE;
2263 cairo_status_t status;
2264 cairo_box_t box;
2266 status = _emit_context (surface);
2267 if (unlikely (status))
2268 return status;
2270 if (path == NULL) {
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))
2292 return status;
2294 status = _emit_fill_rule (surface, fill_rule);
2295 if (unlikely (status))
2296 return status;
2298 if (path->has_curve_to) {
2299 status = _emit_tolerance (surface, tolerance, matrix_updated);
2300 if (unlikely (status))
2301 return status;
2304 if (! _cairo_path_fixed_fill_maybe_region (path)) {
2305 status = _emit_antialias (surface, antialias);
2306 if (unlikely (status))
2307 return status;
2310 status = _emit_path (surface, path, TRUE);
2311 if (unlikely (status))
2312 return 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))
2327 return status;
2329 if (surface->active++ == 0)
2330 to_context (surface)->active++;
2332 return CAIRO_STATUS_SUCCESS;
2335 static void
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)
2343 goto DONE;
2345 assert (ctx->active > 0);
2346 if (--ctx->active)
2347 goto DONE;
2349 cairo_list_init (&sorted);
2350 while (! cairo_list_is_empty (&ctx->deferred)) {
2351 struct deferred_finish *df;
2352 cairo_list_t *operand;
2353 int depth;
2355 df = cairo_list_first_entry (&ctx->deferred,
2356 struct deferred_finish,
2357 link);
2359 depth = 0;
2360 cairo_list_foreach (operand, &ctx->operands) {
2361 if (operand == &df->operand.link)
2362 break;
2363 depth++;
2366 df->operand.type = depth;
2368 if (cairo_list_is_empty (&sorted)) {
2369 cairo_list_move (&df->link, &sorted);
2370 } else {
2371 struct deferred_finish *pos;
2373 cairo_list_foreach_entry (pos, struct deferred_finish,
2374 &sorted,
2375 link)
2377 if (df->operand.type < pos->operand.type)
2378 break;
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;
2387 int depth;
2389 df = cairo_list_first_entry (&sorted,
2390 struct deferred_finish,
2391 link);
2393 depth = 0;
2394 cairo_list_foreach (operand, &ctx->operands) {
2395 if (operand == &df->operand.link)
2396 break;
2397 depth++;
2400 if (depth == 0) {
2401 _cairo_output_stream_printf (ctx->stream,
2402 "pop\n");
2403 } else if (depth == 1) {
2404 _cairo_output_stream_printf (ctx->stream,
2405 "exch pop\n");
2406 } else {
2407 _cairo_output_stream_printf (ctx->stream,
2408 "%d -1 roll pop\n",
2409 depth);
2412 cairo_list_del (&df->operand.link);
2413 cairo_list_del (&df->link);
2414 free (df);
2417 DONE:
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))
2432 return status;
2434 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2435 if (unlikely (status))
2436 goto BAIL;
2438 status = _emit_context (surface);
2439 if (unlikely (status))
2440 goto BAIL;
2442 status = _emit_source (surface, op, source);
2443 if (unlikely (status))
2444 goto BAIL;
2446 status = _emit_operator (surface, op);
2447 if (unlikely (status))
2448 goto BAIL;
2450 _cairo_output_stream_puts (to_context (surface)->stream,
2451 "paint\n");
2453 inactive (surface);
2455 if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2456 return _cairo_surface_wrapper_paint (&surface->wrapper,
2457 op, source, clip);
2460 return CAIRO_STATUS_SUCCESS;
2462 BAIL:
2463 inactive (surface);
2464 return status;
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))
2479 return status;
2481 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2482 if (unlikely (status))
2483 goto BAIL;
2485 status = _emit_context (surface);
2486 if (unlikely (status))
2487 goto BAIL;
2489 status = _emit_source (surface, op, source);
2490 if (unlikely (status))
2491 goto BAIL;
2493 status = _emit_operator (surface, op);
2494 if (unlikely (status))
2495 goto BAIL;
2497 if (_cairo_pattern_equal (source, mask)) {
2498 _cairo_output_stream_puts (to_context (surface)->stream, "/source get");
2499 } else {
2500 status = _emit_pattern (surface, mask);
2501 if (unlikely (status))
2502 goto BAIL;
2505 assert (surface->cr.current_operator == op);
2507 _cairo_output_stream_puts (to_context (surface)->stream,
2508 " mask\n");
2510 inactive (surface);
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;
2519 BAIL:
2520 inactive (surface);
2521 return status;
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,
2532 double tolerance,
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))
2542 return status;
2544 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2545 if (unlikely (status))
2546 goto BAIL;
2548 status = _emit_context (surface);
2549 if (unlikely (status))
2550 goto BAIL;
2552 status = _emit_identity (surface, &matrix_updated);
2553 if (unlikely (status))
2554 goto BAIL;
2556 status = _emit_path (surface, path, FALSE);
2557 if (unlikely (status))
2558 goto BAIL;
2560 status = _emit_source (surface, op, source);
2561 if (unlikely (status))
2562 goto BAIL;
2564 status = _emit_scaling_matrix (surface, ctm, &matrix_updated);
2565 if (unlikely (status))
2566 goto BAIL;
2568 status = _emit_operator (surface, op);
2569 if (unlikely (status))
2570 goto BAIL;
2572 if (_scaling_matrix_equal (&surface->cr.current_ctm,
2573 &surface->cr.current_stroke_matrix))
2575 matrix_updated = FALSE;
2577 else
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))
2585 goto BAIL;
2587 status = _emit_tolerance (surface, tolerance, matrix_updated);
2588 if (unlikely (status))
2589 goto BAIL;
2591 status = _emit_antialias (surface, antialias);
2592 if (unlikely (status))
2593 goto BAIL;
2595 _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n");
2597 inactive (surface);
2599 if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2600 return _cairo_surface_wrapper_stroke (&surface->wrapper,
2601 op, source, path,
2602 style,
2603 ctm, ctm_inverse,
2604 tolerance, antialias,
2605 clip);
2608 return CAIRO_STATUS_SUCCESS;
2610 BAIL:
2611 inactive (surface);
2612 return status;
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,
2621 double tolerance,
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;
2628 cairo_box_t box;
2630 status = active (surface);
2631 if (unlikely (status))
2632 return status;
2634 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
2635 if (unlikely (status))
2636 goto BAIL;
2638 status = _emit_context (surface);
2639 if (unlikely (status))
2640 goto BAIL;
2642 status = _emit_identity (surface, &matrix_updated);
2643 if (unlikely (status))
2644 goto BAIL;
2646 status = _emit_source (surface, op, source);
2647 if (unlikely (status))
2648 goto BAIL;
2650 if (! _cairo_path_fixed_is_box (path, &box)) {
2651 status = _emit_fill_rule (surface, fill_rule);
2652 if (unlikely (status))
2653 goto BAIL;
2656 if (path->has_curve_to) {
2657 status = _emit_tolerance (surface, tolerance, matrix_updated);
2658 if (unlikely (status))
2659 goto BAIL;
2662 if (! _cairo_path_fixed_fill_maybe_region (path)) {
2663 status = _emit_antialias (surface, antialias);
2664 if (unlikely (status))
2665 goto BAIL;
2668 status = _emit_path (surface, path, TRUE);
2669 if (unlikely (status))
2670 goto BAIL;
2672 status = _emit_operator (surface, op);
2673 if (unlikely (status))
2674 goto BAIL;
2676 _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n");
2678 inactive (surface);
2680 if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
2681 return _cairo_surface_wrapper_fill (&surface->wrapper,
2682 op, source, path,
2683 fill_rule,
2684 tolerance,
2685 antialias,
2686 clip);
2689 return CAIRO_STATUS_SUCCESS;
2691 BAIL:
2692 inactive (surface);
2693 return status;
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);
2704 return NULL;
2707 static cairo_bool_t
2708 _cairo_script_surface_has_show_text_glyphs (void *abstract_surface)
2710 return TRUE;
2713 static const char *
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];
2725 static const char *
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];
2737 static const char *
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,
2755 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,
2764 " /antialias //%s",
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;
2799 static void
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",
2811 priv->id,
2812 priv->id);
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);
2820 free (priv);
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;
2844 unsigned long size;
2845 unsigned int load_flags;
2846 uint32_t len;
2847 uint8_t *buf;
2849 backend = scaled_font->backend;
2850 if (backend->load_truetype_table == NULL)
2851 return CAIRO_INT_STATUS_UNSUPPORTED;
2853 size = 0;
2854 status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
2855 if (unlikely (status))
2856 return 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)) {
2864 free (buf);
2865 return status;
2868 #if CAIRO_HAS_FT_FONT
2869 load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font);
2870 #else
2871 load_flags = 0;
2872 #endif
2873 _cairo_output_stream_printf (ctx->stream,
2874 "<< "
2875 "/type 42 "
2876 "/index 0 "
2877 "/flags %d "
2878 "/source <|",
2879 load_flags);
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);
2888 free (buf);
2890 status2 = _cairo_output_stream_destroy (zlib_stream);
2891 if (status == CAIRO_STATUS_SUCCESS)
2892 status = status2;
2894 status2 = _cairo_output_stream_destroy (base85_stream);
2895 if (status == CAIRO_STATUS_SUCCESS)
2896 status = status2;
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));
2902 return status;
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,
2928 &font_private->id);
2929 if (unlikely (status)) {
2930 free (font_private);
2931 return status;
2934 status = _emit_context (surface);
2935 if (unlikely (status)) {
2936 free (font_private);
2937 return status;
2940 status = _emit_type42_font (surface, scaled_font);
2941 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
2942 *font_out = font_private;
2943 return status;
2946 font_private->has_sfnt = FALSE;
2947 _cairo_output_stream_printf (ctx->stream,
2948 "dict\n"
2949 " /type 3 set\n"
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,
2958 font_private->id);
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))
2978 return 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))
2990 return status;
2992 cairo_scaled_font_get_font_options (scaled_font, &options);
2993 status = _emit_font_options (surface, &options);
2994 if (unlikely (status))
2995 return status;
2997 status = _emit_scaled_font_init (surface, scaled_font, &font_private);
2998 if (unlikely (status))
2999 return status;
3001 assert (target_is_active (surface));
3002 _cairo_output_stream_printf (ctx->stream,
3003 " /scaled-font get /sf%lu exch def\n",
3004 font_private->id);
3005 } else {
3006 _cairo_output_stream_printf (ctx->stream,
3007 "sf%lu set-scaled-font\n",
3008 font_private->id);
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,
3030 "%lu <<\n"
3031 " /metrics [%f %f %f %f %f %f]\n"
3032 " /render {\n",
3033 index,
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,
3055 &surface->base);
3056 surface->cr = old_cr;
3058 _cairo_output_stream_puts (ctx->stream, "} >> set\n");
3060 return status;
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,
3078 "%lu <<\n"
3079 " /metrics [%f %f %f %f %f %f]\n"
3080 " /render {\n"
3081 "%f %f translate\n",
3082 index,
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))
3094 return 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;
3135 unsigned int n;
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,
3150 glyphs[n].index,
3151 CAIRO_SCALED_GLYPH_INFO_METRICS,
3152 &scaled_glyph);
3153 if (unlikely (status))
3154 break;
3156 if (scaled_glyph->dev_private_key == ctx)
3157 continue;
3159 status = _cairo_scaled_glyph_lookup (scaled_font,
3160 glyphs[n].index,
3161 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
3162 &scaled_glyph);
3163 if (_cairo_status_is_error (status))
3164 break;
3166 if (status == CAIRO_STATUS_SUCCESS) {
3167 if (! have_glyph_prologue) {
3168 status = _emit_scaled_glyph_prologue (surface, scaled_font);
3169 if (unlikely (status))
3170 break;
3172 have_glyph_prologue = TRUE;
3175 status = _emit_scaled_glyph_vector (surface,
3176 scaled_font, font_private,
3177 scaled_glyph);
3178 if (unlikely (status))
3179 break;
3181 continue;
3184 status = _cairo_scaled_glyph_lookup (scaled_font,
3185 glyphs[n].index,
3186 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3187 &scaled_glyph);
3188 if (_cairo_status_is_error (status))
3189 break;
3191 if (status == CAIRO_STATUS_SUCCESS) {
3192 if (! have_glyph_prologue) {
3193 status = _emit_scaled_glyph_prologue (surface, scaled_font);
3194 if (unlikely (status))
3195 break;
3197 have_glyph_prologue = TRUE;
3200 status = _emit_scaled_glyph_bitmap (surface,
3201 scaled_font,
3202 font_private,
3203 scaled_glyph);
3204 if (unlikely (status))
3205 break;
3207 continue;
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");
3216 return status;
3219 static void
3220 to_octal (int value, char *buf, size_t size)
3222 do {
3223 buf[--size] = '0' + (value & 7);
3224 value >>= 3;
3225 } while (size);
3228 static void
3229 _emit_string_literal (cairo_script_surface_t *surface,
3230 const char *utf8, int len)
3232 cairo_script_context_t *ctx = to_context (surface);
3233 char c;
3234 const char *end;
3236 _cairo_output_stream_puts (ctx->stream, "(");
3238 if (utf8 == NULL) {
3239 end = utf8;
3240 } else {
3241 if (len < 0)
3242 len = strlen (utf8);
3243 end = utf8 + len;
3246 while (utf8 < end) {
3247 switch ((c = *utf8++)) {
3248 case '\n':
3249 c = 'n';
3250 goto ESCAPED_CHAR;
3251 case '\r':
3252 c = 'r';
3253 goto ESCAPED_CHAR;
3254 case '\t':
3255 c = 't';
3256 goto ESCAPED_CHAR;
3257 case '\b':
3258 c = 'b';
3259 goto ESCAPED_CHAR;
3260 case '\f':
3261 c = 'f';
3262 goto ESCAPED_CHAR;
3263 case '\\':
3264 case '(':
3265 case ')':
3266 ESCAPED_CHAR:
3267 _cairo_output_stream_printf (ctx->stream, "\\%c", c);
3268 break;
3269 default:
3270 if (isprint (c) || isspace (c)) {
3271 _cairo_output_stream_printf (ctx->stream, "%c", c);
3272 } else {
3273 char buf[4] = { '\\' };
3275 to_octal (c, buf+1, 3);
3276 _cairo_output_stream_write (ctx->stream, buf, 4);
3278 break;
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,
3288 const char *utf8,
3289 int utf8_len,
3290 cairo_glyph_t *glyphs,
3291 int num_glyphs,
3292 const cairo_text_cluster_t *clusters,
3293 int num_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;
3305 int n;
3306 cairo_output_stream_t *base85_stream = NULL;
3308 status = active (surface);
3309 if (unlikely (status))
3310 return status;
3312 status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
3313 if (unlikely (status))
3314 goto BAIL;
3316 status = _emit_context (surface);
3317 if (unlikely (status))
3318 goto BAIL;
3320 status = _emit_source (surface, op, source);
3321 if (unlikely (status))
3322 goto BAIL;
3324 status = _emit_scaled_font (surface, scaled_font);
3325 if (unlikely (status))
3326 goto BAIL;
3328 status = _emit_operator (surface, op);
3329 if (unlikely (status))
3330 goto BAIL;
3332 status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs);
3333 if (unlikely (status))
3334 goto BAIL;
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,
3358 "[%f %f ",
3359 ix, iy);
3361 for (n = 0; n < num_glyphs; n++) {
3362 if (font_private->has_sfnt) {
3363 if (glyphs[n].index > 256)
3364 break;
3365 } else {
3366 status = _cairo_scaled_glyph_lookup (scaled_font,
3367 glyphs[n].index,
3368 CAIRO_SCALED_GLYPH_INFO_METRICS,
3369 &scaled_glyph);
3370 if (unlikely (status)) {
3371 _cairo_scaled_font_thaw_cache (scaled_font);
3372 goto BAIL;
3375 if ((long unsigned) scaled_glyph->dev_private > 256)
3376 break;
3380 if (n == num_glyphs) {
3381 _cairo_output_stream_puts (ctx->stream, "<~");
3382 base85_stream = _cairo_base85_stream_create (ctx->stream);
3383 } else
3384 _cairo_output_stream_puts (ctx->stream, "[");
3386 for (n = 0; n < num_glyphs; n++) {
3387 double dx, dy;
3389 status = _cairo_scaled_glyph_lookup (scaled_font,
3390 glyphs[n].index,
3391 CAIRO_SCALED_GLYPH_INFO_METRICS,
3392 &scaled_glyph);
3393 if (unlikely (status)) {
3394 _cairo_scaled_font_thaw_cache (scaled_font);
3395 goto BAIL;
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;
3404 break;
3407 _cairo_output_stream_printf (ctx->stream,
3408 "~> %f <~", glyphs[n].x - x);
3409 base85_stream = _cairo_base85_stream_create (ctx->stream);
3410 } else {
3411 _cairo_output_stream_printf (ctx->stream,
3412 " ] %f [ ", glyphs[n].x - x);
3415 x = glyphs[n].x;
3416 } else {
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;
3426 break;
3429 _cairo_output_stream_printf (ctx->stream,
3430 "~> %f %f <~",
3431 ix, iy);
3432 base85_stream = _cairo_base85_stream_create (ctx->stream);
3433 } else {
3434 _cairo_output_stream_printf (ctx->stream,
3435 " ] %f %f [ ",
3436 ix, iy);
3440 if (base85_stream != NULL) {
3441 uint8_t c;
3443 if (font_private->has_sfnt)
3444 c = glyphs[n].index;
3445 else
3446 c = (uint8_t) (long unsigned) scaled_glyph->dev_private;
3448 _cairo_output_stream_write (base85_stream, &c, 1);
3449 } else {
3450 if (font_private->has_sfnt)
3451 _cairo_output_stream_printf (ctx->stream, " %lu",
3452 glyphs[n].index);
3453 else
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);
3461 x += dx;
3462 y += 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)
3471 status = status2;
3473 _cairo_output_stream_printf (ctx->stream, "~>");
3474 } else {
3475 _cairo_output_stream_puts (ctx->stream, " ]");
3477 if (unlikely (status))
3478 return 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)
3485 break;
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,
3493 "%d %d ",
3494 clusters[n].num_bytes,
3495 clusters[n].num_glyphs);
3497 _cairo_output_stream_puts (ctx->stream, "]");
3499 else
3501 _cairo_output_stream_puts (ctx->stream, "] <~");
3502 base85_stream = _cairo_base85_stream_create (ctx->stream);
3503 for (n = 0; n < num_clusters; n++) {
3504 uint8_t c[2];
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))
3511 goto BAIL;
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));
3519 } else {
3520 _cairo_output_stream_puts (ctx->stream,
3521 "] show-glyphs\n");
3524 inactive (surface);
3526 if (_cairo_surface_wrapper_is_active (&surface->wrapper)){
3527 return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
3528 op, source,
3529 utf8, utf8_len,
3530 glyphs, num_glyphs,
3531 clusters, num_clusters,
3532 backward,
3533 scaled_font,
3534 clip);
3537 return CAIRO_STATUS_SUCCESS;
3539 BAIL:
3540 inactive (surface);
3541 return status;
3544 static cairo_bool_t
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,
3552 rectangle);
3555 if (surface->width < 0 || surface->height < 0)
3556 return FALSE;
3558 rectangle->x = 0;
3559 rectangle->y = 0;
3560 rectangle->width = surface->width;
3561 rectangle->height = surface->height;
3563 return TRUE;
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 */
3589 NULL, /* flush */
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 */
3597 NULL, /* glyphs */
3598 _cairo_script_surface_has_show_text_glyphs,
3599 _cairo_script_surface_show_text_glyphs
3602 static void
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,
3611 CAIRO_COLOR_BLACK);
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;
3621 static void
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,
3650 &ctx->base,
3651 content);
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;
3659 if (extents) {
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);
3674 return surface;
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 */
3683 NULL, /* finish */
3684 _device_destroy
3687 cairo_device_t *
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;
3710 return &ctx->base;
3713 void
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))
3731 return &ctx->base;
3733 ctx->owns_stream = TRUE;
3734 _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n");
3735 return &ctx->base;
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
3747 * with it.
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.
3753 * Since: 1.12
3755 cairo_device_t *
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
3778 * with it.
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.
3784 * Since: 1.12
3786 cairo_device_t *
3787 cairo_script_create_for_stream (cairo_write_func_t write_func,
3788 void *closure)
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.
3808 * Since: 1.12
3810 void
3811 cairo_script_write_comment (cairo_device_t *script,
3812 const char *comment,
3813 int len)
3815 cairo_script_context_t *context = (cairo_script_context_t *) script;
3817 if (len < 0)
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
3832 * Since: 1.12
3834 void
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
3851 * Since: 1.12
3853 cairo_script_mode_t
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
3872 * with it.
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.
3878 * Since: 1.12
3880 cairo_surface_t *
3881 cairo_script_surface_create (cairo_device_t *script,
3882 cairo_content_t content,
3883 double width,
3884 double height)
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);
3894 extents = NULL;
3895 if (width > 0 && height > 0) {
3896 r.x = r.y = 0;
3897 r.width = width;
3898 r.height = height;
3899 extents = &r;
3901 return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3902 content, extents,
3903 NULL)->base;
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
3917 * with it.
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.
3923 * Since: 1.12
3925 cairo_surface_t *
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);
3941 r = NULL;
3942 if (_cairo_surface_get_extents (target, &extents)) {
3943 rect.x = rect.y = 0;
3944 rect.width = extents.width;
3945 rect.height = extents.height;
3946 r= &rect;
3948 return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3949 target->content, r,
3950 target)->base;
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.
3962 * Since: 1.12
3964 cairo_status_t
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);
3984 extents = NULL;
3985 if (_cairo_recording_surface_get_bounds (recording_surface, &r))
3986 extents = &r;
3988 surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) script,
3989 recording_surface->content,
3990 extents,
3991 NULL)->base;
3992 if (unlikely (surface->status))
3993 return surface->status;
3995 status = _cairo_recording_surface_replay (recording_surface, surface);
3996 cairo_surface_destroy (surface);
3998 return status;