diff options
Diffstat (limited to 'src/cairo-script-surface.c')
-rw-r--r-- | src/cairo-script-surface.c | 611 |
1 files changed, 494 insertions, 117 deletions
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 059ef95b8..fb1a4f8f2 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -51,6 +51,10 @@ #include "cairo-list-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-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)) @@ -85,6 +89,7 @@ struct _cairo_script_vmcontext { cairo_list_t deferred; cairo_script_surface_font_private_t *fonts; + cairo_list_t defines; }; struct _cairo_script_surface_font_private { @@ -114,7 +119,10 @@ struct _cairo_script_implicit_context { struct _cairo_script_surface { cairo_surface_t base; + cairo_surface_wrapper_t wrapper; + cairo_script_vmcontext_t *ctx; + cairo_surface_clipper_t clipper; unsigned long id; cairo_list_t operand; @@ -131,7 +139,11 @@ 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, double width, - double height); + double height, + cairo_surface_t *passthrough); + +static cairo_status_t +_vmcontext_destroy (cairo_script_vmcontext_t *ctx); static void _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); @@ -637,9 +649,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 { @@ -833,50 +846,46 @@ 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_meta_surface_t *source; cairo_script_surface_t *similar; cairo_status_t status; cairo_box_t bbox; - int width, height; + 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; - 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); + status = _cairo_meta_surface_get_bbox (source, &bbox, NULL); if (unlikely (status)) return status; - width = _cairo_fixed_integer_ceil (bbox.p2.x - bbox.p1.x); - height = _cairo_fixed_integer_ceil (bbox.p2.y - bbox.p1.y); + /* convert to extents so that it matches the public api */ + _cairo_box_round_to_rectangle (&bbox, &rect); similar = _cairo_script_surface_create_internal (surface->ctx, - width, height); + rect.width, + rect.height, + NULL); if (unlikely (similar->base.status)) return similar->base.status; + cairo_surface_set_device_offset (&similar->base, -rect.x, -rect.y); _get_target (surface); _cairo_output_stream_printf (surface->ctx->stream, - "%u %u //%s similar dup context\n", - width, height, + "%d %d //%s similar dup context\n", + rect.width, rect.height, _content_to_string (source->content)); target_push (similar); - status = cairo_meta_surface_replay (source, &similar->base); + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = cairo_meta_surface_replay (&source->base, &similar->base); + surface->cr = old_cr; + if (unlikely (status)) { cairo_surface_destroy (&similar->base); return status; @@ -1048,6 +1057,23 @@ _emit_png_surface (cairo_script_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +struct def { + cairo_script_vmcontext_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 ", def->tag); + free (def); +} + static cairo_status_t _emit_image_surface (cairo_script_surface_t *surface, cairo_image_surface_t *image) @@ -1057,12 +1083,23 @@ _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 = @@ -1078,14 +1115,34 @@ _emit_image_surface (cairo_script_surface_t *surface, "/width %d " "/height %d " "/format //%s " - "/source <~", + "/source ", clone->width, clone->height, _format_to_string (clone->format)); - if (clone->width * clone->height > 8) { + 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); + _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); @@ -1096,23 +1153,42 @@ _emit_image_surface (cairo_script_surface_t *surface, status = status2; if (unlikely (status)) return status; - - _cairo_output_stream_puts (surface->ctx->stream, - " /deflate filter >> image "); } else { + _cairo_output_stream_puts (surface->ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); 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, - " >> 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) { @@ -1126,14 +1202,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"); + 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 @@ -1141,22 +1231,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; } @@ -1249,6 +1334,9 @@ _emit_pattern (cairo_script_surface_t *surface, _extend_to_string (pattern->extend)); } + if (need_newline) + _cairo_output_stream_puts (surface->ctx->stream, "\n "); + return CAIRO_STATUS_SUCCESS; } @@ -1414,13 +1502,21 @@ _emit_path (cairo_script_surface_t *surface, } 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) { + cairo_matrix_t current, ctm_scaling; + assert (target_is_active (surface)); - if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0) + current = surface->cr.current_ctm; + current.x0 = current.y0 = 0; + + ctm_scaling = *ctm; + ctm_scaling.x0 = ctm_scaling.y0 = 0; + + if (memcmp (¤t, &ctm_scaling, sizeof (cairo_matrix_t)) == 0) return CAIRO_STATUS_SUCCESS; *matrix_updated = TRUE; @@ -1475,11 +1571,11 @@ _cairo_script_surface_create_similar (void *abstract_surface, int width, int height) { - cairo_script_surface_t *surface, *other; + cairo_script_surface_t *surface, *other = abstract_surface; + cairo_surface_t *passthrough = NULL; cairo_script_vmcontext_t *ctx; cairo_status_t status; - other = abstract_surface; ctx = other->ctx; if (other->id == (unsigned long) -1) { @@ -1490,8 +1586,20 @@ _cairo_script_surface_create_similar (void *abstract_surface, target_push (other); } - surface = _cairo_script_surface_create_internal (ctx, width, height); - if (surface->base.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; + } + + surface = _cairo_script_surface_create_internal (ctx, + width, height, + passthrough); + cairo_surface_destroy (passthrough); + + if (unlikely (surface->base.status)) return &surface->base; status = _bitmap_next_id (&ctx->surface_id, @@ -1527,6 +1635,16 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx) _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); @@ -1535,13 +1653,49 @@ _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_SUCCESS, status2; + _cairo_surface_wrapper_fini (&surface->wrapper); + + 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->id != (unsigned long) -1) { if (! surface->ctx->active) { @@ -1622,16 +1776,19 @@ _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)) @@ -1645,6 +1802,18 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } + /* skip the trivial clip covering the surface extents */ + if (surface->width >=0 && surface->height >= 0 && + _cairo_path_fixed_is_rectangle (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; @@ -1653,13 +1822,17 @@ _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)) @@ -1721,18 +1894,18 @@ 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; ctx_active (surface->ctx); - status = _emit_context (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; @@ -1740,10 +1913,20 @@ _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"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_paint (&surface->wrapper, + op, source, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1752,18 +1935,18 @@ _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; ctx_active (surface->ctx); - status = _emit_context (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; @@ -1771,14 +1954,30 @@ _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"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_mask (&surface->wrapper, + op, source, mask, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1792,7 +1991,7 @@ _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; @@ -1800,6 +1999,10 @@ _cairo_script_surface_stroke (void *abstract_surface, ctx_active (surface->ctx); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1816,7 +2019,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; @@ -1828,9 +2031,11 @@ _cairo_script_surface_stroke (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)) @@ -1839,6 +2044,16 @@ _cairo_script_surface_stroke (void *abstract_surface, _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); ctx_inactive (surface->ctx); + + 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; } @@ -1850,7 +2065,7 @@ _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; @@ -1858,11 +2073,11 @@ _cairo_script_surface_fill (void *abstract_surface, ctx_active (surface->ctx); - status = _emit_context (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; @@ -1878,21 +2093,39 @@ _cairo_script_surface_fill (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 (! 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"); ctx_inactive (surface->ctx); + + 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; } @@ -2024,6 +2257,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; @@ -2049,13 +2283,15 @@ _emit_type42_font (cairo_script_surface_t *surface, _cairo_output_stream_printf (surface->ctx->stream, "<< " "/type 42 " - "/size %lu " "/index 0 " "/flags %d " - "/source <~", - size, load_flags); + "/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); @@ -2071,7 +2307,6 @@ _emit_type42_font (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; _cairo_output_stream_printf (surface->ctx->stream, - " /deflate filter" " >> font dup /f%lu exch def set-font-face\n", font_private->id); @@ -2146,7 +2381,7 @@ _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; @@ -2268,7 +2503,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, @@ -2390,6 +2625,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, @@ -2402,7 +2696,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; @@ -2415,11 +2709,11 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, ctx_active (surface->ctx); - status = _emit_context (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; @@ -2431,6 +2725,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; @@ -2439,9 +2737,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; @@ -2597,24 +2894,41 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } ctx_inactive (surface->ctx); + + 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 @@ -2622,8 +2936,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 */ @@ -2634,8 +2948,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 */ @@ -2651,10 +2963,10 @@ _cairo_script_surface_backend = { _cairo_script_surface_fill, NULL, - NULL, //_cairo_script_surface_snapshot, + NULL, /* _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 */ @@ -2686,6 +2998,8 @@ _cairo_script_vmcontext_create (cairo_output_stream_t *stream) ctx->stream = stream; ctx->mode = CAIRO_SCRIPT_MODE_ASCII; + cairo_list_init (&ctx->defines); + return ctx; } @@ -2711,7 +3025,8 @@ _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) static cairo_script_surface_t * _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, double width, - double height) + double height, + cairo_surface_t *passthrough) { cairo_script_surface_t *surface; @@ -2726,6 +3041,11 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, &_cairo_script_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); + _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++; @@ -2755,7 +3075,7 @@ cairo_script_surface_create (const char *filename, surface = _cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height); + (_cairo_script_vmcontext_create (stream), width, height, NULL); if (surface->base.status) return &surface->base; @@ -2776,7 +3096,64 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); return &_cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height)->base; + (_cairo_script_vmcontext_create (stream), width, height, NULL)->base; +} + +cairo_surface_t * +cairo_script_surface_create_for_target (cairo_surface_t *target, + cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + cairo_script_surface_t *surface; + cairo_rectangle_int_t extents; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + + 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)); + + if (! _cairo_surface_get_extents (target, &extents)) + extents.width = extents.height = -1; + + surface = _cairo_script_surface_create_internal + (_cairo_script_vmcontext_create (stream), + extents.width, extents.height, + target); + if (unlikely (surface->base.status)) + return &surface->base; + + _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n"); + return &surface->base; +} + +void +cairo_script_surface_write_comment (cairo_surface_t *abstract_surface, + const char *comment, + int len) +{ + cairo_script_surface_t *surface; + cairo_status_t status_ignored; + + if (! _cairo_surface_is_script (abstract_surface)) { + status_ignored = _cairo_surface_set_error (abstract_surface, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return; + } + + if (abstract_surface->status) + return; + + surface = (cairo_script_surface_t *) abstract_surface; + + if (len < 0) + len = strlen (comment); + + _cairo_output_stream_puts (surface->ctx->stream, "% "); + _cairo_output_stream_write (surface->ctx->stream, comment, len); + _cairo_output_stream_puts (surface->ctx->stream, "\n"); } void |