summaryrefslogtreecommitdiff
path: root/src/cairo-script-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-script-surface.c')
-rw-r--r--src/cairo-script-surface.c1751
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);
}