diff options
Diffstat (limited to 'libs/cairo-1.16.0/src/cairo-script-surface.c')
-rw-r--r-- | libs/cairo-1.16.0/src/cairo-script-surface.c | 4003 |
1 files changed, 0 insertions, 4003 deletions
diff --git a/libs/cairo-1.16.0/src/cairo-script-surface.c b/libs/cairo-1.16.0/src/cairo-script-surface.c deleted file mode 100644 index 7db7dc5..0000000 --- a/libs/cairo-1.16.0/src/cairo-script-surface.c +++ /dev/null @@ -1,4003 +0,0 @@ -/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2008 Chris Wilson - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Chris Wilson. - * - * Contributor(s): - * Chris Wilson <chris@chris-wilson.co.uk> - */ - -/* The script surface is one that records all operations performed on - * it in the form of a procedural script, similar in fashion to - * PostScript but using Cairo's imaging model. In essence, this is - * equivalent to the recording-surface, but as there is no impedance mismatch - * between Cairo and CairoScript, we can generate output immediately - * without having to copy and hold the data in memory. - */ - -/** - * SECTION:cairo-script - * @Title: Script Surfaces - * @Short_Description: Rendering to replayable scripts - * @See_Also: #cairo_surface_t - * - * The script surface provides the ability to render to a native - * script that matches the cairo drawing model. The scripts can - * be replayed using tools under the util/cairo-script directory, - * or with cairo-perf-trace. - **/ - -/** - * CAIRO_HAS_SCRIPT_SURFACE: - * - * Defined if the script surface backend is available. - * The script surface backend is always built in since 1.12. - * - * Since: 1.12 - **/ - - -#include "cairoint.h" - -#include "cairo-script.h" -#include "cairo-script-private.h" - -#include "cairo-analysis-surface-private.h" -#include "cairo-default-context-private.h" -#include "cairo-device-private.h" -#include "cairo-error-private.h" -#include "cairo-list-inline.h" -#include "cairo-image-surface-private.h" -#include "cairo-output-stream-private.h" -#include "cairo-pattern-private.h" -#include "cairo-recording-surface-inline.h" -#include "cairo-scaled-font-private.h" -#include "cairo-surface-clipper-private.h" -#include "cairo-surface-snapshot-inline.h" -#include "cairo-surface-subsurface-private.h" -#include "cairo-surface-wrapper-private.h" - -#if CAIRO_HAS_FT_FONT -#include "cairo-ft-private.h" -#endif - -#include <ctype.h> - -#ifdef WORDS_BIGENDIAN -#define to_be32(x) x -#else -#define to_be32(x) bswap_32(x) -#endif - -#define _cairo_output_stream_puts(S, STR) \ - _cairo_output_stream_write ((S), (STR), strlen (STR)) - -#define static cairo_warn static - -typedef struct _cairo_script_context cairo_script_context_t; -typedef struct _cairo_script_surface cairo_script_surface_t; -typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t; -typedef struct _cairo_script_font cairo_script_font_t; - -typedef struct _operand { - enum { - SURFACE, - DEFERRED, - } type; - cairo_list_t link; -} operand_t; - - -struct deferred_finish { - cairo_list_t link; - operand_t operand; -}; - -struct _cairo_script_context { - cairo_device_t base; - - int active; - int attach_snapshots; - - cairo_bool_t owns_stream; - cairo_output_stream_t *stream; - cairo_script_mode_t mode; - - struct _bitmap { - unsigned long min; - unsigned long count; - unsigned int map[64]; - struct _bitmap *next; - } surface_id, font_id; - - cairo_list_t operands; - cairo_list_t deferred; - - cairo_list_t fonts; - cairo_list_t defines; -}; - -struct _cairo_script_font { - cairo_scaled_font_private_t base; - - cairo_bool_t has_sfnt; - unsigned long id; - unsigned long subset_glyph_index; - cairo_list_t link; - cairo_scaled_font_t *parent; -}; - -struct _cairo_script_implicit_context { - cairo_operator_t current_operator; - cairo_fill_rule_t current_fill_rule; - double current_tolerance; - cairo_antialias_t current_antialias; - cairo_stroke_style_t current_style; - cairo_pattern_union_t current_source; - cairo_matrix_t current_ctm; - cairo_matrix_t current_stroke_matrix; - cairo_matrix_t current_font_matrix; - cairo_font_options_t current_font_options; - cairo_scaled_font_t *current_scaled_font; - cairo_path_fixed_t current_path; - cairo_bool_t has_clip; -}; - -struct _cairo_script_surface { - cairo_surface_t base; - - cairo_surface_wrapper_t wrapper; - - cairo_surface_clipper_t clipper; - - operand_t operand; - cairo_bool_t emitted; - cairo_bool_t defined; - cairo_bool_t active; - - double width, height; - - /* implicit flattened context */ - cairo_script_implicit_context_t cr; -}; - -static const cairo_surface_backend_t _cairo_script_surface_backend; - -static cairo_script_surface_t * -_cairo_script_surface_create_internal (cairo_script_context_t *ctx, - cairo_content_t content, - cairo_rectangle_t *extents, - cairo_surface_t *passthrough); - -static void -_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private, - cairo_scaled_font_t *scaled_font); - -static void -_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr); - -static void -_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr); - -static void -_bitmap_release_id (struct _bitmap *b, unsigned long token) -{ - struct _bitmap **prev = NULL; - - do { - if (token < b->min + sizeof (b->map) * CHAR_BIT) { - unsigned int bit, elem; - - token -= b->min; - elem = token / (sizeof (b->map[0]) * CHAR_BIT); - bit = token % (sizeof (b->map[0]) * CHAR_BIT); - b->map[elem] &= ~(1 << bit); - if (! --b->count && prev) { - *prev = b->next; - free (b); - } - return; - } - prev = &b->next; - b = b->next; - } while (b != NULL); -} - -static cairo_status_t -_bitmap_next_id (struct _bitmap *b, - unsigned long *id) -{ - struct _bitmap *bb, **prev = NULL; - unsigned long min = 0; - - do { - if (b->min != min) - break; - - if (b->count < sizeof (b->map) * CHAR_BIT) { - unsigned int n, m, bit; - for (n = 0; n < ARRAY_LENGTH (b->map); n++) { - if (b->map[n] == (unsigned int) -1) - continue; - - for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) { - if ((b->map[n] & bit) == 0) { - b->map[n] |= bit; - b->count++; - *id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min; - return CAIRO_STATUS_SUCCESS; - } - } - } - } - min += sizeof (b->map) * CHAR_BIT; - - prev = &b->next; - b = b->next; - } while (b != NULL); - assert (prev != NULL); - - bb = _cairo_malloc (sizeof (struct _bitmap)); - if (unlikely (bb == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - *prev = bb; - bb->next = b; - bb->min = min; - bb->count = 1; - bb->map[0] = 0x1; - memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0])); - *id = min; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_bitmap_fini (struct _bitmap *b) -{ - while (b != NULL) { - struct _bitmap *next = b->next; - free (b); - b = next; - } -} - -static const char * -_direction_to_string (cairo_bool_t backward) -{ - static const char *names[] = { - "FORWARD", - "BACKWARD" - }; - assert (backward < ARRAY_LENGTH (names)); - return names[backward]; -} - -static const char * -_operator_to_string (cairo_operator_t op) -{ - static const char *names[] = { - "CLEAR", /* CAIRO_OPERATOR_CLEAR */ - - "SOURCE", /* CAIRO_OPERATOR_SOURCE */ - "OVER", /* CAIRO_OPERATOR_OVER */ - "IN", /* CAIRO_OPERATOR_IN */ - "OUT", /* CAIRO_OPERATOR_OUT */ - "ATOP", /* CAIRO_OPERATOR_ATOP */ - - "DEST", /* CAIRO_OPERATOR_DEST */ - "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */ - "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */ - "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */ - "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */ - - "XOR", /* CAIRO_OPERATOR_XOR */ - "ADD", /* CAIRO_OPERATOR_ADD */ - "SATURATE", /* CAIRO_OPERATOR_SATURATE */ - - "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */ - "SCREEN", /* CAIRO_OPERATOR_SCREEN */ - "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */ - "DARKEN", /* CAIRO_OPERATOR_DARKEN */ - "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */ - "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */ - "BURN", /* CAIRO_OPERATOR_COLOR_BURN */ - "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */ - "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */ - "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */ - "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */ - "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */ - "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */ - "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */ - "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */ - }; - assert (op < ARRAY_LENGTH (names)); - return names[op]; -} - -static const char * -_extend_to_string (cairo_extend_t extend) -{ - static const char *names[] = { - "EXTEND_NONE", /* CAIRO_EXTEND_NONE */ - "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */ - "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */ - "EXTEND_PAD" /* CAIRO_EXTEND_PAD */ - }; - assert (extend < ARRAY_LENGTH (names)); - return names[extend]; -} - -static const char * -_filter_to_string (cairo_filter_t filter) -{ - static const char *names[] = { - "FILTER_FAST", /* CAIRO_FILTER_FAST */ - "FILTER_GOOD", /* CAIRO_FILTER_GOOD */ - "FILTER_BEST", /* CAIRO_FILTER_BEST */ - "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */ - "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */ - "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */ - }; - assert (filter < ARRAY_LENGTH (names)); - return names[filter]; -} - -static const char * -_fill_rule_to_string (cairo_fill_rule_t rule) -{ - static const char *names[] = { - "WINDING", /* CAIRO_FILL_RULE_WINDING */ - "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */ - }; - assert (rule < ARRAY_LENGTH (names)); - return names[rule]; -} - -static const char * -_antialias_to_string (cairo_antialias_t antialias) -{ - static const char *names[] = { - "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */ - "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */ - "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */ - "ANTIALIAS_SUBPIXEL", /* CAIRO_ANTIALIAS_SUBPIXEL */ - "ANTIALIAS_FAST", /* CAIRO_ANTIALIAS_FAST */ - "ANTIALIAS_GOOD", /* CAIRO_ANTIALIAS_GOOD */ - "ANTIALIAS_BEST" /* CAIRO_ANTIALIAS_BEST */ - }; - assert (antialias < ARRAY_LENGTH (names)); - return names[antialias]; -} - -static const char * -_line_cap_to_string (cairo_line_cap_t line_cap) -{ - static const char *names[] = { - "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */ - "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */ - "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */ - }; - assert (line_cap < ARRAY_LENGTH (names)); - return names[line_cap]; -} - -static const char * -_line_join_to_string (cairo_line_join_t line_join) -{ - static const char *names[] = { - "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */ - "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */ - "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */ - }; - assert (line_join < ARRAY_LENGTH (names)); - return names[line_join]; -} - -static inline cairo_script_context_t * -to_context (cairo_script_surface_t *surface) -{ - return (cairo_script_context_t *) surface->base.device; -} - -static cairo_bool_t -target_is_active (cairo_script_surface_t *surface) -{ - return cairo_list_is_first (&surface->operand.link, - &to_context (surface)->operands); -} - -static void -target_push (cairo_script_surface_t *surface) -{ - cairo_list_move (&surface->operand.link, &to_context (surface)->operands); -} - -static int -target_depth (cairo_script_surface_t *surface) -{ - cairo_list_t *link; - int depth = 0; - - cairo_list_foreach (link, &to_context (surface)->operands) { - if (link == &surface->operand.link) - break; - depth++; - } - - return depth; -} - -static void -_get_target (cairo_script_surface_t *surface) -{ - cairo_script_context_t *ctx = to_context (surface); - - if (target_is_active (surface)) { - _cairo_output_stream_puts (ctx->stream, "dup "); - return; - } - - if (surface->defined) { - _cairo_output_stream_printf (ctx->stream, "s%u ", - surface->base.unique_id); - } else { - int depth = target_depth (surface); - - assert (! cairo_list_is_empty (&surface->operand.link)); - assert (! target_is_active (surface)); - - if (ctx->active) { - _cairo_output_stream_printf (ctx->stream, "%d index ", depth); - _cairo_output_stream_puts (ctx->stream, "/target get exch pop "); - } else { - if (depth == 1) { - _cairo_output_stream_puts (ctx->stream, "exch "); - } else { - _cairo_output_stream_printf (ctx->stream, - "%d -1 roll ", depth); - } - target_push (surface); - _cairo_output_stream_puts (ctx->stream, "dup "); - } - } -} - -static const char * -_content_to_string (cairo_content_t content) -{ - switch (content) { - case CAIRO_CONTENT_ALPHA: return "ALPHA"; - case CAIRO_CONTENT_COLOR: return "COLOR"; - default: - case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA"; - } -} - -static cairo_status_t -_emit_surface (cairo_script_surface_t *surface) -{ - cairo_script_context_t *ctx = to_context (surface); - - _cairo_output_stream_printf (ctx->stream, - "<< /content //%s", - _content_to_string (surface->base.content)); - if (surface->width != -1 && surface->height != -1) { - _cairo_output_stream_printf (ctx->stream, - " /width %f /height %f", - surface->width, - surface->height); - } - - if (surface->base.x_fallback_resolution != - CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT || - surface->base.y_fallback_resolution != - CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT) - { - _cairo_output_stream_printf (ctx->stream, - " /fallback-resolution [%f %f]", - surface->base.x_fallback_resolution, - surface->base.y_fallback_resolution); - } - - if (surface->base.device_transform.x0 != 0. || - surface->base.device_transform.y0 != 0.) - { - /* XXX device offset is encoded into the pattern matrices etc. */ - if (0) { - _cairo_output_stream_printf (ctx->stream, - " /device-offset [%f %f]", - surface->base.device_transform.x0, - surface->base.device_transform.y0); - } - } - - _cairo_output_stream_puts (ctx->stream, " >> surface context\n"); - surface->emitted = TRUE; - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_context (cairo_script_surface_t *surface) -{ - cairo_script_context_t *ctx = to_context (surface); - - if (target_is_active (surface)) - return CAIRO_STATUS_SUCCESS; - - while (! cairo_list_is_empty (&ctx->operands)) { - operand_t *op; - cairo_script_surface_t *old; - - op = cairo_list_first_entry (&ctx->operands, - operand_t, - link); - if (op->type == DEFERRED) - break; - - old = cairo_container_of (op, cairo_script_surface_t, operand); - if (old == surface) - break; - if (old->active) - break; - - if (! old->defined) { - assert (old->emitted); - _cairo_output_stream_printf (ctx->stream, - "/target get /s%u exch def pop\n", - old->base.unique_id); - old->defined = TRUE; - } else { - _cairo_output_stream_puts (ctx->stream, "pop\n"); - } - - cairo_list_del (&old->operand.link); - } - - if (target_is_active (surface)) - return CAIRO_STATUS_SUCCESS; - - if (! surface->emitted) { - cairo_status_t status; - - status = _emit_surface (surface); - if (unlikely (status)) - return status; - } else if (cairo_list_is_empty (&surface->operand.link)) { - assert (surface->defined); - _cairo_output_stream_printf (ctx->stream, - "s%u context\n", - surface->base.unique_id); - _cairo_script_implicit_context_reset (&surface->cr); - _cairo_surface_clipper_reset (&surface->clipper); - } else { - int depth = target_depth (surface); - if (depth == 1) { - _cairo_output_stream_puts (ctx->stream, "exch\n"); - } else { - _cairo_output_stream_printf (ctx->stream, - "%d -1 roll\n", - depth); - } - } - target_push (surface); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_operator (cairo_script_surface_t *surface, - cairo_operator_t op) -{ - assert (target_is_active (surface)); - - if (surface->cr.current_operator == op) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_operator = op; - - _cairo_output_stream_printf (to_context (surface)->stream, - "//%s set-operator\n", - _operator_to_string (op)); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_fill_rule (cairo_script_surface_t *surface, - cairo_fill_rule_t fill_rule) -{ - assert (target_is_active (surface)); - - if (surface->cr.current_fill_rule == fill_rule) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_fill_rule = fill_rule; - - _cairo_output_stream_printf (to_context (surface)->stream, - "//%s set-fill-rule\n", - _fill_rule_to_string (fill_rule)); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_tolerance (cairo_script_surface_t *surface, - double tolerance, - cairo_bool_t force) -{ - assert (target_is_active (surface)); - - if ((! force || - fabs (tolerance - CAIRO_GSTATE_TOLERANCE_DEFAULT) < 1e-5) && - surface->cr.current_tolerance == tolerance) - { - return CAIRO_STATUS_SUCCESS; - } - - surface->cr.current_tolerance = tolerance; - - _cairo_output_stream_printf (to_context (surface)->stream, - "%f set-tolerance\n", - tolerance); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_antialias (cairo_script_surface_t *surface, - cairo_antialias_t antialias) -{ - assert (target_is_active (surface)); - - if (surface->cr.current_antialias == antialias) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_antialias = antialias; - - _cairo_output_stream_printf (to_context (surface)->stream, - "//%s set-antialias\n", - _antialias_to_string (antialias)); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_line_width (cairo_script_surface_t *surface, - double line_width, - cairo_bool_t force) -{ - assert (target_is_active (surface)); - - if ((! force || - fabs (line_width - CAIRO_GSTATE_LINE_WIDTH_DEFAULT) < 1e-5) && - surface->cr.current_style.line_width == line_width) - { - return CAIRO_STATUS_SUCCESS; - } - - surface->cr.current_style.line_width = line_width; - - _cairo_output_stream_printf (to_context (surface)->stream, - "%f set-line-width\n", - line_width); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_line_cap (cairo_script_surface_t *surface, - cairo_line_cap_t line_cap) -{ - assert (target_is_active (surface)); - - if (surface->cr.current_style.line_cap == line_cap) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_style.line_cap = line_cap; - - _cairo_output_stream_printf (to_context (surface)->stream, - "//%s set-line-cap\n", - _line_cap_to_string (line_cap)); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_line_join (cairo_script_surface_t *surface, - cairo_line_join_t line_join) -{ - assert (target_is_active (surface)); - - if (surface->cr.current_style.line_join == line_join) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_style.line_join = line_join; - - _cairo_output_stream_printf (to_context (surface)->stream, - "//%s set-line-join\n", - _line_join_to_string (line_join)); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_miter_limit (cairo_script_surface_t *surface, - double miter_limit, - cairo_bool_t force) -{ - assert (target_is_active (surface)); - - if ((! force || - fabs (miter_limit - CAIRO_GSTATE_MITER_LIMIT_DEFAULT) < 1e-5) && - surface->cr.current_style.miter_limit == miter_limit) - { - return CAIRO_STATUS_SUCCESS; - } - - surface->cr.current_style.miter_limit = miter_limit; - - _cairo_output_stream_printf (to_context (surface)->stream, - "%f set-miter-limit\n", - miter_limit); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_bool_t -_dashes_equal (const double *a, const double *b, int num_dashes) -{ - while (num_dashes--) { - if (fabs (*a - *b) > 1e-5) - return FALSE; - a++, b++; - } - - return TRUE; -} - -static cairo_status_t -_emit_dash (cairo_script_surface_t *surface, - const double *dash, - unsigned int num_dashes, - double offset, - cairo_bool_t force) -{ - unsigned int n; - - assert (target_is_active (surface)); - - if (force && - num_dashes == 0 && - surface->cr.current_style.num_dashes == 0) - { - return CAIRO_STATUS_SUCCESS; - } - - if (! force && - (surface->cr.current_style.num_dashes == num_dashes && - (num_dashes == 0 || - (fabs (surface->cr.current_style.dash_offset - offset) < 1e-5 && - _dashes_equal (surface->cr.current_style.dash, dash, num_dashes))))) - { - return CAIRO_STATUS_SUCCESS; - } - - - if (num_dashes) { - surface->cr.current_style.dash = _cairo_realloc_ab - (surface->cr.current_style.dash, num_dashes, sizeof (double)); - if (unlikely (surface->cr.current_style.dash == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - memcpy (surface->cr.current_style.dash, dash, - sizeof (double) * num_dashes); - } else { - free (surface->cr.current_style.dash); - surface->cr.current_style.dash = NULL; - } - - surface->cr.current_style.num_dashes = num_dashes; - surface->cr.current_style.dash_offset = offset; - - _cairo_output_stream_puts (to_context (surface)->stream, "["); - for (n = 0; n < num_dashes; n++) { - _cairo_output_stream_printf (to_context (surface)->stream, "%f", dash[n]); - if (n < num_dashes-1) - _cairo_output_stream_puts (to_context (surface)->stream, " "); - } - _cairo_output_stream_printf (to_context (surface)->stream, - "] %f set-dash\n", - offset); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_stroke_style (cairo_script_surface_t *surface, - const cairo_stroke_style_t *style, - cairo_bool_t force) -{ - cairo_status_t status; - - assert (target_is_active (surface)); - - status = _emit_line_width (surface, style->line_width, force); - if (unlikely (status)) - return status; - - status = _emit_line_cap (surface, style->line_cap); - if (unlikely (status)) - return status; - - status = _emit_line_join (surface, style->line_join); - if (unlikely (status)) - return status; - - status = _emit_miter_limit (surface, style->miter_limit, force); - if (unlikely (status)) - return status; - - status = _emit_dash (surface, - style->dash, style->num_dashes, style->dash_offset, - force); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; -} - -static const char * -_format_to_string (cairo_format_t format) -{ - switch (format) { - case CAIRO_FORMAT_ARGB32: return "ARGB32"; - case CAIRO_FORMAT_RGB30: return "RGB30"; - case CAIRO_FORMAT_RGB24: return "RGB24"; - case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; - case CAIRO_FORMAT_A8: return "A8"; - case CAIRO_FORMAT_A1: return "A1"; - case CAIRO_FORMAT_INVALID: return "INVALID"; - } - ASSERT_NOT_REACHED; - return "INVALID"; -} - -static cairo_status_t -_emit_solid_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; - cairo_script_context_t *ctx = to_context (surface); - - if (! CAIRO_COLOR_IS_OPAQUE (&solid->color)) - { - if (! (surface->base.content & CAIRO_CONTENT_COLOR) || - ((solid->color.red_short == 0 || solid->color.red_short == 0xffff) && - (solid->color.green_short == 0 || solid->color.green_short == 0xffff) && - (solid->color.blue_short == 0 || solid->color.blue_short == 0xffff) )) - { - _cairo_output_stream_printf (ctx->stream, - "%f a", - solid->color.alpha); - } - else - { - _cairo_output_stream_printf (ctx->stream, - "%f %f %f %f rgba", - solid->color.red, - solid->color.green, - solid->color.blue, - solid->color.alpha); - } - } - else - { - if (solid->color.red_short == solid->color.green_short && - solid->color.red_short == solid->color.blue_short) - { - _cairo_output_stream_printf (ctx->stream, - "%f g", - solid->color.red); - } - else - { - _cairo_output_stream_printf (ctx->stream, - "%f %f %f rgb", - solid->color.red, - solid->color.green, - solid->color.blue); - } - } - - return CAIRO_STATUS_SUCCESS; -} - - -static cairo_status_t -_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient, - cairo_output_stream_t *output) -{ - unsigned int n; - - for (n = 0; n < gradient->n_stops; n++) { - _cairo_output_stream_printf (output, - "\n %f %f %f %f %f add-color-stop", - gradient->stops[n].offset, - gradient->stops[n].color.red, - gradient->stops[n].color.green, - gradient->stops[n].color.blue, - gradient->stops[n].color.alpha); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_linear_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_linear_pattern_t *linear; - - linear = (cairo_linear_pattern_t *) pattern; - - _cairo_output_stream_printf (ctx->stream, - "%f %f %f %f linear", - linear->pd1.x, linear->pd1.y, - linear->pd2.x, linear->pd2.y); - return _emit_gradient_color_stops (&linear->base, ctx->stream); -} - -static cairo_status_t -_emit_radial_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_radial_pattern_t *radial; - - radial = (cairo_radial_pattern_t *) pattern; - - _cairo_output_stream_printf (ctx->stream, - "%f %f %f %f %f %f radial", - radial->cd1.center.x, - radial->cd1.center.y, - radial->cd1.radius, - radial->cd2.center.x, - radial->cd2.center.y, - radial->cd2.radius); - return _emit_gradient_color_stops (&radial->base, ctx->stream); -} - -static cairo_status_t -_emit_mesh_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_pattern_t *mesh; - cairo_status_t status; - unsigned int i, n; - - mesh = (cairo_pattern_t *) pattern; - status = cairo_mesh_pattern_get_patch_count (mesh, &n); - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (ctx->stream, "mesh"); - for (i = 0; i < n; i++) { - cairo_path_t *path; - cairo_path_data_t *data; - int j; - - _cairo_output_stream_printf (ctx->stream, "\n begin-patch"); - - path = cairo_mesh_pattern_get_path (mesh, i); - if (unlikely (path->status)) - return path->status; - - for (j = 0; j < path->num_data; j+=data[0].header.length) { - data = &path->data[j]; - switch (data->header.type) { - case CAIRO_PATH_MOVE_TO: - _cairo_output_stream_printf (ctx->stream, - "\n %f %f m", - data[1].point.x, data[1].point.y); - break; - case CAIRO_PATH_LINE_TO: - _cairo_output_stream_printf (ctx->stream, - "\n %f %f l", - data[1].point.x, data[1].point.y); - break; - case CAIRO_PATH_CURVE_TO: - _cairo_output_stream_printf (ctx->stream, - "\n %f %f %f %f %f %f c", - data[1].point.x, data[1].point.y, - data[2].point.x, data[2].point.y, - data[3].point.x, data[3].point.y); - break; - case CAIRO_PATH_CLOSE_PATH: - break; - } - } - cairo_path_destroy (path); - - for (j = 0; j < 4; j++) { - double x, y; - - status = cairo_mesh_pattern_get_control_point (mesh, i, j, &x, &y); - if (unlikely (status)) - return status; - _cairo_output_stream_printf (ctx->stream, - "\n %d %f %f set-control-point", - j, x, y); - } - - for (j = 0; j < 4; j++) { - double r, g, b, a; - - status = cairo_mesh_pattern_get_corner_color_rgba (mesh, i, j, &r, &g, &b, &a); - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (ctx->stream, - "\n %d %f %f %f %f set-corner-color", - j, r, g, b, a); - } - - _cairo_output_stream_printf (ctx->stream, "\n end-patch"); - } - - return CAIRO_STATUS_SUCCESS; -} - -struct script_snapshot { - cairo_surface_t base; -}; - -static cairo_status_t -script_snapshot_finish (void *abstract_surface) -{ - return CAIRO_STATUS_SUCCESS; -} - -static const cairo_surface_backend_t script_snapshot_backend = { - CAIRO_SURFACE_TYPE_SCRIPT, - script_snapshot_finish, -}; - -static void -detach_snapshot (cairo_surface_t *abstract_surface) -{ - cairo_script_surface_t *surface = (cairo_script_surface_t *)abstract_surface; - cairo_script_context_t *ctx = to_context (surface); - - _cairo_output_stream_printf (ctx->stream, - "/s%d undef\n", - surface->base.unique_id); -} - -static void -attach_snapshot (cairo_script_context_t *ctx, - cairo_surface_t *source) -{ - struct script_snapshot *surface; - - if (! ctx->attach_snapshots) - return; - - surface = _cairo_malloc (sizeof (*surface)); - if (unlikely (surface == NULL)) - return; - - _cairo_surface_init (&surface->base, - &script_snapshot_backend, - &ctx->base, - source->content, - source->is_vector); - - _cairo_output_stream_printf (ctx->stream, - "dup /s%d exch def ", - surface->base.unique_id); - - _cairo_surface_attach_snapshot (source, &surface->base, detach_snapshot); - cairo_surface_destroy (&surface->base); -} - -static cairo_status_t -_emit_recording_surface_pattern (cairo_script_surface_t *surface, - cairo_recording_surface_t *source) -{ - cairo_script_implicit_context_t old_cr; - cairo_script_context_t *ctx = to_context (surface); - cairo_script_surface_t *similar; - cairo_surface_t *snapshot; - cairo_rectangle_t r, *extents; - cairo_status_t status; - - snapshot = _cairo_surface_has_snapshot (&source->base, &script_snapshot_backend); - if (snapshot) { - _cairo_output_stream_printf (ctx->stream, "s%d", snapshot->unique_id); - return CAIRO_INT_STATUS_SUCCESS; - } - - extents = NULL; - if (_cairo_recording_surface_get_bounds (&source->base, &r)) - extents = &r; - - similar = _cairo_script_surface_create_internal (ctx, - source->base.content, - extents, - NULL); - if (unlikely (similar->base.status)) - return similar->base.status; - - similar->base.is_clear = TRUE; - - _cairo_output_stream_printf (ctx->stream, "//%s ", - _content_to_string (source->base.content)); - if (extents) { - _cairo_output_stream_printf (ctx->stream, "[%f %f %f %f]", - extents->x, extents->y, - extents->width, extents->height); - } else - _cairo_output_stream_puts (ctx->stream, "[]"); - _cairo_output_stream_puts (ctx->stream, " record\n"); - - attach_snapshot (ctx, &source->base); - - _cairo_output_stream_puts (ctx->stream, "dup context\n"); - - target_push (similar); - similar->emitted = TRUE; - - - old_cr = surface->cr; - _cairo_script_implicit_context_init (&surface->cr); - status = _cairo_recording_surface_replay (&source->base, &similar->base); - surface->cr = old_cr; - - if (unlikely (status)) { - cairo_surface_destroy (&similar->base); - return status; - } - - cairo_list_del (&similar->operand.link); - assert (target_is_active (surface)); - - _cairo_output_stream_puts (ctx->stream, "pop "); - cairo_surface_destroy (&similar->base); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_script_surface_pattern (cairo_script_surface_t *surface, - cairo_script_surface_t *source) -{ - _get_target (source); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_write_image_surface (cairo_output_stream_t *output, - const cairo_image_surface_t *image) -{ - int row, width; - ptrdiff_t stride; - uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE]; - uint8_t *rowdata; - uint8_t *data; - - stride = image->stride; - width = image->width; - data = image->data; -#if WORDS_BIGENDIAN - switch (image->format) { - case CAIRO_FORMAT_A1: - for (row = image->height; row--; ) { - _cairo_output_stream_write (output, data, (width+7)/8); - data += stride; - } - break; - case CAIRO_FORMAT_A8: - for (row = image->height; row--; ) { - _cairo_output_stream_write (output, data, width); - data += stride; - } - break; - case CAIRO_FORMAT_RGB16_565: - for (row = image->height; row--; ) { - _cairo_output_stream_write (output, data, 2*width); - data += stride; - } - break; - case CAIRO_FORMAT_RGB24: - for (row = image->height; row--; ) { - int col; - rowdata = data; - for (col = width; col--; ) { - _cairo_output_stream_write (output, rowdata, 3); - rowdata+=4; - } - data += stride; - } - break; - case CAIRO_FORMAT_ARGB32: - for (row = image->height; row--; ) { - _cairo_output_stream_write (output, data, 4*width); - data += stride; - } - break; - case CAIRO_FORMAT_INVALID: - default: - ASSERT_NOT_REACHED; - break; - } -#else - if (stride > ARRAY_LENGTH (row_stack)) { - rowdata = _cairo_malloc (stride); - if (unlikely (rowdata == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } else - rowdata = row_stack; - - switch (image->format) { - case CAIRO_FORMAT_A1: - for (row = image->height; row--; ) { - int col; - for (col = 0; col < (width + 7)/8; col++) - rowdata[col] = CAIRO_BITSWAP8 (data[col]); - _cairo_output_stream_write (output, rowdata, (width+7)/8); - data += stride; - } - break; - case CAIRO_FORMAT_A8: - for (row = image->height; row--; ) { - _cairo_output_stream_write (output, data, width); - data += stride; - } - break; - case CAIRO_FORMAT_RGB16_565: - for (row = image->height; row--; ) { - uint16_t *src = (uint16_t *) data; - uint16_t *dst = (uint16_t *) rowdata; - int col; - for (col = 0; col < width; col++) - dst[col] = bswap_16 (src[col]); - _cairo_output_stream_write (output, rowdata, 2*width); - data += stride; - } - break; - case CAIRO_FORMAT_RGB24: - for (row = image->height; row--; ) { - uint8_t *src = data; - int col; - for (col = 0; col < width; col++) { - rowdata[3*col+2] = *src++; - rowdata[3*col+1] = *src++; - rowdata[3*col+0] = *src++; - src++; - } - _cairo_output_stream_write (output, rowdata, 3*width); - data += stride; - } - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_ARGB32: - for (row = image->height; row--; ) { - uint32_t *src = (uint32_t *) data; - uint32_t *dst = (uint32_t *) rowdata; - int col; - for (col = 0; col < width; col++) - dst[col] = bswap_32 (src[col]); - _cairo_output_stream_write (output, rowdata, 4*width); - data += stride; - } - break; - case CAIRO_FORMAT_INVALID: - default: - ASSERT_NOT_REACHED; - break; - } - if (rowdata != row_stack) - free (rowdata); -#endif - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_png_surface (cairo_script_surface_t *surface, - cairo_image_surface_t *image) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_output_stream_t *base85_stream; - cairo_status_t status; - const uint8_t *mime_data; - unsigned long mime_data_length; - - cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG, - &mime_data, &mime_data_length); - if (mime_data == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - _cairo_output_stream_printf (ctx->stream, - "<< " - "/width %d " - "/height %d " - "/format //%s " - "/mime-type (image/png) " - "/source <~", - image->width, image->height, - _format_to_string (image->format)); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (ctx->stream, "~> >> image "); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_image_surface (cairo_script_surface_t *surface, - cairo_image_surface_t *image) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_output_stream_t *base85_stream; - cairo_output_stream_t *zlib_stream; - cairo_int_status_t status, status2; - cairo_surface_t *snapshot; - const uint8_t *mime_data; - unsigned long mime_data_length; - - snapshot = _cairo_surface_has_snapshot (&image->base, - &script_snapshot_backend); - if (snapshot) { - _cairo_output_stream_printf (ctx->stream, "s%u ", snapshot->unique_id); - return CAIRO_INT_STATUS_SUCCESS; - } - - status = _emit_png_surface (surface, image); - if (_cairo_int_status_is_error (status)) { - return status; - } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - cairo_image_surface_t *clone; - uint32_t len; - - if (image->format == CAIRO_FORMAT_INVALID) { - clone = _cairo_image_surface_coerce (image); - } else { - clone = (cairo_image_surface_t *) - cairo_surface_reference (&image->base); - } - - _cairo_output_stream_printf (ctx->stream, - "<< " - "/width %d " - "/height %d " - "/format //%s " - "/source ", - clone->width, clone->height, - _format_to_string (clone->format)); - - switch (clone->format) { - case CAIRO_FORMAT_A1: - len = (clone->width + 7)/8; - break; - case CAIRO_FORMAT_A8: - len = clone->width; - break; - case CAIRO_FORMAT_RGB16_565: - len = clone->width * 2; - break; - case CAIRO_FORMAT_RGB24: - len = clone->width * 3; - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_ARGB32: - len = clone->width * 4; - break; - case CAIRO_FORMAT_INVALID: - default: - ASSERT_NOT_REACHED; - len = 0; - break; - } - len *= clone->height; - - if (len > 24) { - _cairo_output_stream_puts (ctx->stream, "<|"); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - - len = to_be32 (len); - _cairo_output_stream_write (base85_stream, &len, sizeof (len)); - - zlib_stream = _cairo_deflate_stream_create (base85_stream); - status = _write_image_surface (zlib_stream, clone); - - status2 = _cairo_output_stream_destroy (zlib_stream); - if (status == CAIRO_INT_STATUS_SUCCESS) - status = status2; - status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_INT_STATUS_SUCCESS) - status = status2; - if (unlikely (status)) - return status; - } else { - _cairo_output_stream_puts (ctx->stream, "<~"); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - status = _write_image_surface (base85_stream, clone); - status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_INT_STATUS_SUCCESS) - status = status2; - if (unlikely (status)) - return status; - } - _cairo_output_stream_puts (ctx->stream, "~> >> image "); - - cairo_surface_destroy (&clone->base); - } - - cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, - &mime_data, &mime_data_length); - if (mime_data != NULL) { - _cairo_output_stream_printf (ctx->stream, - "\n (%s) <~", - CAIRO_MIME_TYPE_JPEG); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); - } - - cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2, - &mime_data, &mime_data_length); - if (mime_data != NULL) { - _cairo_output_stream_printf (ctx->stream, - "\n (%s) <~", - CAIRO_MIME_TYPE_JP2); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); - } - - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_image_surface_pattern (cairo_script_surface_t *surface, - cairo_surface_t *source) -{ - cairo_image_surface_t *image; - cairo_status_t status; - void *extra; - - status = _cairo_surface_acquire_source_image (source, &image, &extra); - if (likely (status == CAIRO_STATUS_SUCCESS)) { - status = _emit_image_surface (surface, image); - _cairo_surface_release_source_image (source, image, extra); - } - - return status; -} - -static cairo_int_status_t -_emit_subsurface_pattern (cairo_script_surface_t *surface, - cairo_surface_subsurface_t *sub) -{ - cairo_surface_t *source = sub->target; - cairo_int_status_t status; - - switch ((int) source->backend->type) { - case CAIRO_SURFACE_TYPE_RECORDING: - status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); - break; - case CAIRO_SURFACE_TYPE_SCRIPT: - status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); - break; - default: - status = _emit_image_surface_pattern (surface, source); - break; - } - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (to_context (surface)->stream, - "%d %d %d %d subsurface ", - sub->extents.x, - sub->extents.y, - sub->extents.width, - sub->extents.height); - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_surface_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_surface_pattern_t *surface_pattern; - cairo_surface_t *source, *snapshot, *free_me = NULL; - cairo_surface_t *take_snapshot = NULL; - cairo_int_status_t status; - - surface_pattern = (cairo_surface_pattern_t *) pattern; - source = surface_pattern->surface; - - if (_cairo_surface_is_snapshot (source)) { - snapshot = _cairo_surface_has_snapshot (source, &script_snapshot_backend); - if (snapshot) { - _cairo_output_stream_printf (ctx->stream, - "s%d pattern ", - snapshot->unique_id); - return CAIRO_INT_STATUS_SUCCESS; - } - - if (_cairo_surface_snapshot_is_reused (source)) - take_snapshot = source; - - free_me = source = _cairo_surface_snapshot_get_target (source); - } - - switch ((int) source->backend->type) { - case CAIRO_SURFACE_TYPE_RECORDING: - status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); - break; - case CAIRO_SURFACE_TYPE_SCRIPT: - status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); - break; - case CAIRO_SURFACE_TYPE_SUBSURFACE: - status = _emit_subsurface_pattern (surface, (cairo_surface_subsurface_t *) source); - break; - default: - status = _emit_image_surface_pattern (surface, source); - break; - } - cairo_surface_destroy (free_me); - if (unlikely (status)) - return status; - - if (take_snapshot) - attach_snapshot (ctx, take_snapshot); - - _cairo_output_stream_puts (ctx->stream, "pattern"); - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_raster_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_surface_t *source; - cairo_int_status_t status; - - source = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL); - if (unlikely (source == NULL)) { - ASSERT_NOT_REACHED; - return CAIRO_INT_STATUS_UNSUPPORTED; - } - if (unlikely (source->status)) - return source->status; - - status = _emit_image_surface_pattern (surface, source); - _cairo_raster_source_pattern_release (pattern, source); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (to_context(surface)->stream, "pattern"); - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_int_status_t status; - cairo_bool_t is_default_extend; - cairo_bool_t need_newline = TRUE; - - switch (pattern->type) { - case CAIRO_PATTERN_TYPE_SOLID: - /* solid colors do not need filter/extend/matrix */ - return _emit_solid_pattern (surface, pattern); - - case CAIRO_PATTERN_TYPE_LINEAR: - status = _emit_linear_pattern (surface, pattern); - is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT; - break; - case CAIRO_PATTERN_TYPE_RADIAL: - status = _emit_radial_pattern (surface, pattern); - is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT; - break; - case CAIRO_PATTERN_TYPE_MESH: - status = _emit_mesh_pattern (surface, pattern); - is_default_extend = TRUE; - break; - case CAIRO_PATTERN_TYPE_SURFACE: - status = _emit_surface_pattern (surface, pattern); - is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT; - break; - case CAIRO_PATTERN_TYPE_RASTER_SOURCE: - status = _emit_raster_pattern (surface, pattern); - is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT; - break; - - default: - ASSERT_NOT_REACHED; - status = CAIRO_INT_STATUS_UNSUPPORTED; - } - if (unlikely (status)) - return status; - - if (! _cairo_matrix_is_identity (&pattern->matrix)) { - if (need_newline) { - _cairo_output_stream_puts (ctx->stream, "\n "); - need_newline = FALSE; - } - - _cairo_output_stream_printf (ctx->stream, - " [%f %f %f %f %f %f] set-matrix\n ", - pattern->matrix.xx, pattern->matrix.yx, - pattern->matrix.xy, pattern->matrix.yy, - pattern->matrix.x0, pattern->matrix.y0); - } - - /* XXX need to discriminate the user explicitly setting the default */ - if (pattern->filter != CAIRO_FILTER_DEFAULT) { - if (need_newline) { - _cairo_output_stream_puts (ctx->stream, "\n "); - need_newline = FALSE; - } - - _cairo_output_stream_printf (ctx->stream, - " //%s set-filter\n ", - _filter_to_string (pattern->filter)); - } - if (! is_default_extend ){ - if (need_newline) { - _cairo_output_stream_puts (ctx->stream, "\n "); - need_newline = FALSE; - } - - _cairo_output_stream_printf (ctx->stream, - " //%s set-extend\n ", - _extend_to_string (pattern->extend)); - } - - if (need_newline) - _cairo_output_stream_puts (ctx->stream, "\n "); - - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_identity (cairo_script_surface_t *surface, - cairo_bool_t *matrix_updated) -{ - assert (target_is_active (surface)); - - if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) - return CAIRO_INT_STATUS_SUCCESS; - - _cairo_output_stream_puts (to_context (surface)->stream, - "identity set-matrix\n"); - - *matrix_updated = TRUE; - cairo_matrix_init_identity (&surface->cr.current_ctm); - - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t -_emit_source (cairo_script_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *source) -{ - cairo_bool_t matrix_updated = FALSE; - cairo_int_status_t status; - - assert (target_is_active (surface)); - - if (op == CAIRO_OPERATOR_CLEAR) { - /* the source is ignored, so don't change it */ - return CAIRO_INT_STATUS_SUCCESS; - } - - if (_cairo_pattern_equal (&surface->cr.current_source.base, source)) - return CAIRO_INT_STATUS_SUCCESS; - - _cairo_pattern_fini (&surface->cr.current_source.base); - status = _cairo_pattern_init_copy (&surface->cr.current_source.base, - source); - if (unlikely (status)) - return status; - - status = _emit_identity (surface, &matrix_updated); - if (unlikely (status)) - return status; - - status = _emit_pattern (surface, source); - if (unlikely (status)) - return status; - - assert (target_is_active (surface)); - _cairo_output_stream_puts (to_context (surface)->stream, - " set-source\n"); - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_status_t -_path_move_to (void *closure, - const cairo_point_t *point) -{ - _cairo_output_stream_printf (closure, - " %f %f m", - _cairo_fixed_to_double (point->x), - _cairo_fixed_to_double (point->y)); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_path_line_to (void *closure, - const cairo_point_t *point) -{ - _cairo_output_stream_printf (closure, - " %f %f l", - _cairo_fixed_to_double (point->x), - _cairo_fixed_to_double (point->y)); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_path_curve_to (void *closure, - const cairo_point_t *p1, - const cairo_point_t *p2, - const cairo_point_t *p3) -{ - _cairo_output_stream_printf (closure, - " %f %f %f %f %f %f c", - _cairo_fixed_to_double (p1->x), - _cairo_fixed_to_double (p1->y), - _cairo_fixed_to_double (p2->x), - _cairo_fixed_to_double (p2->y), - _cairo_fixed_to_double (p3->x), - _cairo_fixed_to_double (p3->y)); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_path_close (void *closure) -{ - _cairo_output_stream_printf (closure, - " h"); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_path_boxes (cairo_script_surface_t *surface, - const cairo_path_fixed_t *path) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_path_fixed_iter_t iter; - cairo_status_t status; - struct _cairo_boxes_chunk *chunk; - cairo_boxes_t boxes; - cairo_box_t box; - int i; - - _cairo_boxes_init (&boxes); - _cairo_path_fixed_iter_init (&iter, path); - while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { - if (box.p1.y == box.p2.y || box.p1.x == box.p2.x) - continue; - - status = _cairo_boxes_add (&boxes, CAIRO_ANTIALIAS_DEFAULT, &box); - if (unlikely (status)) { - _cairo_boxes_fini (&boxes); - return status; - } - } - - if (! _cairo_path_fixed_iter_at_end (&iter)) { - _cairo_boxes_fini (&boxes); - return CAIRO_STATUS_INVALID_PATH_DATA; - } - - for (chunk = &boxes.chunks; chunk; chunk = chunk->next) { - for (i = 0; i < chunk->count; i++) { - const cairo_box_t *b = &chunk->base[i]; - double x1 = _cairo_fixed_to_double (b->p1.x); - double y1 = _cairo_fixed_to_double (b->p1.y); - double x2 = _cairo_fixed_to_double (b->p2.x); - double y2 = _cairo_fixed_to_double (b->p2.y); - - _cairo_output_stream_printf (ctx->stream, - "\n %f %f %f %f rectangle", - x1, y1, x2 - x1, y2 - y1); - } - } - - _cairo_boxes_fini (&boxes); - return status; -} - -static cairo_status_t -_emit_path (cairo_script_surface_t *surface, - const cairo_path_fixed_t *path, - cairo_bool_t is_fill) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_box_t box; - cairo_int_status_t status; - - assert (target_is_active (surface)); - assert (_cairo_matrix_is_identity (&surface->cr.current_ctm)); - - if (_cairo_path_fixed_equal (&surface->cr.current_path, path)) - return CAIRO_STATUS_SUCCESS; - - _cairo_path_fixed_fini (&surface->cr.current_path); - - _cairo_output_stream_puts (ctx->stream, "n"); - - if (path == NULL) { - _cairo_path_fixed_init (&surface->cr.current_path); - _cairo_output_stream_puts (ctx->stream, "\n"); - return CAIRO_STATUS_SUCCESS; - } - - status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); - if (unlikely (status)) - return status; - - status = CAIRO_INT_STATUS_UNSUPPORTED; - if (_cairo_path_fixed_is_rectangle (path, &box)) { - double x1 = _cairo_fixed_to_double (box.p1.x); - double y1 = _cairo_fixed_to_double (box.p1.y); - double x2 = _cairo_fixed_to_double (box.p2.x); - double y2 = _cairo_fixed_to_double (box.p2.y); - - assert (x1 > -9999); - - _cairo_output_stream_printf (ctx->stream, - " %f %f %f %f rectangle", - x1, y1, x2 - x1, y2 - y1); - status = CAIRO_INT_STATUS_SUCCESS; - } else if (is_fill && _cairo_path_fixed_fill_is_rectilinear (path)) { - status = _emit_path_boxes (surface, path); - } - - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - status = _cairo_path_fixed_interpret (path, - _path_move_to, - _path_line_to, - _path_curve_to, - _path_close, - ctx->stream); - } - - _cairo_output_stream_puts (ctx->stream, "\n"); - - return status; -} -static cairo_bool_t -_scaling_matrix_equal (const cairo_matrix_t *a, - const cairo_matrix_t *b) -{ - return fabs (a->xx - b->xx) < 1e-5 && - fabs (a->xy - b->xy) < 1e-5 && - fabs (a->yx - b->yx) < 1e-5 && - fabs (a->yy - b->yy) < 1e-5; -} - -static cairo_status_t -_emit_scaling_matrix (cairo_script_surface_t *surface, - const cairo_matrix_t *ctm, - cairo_bool_t *matrix_updated) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_bool_t was_identity; - assert (target_is_active (surface)); - - if (_scaling_matrix_equal (&surface->cr.current_ctm, ctm)) - return CAIRO_STATUS_SUCCESS; - - was_identity = _cairo_matrix_is_identity (&surface->cr.current_ctm); - - *matrix_updated = TRUE; - surface->cr.current_ctm = *ctm; - surface->cr.current_ctm.x0 = 0.; - surface->cr.current_ctm.y0 = 0.; - - if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) { - _cairo_output_stream_puts (ctx->stream, - "identity set-matrix\n"); - } else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) { - _cairo_output_stream_printf (ctx->stream, - "%f %f scale\n", - ctm->xx, ctm->yy); - } else { - _cairo_output_stream_printf (ctx->stream, - "[%f %f %f %f 0 0] set-matrix\n", - ctm->xx, ctm->yx, - ctm->xy, ctm->yy); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_font_matrix (cairo_script_surface_t *surface, - const cairo_matrix_t *font_matrix) -{ - cairo_script_context_t *ctx = to_context (surface); - assert (target_is_active (surface)); - - if (memcmp (&surface->cr.current_font_matrix, - font_matrix, - sizeof (cairo_matrix_t)) == 0) - { - return CAIRO_STATUS_SUCCESS; - } - - surface->cr.current_font_matrix = *font_matrix; - - if (_cairo_matrix_is_identity (font_matrix)) { - _cairo_output_stream_puts (ctx->stream, - "identity set-font-matrix\n"); - } else { - _cairo_output_stream_printf (ctx->stream, - "[%f %f %f %f %f %f] set-font-matrix\n", - font_matrix->xx, font_matrix->yx, - font_matrix->xy, font_matrix->yy, - font_matrix->x0, font_matrix->y0); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_surface_t * -_cairo_script_surface_create_similar (void *abstract_surface, - cairo_content_t content, - int width, - int height) -{ - cairo_script_surface_t *surface, *other = abstract_surface; - cairo_surface_t *passthrough = NULL; - cairo_script_context_t *ctx; - cairo_rectangle_t extents; - cairo_status_t status; - - ctx = to_context (other); - - status = cairo_device_acquire (&ctx->base); - if (unlikely (status)) - return _cairo_surface_create_in_error (status); - - if (! other->emitted) { - status = _emit_surface (other); - if (unlikely (status)) { - cairo_device_release (&ctx->base); - return _cairo_surface_create_in_error (status); - } - - target_push (other); - } - - if (_cairo_surface_wrapper_is_active (&other->wrapper)) { - passthrough = - _cairo_surface_wrapper_create_similar (&other->wrapper, - content, width, height); - if (unlikely (passthrough->status)) { - cairo_device_release (&ctx->base); - return passthrough; - } - } - - extents.x = extents.y = 0; - extents.width = width; - extents.height = height; - surface = _cairo_script_surface_create_internal (ctx, content, - &extents, passthrough); - cairo_surface_destroy (passthrough); - - if (unlikely (surface->base.status)) { - cairo_device_release (&ctx->base); - return &surface->base; - } - - _get_target (other); - _cairo_output_stream_printf (ctx->stream, - "%u %u //%s similar dup /s%u exch def context\n", - width, height, - _content_to_string (content), - surface->base.unique_id); - - surface->emitted = TRUE; - surface->defined = TRUE; - surface->base.is_clear = TRUE; - target_push (surface); - - cairo_device_release (&ctx->base); - return &surface->base; -} - -static cairo_status_t -_device_flush (void *abstract_device) -{ - cairo_script_context_t *ctx = abstract_device; - - return _cairo_output_stream_flush (ctx->stream); -} - -static void -_device_destroy (void *abstract_device) -{ - cairo_script_context_t *ctx = abstract_device; - cairo_status_t status; - - while (! cairo_list_is_empty (&ctx->fonts)) { - cairo_script_font_t *font; - - font = cairo_list_first_entry (&ctx->fonts, cairo_script_font_t, link); - cairo_list_del (&font->base.link); - cairo_list_del (&font->link); - free (font); - } - - _bitmap_fini (ctx->surface_id.next); - _bitmap_fini (ctx->font_id.next); - - if (ctx->owns_stream) - status = _cairo_output_stream_destroy (ctx->stream); - - free (ctx); -} - -static cairo_surface_t * -_cairo_script_surface_source (void *abstract_surface, - cairo_rectangle_int_t *extents) -{ - cairo_script_surface_t *surface = abstract_surface; - - if (extents) { - extents->x = extents->y = 0; - extents->width = surface->width; - extents->height = surface->height; - } - - return &surface->base; -} - -static cairo_status_t -_cairo_script_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) -{ - cairo_script_surface_t *surface = abstract_surface; - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper, - image_out, - image_extra); - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static void -_cairo_script_surface_release_source_image (void *abstract_surface, - cairo_image_surface_t *image, - void *image_extra) -{ - cairo_script_surface_t *surface = abstract_surface; - - assert (_cairo_surface_wrapper_is_active (&surface->wrapper)); - _cairo_surface_wrapper_release_source_image (&surface->wrapper, - image, - image_extra); -} - -static cairo_status_t -_cairo_script_surface_finish (void *abstract_surface) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_script_context_t *ctx = to_context (surface); - cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; - - _cairo_surface_wrapper_fini (&surface->wrapper); - - free (surface->cr.current_style.dash); - surface->cr.current_style.dash = NULL; - - _cairo_pattern_fini (&surface->cr.current_source.base); - _cairo_path_fixed_fini (&surface->cr.current_path); - _cairo_surface_clipper_reset (&surface->clipper); - - status = cairo_device_acquire (&ctx->base); - if (unlikely (status)) - return status; - - if (surface->emitted) { - assert (! surface->active); - - if (! cairo_list_is_empty (&surface->operand.link)) { - if (! ctx->active) { - if (target_is_active (surface)) { - _cairo_output_stream_printf (ctx->stream, - "pop\n"); - } else { - int depth = target_depth (surface); - if (depth == 1) { - _cairo_output_stream_printf (ctx->stream, - "exch pop\n"); - } else { - _cairo_output_stream_printf (ctx->stream, - "%d -1 roll pop\n", - depth); - } - } - cairo_list_del (&surface->operand.link); - } else { - struct deferred_finish *link = _cairo_malloc (sizeof (*link)); - if (link == NULL) { - status2 = _cairo_error (CAIRO_STATUS_NO_MEMORY); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - cairo_list_del (&surface->operand.link); - } else { - link->operand.type = DEFERRED; - cairo_list_swap (&link->operand.link, - &surface->operand.link); - cairo_list_add (&link->link, &ctx->deferred); - } - } - } - - if (surface->defined) { - _cairo_output_stream_printf (ctx->stream, - "/s%u undef\n", - surface->base.unique_id); - } - } - - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_output_stream_flush (to_context (surface)->stream); - - cairo_device_release (&ctx->base); - - return status; -} - -static cairo_int_status_t -_cairo_script_surface_copy_page (void *abstract_surface) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = cairo_device_acquire (surface->base.device); - if (unlikely (status)) - return status; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n"); - -BAIL: - cairo_device_release (surface->base.device); - return status; -} - -static cairo_int_status_t -_cairo_script_surface_show_page (void *abstract_surface) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = cairo_device_acquire (surface->base.device); - if (unlikely (status)) - return status; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n"); - -BAIL: - cairo_device_release (surface->base.device); - return status; -} - -static cairo_status_t -_cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_script_surface_t *surface = cairo_container_of (clipper, - cairo_script_surface_t, - clipper); - cairo_script_context_t *ctx = to_context (surface); - cairo_bool_t matrix_updated = FALSE; - cairo_status_t status; - cairo_box_t box; - - status = _emit_context (surface); - if (unlikely (status)) - return status; - - if (path == NULL) { - if (surface->cr.has_clip) { - _cairo_output_stream_puts (ctx->stream, "reset-clip\n"); - surface->cr.has_clip = FALSE; - } - return CAIRO_STATUS_SUCCESS; - } - - /* skip the trivial clip covering the surface extents */ - if (surface->width >= 0 && surface->height >= 0 && - _cairo_path_fixed_is_box (path, &box)) - { - if (box.p1.x <= 0 && box.p1.y <= 0 && - box.p2.x >= _cairo_fixed_from_double (surface->width) && - box.p2.y >= _cairo_fixed_from_double (surface->height)) - { - return CAIRO_STATUS_SUCCESS; - } - } - - status = _emit_identity (surface, &matrix_updated); - if (unlikely (status)) - return status; - - status = _emit_fill_rule (surface, fill_rule); - if (unlikely (status)) - return status; - - if (path->has_curve_to) { - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; - } - - if (! _cairo_path_fixed_fill_maybe_region (path)) { - status = _emit_antialias (surface, antialias); - if (unlikely (status)) - return status; - } - - status = _emit_path (surface, path, TRUE); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (ctx->stream, "clip+\n"); - surface->cr.has_clip = TRUE; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -active (cairo_script_surface_t *surface) -{ - cairo_status_t status; - - status = cairo_device_acquire (surface->base.device); - if (unlikely (status)) - return status; - - if (surface->active++ == 0) - to_context (surface)->active++; - - return CAIRO_STATUS_SUCCESS; -} - -static void -inactive (cairo_script_surface_t *surface) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_list_t sorted; - - assert (surface->active > 0); - if (--surface->active) - goto DONE; - - assert (ctx->active > 0); - if (--ctx->active) - goto DONE; - - cairo_list_init (&sorted); - while (! cairo_list_is_empty (&ctx->deferred)) { - struct deferred_finish *df; - cairo_list_t *operand; - int depth; - - df = cairo_list_first_entry (&ctx->deferred, - struct deferred_finish, - link); - - depth = 0; - cairo_list_foreach (operand, &ctx->operands) { - if (operand == &df->operand.link) - break; - depth++; - } - - df->operand.type = depth; - - if (cairo_list_is_empty (&sorted)) { - cairo_list_move (&df->link, &sorted); - } else { - struct deferred_finish *pos; - - cairo_list_foreach_entry (pos, struct deferred_finish, - &sorted, - link) - { - if (df->operand.type < pos->operand.type) - break; - } - cairo_list_move_tail (&df->link, &pos->link); - } - } - - while (! cairo_list_is_empty (&sorted)) { - struct deferred_finish *df; - cairo_list_t *operand; - int depth; - - df = cairo_list_first_entry (&sorted, - struct deferred_finish, - link); - - depth = 0; - cairo_list_foreach (operand, &ctx->operands) { - if (operand == &df->operand.link) - break; - depth++; - } - - if (depth == 0) { - _cairo_output_stream_printf (ctx->stream, - "pop\n"); - } else if (depth == 1) { - _cairo_output_stream_printf (ctx->stream, - "exch pop\n"); - } else { - _cairo_output_stream_printf (ctx->stream, - "%d -1 roll pop\n", - depth); - } - - cairo_list_del (&df->operand.link); - cairo_list_del (&df->link); - free (df); - } - -DONE: - cairo_device_release (surface->base.device); -} - -static cairo_int_status_t -_cairo_script_surface_paint (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_clip_t *clip) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = active (surface); - if (unlikely (status)) - return status; - - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); - if (unlikely (status)) - goto BAIL; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - status = _emit_source (surface, op, source); - if (unlikely (status)) - goto BAIL; - - status = _emit_operator (surface, op); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (to_context (surface)->stream, - "paint\n"); - - inactive (surface); - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_paint (&surface->wrapper, - op, source, clip); - } - - return CAIRO_STATUS_SUCCESS; - -BAIL: - inactive (surface); - return status; -} - -static cairo_int_status_t -_cairo_script_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - const cairo_clip_t *clip) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = active (surface); - if (unlikely (status)) - return status; - - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); - if (unlikely (status)) - goto BAIL; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - status = _emit_source (surface, op, source); - if (unlikely (status)) - goto BAIL; - - status = _emit_operator (surface, op); - if (unlikely (status)) - goto BAIL; - - if (_cairo_pattern_equal (source, mask)) { - _cairo_output_stream_puts (to_context (surface)->stream, "/source get"); - } else { - status = _emit_pattern (surface, mask); - if (unlikely (status)) - goto BAIL; - } - - assert (surface->cr.current_operator == op); - - _cairo_output_stream_puts (to_context (surface)->stream, - " mask\n"); - - inactive (surface); - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_mask (&surface->wrapper, - op, source, mask, clip); - } - - return CAIRO_STATUS_SUCCESS; - -BAIL: - inactive (surface); - return status; -} - -static cairo_int_status_t -_cairo_script_surface_stroke (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_bool_t matrix_updated = FALSE; - cairo_status_t status; - - status = active (surface); - if (unlikely (status)) - return status; - - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); - if (unlikely (status)) - goto BAIL; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - status = _emit_identity (surface, &matrix_updated); - if (unlikely (status)) - goto BAIL; - - status = _emit_path (surface, path, FALSE); - if (unlikely (status)) - goto BAIL; - - status = _emit_source (surface, op, source); - if (unlikely (status)) - goto BAIL; - - status = _emit_scaling_matrix (surface, ctm, &matrix_updated); - if (unlikely (status)) - goto BAIL; - - status = _emit_operator (surface, op); - if (unlikely (status)) - goto BAIL; - - if (_scaling_matrix_equal (&surface->cr.current_ctm, - &surface->cr.current_stroke_matrix)) - { - matrix_updated = FALSE; - } - else - { - matrix_updated = TRUE; - surface->cr.current_stroke_matrix = surface->cr.current_ctm; - } - - status = _emit_stroke_style (surface, style, matrix_updated); - if (unlikely (status)) - goto BAIL; - - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - goto BAIL; - - status = _emit_antialias (surface, antialias); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n"); - - inactive (surface); - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_stroke (&surface->wrapper, - op, source, path, - style, - ctm, ctm_inverse, - tolerance, antialias, - clip); - } - - return CAIRO_STATUS_SUCCESS; - -BAIL: - inactive (surface); - return status; -} - -static cairo_int_status_t -_cairo_script_surface_fill (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_clip_t *clip) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_bool_t matrix_updated = FALSE; - cairo_status_t status; - cairo_box_t box; - - status = active (surface); - if (unlikely (status)) - return status; - - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); - if (unlikely (status)) - goto BAIL; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - status = _emit_identity (surface, &matrix_updated); - if (unlikely (status)) - goto BAIL; - - status = _emit_source (surface, op, source); - if (unlikely (status)) - goto BAIL; - - if (! _cairo_path_fixed_is_box (path, &box)) { - status = _emit_fill_rule (surface, fill_rule); - if (unlikely (status)) - goto BAIL; - } - - if (path->has_curve_to) { - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - goto BAIL; - } - - if (! _cairo_path_fixed_fill_maybe_region (path)) { - status = _emit_antialias (surface, antialias); - if (unlikely (status)) - goto BAIL; - } - - status = _emit_path (surface, path, TRUE); - if (unlikely (status)) - goto BAIL; - - status = _emit_operator (surface, op); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n"); - - inactive (surface); - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_fill (&surface->wrapper, - op, source, path, - fill_rule, - tolerance, - antialias, - clip); - } - - return CAIRO_STATUS_SUCCESS; - -BAIL: - inactive (surface); - return status; -} - -static cairo_surface_t * -_cairo_script_surface_snapshot (void *abstract_surface) -{ - cairo_script_surface_t *surface = abstract_surface; - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) - return _cairo_surface_wrapper_snapshot (&surface->wrapper); - - return NULL; -} - -static cairo_bool_t -_cairo_script_surface_has_show_text_glyphs (void *abstract_surface) -{ - return TRUE; -} - -static const char * -_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order) -{ - static const char *names[] = { - "SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */ - "SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */ - "SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */ - "SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */ - "SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */ - }; - return names[subpixel_order]; -} -static const char * -_hint_style_to_string (cairo_hint_style_t hint_style) -{ - static const char *names[] = { - "HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */ - "HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */ - "HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */ - "HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */ - "HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */ - }; - return names[hint_style]; -} -static const char * -_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics) -{ - static const char *names[] = { - "HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */ - "HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */ - "HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */ - }; - return names[hint_metrics]; -} - -static cairo_status_t -_emit_font_options (cairo_script_surface_t *surface, - cairo_font_options_t *font_options) -{ - cairo_script_context_t *ctx = to_context (surface); - - if (cairo_font_options_equal (&surface->cr.current_font_options, - font_options)) - { - return CAIRO_STATUS_SUCCESS; - } - - _cairo_output_stream_printf (ctx->stream, "<<"); - - if (font_options->antialias != surface->cr.current_font_options.antialias) { - _cairo_output_stream_printf (ctx->stream, - " /antialias //%s", - _antialias_to_string (font_options->antialias)); - } - - if (font_options->subpixel_order != - surface->cr.current_font_options.subpixel_order) - { - _cairo_output_stream_printf (ctx->stream, - " /subpixel-order //%s", - _subpixel_order_to_string (font_options->subpixel_order)); - } - - if (font_options->hint_style != - surface->cr.current_font_options.hint_style) - { - _cairo_output_stream_printf (ctx->stream, - " /hint-style //%s", - _hint_style_to_string (font_options->hint_style)); - } - - if (font_options->hint_metrics != - surface->cr.current_font_options.hint_metrics) - { - _cairo_output_stream_printf (ctx->stream, - " /hint-metrics //%s", - _hint_metrics_to_string (font_options->hint_metrics)); - } - - _cairo_output_stream_printf (ctx->stream, - " >> set-font-options\n"); - - surface->cr.current_font_options = *font_options; - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private, - cairo_scaled_font_t *scaled_font) -{ - cairo_script_font_t *priv = (cairo_script_font_t *)abstract_private; - cairo_script_context_t *ctx = (cairo_script_context_t *)abstract_private->key; - cairo_status_t status; - - status = cairo_device_acquire (&ctx->base); - if (likely (status == CAIRO_STATUS_SUCCESS)) { - _cairo_output_stream_printf (ctx->stream, - "/f%lu undef /sf%lu undef\n", - priv->id, - priv->id); - - _bitmap_release_id (&ctx->font_id, priv->id); - cairo_device_release (&ctx->base); - } - - cairo_list_del (&priv->link); - cairo_list_del (&priv->base.link); - free (priv); -} - -static cairo_script_font_t * -_cairo_script_font_get (cairo_script_context_t *ctx, cairo_scaled_font_t *font) -{ - return (cairo_script_font_t *) _cairo_scaled_font_find_private (font, ctx); -} - -static long unsigned -_cairo_script_font_id (cairo_script_context_t *ctx, cairo_scaled_font_t *font) -{ - return _cairo_script_font_get (ctx, font)->id; -} - -static cairo_status_t -_emit_type42_font (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font) -{ - cairo_script_context_t *ctx = to_context (surface); - const cairo_scaled_font_backend_t *backend; - cairo_output_stream_t *base85_stream; - cairo_output_stream_t *zlib_stream; - cairo_status_t status, status2; - unsigned long size; - unsigned int load_flags; - uint32_t len; - uint8_t *buf; - - backend = scaled_font->backend; - if (backend->load_truetype_table == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - size = 0; - status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size); - if (unlikely (status)) - return status; - - buf = _cairo_malloc (size); - if (unlikely (buf == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size); - if (unlikely (status)) { - free (buf); - return status; - } - -#if CAIRO_HAS_FT_FONT - load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font); -#else - load_flags = 0; -#endif - _cairo_output_stream_printf (ctx->stream, - "<< " - "/type 42 " - "/index 0 " - "/flags %d " - "/source <|", - load_flags); - - base85_stream = _cairo_base85_stream_create (ctx->stream); - len = to_be32 (size); - _cairo_output_stream_write (base85_stream, &len, sizeof (len)); - - zlib_stream = _cairo_deflate_stream_create (base85_stream); - - _cairo_output_stream_write (zlib_stream, buf, size); - free (buf); - - status2 = _cairo_output_stream_destroy (zlib_stream); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - - status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - - _cairo_output_stream_printf (ctx->stream, - "~> >> font dup /f%lu exch def set-font-face", - _cairo_script_font_id (ctx, scaled_font)); - - return status; -} - -static cairo_status_t -_emit_scaled_font_init (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font, - cairo_script_font_t **font_out) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_script_font_t *font_private; - cairo_int_status_t status; - - font_private = _cairo_malloc (sizeof (cairo_script_font_t)); - if (unlikely (font_private == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - _cairo_scaled_font_attach_private (scaled_font, &font_private->base, ctx, - _cairo_script_scaled_font_fini); - - font_private->parent = scaled_font; - font_private->subset_glyph_index = 0; - font_private->has_sfnt = TRUE; - - cairo_list_add (&font_private->link, &ctx->fonts); - - status = _bitmap_next_id (&ctx->font_id, - &font_private->id); - if (unlikely (status)) { - free (font_private); - return status; - } - - status = _emit_context (surface); - if (unlikely (status)) { - free (font_private); - return status; - } - - status = _emit_type42_font (surface, scaled_font); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - *font_out = font_private; - return status; - } - - font_private->has_sfnt = FALSE; - _cairo_output_stream_printf (ctx->stream, - "dict\n" - " /type 3 set\n" - " /metrics [%f %f %f %f %f] set\n" - " /glyphs array set\n" - " font dup /f%lu exch def set-font-face", - scaled_font->fs_extents.ascent, - scaled_font->fs_extents.descent, - scaled_font->fs_extents.height, - scaled_font->fs_extents.max_x_advance, - scaled_font->fs_extents.max_y_advance, - font_private->id); - - *font_out = font_private; - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_scaled_font (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_matrix_t matrix; - cairo_font_options_t options; - cairo_bool_t matrix_updated = FALSE; - cairo_status_t status; - cairo_script_font_t *font_private; - - cairo_scaled_font_get_ctm (scaled_font, &matrix); - status = _emit_scaling_matrix (surface, &matrix, &matrix_updated); - if (unlikely (status)) - return status; - - if (! matrix_updated && surface->cr.current_scaled_font == scaled_font) - return CAIRO_STATUS_SUCCESS; - - surface->cr.current_scaled_font = scaled_font; - - font_private = _cairo_script_font_get (ctx, scaled_font); - if (font_private == NULL) { - cairo_scaled_font_get_font_matrix (scaled_font, &matrix); - status = _emit_font_matrix (surface, &matrix); - if (unlikely (status)) - return status; - - cairo_scaled_font_get_font_options (scaled_font, &options); - status = _emit_font_options (surface, &options); - if (unlikely (status)) - return status; - - status = _emit_scaled_font_init (surface, scaled_font, &font_private); - if (unlikely (status)) - return status; - - assert (target_is_active (surface)); - _cairo_output_stream_printf (ctx->stream, - " /scaled-font get /sf%lu exch def\n", - font_private->id); - } else { - _cairo_output_stream_printf (ctx->stream, - "sf%lu set-scaled-font\n", - font_private->id); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_scaled_glyph_vector (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font, - cairo_script_font_t *font_private, - cairo_scaled_glyph_t *scaled_glyph) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_script_implicit_context_t old_cr; - cairo_status_t status; - unsigned long index; - - index = ++font_private->subset_glyph_index; - scaled_glyph->dev_private_key = ctx; - scaled_glyph->dev_private = (void *) index; - - _cairo_output_stream_printf (ctx->stream, - "%lu <<\n" - " /metrics [%f %f %f %f %f %f]\n" - " /render {\n", - index, - scaled_glyph->fs_metrics.x_bearing, - scaled_glyph->fs_metrics.y_bearing, - scaled_glyph->fs_metrics.width, - scaled_glyph->fs_metrics.height, - scaled_glyph->fs_metrics.x_advance, - scaled_glyph->fs_metrics.y_advance); - - if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) { - _cairo_output_stream_printf (ctx->stream, - "[%f %f %f %f %f %f] transform\n", - scaled_font->scale_inverse.xx, - scaled_font->scale_inverse.yx, - scaled_font->scale_inverse.xy, - scaled_font->scale_inverse.yy, - scaled_font->scale_inverse.x0, - scaled_font->scale_inverse.y0); - } - - old_cr = surface->cr; - _cairo_script_implicit_context_init (&surface->cr); - status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, - &surface->base); - surface->cr = old_cr; - - _cairo_output_stream_puts (ctx->stream, "} >> set\n"); - - return status; -} - -static cairo_status_t -_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font, - cairo_script_font_t *font_private, - cairo_scaled_glyph_t *scaled_glyph) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_status_t status; - unsigned long index; - - index = ++font_private->subset_glyph_index; - scaled_glyph->dev_private_key = ctx; - scaled_glyph->dev_private = (void *) index; - - _cairo_output_stream_printf (ctx->stream, - "%lu <<\n" - " /metrics [%f %f %f %f %f %f]\n" - " /render {\n" - "%f %f translate\n", - index, - scaled_glyph->fs_metrics.x_bearing, - scaled_glyph->fs_metrics.y_bearing, - scaled_glyph->fs_metrics.width, - scaled_glyph->fs_metrics.height, - scaled_glyph->fs_metrics.x_advance, - scaled_glyph->fs_metrics.y_advance, - scaled_glyph->fs_metrics.x_bearing, - scaled_glyph->fs_metrics.y_bearing); - - status = _emit_image_surface (surface, scaled_glyph->surface); - if (unlikely (status)) - return status; - - _cairo_output_stream_puts (ctx->stream, "pattern "); - - if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { - _cairo_output_stream_printf (ctx->stream, - "\n [%f %f %f %f %f %f] set-matrix\n", - scaled_font->font_matrix.xx, - scaled_font->font_matrix.yx, - scaled_font->font_matrix.xy, - scaled_font->font_matrix.yy, - scaled_font->font_matrix.x0, - scaled_font->font_matrix.y0); - } - _cairo_output_stream_puts (ctx->stream, - "mask\n} >> set\n"); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_scaled_glyph_prologue (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font) -{ - cairo_script_context_t *ctx = to_context (surface); - - _cairo_output_stream_printf (ctx->stream, "f%lu /glyphs get\n", - _cairo_script_font_id (ctx, scaled_font)); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_emit_scaled_glyphs (cairo_script_surface_t *surface, - cairo_scaled_font_t *scaled_font, - cairo_glyph_t *glyphs, - unsigned int num_glyphs) -{ - cairo_script_context_t *ctx = to_context (surface); - cairo_script_font_t *font_private; - cairo_status_t status; - unsigned int n; - cairo_bool_t have_glyph_prologue = FALSE; - - if (num_glyphs == 0) - return CAIRO_STATUS_SUCCESS; - - font_private = _cairo_script_font_get (ctx, scaled_font); - if (font_private->has_sfnt) - return CAIRO_STATUS_SUCCESS; - - _cairo_scaled_font_freeze_cache (scaled_font); - for (n = 0; n < num_glyphs; n++) { - cairo_scaled_glyph_t *scaled_glyph; - - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[n].index, - CAIRO_SCALED_GLYPH_INFO_METRICS, - &scaled_glyph); - if (unlikely (status)) - break; - - if (scaled_glyph->dev_private_key == ctx) - continue; - - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[n].index, - CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, - &scaled_glyph); - if (_cairo_status_is_error (status)) - break; - - if (status == CAIRO_STATUS_SUCCESS) { - if (! have_glyph_prologue) { - status = _emit_scaled_glyph_prologue (surface, scaled_font); - if (unlikely (status)) - break; - - have_glyph_prologue = TRUE; - } - - status = _emit_scaled_glyph_vector (surface, - scaled_font, font_private, - scaled_glyph); - if (unlikely (status)) - break; - - continue; - } - - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[n].index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (_cairo_status_is_error (status)) - break; - - if (status == CAIRO_STATUS_SUCCESS) { - if (! have_glyph_prologue) { - status = _emit_scaled_glyph_prologue (surface, scaled_font); - if (unlikely (status)) - break; - - have_glyph_prologue = TRUE; - } - - status = _emit_scaled_glyph_bitmap (surface, - scaled_font, - font_private, - scaled_glyph); - if (unlikely (status)) - break; - - continue; - } - } - _cairo_scaled_font_thaw_cache (scaled_font); - - if (have_glyph_prologue) { - _cairo_output_stream_puts (to_context (surface)->stream, "pop pop\n"); - } - - return status; -} - -static void -to_octal (int value, char *buf, size_t size) -{ - do { - buf[--size] = '0' + (value & 7); - value >>= 3; - } while (size); -} - -static void -_emit_string_literal (cairo_script_surface_t *surface, - const char *utf8, int len) -{ - cairo_script_context_t *ctx = to_context (surface); - char c; - const char *end; - - _cairo_output_stream_puts (ctx->stream, "("); - - if (utf8 == NULL) { - end = utf8; - } else { - if (len < 0) - len = strlen (utf8); - end = utf8 + len; - } - - while (utf8 < end) { - switch ((c = *utf8++)) { - case '\n': - c = 'n'; - goto ESCAPED_CHAR; - case '\r': - c = 'r'; - goto ESCAPED_CHAR; - case '\t': - c = 't'; - goto ESCAPED_CHAR; - case '\b': - c = 'b'; - goto ESCAPED_CHAR; - case '\f': - c = 'f'; - goto ESCAPED_CHAR; - case '\\': - case '(': - case ')': -ESCAPED_CHAR: - _cairo_output_stream_printf (ctx->stream, "\\%c", c); - break; - default: - if (isprint (c) || isspace (c)) { - _cairo_output_stream_printf (ctx->stream, "%c", c); - } else { - char buf[4] = { '\\' }; - - to_octal (c, buf+1, 3); - _cairo_output_stream_write (ctx->stream, buf, 4); - } - break; - } - } - _cairo_output_stream_puts (ctx->stream, ")"); -} - -static cairo_int_status_t -_cairo_script_surface_show_text_glyphs (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const char *utf8, - int utf8_len, - cairo_glyph_t *glyphs, - int num_glyphs, - const cairo_text_cluster_t *clusters, - int num_clusters, - cairo_text_cluster_flags_t backward, - cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip) -{ - cairo_script_surface_t *surface = abstract_surface; - cairo_script_context_t *ctx = to_context (surface); - cairo_script_font_t *font_private; - cairo_scaled_glyph_t *scaled_glyph; - cairo_matrix_t matrix; - cairo_status_t status; - double x, y, ix, iy; - int n; - cairo_output_stream_t *base85_stream = NULL; - - status = active (surface); - if (unlikely (status)) - return status; - - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); - if (unlikely (status)) - goto BAIL; - - status = _emit_context (surface); - if (unlikely (status)) - goto BAIL; - - status = _emit_source (surface, op, source); - if (unlikely (status)) - goto BAIL; - - status = _emit_scaled_font (surface, scaled_font); - if (unlikely (status)) - goto BAIL; - - status = _emit_operator (surface, op); - if (unlikely (status)) - goto BAIL; - - status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); - if (unlikely (status)) - goto BAIL; - - /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */ - /* [cx cy [glyphs]] show_glyphs */ - - if (utf8 != NULL && clusters != NULL) { - _emit_string_literal (surface, utf8, utf8_len); - _cairo_output_stream_puts (ctx->stream, " "); - } - - matrix = surface->cr.current_ctm; - status = cairo_matrix_invert (&matrix); - assert (status == CAIRO_STATUS_SUCCESS); - - ix = x = glyphs[0].x; - iy = y = glyphs[0].y; - cairo_matrix_transform_point (&matrix, &ix, &iy); - ix -= scaled_font->font_matrix.x0; - iy -= scaled_font->font_matrix.y0; - - _cairo_scaled_font_freeze_cache (scaled_font); - font_private = _cairo_script_font_get (ctx, scaled_font); - - _cairo_output_stream_printf (ctx->stream, - "[%f %f ", - ix, iy); - - for (n = 0; n < num_glyphs; n++) { - if (font_private->has_sfnt) { - if (glyphs[n].index > 256) - break; - } else { - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[n].index, - CAIRO_SCALED_GLYPH_INFO_METRICS, - &scaled_glyph); - if (unlikely (status)) { - _cairo_scaled_font_thaw_cache (scaled_font); - goto BAIL; - } - - if ((long unsigned) scaled_glyph->dev_private > 256) - break; - } - } - - if (n == num_glyphs) { - _cairo_output_stream_puts (ctx->stream, "<~"); - base85_stream = _cairo_base85_stream_create (ctx->stream); - } else - _cairo_output_stream_puts (ctx->stream, "["); - - for (n = 0; n < num_glyphs; n++) { - double dx, dy; - - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[n].index, - CAIRO_SCALED_GLYPH_INFO_METRICS, - &scaled_glyph); - if (unlikely (status)) { - _cairo_scaled_font_thaw_cache (scaled_font); - goto BAIL; - } - - if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { - if (fabs (glyphs[n].y - y) < 1e-5) { - if (base85_stream != NULL) { - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) { - base85_stream = NULL; - break; - } - - _cairo_output_stream_printf (ctx->stream, - "~> %f <~", glyphs[n].x - x); - base85_stream = _cairo_base85_stream_create (ctx->stream); - } else { - _cairo_output_stream_printf (ctx->stream, - " ] %f [ ", glyphs[n].x - x); - } - - x = glyphs[n].x; - } else { - ix = x = glyphs[n].x; - iy = y = glyphs[n].y; - cairo_matrix_transform_point (&matrix, &ix, &iy); - ix -= scaled_font->font_matrix.x0; - iy -= scaled_font->font_matrix.y0; - if (base85_stream != NULL) { - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) { - base85_stream = NULL; - break; - } - - _cairo_output_stream_printf (ctx->stream, - "~> %f %f <~", - ix, iy); - base85_stream = _cairo_base85_stream_create (ctx->stream); - } else { - _cairo_output_stream_printf (ctx->stream, - " ] %f %f [ ", - ix, iy); - } - } - } - if (base85_stream != NULL) { - uint8_t c; - - if (font_private->has_sfnt) - c = glyphs[n].index; - else - c = (uint8_t) (long unsigned) scaled_glyph->dev_private; - - _cairo_output_stream_write (base85_stream, &c, 1); - } else { - if (font_private->has_sfnt) - _cairo_output_stream_printf (ctx->stream, " %lu", - glyphs[n].index); - else - _cairo_output_stream_printf (ctx->stream, " %lu", - (long unsigned) scaled_glyph->dev_private); - } - - dx = scaled_glyph->metrics.x_advance; - dy = scaled_glyph->metrics.y_advance; - cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy); - x += dx; - y += dy; - } - _cairo_scaled_font_thaw_cache (scaled_font); - - if (base85_stream != NULL) { - cairo_status_t status2; - - status2 = _cairo_output_stream_destroy (base85_stream); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - - _cairo_output_stream_printf (ctx->stream, "~>"); - } else { - _cairo_output_stream_puts (ctx->stream, " ]"); - } - if (unlikely (status)) - return status; - - if (utf8 != NULL && clusters != NULL) { - for (n = 0; n < num_clusters; n++) { - if (clusters[n].num_bytes > UCHAR_MAX || - clusters[n].num_glyphs > UCHAR_MAX) - { - break; - } - } - - if (n < num_clusters) { - _cairo_output_stream_puts (ctx->stream, "] [ "); - for (n = 0; n < num_clusters; n++) { - _cairo_output_stream_printf (ctx->stream, - "%d %d ", - clusters[n].num_bytes, - clusters[n].num_glyphs); - } - _cairo_output_stream_puts (ctx->stream, "]"); - } - else - { - _cairo_output_stream_puts (ctx->stream, "] <~"); - base85_stream = _cairo_base85_stream_create (ctx->stream); - for (n = 0; n < num_clusters; n++) { - uint8_t c[2]; - c[0] = clusters[n].num_bytes; - c[1] = clusters[n].num_glyphs; - _cairo_output_stream_write (base85_stream, c, 2); - } - status = _cairo_output_stream_destroy (base85_stream); - if (unlikely (status)) - goto BAIL; - - _cairo_output_stream_puts (ctx->stream, "~>"); - } - - _cairo_output_stream_printf (ctx->stream, - " //%s show-text-glyphs\n", - _direction_to_string (backward)); - } else { - _cairo_output_stream_puts (ctx->stream, - "] show-glyphs\n"); - } - - inactive (surface); - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)){ - return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper, - op, source, - utf8, utf8_len, - glyphs, num_glyphs, - clusters, num_clusters, - backward, - scaled_font, - clip); - } - - return CAIRO_STATUS_SUCCESS; - -BAIL: - inactive (surface); - return status; -} - -static cairo_bool_t -_cairo_script_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *rectangle) -{ - cairo_script_surface_t *surface = abstract_surface; - - if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { - return _cairo_surface_wrapper_get_extents (&surface->wrapper, - rectangle); - } - - if (surface->width < 0 || surface->height < 0) - return FALSE; - - rectangle->x = 0; - rectangle->y = 0; - rectangle->width = surface->width; - rectangle->height = surface->height; - - return TRUE; -} - -static const cairo_surface_backend_t -_cairo_script_surface_backend = { - CAIRO_SURFACE_TYPE_SCRIPT, - _cairo_script_surface_finish, - - _cairo_default_context_create, - - _cairo_script_surface_create_similar, - NULL, /* create similar image */ - NULL, /* map to image */ - NULL, /* unmap image */ - - _cairo_script_surface_source, - _cairo_script_surface_acquire_source_image, - _cairo_script_surface_release_source_image, - _cairo_script_surface_snapshot, - - _cairo_script_surface_copy_page, - _cairo_script_surface_show_page, - - _cairo_script_surface_get_extents, - NULL, /* get_font_options */ - - NULL, /* flush */ - NULL, /* mark_dirty_rectangle */ - - _cairo_script_surface_paint, - _cairo_script_surface_mask, - _cairo_script_surface_stroke, - _cairo_script_surface_fill, - NULL, /* fill/stroke */ - NULL, /* glyphs */ - _cairo_script_surface_has_show_text_glyphs, - _cairo_script_surface_show_text_glyphs -}; - -static void -_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) -{ - cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT; - cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; - cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; - cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT; - _cairo_stroke_style_init (&cr->current_style); - _cairo_pattern_init_solid (&cr->current_source.solid, - CAIRO_COLOR_BLACK); - _cairo_path_fixed_init (&cr->current_path); - cairo_matrix_init_identity (&cr->current_ctm); - cairo_matrix_init_identity (&cr->current_stroke_matrix); - cairo_matrix_init_identity (&cr->current_font_matrix); - _cairo_font_options_init_default (&cr->current_font_options); - cr->current_scaled_font = NULL; - cr->has_clip = FALSE; -} - -static void -_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr) -{ - free (cr->current_style.dash); - cr->current_style.dash = NULL; - - _cairo_pattern_fini (&cr->current_source.base); - _cairo_path_fixed_fini (&cr->current_path); - - _cairo_script_implicit_context_init (cr); -} - -static cairo_script_surface_t * -_cairo_script_surface_create_internal (cairo_script_context_t *ctx, - cairo_content_t content, - cairo_rectangle_t *extents, - cairo_surface_t *passthrough) -{ - cairo_script_surface_t *surface; - - if (unlikely (ctx == NULL)) - return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); - - surface = _cairo_malloc (sizeof (cairo_script_surface_t)); - if (unlikely (surface == NULL)) - return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - _cairo_surface_init (&surface->base, - &_cairo_script_surface_backend, - &ctx->base, - content, - TRUE); /* is_vector */ - - _cairo_surface_wrapper_init (&surface->wrapper, passthrough); - - _cairo_surface_clipper_init (&surface->clipper, - _cairo_script_surface_clipper_intersect_clip_path); - - surface->width = surface->height = -1; - if (extents) { - surface->width = extents->width; - surface->height = extents->height; - cairo_surface_set_device_offset (&surface->base, - -extents->x, -extents->y); - } - - surface->emitted = FALSE; - surface->defined = FALSE; - surface->active = FALSE; - surface->operand.type = SURFACE; - cairo_list_init (&surface->operand.link); - - _cairo_script_implicit_context_init (&surface->cr); - - return surface; -} - -static const cairo_device_backend_t _cairo_script_device_backend = { - CAIRO_DEVICE_TYPE_SCRIPT, - - NULL, NULL, /* lock, unlock */ - - _device_flush, /* flush */ - NULL, /* finish */ - _device_destroy -}; - -cairo_device_t * -_cairo_script_context_create_internal (cairo_output_stream_t *stream) -{ - cairo_script_context_t *ctx; - - ctx = _cairo_malloc (sizeof (cairo_script_context_t)); - if (unlikely (ctx == NULL)) - return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - memset (ctx, 0, sizeof (cairo_script_context_t)); - - _cairo_device_init (&ctx->base, &_cairo_script_device_backend); - - cairo_list_init (&ctx->operands); - cairo_list_init (&ctx->deferred); - ctx->stream = stream; - ctx->mode = CAIRO_SCRIPT_MODE_ASCII; - - cairo_list_init (&ctx->fonts); - cairo_list_init (&ctx->defines); - - ctx->attach_snapshots = TRUE; - - return &ctx->base; -} - -void -_cairo_script_context_attach_snapshots (cairo_device_t *device, - cairo_bool_t enable) -{ - cairo_script_context_t *ctx; - - ctx = (cairo_script_context_t *) device; - ctx->attach_snapshots = enable; -} - -static cairo_device_t * -_cairo_script_context_create (cairo_output_stream_t *stream) -{ - cairo_script_context_t *ctx; - - ctx = (cairo_script_context_t *) - _cairo_script_context_create_internal (stream); - if (unlikely (ctx->base.status)) - return &ctx->base; - - ctx->owns_stream = TRUE; - _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n"); - return &ctx->base; -} - -/** - * cairo_script_create: - * @filename: the name (path) of the file to write the script to - * - * Creates a output device for emitting the script, used when - * creating the individual surfaces. - * - * Return value: a pointer to the newly created device. The caller - * owns the surface and should call cairo_device_destroy() when done - * with it. - * - * This function always returns a valid pointer, but it will return a - * pointer to a "nil" device if an error such as out of memory - * occurs. You can use cairo_device_status() to check for this. - * - * Since: 1.12 - **/ -cairo_device_t * -cairo_script_create (const char *filename) -{ - cairo_output_stream_t *stream; - cairo_status_t status; - - stream = _cairo_output_stream_create_for_filename (filename); - if ((status = _cairo_output_stream_get_status (stream))) - return _cairo_device_create_in_error (status); - - return _cairo_script_context_create (stream); -} - -/** - * cairo_script_create_for_stream: - * @write_func: callback function passed the bytes written to the script - * @closure: user data to be passed to the callback - * - * Creates a output device for emitting the script, used when - * creating the individual surfaces. - * - * Return value: a pointer to the newly created device. The caller - * owns the surface and should call cairo_device_destroy() when done - * with it. - * - * This function always returns a valid pointer, but it will return a - * pointer to a "nil" device if an error such as out of memory - * occurs. You can use cairo_device_status() to check for this. - * - * Since: 1.12 - **/ -cairo_device_t * -cairo_script_create_for_stream (cairo_write_func_t write_func, - void *closure) -{ - cairo_output_stream_t *stream; - cairo_status_t status; - - stream = _cairo_output_stream_create (write_func, NULL, closure); - if ((status = _cairo_output_stream_get_status (stream))) - return _cairo_device_create_in_error (status); - - return _cairo_script_context_create (stream); -} - -/** - * cairo_script_write_comment: - * @script: the script (output device) - * @comment: the string to emit - * @len:the length of the sting to write, or -1 to use strlen() - * - * Emit a string verbatim into the script. - * - * Since: 1.12 - **/ -void -cairo_script_write_comment (cairo_device_t *script, - const char *comment, - int len) -{ - cairo_script_context_t *context = (cairo_script_context_t *) script; - - if (len < 0) - len = strlen (comment); - - _cairo_output_stream_puts (context->stream, "% "); - _cairo_output_stream_write (context->stream, comment, len); - _cairo_output_stream_puts (context->stream, "\n"); -} - -/** - * cairo_script_set_mode: - * @script: The script (output device) - * @mode: the new mode - * - * Change the output mode of the script - * - * Since: 1.12 - **/ -void -cairo_script_set_mode (cairo_device_t *script, - cairo_script_mode_t mode) -{ - cairo_script_context_t *context = (cairo_script_context_t *) script; - - context->mode = mode; -} - -/** - * cairo_script_get_mode: - * @script: The script (output device) to query - * - * Queries the script for its current output mode. - * - * Return value: the current output mode of the script - * - * Since: 1.12 - **/ -cairo_script_mode_t -cairo_script_get_mode (cairo_device_t *script) -{ - cairo_script_context_t *context = (cairo_script_context_t *) script; - - return context->mode; -} - -/** - * cairo_script_surface_create: - * @script: the script (output device) - * @content: the content of the surface - * @width: width in pixels - * @height: height in pixels - * - * Create a new surface that will emit its rendering through @script - * - * Return value: a pointer to the newly created surface. The caller - * owns the surface and should call cairo_surface_destroy() when done - * with it. - * - * This function always returns a valid pointer, but it will return a - * pointer to a "nil" surface if an error such as out of memory - * occurs. You can use cairo_surface_status() to check for this. - * - * Since: 1.12 - **/ -cairo_surface_t * -cairo_script_surface_create (cairo_device_t *script, - cairo_content_t content, - double width, - double height) -{ - cairo_rectangle_t *extents, r; - - if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) - return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); - - if (unlikely (script->status)) - return _cairo_surface_create_in_error (script->status); - - extents = NULL; - if (width > 0 && height > 0) { - r.x = r.y = 0; - r.width = width; - r.height = height; - extents = &r; - } - return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, - content, extents, - NULL)->base; -} -slim_hidden_def (cairo_script_surface_create); - -/** - * cairo_script_surface_create_for_target: - * @script: the script (output device) - * @target: a target surface to wrap - * - * Create a pxoy surface that will render to @target and record - * the operations to @device. - * - * Return value: a pointer to the newly created surface. The caller - * owns the surface and should call cairo_surface_destroy() when done - * with it. - * - * This function always returns a valid pointer, but it will return a - * pointer to a "nil" surface if an error such as out of memory - * occurs. You can use cairo_surface_status() to check for this. - * - * Since: 1.12 - **/ -cairo_surface_t * -cairo_script_surface_create_for_target (cairo_device_t *script, - cairo_surface_t *target) -{ - cairo_rectangle_int_t extents; - cairo_rectangle_t rect, *r; - - if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) - return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); - - if (unlikely (script->status)) - return _cairo_surface_create_in_error (script->status); - - if (unlikely (target->status)) - return _cairo_surface_create_in_error (target->status); - - r = NULL; - if (_cairo_surface_get_extents (target, &extents)) { - rect.x = rect.y = 0; - rect.width = extents.width; - rect.height = extents.height; - r= ▭ - } - return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, - target->content, r, - target)->base; -} - -/** - * cairo_script_from_recording_surface: - * @script: the script (output device) - * @recording_surface: the recording surface to replay - * - * Converts the record operations in @recording_surface into a script. - * - * Return value: #CAIRO_STATUS_SUCCESS on successful completion or an error code. - * - * Since: 1.12 - **/ -cairo_status_t -cairo_script_from_recording_surface (cairo_device_t *script, - cairo_surface_t *recording_surface) -{ - cairo_rectangle_t r, *extents; - cairo_surface_t *surface; - cairo_status_t status; - - if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) - return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); - - if (unlikely (script->status)) - return _cairo_error (script->status); - - if (unlikely (recording_surface->status)) - return recording_surface->status; - - if (unlikely (! _cairo_surface_is_recording (recording_surface))) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - - extents = NULL; - if (_cairo_recording_surface_get_bounds (recording_surface, &r)) - extents = &r; - - surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, - recording_surface->content, - extents, - NULL)->base; - if (unlikely (surface->status)) - return surface->status; - - status = _cairo_recording_surface_replay (recording_surface, surface); - cairo_surface_destroy (surface); - - return status; -} |