diff options
Diffstat (limited to 'src/cairo-script-surface.c')
-rw-r--r-- | src/cairo-script-surface.c | 1751 |
1 files changed, 1298 insertions, 453 deletions
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 2585a50..93b09da 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -48,21 +48,43 @@ #include "cairo-analysis-surface-private.h" #include "cairo-ft-private.h" +#include "cairo-list-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-wrapper-private.h" + +#include <ctype.h> #define _cairo_output_stream_puts(S, STR) \ _cairo_output_stream_write ((S), (STR), strlen (STR)) #define static cairo_warn static -typedef struct _cairo_script_vmcontext cairo_script_vmcontext_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_surface_font_private cairo_script_surface_font_private_t; -struct _cairo_script_vmcontext { +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_status_t status; + int ref; + int active; cairo_output_stream_t *stream; cairo_script_mode_t mode; @@ -74,17 +96,19 @@ struct _cairo_script_vmcontext { struct _bitmap *next; } surface_id, font_id; - cairo_script_surface_t *current_target; + cairo_list_t operands; + cairo_list_t deferred; - cairo_script_surface_font_private_t *fonts; + cairo_list_t fonts; + cairo_list_t defines; }; struct _cairo_script_surface_font_private { - cairo_script_vmcontext_t *ctx; + cairo_script_context_t *ctx; cairo_bool_t has_sfnt; unsigned long id; unsigned long subset_glyph_index; - cairo_script_surface_font_private_t *prev, *next; + cairo_list_t link; cairo_scaled_font_t *parent; }; @@ -94,20 +118,29 @@ struct _cairo_script_implicit_context { double current_tolerance; cairo_antialias_t current_antialias; cairo_stroke_style_t current_style; - cairo_pattern_t *current_source; + 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_script_vmcontext_t *ctx; + cairo_surface_wrapper_t wrapper; - unsigned long id; + cairo_script_context_t *ctx; + cairo_surface_clipper_t clipper; + + operand_t operand; + cairo_bool_t emitted; + cairo_bool_t defined; + cairo_bool_t is_clear; + cairo_bool_t active; double width, height; @@ -118,9 +151,14 @@ struct _cairo_script_surface { static const cairo_surface_backend_t _cairo_script_surface_backend; static cairo_script_surface_t * -_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, +_cairo_script_surface_create_internal (cairo_script_context_t *ctx, + cairo_content_t content, double width, - double height); + double height, + cairo_surface_t *passthrough); + +static cairo_status_t +_context_destroy (cairo_script_context_t *ctx); static void _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); @@ -129,6 +167,9 @@ 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; @@ -231,7 +272,23 @@ _operator_to_string (cairo_operator_t op) "XOR", /* CAIRO_OPERATOR_XOR */ "ADD", /* CAIRO_OPERATOR_ADD */ - "SATURATE" /* CAIRO_OPERATOR_SATURATE */ + "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]; @@ -314,65 +371,182 @@ _line_join_to_string (cairo_line_join_t line_join) } static cairo_bool_t -_cairo_script_surface_owns_context (cairo_script_surface_t *surface) +target_is_active (cairo_script_surface_t *surface) { - return surface->ctx->current_target == surface; + return cairo_list_is_first (&surface->operand.link, + &surface->ctx->operands); } -static cairo_status_t -_emit_context (cairo_script_surface_t *surface) +static void +target_push (cairo_script_surface_t *surface) { - if (_cairo_script_surface_owns_context (surface)) - return CAIRO_STATUS_SUCCESS; + cairo_list_move (&surface->operand.link, &surface->ctx->operands); +} + +static int +target_depth (cairo_script_surface_t *surface) +{ + cairo_list_t *link; + int depth = 0; - if (surface->ctx->current_target != NULL) - _cairo_output_stream_puts (surface->ctx->stream, "pop\n"); + cairo_list_foreach (link, &surface->ctx->operands) { + if (link == &surface->operand.link) + break; + depth++; + } - surface->ctx->current_target = surface; + return depth; +} - if (surface->id == (unsigned long) -1) { - cairo_status_t status; +static void +_get_target (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = surface->ctx; - status = _bitmap_next_id (&surface->ctx->surface_id, - &surface->id); - if (unlikely (status)) - return status; + if (surface->defined) { + _cairo_output_stream_printf (ctx->stream, "s%u ", + surface->base.unique_id); + } else { + assert (! cairo_list_is_empty (&surface->operand.link)); + if (! target_is_active (surface)) { + int depth = target_depth (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 (surface->ctx->stream, + "exch\n"); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + "%d -1 roll\n", + depth); + } + _cairo_output_stream_puts (ctx->stream, "/target get "); + target_push (surface); + } + } else { + _cairo_output_stream_puts (ctx->stream, "/target get "); + } + } +} +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_output_stream_printf (surface->ctx->stream, + "<< /content //%s", + _content_to_string (surface->base.content)); + if (surface->width != -1 && surface->height != -1) { _cairo_output_stream_printf (surface->ctx->stream, - "dict\n" - " /width %f set\n" - " /height %f set\n", + " /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 (surface->ctx->stream, - " /fallback-resolution [%f %f] set\n", - surface->base.x_fallback_resolution, - surface->base.y_fallback_resolution); + } + + 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 (surface->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 (surface->ctx->stream, + " /device-offset [%f %f]", + surface->base.device_transform.x0, + surface->base.device_transform.y0); } - if (surface->base.device_transform.x0 != 0. || - surface->base.device_transform.y0 != 0.) - { - /* XXX device offset is encoded into the pattern matrices etc. */ - _cairo_output_stream_printf (surface->ctx->stream, - " %%/device-offset [%f %f] set\n", - surface->base.device_transform.x0, - surface->base.device_transform.y0); + } + + _cairo_output_stream_puts (surface->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 = surface->ctx; + + 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_output_stream_printf (surface->ctx->stream, - " surface dup /s%lu exch def\n" - "context dup /c%lu exch def\n", - surface->id, - surface->id); + + 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 { - _cairo_output_stream_printf (surface->ctx->stream, - "c%lu\n", - surface->id); + 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; } @@ -381,7 +555,7 @@ static cairo_status_t _emit_operator (cairo_script_surface_t *surface, cairo_operator_t op) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (surface->cr.current_operator == op) return CAIRO_STATUS_SUCCESS; @@ -398,7 +572,7 @@ static cairo_status_t _emit_fill_rule (cairo_script_surface_t *surface, cairo_fill_rule_t fill_rule) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (surface->cr.current_fill_rule == fill_rule) return CAIRO_STATUS_SUCCESS; @@ -416,10 +590,14 @@ _emit_tolerance (cairo_script_surface_t *surface, double tolerance, cairo_bool_t force) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); - if (! force && surface->cr.current_tolerance == tolerance) + if ((! force || + fabs (tolerance - CAIRO_GSTATE_TOLERANCE_DEFAULT) < 1e-5) && + surface->cr.current_tolerance == tolerance) + { return CAIRO_STATUS_SUCCESS; + } surface->cr.current_tolerance = tolerance; @@ -433,7 +611,7 @@ static cairo_status_t _emit_antialias (cairo_script_surface_t *surface, cairo_antialias_t antialias) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (surface->cr.current_antialias == antialias) return CAIRO_STATUS_SUCCESS; @@ -452,10 +630,14 @@ _emit_line_width (cairo_script_surface_t *surface, double line_width, cairo_bool_t force) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); - if (! force && surface->cr.current_style.line_width == line_width) + 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; @@ -469,7 +651,7 @@ static cairo_status_t _emit_line_cap (cairo_script_surface_t *surface, cairo_line_cap_t line_cap) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (surface->cr.current_style.line_cap == line_cap) return CAIRO_STATUS_SUCCESS; @@ -486,7 +668,7 @@ static cairo_status_t _emit_line_join (cairo_script_surface_t *surface, cairo_line_join_t line_join) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (surface->cr.current_style.line_join == line_join) return CAIRO_STATUS_SUCCESS; @@ -504,10 +686,14 @@ _emit_miter_limit (cairo_script_surface_t *surface, double miter_limit, cairo_bool_t force) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); - if (! force && surface->cr.current_style.miter_limit == miter_limit) + 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; @@ -517,6 +703,18 @@ _emit_miter_limit (cairo_script_surface_t *surface, 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, @@ -526,7 +724,7 @@ _emit_dash (cairo_script_surface_t *surface, { unsigned int n; - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (force && num_dashes == 0 && @@ -538,9 +736,8 @@ _emit_dash (cairo_script_surface_t *surface, if (! force && (surface->cr.current_style.num_dashes == num_dashes && (num_dashes == 0 || - (surface->cr.current_style.dash_offset == offset && - memcmp (surface->cr.current_style.dash, dash, - sizeof (double) * num_dashes))))) + (fabs (surface->cr.current_style.dash_offset - offset) < 1e-5 && + _dashes_equal (surface->cr.current_style.dash, dash, num_dashes))))) { return CAIRO_STATUS_SUCCESS; } @@ -548,9 +745,10 @@ _emit_dash (cairo_script_surface_t *surface, if (num_dashes) { surface->cr.current_style.dash = _cairo_realloc_ab - (surface->cr.current_style.dash, - num_dashes, - sizeof (double)); + (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 { @@ -563,7 +761,7 @@ _emit_dash (cairo_script_surface_t *surface, surface->cr.current_style.num_dashes = num_dashes; surface->cr.current_style.dash_offset = offset; - _cairo_output_stream_printf (surface->ctx->stream, "["); + _cairo_output_stream_puts (surface->ctx->stream, "["); for (n = 0; n < num_dashes; n++) { _cairo_output_stream_printf (surface->ctx->stream, "%f", dash[n]); if (n < num_dashes-1) @@ -583,7 +781,7 @@ _emit_stroke_style (cairo_script_surface_t *surface, { cairo_status_t status; - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); status = _emit_line_width (surface, style->line_width, force); if (unlikely (status)) @@ -633,9 +831,10 @@ _emit_solid_pattern (cairo_script_surface_t *surface, ! CAIRO_COLOR_IS_OPAQUE (&solid->color)) { if (! (solid->content & CAIRO_CONTENT_COLOR) || - (solid->color.red_short == 0 && - solid->color.green_short == 0 && - solid->color.blue_short == 0)) + ! (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 (surface->ctx->stream, "%f a", @@ -682,7 +881,7 @@ _emit_gradient_color_stops (cairo_gradient_pattern_t *gradient, for (n = 0; n < gradient->n_stops; n++) { _cairo_output_stream_printf (output, - " %f %f %f %f %f add-color-stop\n ", + "\n %f %f %f %f %f add-color-stop", gradient->stops[n].offset, gradient->stops[n].color.red, gradient->stops[n].color.green, @@ -702,7 +901,7 @@ _emit_linear_pattern (cairo_script_surface_t *surface, linear = (cairo_linear_pattern_t *) pattern; _cairo_output_stream_printf (surface->ctx->stream, - "%f %f %f %f linear\n ", + "%f %f %f %f linear", _cairo_fixed_to_double (linear->p1.x), _cairo_fixed_to_double (linear->p1.y), _cairo_fixed_to_double (linear->p2.x), @@ -719,7 +918,7 @@ _emit_radial_pattern (cairo_script_surface_t *surface, radial = (cairo_radial_pattern_t *) pattern; _cairo_output_stream_printf (surface->ctx->stream, - "%f %f %f %f %f %f radial\n ", + "%f %f %f %f %f %f radial", _cairo_fixed_to_double (radial->c1.x), _cairo_fixed_to_double (radial->c1.y), _cairo_fixed_to_double (radial->r1), @@ -733,55 +932,59 @@ static cairo_status_t _emit_meta_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { + cairo_script_implicit_context_t old_cr; cairo_surface_pattern_t *surface_pattern; - cairo_surface_t *source; - cairo_surface_t *null_surface; - cairo_surface_t *analysis_surface; - cairo_surface_t *similar; + cairo_meta_surface_t *source; + cairo_script_surface_t *similar; cairo_status_t status; cairo_box_t bbox; + cairo_rectangle_int_t rect; surface_pattern = (cairo_surface_pattern_t *) pattern; - source = surface_pattern->surface; + source = (cairo_meta_surface_t *) surface_pattern->surface; /* first measure the extents */ - null_surface = _cairo_null_surface_create (source->content); - analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); - cairo_surface_destroy (null_surface); - - status = analysis_surface->status; + status = _cairo_meta_surface_get_bbox (source, &bbox, NULL); if (unlikely (status)) return status; - status = _cairo_meta_surface_replay (source, analysis_surface); - _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); - cairo_surface_destroy (analysis_surface); - if (unlikely (status)) - return status; + /* convert to extents so that it matches the public api */ + _cairo_box_round_to_rectangle (&bbox, &rect); - similar = cairo_surface_create_similar (&surface->base, - source->content, - _cairo_fixed_to_double (bbox.p2.x-bbox.p1.x), - _cairo_fixed_to_double (bbox.p2.y-bbox.p1.y)); - if (similar->status) - return similar->status; + similar = _cairo_script_surface_create_internal (surface->ctx, + source->content, + rect.width, + rect.height, + NULL); + if (unlikely (similar->base.status)) + return similar->base.status; - status = _cairo_meta_surface_replay (source, similar); - if (unlikely (status)) { - cairo_surface_destroy (similar); - return status; - } + cairo_surface_set_device_offset (&similar->base, -rect.x, -rect.y); + surface->is_clear = TRUE; + + _get_target (surface); + _cairo_output_stream_printf (surface->ctx->stream, + "%d %d //%s similar dup context\n", + rect.width, rect.height, + _content_to_string (source->content)); + target_push (similar); + similar->emitted = TRUE; + + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = _cairo_meta_surface_replay (&source->base, &similar->base); + surface->cr = old_cr; - status = _emit_context (surface); if (unlikely (status)) { - cairo_surface_destroy (similar); + cairo_surface_destroy (&similar->base); return status; } - _cairo_output_stream_printf (surface->ctx->stream, - "s%lu pattern\n ", - ((cairo_script_surface_t *) similar)->id); - cairo_surface_destroy (similar); + cairo_list_del (&similar->operand.link); + assert (target_is_active (surface)); + + _cairo_output_stream_puts (surface->ctx->stream, "pop pattern"); + cairo_surface_destroy (&similar->base); return CAIRO_STATUS_SUCCESS; } @@ -796,8 +999,8 @@ _emit_script_surface_pattern (cairo_script_surface_t *surface, surface_pattern = (cairo_surface_pattern_t *) pattern; source = (cairo_script_surface_t *) surface_pattern->surface; - _cairo_output_stream_printf (surface->ctx->stream, - "s%lu pattern\n ", source->id); + _get_target (source); + _cairo_output_stream_puts (surface->ctx->stream, "pattern"); return CAIRO_STATUS_SUCCESS; } @@ -924,12 +1127,12 @@ _emit_png_surface (cairo_script_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; _cairo_output_stream_printf (surface->ctx->stream, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //%s set\n" - " /mime-type (image/png) set\n" - " /source <~", + "<< " + "/width %d " + "/height %d " + "/format //%s " + "/mime-type (image/png) " + "/source <~", image->width, image->height, _format_to_string (image->format)); @@ -939,11 +1142,27 @@ _emit_png_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, - " set\n image"); + _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); return CAIRO_STATUS_SUCCESS; } +struct def { + cairo_script_context_t *ctx; + cairo_user_data_array_t *user_data; + unsigned int tag; + cairo_list_t link; +}; + +static void +_undef (void *data) +{ + struct def *def = data; + + cairo_list_del (&def->link); + _cairo_output_stream_printf (def->ctx->stream, "/s%u undef\n", def->tag); + free (def); +} + static cairo_status_t _emit_image_surface (cairo_script_surface_t *surface, cairo_image_surface_t *image) @@ -953,25 +1172,67 @@ _emit_image_surface (cairo_script_surface_t *surface, cairo_status_t status, status2; const uint8_t *mime_data; unsigned int mime_data_length; + struct def *tag; + + if (_cairo_user_data_array_get_data (&image->base.user_data, + (cairo_user_data_key_t *) surface->ctx)) + { + _cairo_output_stream_printf (surface->ctx->stream, + "s%u pattern ", + image->base.unique_id); + return CAIRO_STATUS_SUCCESS; + } status = _emit_png_surface (surface, image); if (_cairo_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, + _cairo_format_from_content (image->base.content)); + } else { + clone = (cairo_image_surface_t *) + cairo_surface_reference (&image->base); + } + _cairo_output_stream_printf (surface->ctx->stream, - "dict\n" - " /width %d set\n" - " /height %d set\n" - " /format //%s set\n" - " /source <~", - image->width, image->height, - _format_to_string (image->format)); - - if (image->width * image->height > 8) { + "<< " + "/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_RGB24: + len = clone->width * 3; + break; + case CAIRO_FORMAT_ARGB32: + len = clone->width * 4; + break; + } + len *= clone->height; + + if (len > 24) { + _cairo_output_stream_puts (surface->ctx->stream, "<|"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); - zlib_stream = _cairo_deflate_stream_create (base85_stream); - status = _write_image_surface (zlib_stream, image); + _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_STATUS_SUCCESS) @@ -981,26 +1242,47 @@ _emit_image_surface (cairo_script_surface_t *surface, status = status2; if (unlikely (status)) return status; - - _cairo_output_stream_puts (surface->ctx->stream, - " /deflate filter set\n image"); } else { + _cairo_output_stream_puts (surface->ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); - status = _write_image_surface (base85_stream, image); + status = _write_image_surface (base85_stream, clone); status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; - - _cairo_output_stream_puts (surface->ctx->stream, - " set\n image"); + if (unlikely (status)) + return status; } + _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); + + cairo_surface_destroy (&clone->base); + } + + tag = malloc (sizeof (*tag)); + if (unlikely (tag == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + tag->ctx = surface->ctx; + tag->tag = image->base.unique_id; + tag->user_data = &image->base.user_data; + cairo_list_add (&tag->link, &surface->ctx->defines); + status = _cairo_user_data_array_set_data (&image->base.user_data, + (cairo_user_data_key_t *) surface->ctx, + tag, _undef); + if (unlikely (status)) { + free (tag); + return status; } + _cairo_output_stream_printf (surface->ctx->stream, + "dup /s%u exch def ", + image->base.unique_id); + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); if (mime_data != NULL) { _cairo_output_stream_printf (surface->ctx->stream, - "\n (%s) <~", + "\n (%s) <~", CAIRO_MIME_TYPE_JPEG); base85_stream = _cairo_base85_stream_create (surface->ctx->stream); @@ -1009,14 +1291,28 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, - " set-mime-data\n "); + _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n"); } - _cairo_output_stream_puts (surface->ctx->stream, - " pattern\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 (surface->ctx->stream, + "\n (%s) <~", + CAIRO_MIME_TYPE_JP2); - return status; + base85_stream = _cairo_base85_stream_create (surface->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 (surface->ctx->stream, "~> set-mime-data\n"); + } + + _cairo_output_stream_puts (surface->ctx->stream, "pattern"); + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1024,22 +1320,17 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_surface_pattern_t *surface_pattern; - cairo_surface_t *source; cairo_image_surface_t *image; - void *image_extra; cairo_status_t status; + /* XXX keeping a copy is nasty, but we want to hook into the surface's + * lifetime. Using a snapshot is a convenient method. + */ surface_pattern = (cairo_surface_pattern_t *) pattern; - source = surface_pattern->surface; - - /* XXX snapshot-cow */ - status = _cairo_surface_acquire_source_image (source, &image, &image_extra); - if (unlikely (status)) - return status; - + image = (cairo_image_surface_t *) + _cairo_surface_snapshot (surface_pattern->surface); status = _emit_image_surface (surface, image); - - _cairo_surface_release_source_image (source, image, image_extra); + cairo_surface_destroy (&image->base); return status; } @@ -1055,7 +1346,7 @@ _emit_surface_pattern (cairo_script_surface_t *surface, source = surface_pattern->surface; switch ((int) source->type) { - case CAIRO_INTERNAL_SURFACE_TYPE_META: + case CAIRO_SURFACE_TYPE_META: return _emit_meta_surface_pattern (surface, pattern); case CAIRO_SURFACE_TYPE_SCRIPT: return _emit_script_surface_pattern (surface, pattern); @@ -1069,6 +1360,8 @@ _emit_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_status_t status; + cairo_bool_t is_default_extend; + cairo_bool_t need_newline = TRUE; switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: @@ -1077,12 +1370,15 @@ _emit_pattern (cairo_script_surface_t *surface, 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_SURFACE: status = _emit_surface_pattern (surface, pattern); + is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT; break; default: @@ -1093,6 +1389,11 @@ _emit_pattern (cairo_script_surface_t *surface, return status; if (! _cairo_matrix_is_identity (&pattern->matrix)) { + if (need_newline) { + _cairo_output_stream_puts (surface->ctx->stream, "\n "); + need_newline = FALSE; + } + _cairo_output_stream_printf (surface->ctx->stream, " [%f %f %f %f %f %f] set-matrix\n ", pattern->matrix.xx, pattern->matrix.yx, @@ -1100,11 +1401,30 @@ _emit_pattern (cairo_script_surface_t *surface, pattern->matrix.x0, pattern->matrix.y0); } - _cairo_output_stream_printf (surface->ctx->stream, - " //%s set-extend\n " - " //%s set-filter\n ", - _extend_to_string (pattern->extend), - _filter_to_string (pattern->filter)); + /* XXX need to discriminate the user explicitly setting the default */ + if (pattern->filter != CAIRO_FILTER_DEFAULT) { + if (need_newline) { + _cairo_output_stream_puts (surface->ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (surface->ctx->stream, + " //%s set-filter\n ", + _filter_to_string (pattern->filter)); + } + if (! is_default_extend ){ + if (need_newline) { + _cairo_output_stream_puts (surface->ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (surface->ctx->stream, + " //%s set-extend\n ", + _extend_to_string (pattern->extend)); + } + + if (need_newline) + _cairo_output_stream_puts (surface->ctx->stream, "\n "); return CAIRO_STATUS_SUCCESS; } @@ -1113,7 +1433,7 @@ static cairo_status_t _emit_identity (cairo_script_surface_t *surface, cairo_bool_t *matrix_updated) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) return CAIRO_STATUS_SUCCESS; @@ -1135,22 +1455,19 @@ _emit_source (cairo_script_surface_t *surface, cairo_bool_t matrix_updated = FALSE; cairo_status_t status; - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (op == CAIRO_OPERATOR_CLEAR) { /* the source is ignored, so don't change it */ return CAIRO_STATUS_SUCCESS; } - if (surface->cr.current_source == source) + if (_cairo_pattern_equal (&surface->cr.current_source.base, source)) return CAIRO_STATUS_SUCCESS; - if (_cairo_pattern_equal (surface->cr.current_source, source)) - return CAIRO_STATUS_SUCCESS; - - cairo_pattern_destroy (surface->cr.current_source); - status = _cairo_pattern_create_copy (&surface->cr.current_source, - source); + _cairo_pattern_fini (&surface->cr.current_source.base); + status = _cairo_pattern_init_copy (&surface->cr.current_source.base, + source); if (unlikely (status)) return status; @@ -1225,7 +1542,7 @@ _emit_path (cairo_script_surface_t *surface, cairo_box_t box; cairo_status_t status; - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); assert (_cairo_matrix_is_identity (&surface->cr.current_ctm)); if (_cairo_path_fixed_equal (&surface->cr.current_path, path)) @@ -1237,7 +1554,7 @@ _emit_path (cairo_script_surface_t *surface, if (path == NULL) { _cairo_path_fixed_init (&surface->cr.current_path); - } else if (_cairo_path_fixed_is_rectangle (path, &box)) { + } else if (_cairo_path_fixed_is_box (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); @@ -1272,29 +1589,46 @@ _emit_path (cairo_script_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +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_matrix (cairo_script_surface_t *surface, - const cairo_matrix_t *ctm, - cairo_bool_t *matrix_updated) +_emit_scaling_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *ctm, + cairo_bool_t *matrix_updated) { - assert (_cairo_script_surface_owns_context (surface)); + cairo_bool_t was_identity; + assert (target_is_active (surface)); - if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0) + 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 (ctm)) { + if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) { _cairo_output_stream_puts (surface->ctx->stream, "identity set-matrix\n"); + } else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) { + _cairo_output_stream_printf (surface->ctx->stream, + "%f %f scale\n", + ctm->xx, ctm->yy); } else { _cairo_output_stream_printf (surface->ctx->stream, - "[%f %f %f %f %f %f] set-matrix\n", + "[%f %f %f %f 0 0] set-matrix\n", ctm->xx, ctm->yx, - ctm->xy, ctm->yy, - ctm->x0, ctm->y0); + ctm->xy, ctm->yy); } return CAIRO_STATUS_SUCCESS; @@ -1304,7 +1638,7 @@ static cairo_status_t _emit_font_matrix (cairo_script_surface_t *surface, const cairo_matrix_t *font_matrix) { - assert (_cairo_script_surface_owns_context (surface)); + assert (target_is_active (surface)); if (memcmp (&surface->cr.current_font_matrix, font_matrix, @@ -1329,92 +1663,87 @@ _emit_font_matrix (cairo_script_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -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_surface_t * _cairo_script_surface_create_similar (void *abstract_surface, cairo_content_t content, int width, int height) { - cairo_script_surface_t *surface, *other; - cairo_script_vmcontext_t *ctx; + cairo_script_surface_t *surface, *other = abstract_surface; + cairo_surface_t *passthrough = NULL; + cairo_script_context_t *ctx; cairo_status_t status; - other = abstract_surface; ctx = other->ctx; - if (other->id == (unsigned long) -1) { - cairo_status_t status; - - status = _bitmap_next_id (&ctx->surface_id, - &other->id); + if (! other->emitted) { + status = _emit_surface (other); if (unlikely (status)) return _cairo_surface_create_in_error (status); - _cairo_output_stream_printf (ctx->stream, - "dict\n" - " /width %f set\n" - " /height %f set\n" - " surface dup /s%lu exch def\n" - "context /c%lu exch def\n", - other->width, - other->height, - other->id, - other->id); + target_push (other); } - - surface = _cairo_script_surface_create_internal (ctx, width, height); - if (surface->base.status) - return &surface->base; - - status = _bitmap_next_id (&ctx->surface_id, - &surface->id); - if (unlikely (status)) { - cairo_surface_destroy (&surface->base); - return _cairo_surface_create_in_error (status); + if (_cairo_surface_wrapper_is_active (&other->wrapper)) { + passthrough = + _cairo_surface_wrapper_create_similar (&other->wrapper, + content, width, height); + if (unlikely (passthrough->status)) + return passthrough; } - if (ctx->current_target != NULL) - _cairo_output_stream_printf (ctx->stream, "pop\n"); + surface = _cairo_script_surface_create_internal (ctx, + content, + width, height, + passthrough); + cairo_surface_destroy (passthrough); + if (unlikely (surface->base.status)) + return &surface->base; + + _get_target (other); _cairo_output_stream_printf (ctx->stream, - "s%lu %u %u //%s similar dup /s%lu exch def\n" - "context dup /c%lu exch def\n", - other->id, width, height, + "%u %u //%s similar dup /s%u exch def context\n", + width, height, _content_to_string (content), - surface->id, - surface->id); - - ctx->current_target = surface; + surface->base.unique_id); + surface->emitted = TRUE; + surface->defined = TRUE; + surface->is_clear = TRUE; + target_push (surface); return &surface->base; } static cairo_status_t -_vmcontext_destroy (cairo_script_vmcontext_t *ctx) +_context_destroy (cairo_script_context_t *ctx) { cairo_status_t status; + assert (ctx->ref > 0); if (--ctx->ref) return _cairo_output_stream_flush (ctx->stream); - while (ctx->fonts != NULL ){ - cairo_script_surface_font_private_t *font = ctx->fonts; - ctx->fonts = font->next; + while (! cairo_list_is_empty (&ctx->fonts)) { + cairo_script_surface_font_private_t *font; + + font = cairo_list_first_entry (&ctx->fonts, + cairo_script_surface_font_private_t, + link); + cairo_list_del (&font->link); _cairo_script_surface_scaled_font_fini (font->parent); } + while (! cairo_list_is_empty (&ctx->defines)) { + struct def *def = cairo_list_first_entry (&ctx->defines, + struct def, link); + + status = _cairo_user_data_array_set_data (def->user_data, + (cairo_user_data_key_t *) ctx, + NULL, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + } + status = _cairo_output_stream_destroy (ctx->stream); free (ctx); @@ -1423,29 +1752,96 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx) } 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_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; - cairo_pattern_destroy (surface->cr.current_source); - _cairo_path_fixed_fini (&surface->cr.current_path); + _cairo_surface_wrapper_fini (&surface->wrapper); - if (surface->ctx->current_target == surface) { - _cairo_output_stream_printf (surface->ctx->stream, - "pop\n"); - surface->ctx->current_target = NULL; + if (surface->cr.current_style.dash != NULL) { + 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); + + if (surface->emitted) { + assert (! surface->active); + + if (! cairo_list_is_empty (&surface->operand.link)) { + if (! surface->ctx->active) { + if (target_is_active (surface)) { + _cairo_output_stream_printf (surface->ctx->stream, + "pop\n"); + } else { + int depth = target_depth (surface); + if (depth == 1) { + _cairo_output_stream_printf (surface->ctx->stream, + "exch pop\n"); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + "%d -1 roll pop\n", + depth); + } + } + cairo_list_del (&surface->operand.link); + } else { + struct deferred_finish *link = 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, &surface->ctx->deferred); + } + } + } - _cairo_output_stream_printf (surface->ctx->stream, - "/c%lu undef\n" - "/s%lu undef\n", - surface->id, - surface->id); - - _bitmap_release_id (&surface->ctx->surface_id, surface->id); + if (surface->defined) { + _cairo_output_stream_printf (surface->ctx->stream, + "/s%u undef\n", + surface->base.unique_id); + } + } - status = _vmcontext_destroy (surface->ctx); + status2 = _context_destroy (surface->ctx); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; return status; } @@ -1480,26 +1876,44 @@ _cairo_script_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_script_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_script_surface_t *surface = abstract_surface; +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_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) { - _cairo_output_stream_puts (surface->ctx->stream, "reset-clip\n"); + if (surface->cr.has_clip) { + _cairo_output_stream_puts (surface->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 - box.p1.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + status = _emit_identity (surface, &matrix_updated); if (unlikely (status)) return status; @@ -1508,37 +1922,137 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } - status = _emit_antialias (surface, antialias); - if (unlikely (status)) - return status; + if (! path->maybe_fill_region) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + } status = _emit_path (surface, path); if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "clip+\n"); + surface->cr.has_clip = TRUE; return CAIRO_STATUS_SUCCESS; } +static void +active (cairo_script_surface_t *surface) +{ + if (surface->active++ == 0) + surface->ctx->active++; +} + +static void +inactive (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = surface->ctx; + cairo_list_t sorted; + + if (--surface->active) + return; + + if (--ctx->active) + return; + + 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); + } +} + static cairo_int_status_t _cairo_script_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - status = _emit_context (surface); + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->is_clear) + goto DONE; + } + + active (surface); + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1546,9 +2060,23 @@ _cairo_script_surface_paint (void *abstract_surface, if (unlikely (status)) return status; + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + _cairo_output_stream_puts (surface->ctx->stream, "paint\n"); + surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL; + + inactive (surface); + + DONE: + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_paint (&surface->wrapper, + op, source, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1557,16 +2085,23 @@ _cairo_script_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - status = _emit_context (surface); + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->is_clear) + goto DONE; + } + + active (surface); + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1574,13 +2109,33 @@ _cairo_script_surface_mask (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_pattern (surface, mask); + status = _emit_operator (surface, op); if (unlikely (status)) return status; + if (_cairo_pattern_equal (source, mask)) { + _cairo_output_stream_puts (surface->ctx->stream, "/source get"); + } else { + status = _emit_pattern (surface, mask); + if (unlikely (status)) + return status; + } + + assert (surface->cr.current_operator == op); + _cairo_output_stream_puts (surface->ctx->stream, " mask\n"); + surface->is_clear = FALSE; + + inactive (surface); + + DONE: + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_mask (&surface->wrapper, + op, source, mask, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1594,12 +2149,23 @@ _cairo_script_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_bool_t matrix_updated = FALSE; cairo_status_t status; + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->is_clear) + goto DONE; + } + + active (surface); + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1616,7 +2182,7 @@ _cairo_script_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_matrix (surface, ctm, &matrix_updated); + status = _emit_scaling_matrix (surface, ctm, &matrix_updated); if (unlikely (status)) return status; @@ -1624,13 +2190,26 @@ _cairo_script_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; + 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)) return status; - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } status = _emit_antialias (surface, antialias); if (unlikely (status)) @@ -1638,6 +2217,20 @@ _cairo_script_surface_stroke (void *abstract_surface, _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); + surface->is_clear = FALSE; + + inactive (surface); + + DONE: + 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; } @@ -1649,17 +2242,25 @@ _cairo_script_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + 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 = _emit_context (surface); + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->is_clear) + goto DONE; + } + + active (surface); + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1671,27 +2272,62 @@ _cairo_script_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_fill_rule (surface, fill_rule); - if (unlikely (status)) - return status; + if (! _cairo_path_fixed_is_box (path, &box)) { + status = _emit_fill_rule (surface, fill_rule); + if (unlikely (status)) + return status; + } - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } - status = _emit_antialias (surface, antialias); + if (! path->maybe_fill_region) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + } + + status = _emit_path (surface, path); if (unlikely (status)) return status; - status = _emit_path (surface, path); + status = _emit_operator (surface, op); if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "fill+\n"); + surface->is_clear = FALSE; + + inactive (surface); + + DONE: + 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; } +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) { @@ -1743,11 +2379,11 @@ _emit_font_options (cairo_script_surface_t *surface, return CAIRO_STATUS_SUCCESS; } - _cairo_output_stream_printf (surface->ctx->stream, "dict\n"); + _cairo_output_stream_printf (surface->ctx->stream, "<<"); if (font_options->antialias != surface->cr.current_font_options.antialias) { _cairo_output_stream_printf (surface->ctx->stream, - " /antialias //%s set\n", + " /antialias //%s", _antialias_to_string (font_options->antialias)); } @@ -1755,7 +2391,7 @@ _emit_font_options (cairo_script_surface_t *surface, surface->cr.current_font_options.subpixel_order) { _cairo_output_stream_printf (surface->ctx->stream, - " /subpixel-order //%s set\n", + " /subpixel-order //%s", _subpixel_order_to_string (font_options->subpixel_order)); } @@ -1763,7 +2399,7 @@ _emit_font_options (cairo_script_surface_t *surface, surface->cr.current_font_options.hint_style) { _cairo_output_stream_printf (surface->ctx->stream, - " /hint-style //%s set\n", + " /hint-style //%s", _hint_style_to_string (font_options->hint_style)); } @@ -1771,16 +2407,14 @@ _emit_font_options (cairo_script_surface_t *surface, surface->cr.current_font_options.hint_metrics) { _cairo_output_stream_printf (surface->ctx->stream, - " /hint-metrics //%s set\n", + " /hint-metrics //%s", _hint_metrics_to_string (font_options->hint_metrics)); } _cairo_output_stream_printf (surface->ctx->stream, - " set-font-options\n"); + " >> set-font-options\n"); surface->cr.current_font_options = *font_options; - - return CAIRO_STATUS_SUCCESS; } @@ -1792,19 +2426,12 @@ _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) font_private = scaled_font->surface_private; if (font_private != NULL) { _cairo_output_stream_printf (font_private->ctx->stream, - "/f%lu undef\n", + "/f%lu undef /sf%lu undef\n", + font_private->id, font_private->id); _bitmap_release_id (&font_private->ctx->font_id, font_private->id); - - if (font_private->prev != NULL) - font_private->prev = font_private->next; - else - font_private->ctx->fonts = font_private->next; - - if (font_private->next != NULL) - font_private->next = font_private->prev; - + cairo_list_del (&font_private->link); free (font_private); scaled_font->surface_private = NULL; @@ -1822,6 +2449,7 @@ _emit_type42_font (cairo_script_surface_t *surface, cairo_status_t status, status2; unsigned long size; unsigned int load_flags; + uint32_t len; uint8_t *buf; backend = scaled_font->backend; @@ -1845,15 +2473,17 @@ _emit_type42_font (cairo_script_surface_t *surface, load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font); _cairo_output_stream_printf (surface->ctx->stream, - "dict\n" - " /type 42 set\n" - " /size %lu set\n" - " /index 0 set\n" - " /flags %d set\n" - " /source <~", - size, load_flags); + "<< " + "/type 42 " + "/index 0 " + "/flags %d " + "/source <|", + load_flags); base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + len = 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); @@ -1869,8 +2499,7 @@ _emit_type42_font (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; _cairo_output_stream_printf (surface->ctx->stream, - " /deflate filter set\n" - " font dup /f%lu exch def set-font-face\n", + "~> >> font dup /f%lu exch def set-font-face", font_private->id); return status; @@ -1892,11 +2521,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, font_private->subset_glyph_index = 0; font_private->has_sfnt = TRUE; - font_private->next = font_private->ctx->fonts; - font_private->prev = NULL; - if (font_private->ctx->fonts != NULL) - font_private->ctx->fonts->prev = font_private; - font_private->ctx->fonts = font_private; + cairo_list_add (&font_private->link, &surface->ctx->fonts); status = _bitmap_next_id (&surface->ctx->font_id, &font_private->id); @@ -1922,7 +2547,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, " /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\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, @@ -1944,40 +2569,47 @@ _emit_scaled_font (cairo_script_surface_t *surface, cairo_script_surface_font_private_t *font_private; cairo_scaled_font_get_ctm (scaled_font, &matrix); - status = _emit_matrix (surface, &matrix, &matrix_updated); + 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; - 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; - surface->cr.current_scaled_font = scaled_font; - assert (scaled_font->surface_backend == NULL || - scaled_font->surface_backend == &_cairo_script_surface_backend); + if (! (scaled_font->surface_backend == NULL || + scaled_font->surface_backend == &_cairo_script_surface_backend)) + { + _cairo_scaled_font_revoke_ownership (scaled_font); + } font_private = scaled_font->surface_private; if (font_private == NULL) { - status = _emit_scaled_font_init (surface, scaled_font); + cairo_scaled_font_get_font_matrix (scaled_font, &matrix); + status = _emit_font_matrix (surface, &matrix); if (unlikely (status)) return status; - } else { - status = _emit_context (surface); + + 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); + if (unlikely (status)) + return status; + + font_private = scaled_font->surface_private; + assert (font_private != NULL); + + assert (target_is_active (surface)); + _cairo_output_stream_printf (surface->ctx->stream, + " /scaled-font get /sf%lu exch def\n", + font_private->id); + } else { _cairo_output_stream_printf (surface->ctx->stream, - "f%lu set-font-face\n", + "sf%lu set-scaled-font\n", font_private->id); } @@ -1999,8 +2631,8 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, scaled_glyph->surface_private = (void *) index; _cairo_output_stream_printf (surface->ctx->stream, - "%lu dict\n" - " /metrics [%f %f %f %f %f %f] set\n" + "%lu <<\n" + " /metrics [%f %f %f %f %f %f]\n" " /render {\n", index, scaled_glyph->fs_metrics.x_bearing, @@ -2024,10 +2656,10 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, old_cr = surface->cr; _cairo_script_implicit_context_init (&surface->cr); status = _cairo_meta_surface_replay (scaled_glyph->meta_surface, - &surface->base); + &surface->base); surface->cr = old_cr; - _cairo_output_stream_puts (surface->ctx->stream, "} set set\n"); + _cairo_output_stream_puts (surface->ctx->stream, "} >> set\n"); return status; } @@ -2046,8 +2678,8 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, scaled_glyph->surface_private = (void *) index; _cairo_output_stream_printf (surface->ctx->stream, - "%lu dict\n" - " /metrics [%f %f %f %f %f %f] set\n" + "%lu <<\n" + " /metrics [%f %f %f %f %f %f]\n" " /render {\n" "%f %f translate\n", index, @@ -2066,7 +2698,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { _cairo_output_stream_printf (surface->ctx->stream, - " [%f %f %f %f %f %f] set-matrix\n", + "\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, @@ -2075,7 +2707,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, scaled_font->font_matrix.y0); } _cairo_output_stream_puts (surface->ctx->stream, - "mask\n} set set\n"); + "mask\n} >> set\n"); return CAIRO_STATUS_SUCCESS; } @@ -2188,6 +2820,65 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, return status; } +static void +_emit_string_literal (cairo_script_surface_t *surface, + const char *utf8, int len) +{ + char c; + const char *end; + + _cairo_output_stream_puts (surface->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 (surface->ctx->stream, "\\%c", c); + break; + default: + if (isprint (c) || isspace (c)) { + _cairo_output_stream_printf (surface->ctx->stream, "%c", c); + } else { + int octal = 0; + while (c) { + octal *= 10; + octal += c&7; + c /= 8; + } + _cairo_output_stream_printf (surface->ctx->stream, + "\\%03d", octal); + } + break; + } + } + _cairo_output_stream_puts (surface->ctx->stream, ")"); +} + static cairo_int_status_t _cairo_script_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, @@ -2200,7 +2891,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t backward, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_script_surface_font_private_t *font_private; @@ -2211,11 +2902,18 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, int n; cairo_output_stream_t *base85_stream = NULL; - status = _emit_context (surface); + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->is_clear) + goto DONE; + } + + active (surface); + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -2227,6 +2925,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, if (unlikely (status)) return status; + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); if (unlikely (status)) return status; @@ -2235,9 +2937,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, /* [cx cy [glyphs]] show_glyphs */ if (utf8 != NULL && clusters != NULL) { - _cairo_output_stream_printf (surface->ctx->stream, - "(%s) ", - utf8); + _emit_string_literal (surface, utf8, utf8_len); + _cairo_output_stream_puts (surface->ctx->stream, " "); } matrix = surface->cr.current_ctm; @@ -2270,6 +2971,9 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, _cairo_scaled_font_thaw_cache (scaled_font); return status; } + + if ((long unsigned) scaled_glyph->surface_private > 256) + break; } } @@ -2290,26 +2994,45 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, break; if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { - 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; + 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 (surface->ctx->stream, + "~> %f <~", glyphs[n].x - x); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + " ] %f [ ", glyphs[n].x - x); } - _cairo_output_stream_printf (surface->ctx->stream, - " %f %f <~", - ix, iy); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + x = glyphs[n].x; } else { - _cairo_output_stream_printf (surface->ctx->stream, - " ] %f %f [ ", - ix, iy); + 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 (surface->ctx->stream, + "~> %f %f <~", + ix, iy); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + } else { + _cairo_output_stream_printf (surface->ctx->stream, + " ] %f %f [ ", + ix, iy); + } } } if (base85_stream != NULL) { @@ -2344,6 +3067,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; + + _cairo_output_stream_printf (surface->ctx->stream, "~>"); } else { _cairo_output_stream_puts (surface->ctx->stream, " ]"); } @@ -2382,6 +3107,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) return status; + + _cairo_output_stream_puts (surface->ctx->stream, "~>"); } _cairo_output_stream_printf (surface->ctx->stream, @@ -2392,24 +3119,45 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, "] show-glyphs\n"); } + surface->is_clear = FALSE; + + inactive (surface); + + DONE: + 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; } -static cairo_int_status_t +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 CAIRO_INT_STATUS_UNSUPPORTED; + return FALSE; rectangle->x = 0; rectangle->y = 0; rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } static const cairo_surface_backend_t @@ -2417,8 +3165,8 @@ _cairo_script_surface_backend = { CAIRO_SURFACE_TYPE_SCRIPT, _cairo_script_surface_create_similar, _cairo_script_surface_finish, - NULL, //_cairo_script_surface_acquire_source_image, - NULL, //_cairo_script_surface_release_source_image, + _cairo_script_surface_acquire_source_image, + _cairo_script_surface_release_source_image, NULL, /* acquire_dest_image */ NULL, /* release_dest_image */ NULL, /* clone_similar */ @@ -2429,8 +3177,6 @@ _cairo_script_surface_backend = { NULL, /* check_span_renderer */ _cairo_script_surface_copy_page, _cairo_script_surface_show_page, - NULL, /* set_clip_region */ - _cairo_script_surface_intersect_clip_path, _cairo_script_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -2446,10 +3192,10 @@ _cairo_script_surface_backend = { _cairo_script_surface_fill, NULL, - NULL, //_cairo_script_surface_snapshot, + _cairo_script_surface_snapshot, NULL, /* is_similar */ - NULL, /* reset */ + /* XXX need fill-stroke for passthrough */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -2459,29 +3205,6 @@ _cairo_script_surface_backend = { _cairo_script_surface_show_text_glyphs }; -static cairo_bool_t -_cairo_surface_is_script (cairo_surface_t *surface) -{ - return surface->backend == &_cairo_script_surface_backend; -} - -static cairo_script_vmcontext_t * -_cairo_script_vmcontext_create (cairo_output_stream_t *stream) -{ - cairo_script_vmcontext_t *ctx; - - ctx = malloc (sizeof (cairo_script_vmcontext_t)); - if (unlikely (ctx == NULL)) - return NULL; - - memset (ctx, 0, sizeof (cairo_script_vmcontext_t)); - - ctx->stream = stream; - ctx->mode = CAIRO_SCRIPT_MODE_ASCII; - - return ctx; -} - static void _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) { @@ -2490,23 +3213,42 @@ _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT; _cairo_stroke_style_init (&cr->current_style); - cr->current_source = (cairo_pattern_t *) &_cairo_pattern_black.base; + _cairo_pattern_init_solid (&cr->current_source.solid, + CAIRO_COLOR_BLACK, + CAIRO_CONTENT_COLOR); _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) +{ + if (cr->current_style.dash != NULL) { + 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_vmcontext_t *ctx, +_cairo_script_surface_create_internal (cairo_script_context_t *ctx, + cairo_content_t content, double width, - double height) + double height, + 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_NO_MEMORY)); + return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); surface = malloc (sizeof (cairo_script_surface_t)); if (unlikely (surface == NULL)) @@ -2514,7 +3256,12 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, _cairo_surface_init (&surface->base, &_cairo_script_surface_backend, - CAIRO_CONTENT_COLOR_ALPHA); + content); + + _cairo_surface_wrapper_init (&surface->wrapper, passthrough); + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_script_surface_clipper_intersect_clip_path); surface->ctx = ctx; ctx->ref++; @@ -2522,82 +3269,180 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, surface->width = width; surface->height = height; - surface->id = (unsigned long) -1; + surface->emitted = FALSE; + surface->defined = FALSE; + surface->is_clear = FALSE; + surface->active = FALSE; + surface->operand.type = SURFACE; + cairo_list_init (&surface->operand.link); _cairo_script_implicit_context_init (&surface->cr); return surface; } -cairo_surface_t * -cairo_script_surface_create (const char *filename, - double width, - double height) +static const cairo_script_context_t _nil_context = { + CAIRO_STATUS_NO_MEMORY, + -1 +}; + +static cairo_script_context_t * +_cairo_script_context_create_internal (cairo_output_stream_t *stream) +{ + cairo_script_context_t *ctx; + + ctx = malloc (sizeof (cairo_script_context_t)); + if (unlikely (ctx == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_script_context_t *) &_nil_context; + } + + memset (ctx, 0, sizeof (cairo_script_context_t)); + ctx->status = CAIRO_STATUS_SUCCESS; + ctx->ref = 1; + + 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); + + _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n"); + + return ctx; +} + +cairo_script_context_t * +cairo_script_context_create (const char *filename) { cairo_output_stream_t *stream; - cairo_script_surface_t *surface; stream = _cairo_output_stream_create_for_filename (filename); if (_cairo_output_stream_get_status (stream)) - return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + return (cairo_script_context_t *) &_nil_context; - - surface = _cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height); - if (surface->base.status) - return &surface->base; - - _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n"); - return &surface->base; + return _cairo_script_context_create_internal (stream); } -cairo_surface_t * -cairo_script_surface_create_for_stream (cairo_write_func_t write_func, - void *closure, - double width, - double height) +cairo_script_context_t * +cairo_script_context_create_for_stream (cairo_write_func_t write_func, + void *closure) { cairo_output_stream_t *stream; stream = _cairo_output_stream_create (write_func, NULL, closure); if (_cairo_output_stream_get_status (stream)) - return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + return (cairo_script_context_t *) &_nil_context; + + return _cairo_script_context_create_internal (stream); +} - return &_cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height)->base; +void +cairo_script_context_write_comment (cairo_script_context_t *context, + const char *comment, + int len) +{ + 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"); } void -cairo_script_surface_set_mode (cairo_surface_t *abstract_surface, +cairo_script_context_set_mode (cairo_script_context_t *context, cairo_script_mode_t mode) { - cairo_script_surface_t *surface; - cairo_status_t status_ignored; + context->mode = mode; +} - if (! _cairo_surface_is_script (abstract_surface)) { - status_ignored = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - return; - } +cairo_script_mode_t +cairo_script_context_get_mode (cairo_script_context_t *context) +{ + return context->mode; +} - if (abstract_surface->status) - return; +cairo_surface_t * +cairo_script_surface_create (cairo_script_context_t *context, + cairo_content_t content, + double width, + double height) +{ + return &_cairo_script_surface_create_internal (context, + content, + width, height, + NULL)->base; +} - surface = (cairo_script_surface_t *) abstract_surface; - surface->ctx->mode = mode; +cairo_surface_t * +cairo_script_surface_create_for_target (cairo_script_context_t *context, + cairo_surface_t *target) +{ + cairo_rectangle_int_t extents; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + + if (! _cairo_surface_get_extents (target, &extents)) + extents.width = extents.height = -1; + + return &_cairo_script_surface_create_internal (context, + target->content, + extents.width, + extents.height, + target)->base; } -cairo_script_mode_t -cairo_script_surface_get_mode (cairo_surface_t *abstract_surface) +cairo_status_t +cairo_script_from_meta_surface (cairo_script_context_t *context, + cairo_surface_t *meta) { - cairo_script_surface_t *surface; + cairo_box_t bbox; + cairo_rectangle_int_t extents; + cairo_surface_t *surface; + cairo_status_t status; - if (! _cairo_surface_is_script (abstract_surface) || - abstract_surface->status) - { - return CAIRO_SCRIPT_MODE_ASCII; - } + if (unlikely (context->status)) + return context->status; + + if (unlikely (meta->status)) + return meta->status; + + if (unlikely (! _cairo_surface_is_meta (meta))) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + status = _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta, + &bbox, NULL); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&bbox, &extents); + + surface = &_cairo_script_surface_create_internal (context, + meta->content, + extents.width, + extents.height, + NULL)->base; + if (unlikely (surface->status)) + return surface->status; + + cairo_surface_set_device_offset (surface, -extents.x, -extents.y); + status = _cairo_meta_surface_replay (meta, surface); + cairo_surface_destroy (surface); + + return status; +} + +void +cairo_script_context_destroy (cairo_script_context_t *context) +{ + cairo_status_t status_ignored; + + if (context == NULL || context->ref < 0) + return; - surface = (cairo_script_surface_t *) abstract_surface; - return surface->ctx->mode; + status_ignored = _context_destroy (context); } |