mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-28 04:00:11 +01:00
Handling clip as part of the surface state, as opposed to being part of the operation state, is cumbersome and a hindrance to providing true proxy surface support. For example, the clip must be copied from the surface onto the fallback image, but this was forgotten causing undue hassle in each backend. Another example is the contortion the meta surface endures to ensure the clip is correctly recorded. By contrast passing the clip along with the operation is quite simple and enables us to write generic handlers for providing surface wrappers. (And in the future, we should be able to write more esoteric wrappers, e.g. automatic 2x FSAA, trivially.) In brief, instead of the surface automatically applying the clip before calling the backend, the backend can call into a generic helper to apply clipping. For raster surfaces, clip regions are handled automatically as part of the composite interface. For vector surfaces, a clip helper is introduced to replay and callback into an intersect_clip_path() function as necessary. Whilst this is not primarily a performance related change (the change should just move the computation of the clip from the moment it is applied by the user to the moment it is required by the backend), it is important to track any potential regression: ppc: Speedups ======== image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup ▌ image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup ▎ image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup ▏ image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup ▏ Slowdowns ========= image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown ▏
3192 lines
85 KiB
C
3192 lines
85 KiB
C
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
|
/* cairo - a vector graphics library with display and print output
|
|
*
|
|
* Copyright © 2008 Chris Wilson
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it either under the terms of the GNU Lesser General Public
|
|
* License version 2.1 as published by the Free Software Foundation
|
|
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
* notice, a recipient may use your version of this file under either
|
|
* the MPL or the LGPL.
|
|
*
|
|
* You should have received a copy of the LGPL along with this library
|
|
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
* You should have received a copy of the MPL along with this library
|
|
* in the file COPYING-MPL-1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
* the specific language governing rights and limitations.
|
|
*
|
|
* The Original Code is the cairo graphics library.
|
|
*
|
|
* The Initial Developer of the Original Code is Chris Wilson.
|
|
*
|
|
* Contributor(s):
|
|
* Chris Wilson <chris@chris-wilson.co.uk>
|
|
*/
|
|
|
|
/* The script surface is one that records all operations performed on
|
|
* it in the form of a procedural script, similar in fashion to
|
|
* PostScript but using Cairo's imaging model. In essence, this is
|
|
* equivalent to the meta-surface, but as there is no impedance mismatch
|
|
* between Cairo and CairoScript, we can generate output immediately
|
|
* without having to copy and hold the data in memory.
|
|
*/
|
|
|
|
#include "cairoint.h"
|
|
|
|
#include "cairo-script.h"
|
|
|
|
#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-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 deferred_finish {
|
|
cairo_list_t link;
|
|
cairo_list_t operand;
|
|
};
|
|
|
|
struct _cairo_script_vmcontext {
|
|
int ref;
|
|
int active;
|
|
|
|
cairo_output_stream_t *stream;
|
|
cairo_script_mode_t mode;
|
|
|
|
struct _bitmap {
|
|
unsigned long min;
|
|
unsigned long count;
|
|
unsigned int map[64];
|
|
struct _bitmap *next;
|
|
} surface_id, font_id;
|
|
|
|
cairo_list_t operands;
|
|
cairo_list_t deferred;
|
|
|
|
cairo_script_surface_font_private_t *fonts;
|
|
cairo_list_t defines;
|
|
};
|
|
|
|
struct _cairo_script_surface_font_private {
|
|
cairo_script_vmcontext_t *ctx;
|
|
cairo_bool_t has_sfnt;
|
|
unsigned long id;
|
|
unsigned long subset_glyph_index;
|
|
cairo_script_surface_font_private_t *prev, *next;
|
|
cairo_scaled_font_t *parent;
|
|
};
|
|
|
|
struct _cairo_script_implicit_context {
|
|
cairo_operator_t current_operator;
|
|
cairo_fill_rule_t current_fill_rule;
|
|
double current_tolerance;
|
|
cairo_antialias_t current_antialias;
|
|
cairo_stroke_style_t current_style;
|
|
cairo_pattern_union_t current_source;
|
|
cairo_matrix_t current_ctm;
|
|
cairo_matrix_t current_font_matrix;
|
|
cairo_font_options_t current_font_options;
|
|
cairo_scaled_font_t *current_scaled_font;
|
|
cairo_path_fixed_t current_path;
|
|
cairo_bool_t has_clip;
|
|
};
|
|
|
|
struct _cairo_script_surface {
|
|
cairo_surface_t base;
|
|
|
|
cairo_surface_wrapper_t wrapper;
|
|
|
|
cairo_script_vmcontext_t *ctx;
|
|
cairo_surface_clipper_t clipper;
|
|
|
|
unsigned long id;
|
|
cairo_list_t operand;
|
|
cairo_bool_t defined;
|
|
|
|
double width, height;
|
|
|
|
/* implicit flattened context */
|
|
cairo_script_implicit_context_t cr;
|
|
};
|
|
|
|
static const cairo_surface_backend_t _cairo_script_surface_backend;
|
|
|
|
static cairo_script_surface_t *
|
|
_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
|
|
double width,
|
|
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);
|
|
|
|
static void
|
|
_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
|
|
|
|
static void
|
|
_bitmap_release_id (struct _bitmap *b, unsigned long token)
|
|
{
|
|
struct _bitmap **prev = NULL;
|
|
|
|
do {
|
|
if (token < b->min + sizeof (b->map) * CHAR_BIT) {
|
|
unsigned int bit, elem;
|
|
|
|
token -= b->min;
|
|
elem = token / (sizeof (b->map[0]) * CHAR_BIT);
|
|
bit = token % (sizeof (b->map[0]) * CHAR_BIT);
|
|
b->map[elem] &= ~(1 << bit);
|
|
if (! --b->count && prev) {
|
|
*prev = b->next;
|
|
free (b);
|
|
}
|
|
return;
|
|
}
|
|
prev = &b->next;
|
|
b = b->next;
|
|
} while (b != NULL);
|
|
}
|
|
|
|
static cairo_status_t
|
|
_bitmap_next_id (struct _bitmap *b,
|
|
unsigned long *id)
|
|
{
|
|
struct _bitmap *bb, **prev = NULL;
|
|
unsigned long min = 0;
|
|
|
|
do {
|
|
if (b->min != min)
|
|
break;
|
|
|
|
if (b->count < sizeof (b->map) * CHAR_BIT) {
|
|
unsigned int n, m, bit;
|
|
for (n = 0; n < ARRAY_LENGTH (b->map); n++) {
|
|
if (b->map[n] == (unsigned int) -1)
|
|
continue;
|
|
|
|
for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) {
|
|
if ((b->map[n] & bit) == 0) {
|
|
b->map[n] |= bit;
|
|
b->count++;
|
|
*id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min;
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
min += sizeof (b->map) * CHAR_BIT;
|
|
|
|
prev = &b->next;
|
|
b = b->next;
|
|
} while (b != NULL);
|
|
|
|
bb = malloc (sizeof (struct _bitmap));
|
|
if (unlikely (bb == NULL))
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
*prev = bb;
|
|
bb->next = b;
|
|
bb->min = min;
|
|
bb->count = 1;
|
|
bb->map[0] = 0x1;
|
|
memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0]));
|
|
*id = min;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static const char *
|
|
_direction_to_string (cairo_bool_t backward)
|
|
{
|
|
static const char *names[] = {
|
|
"FORWARD",
|
|
"BACKWARD"
|
|
};
|
|
assert (backward < ARRAY_LENGTH (names));
|
|
return names[backward];
|
|
}
|
|
|
|
static const char *
|
|
_operator_to_string (cairo_operator_t op)
|
|
{
|
|
static const char *names[] = {
|
|
"CLEAR", /* CAIRO_OPERATOR_CLEAR */
|
|
|
|
"SOURCE", /* CAIRO_OPERATOR_SOURCE */
|
|
"OVER", /* CAIRO_OPERATOR_OVER */
|
|
"IN", /* CAIRO_OPERATOR_IN */
|
|
"OUT", /* CAIRO_OPERATOR_OUT */
|
|
"ATOP", /* CAIRO_OPERATOR_ATOP */
|
|
|
|
"DEST", /* CAIRO_OPERATOR_DEST */
|
|
"DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */
|
|
"DEST_IN", /* CAIRO_OPERATOR_DEST_IN */
|
|
"DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */
|
|
"DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */
|
|
|
|
"XOR", /* CAIRO_OPERATOR_XOR */
|
|
"ADD", /* CAIRO_OPERATOR_ADD */
|
|
"SATURATE", /* CAIRO_OPERATOR_SATURATE */
|
|
|
|
"MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */
|
|
"SCREEN", /* CAIRO_OPERATOR_SCREEN */
|
|
"OVERLAY", /* CAIRO_OPERATOR_OVERLAY */
|
|
"DARKEN", /* CAIRO_OPERATOR_DARKEN */
|
|
"LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */
|
|
"DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */
|
|
"BURN", /* CAIRO_OPERATOR_COLOR_BURN */
|
|
"HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */
|
|
"SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */
|
|
"DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */
|
|
"EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */
|
|
"HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */
|
|
"HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
|
|
"HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */
|
|
"HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
|
|
};
|
|
assert (op < ARRAY_LENGTH (names));
|
|
return names[op];
|
|
}
|
|
|
|
static const char *
|
|
_extend_to_string (cairo_extend_t extend)
|
|
{
|
|
static const char *names[] = {
|
|
"EXTEND_NONE", /* CAIRO_EXTEND_NONE */
|
|
"EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */
|
|
"EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */
|
|
"EXTEND_PAD" /* CAIRO_EXTEND_PAD */
|
|
};
|
|
assert (extend < ARRAY_LENGTH (names));
|
|
return names[extend];
|
|
}
|
|
|
|
static const char *
|
|
_filter_to_string (cairo_filter_t filter)
|
|
{
|
|
static const char *names[] = {
|
|
"FILTER_FAST", /* CAIRO_FILTER_FAST */
|
|
"FILTER_GOOD", /* CAIRO_FILTER_GOOD */
|
|
"FILTER_BEST", /* CAIRO_FILTER_BEST */
|
|
"FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */
|
|
"FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */
|
|
"FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */
|
|
};
|
|
assert (filter < ARRAY_LENGTH (names));
|
|
return names[filter];
|
|
}
|
|
|
|
static const char *
|
|
_fill_rule_to_string (cairo_fill_rule_t rule)
|
|
{
|
|
static const char *names[] = {
|
|
"WINDING", /* CAIRO_FILL_RULE_WINDING */
|
|
"EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */
|
|
};
|
|
assert (rule < ARRAY_LENGTH (names));
|
|
return names[rule];
|
|
}
|
|
|
|
static const char *
|
|
_antialias_to_string (cairo_antialias_t antialias)
|
|
{
|
|
static const char *names[] = {
|
|
"ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */
|
|
"ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */
|
|
"ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */
|
|
"ANTIALIAS_SUBPIXEL" /* CAIRO_ANTIALIAS_SUBPIXEL */
|
|
};
|
|
assert (antialias < ARRAY_LENGTH (names));
|
|
return names[antialias];
|
|
}
|
|
|
|
static const char *
|
|
_line_cap_to_string (cairo_line_cap_t line_cap)
|
|
{
|
|
static const char *names[] = {
|
|
"LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */
|
|
"LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */
|
|
"LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */
|
|
};
|
|
assert (line_cap < ARRAY_LENGTH (names));
|
|
return names[line_cap];
|
|
}
|
|
|
|
static const char *
|
|
_line_join_to_string (cairo_line_join_t line_join)
|
|
{
|
|
static const char *names[] = {
|
|
"LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */
|
|
"LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */
|
|
"LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */
|
|
};
|
|
assert (line_join < ARRAY_LENGTH (names));
|
|
return names[line_join];
|
|
}
|
|
|
|
static cairo_bool_t
|
|
target_is_active (cairo_script_surface_t *surface)
|
|
{
|
|
return cairo_list_is_first (&surface->operand, &surface->ctx->operands);
|
|
}
|
|
|
|
static void
|
|
target_push (cairo_script_surface_t *surface)
|
|
{
|
|
cairo_list_move (&surface->operand, &surface->ctx->operands);
|
|
}
|
|
|
|
static int
|
|
target_depth (cairo_script_surface_t *surface)
|
|
{
|
|
cairo_list_t *link;
|
|
int depth = 0;
|
|
|
|
cairo_list_foreach (link, &surface->ctx->operands) {
|
|
if (link == &surface->operand)
|
|
break;
|
|
depth++;
|
|
}
|
|
|
|
return depth;
|
|
}
|
|
|
|
static void
|
|
_get_target (cairo_script_surface_t *surface)
|
|
{
|
|
cairo_script_vmcontext_t *ctx = surface->ctx;
|
|
|
|
if (! target_is_active (surface)) {
|
|
int depth = target_depth (surface);
|
|
if (ctx->active) {
|
|
if (surface->defined) {
|
|
_cairo_output_stream_printf (ctx->stream, "s%ld ", surface->id);
|
|
} else {
|
|
_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 cairo_status_t
|
|
_emit_surface (cairo_script_surface_t *surface)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
status = _bitmap_next_id (&surface->ctx->surface_id,
|
|
&surface->id);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"<< /width %f /height %f",
|
|
surface->width,
|
|
surface->height);
|
|
|
|
if (surface->base.x_fallback_resolution !=
|
|
CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT ||
|
|
surface->base.y_fallback_resolution !=
|
|
CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT)
|
|
{
|
|
_cairo_output_stream_printf (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);
|
|
}
|
|
}
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, " >> surface context\n");
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_context (cairo_script_surface_t *surface)
|
|
{
|
|
if (target_is_active (surface))
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
if (surface->id == (unsigned long) -1) {
|
|
cairo_status_t status;
|
|
|
|
status = _emit_surface (surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
} else {
|
|
int depth = target_depth (surface);
|
|
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);
|
|
}
|
|
}
|
|
target_push (surface);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_operator (cairo_script_surface_t *surface,
|
|
cairo_operator_t op)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (surface->cr.current_operator == op)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_operator = op;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"//%s set-operator\n",
|
|
_operator_to_string (op));
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_fill_rule (cairo_script_surface_t *surface,
|
|
cairo_fill_rule_t fill_rule)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (surface->cr.current_fill_rule == fill_rule)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_fill_rule = fill_rule;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"//%s set-fill-rule\n",
|
|
_fill_rule_to_string (fill_rule));
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_tolerance (cairo_script_surface_t *surface,
|
|
double tolerance,
|
|
cairo_bool_t force)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (! force && surface->cr.current_tolerance == tolerance)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_tolerance = tolerance;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f set-tolerance\n",
|
|
tolerance);
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_antialias (cairo_script_surface_t *surface,
|
|
cairo_antialias_t antialias)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (surface->cr.current_antialias == antialias)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_antialias = antialias;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"//%s set-antialias\n",
|
|
_antialias_to_string (antialias));
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_line_width (cairo_script_surface_t *surface,
|
|
double line_width,
|
|
cairo_bool_t force)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (! force && surface->cr.current_style.line_width == line_width)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_style.line_width = line_width;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f set-line-width\n",
|
|
line_width);
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_line_cap (cairo_script_surface_t *surface,
|
|
cairo_line_cap_t line_cap)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (surface->cr.current_style.line_cap == line_cap)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_style.line_cap = line_cap;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"//%s set-line-cap\n",
|
|
_line_cap_to_string (line_cap));
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_line_join (cairo_script_surface_t *surface,
|
|
cairo_line_join_t line_join)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (surface->cr.current_style.line_join == line_join)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_style.line_join = line_join;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"//%s set-line-join\n",
|
|
_line_join_to_string (line_join));
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_miter_limit (cairo_script_surface_t *surface,
|
|
double miter_limit,
|
|
cairo_bool_t force)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (! force && surface->cr.current_style.miter_limit == miter_limit)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
surface->cr.current_style.miter_limit = miter_limit;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f set-miter-limit\n",
|
|
miter_limit);
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_dash (cairo_script_surface_t *surface,
|
|
const double *dash,
|
|
unsigned int num_dashes,
|
|
double offset,
|
|
cairo_bool_t force)
|
|
{
|
|
unsigned int n;
|
|
|
|
assert (target_is_active (surface));
|
|
|
|
if (force &&
|
|
num_dashes == 0 &&
|
|
surface->cr.current_style.num_dashes == 0)
|
|
{
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (! force &&
|
|
(surface->cr.current_style.num_dashes == num_dashes &&
|
|
(num_dashes == 0 ||
|
|
(surface->cr.current_style.dash_offset == offset &&
|
|
memcmp (surface->cr.current_style.dash, dash,
|
|
sizeof (double) * num_dashes)))))
|
|
{
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
if (num_dashes) {
|
|
surface->cr.current_style.dash = _cairo_realloc_ab
|
|
(surface->cr.current_style.dash, num_dashes, sizeof (double));
|
|
if (unlikely (surface->cr.current_style.dash == NULL))
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
memcpy (surface->cr.current_style.dash, dash,
|
|
sizeof (double) * num_dashes);
|
|
} else {
|
|
if (surface->cr.current_style.dash != NULL) {
|
|
free (surface->cr.current_style.dash);
|
|
surface->cr.current_style.dash = NULL;
|
|
}
|
|
}
|
|
|
|
surface->cr.current_style.num_dashes = num_dashes;
|
|
surface->cr.current_style.dash_offset = offset;
|
|
|
|
_cairo_output_stream_puts (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)
|
|
_cairo_output_stream_puts (surface->ctx->stream, " ");
|
|
}
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"] %f set-dash\n",
|
|
offset);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_stroke_style (cairo_script_surface_t *surface,
|
|
const cairo_stroke_style_t *style,
|
|
cairo_bool_t force)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
assert (target_is_active (surface));
|
|
|
|
status = _emit_line_width (surface, style->line_width, force);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_line_cap (surface, style->line_cap);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_line_join (surface, style->line_join);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_miter_limit (surface, style->miter_limit, force);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_dash (surface,
|
|
style->dash, style->num_dashes, style->dash_offset,
|
|
force);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static const char *
|
|
_format_to_string (cairo_format_t format)
|
|
{
|
|
static const char *names[] = {
|
|
"ARGB32", /* CAIRO_FORMAT_ARGB32 */
|
|
"RGB24", /* CAIRO_FORMAT_RGB24 */
|
|
"A8", /* CAIRO_FORMAT_A8 */
|
|
"A1" /* CAIRO_FORMAT_A1 */
|
|
};
|
|
assert (format < ARRAY_LENGTH (names));
|
|
return names[format];
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_solid_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
|
|
|
|
if (solid->content & CAIRO_CONTENT_ALPHA &&
|
|
! 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))
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f a",
|
|
solid->color.alpha);
|
|
}
|
|
else
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f %f %f %f rgba",
|
|
solid->color.red,
|
|
solid->color.green,
|
|
solid->color.blue,
|
|
solid->color.alpha);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (solid->color.red_short == solid->color.green_short &&
|
|
solid->color.red_short == solid->color.blue_short)
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f g",
|
|
solid->color.red);
|
|
}
|
|
else
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%f %f %f rgb",
|
|
solid->color.red,
|
|
solid->color.green,
|
|
solid->color.blue);
|
|
}
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static cairo_status_t
|
|
_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient,
|
|
cairo_output_stream_t *output)
|
|
{
|
|
unsigned int n;
|
|
|
|
for (n = 0; n < gradient->n_stops; n++) {
|
|
_cairo_output_stream_printf (output,
|
|
"\n %f %f %f %f %f add-color-stop",
|
|
gradient->stops[n].offset,
|
|
gradient->stops[n].color.red,
|
|
gradient->stops[n].color.green,
|
|
gradient->stops[n].color.blue,
|
|
gradient->stops[n].color.alpha);
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_linear_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_linear_pattern_t *linear;
|
|
|
|
linear = (cairo_linear_pattern_t *) pattern;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%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),
|
|
_cairo_fixed_to_double (linear->p2.y));
|
|
return _emit_gradient_color_stops (&linear->base, surface->ctx->stream);
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_radial_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_radial_pattern_t *radial;
|
|
|
|
radial = (cairo_radial_pattern_t *) pattern;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%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),
|
|
_cairo_fixed_to_double (radial->c2.x),
|
|
_cairo_fixed_to_double (radial->c2.y),
|
|
_cairo_fixed_to_double (radial->r2));
|
|
return _emit_gradient_color_stops (&radial->base, surface->ctx->stream);
|
|
}
|
|
|
|
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_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_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 = (cairo_meta_surface_t *) surface_pattern->surface;
|
|
|
|
/* first measure the extents */
|
|
status = _cairo_meta_surface_get_bbox (source, &bbox, NULL);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
/* 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,
|
|
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,
|
|
"%d %d //%s similar dup context\n",
|
|
rect.width, rect.height,
|
|
_content_to_string (source->content));
|
|
target_push (similar);
|
|
|
|
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;
|
|
}
|
|
|
|
cairo_list_del (&similar->operand);
|
|
assert (target_is_active (surface));
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "pop pattern");
|
|
cairo_surface_destroy (&similar->base);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_script_surface_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_surface_pattern_t *surface_pattern;
|
|
cairo_script_surface_t *source;
|
|
|
|
surface_pattern = (cairo_surface_pattern_t *) pattern;
|
|
source = (cairo_script_surface_t *) surface_pattern->surface;
|
|
|
|
_get_target (source);
|
|
_cairo_output_stream_puts (surface->ctx->stream, "pattern");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_write_image_surface (cairo_output_stream_t *output,
|
|
const cairo_image_surface_t *image)
|
|
{
|
|
int stride, row, width;
|
|
uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE];
|
|
uint8_t *rowdata;
|
|
uint8_t *data;
|
|
|
|
stride = image->stride;
|
|
width = image->width;
|
|
data = image->data;
|
|
#if WORDS_BIGENDIAN
|
|
switch (image->format) {
|
|
case CAIRO_FORMAT_A1:
|
|
for (row = image->height; row--; ) {
|
|
_cairo_output_stream_write (output, data, (width+7)/8);
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_A8:
|
|
for (row = image->height; row--; ) {
|
|
_cairo_output_stream_write (output, data, width);
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_RGB24:
|
|
for (row = image->height; row--; ) {
|
|
int col;
|
|
rowdata = data;
|
|
for (col = width; col--; ) {
|
|
_cairo_output_stream_write (output, rowdata, 3);
|
|
rowdata+=4;
|
|
}
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_ARGB32:
|
|
for (row = image->height; row--; ) {
|
|
_cairo_output_stream_write (output, data, 4*width);
|
|
data += stride;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT_NOT_REACHED;
|
|
break;
|
|
}
|
|
#else
|
|
if (stride > ARRAY_LENGTH (row_stack)) {
|
|
rowdata = malloc (stride);
|
|
if (unlikely (rowdata == NULL))
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
} else
|
|
rowdata = row_stack;
|
|
|
|
switch (image->format) {
|
|
case CAIRO_FORMAT_A1:
|
|
for (row = image->height; row--; ) {
|
|
int col;
|
|
for (col = 0; col < (width + 7)/8; col++)
|
|
rowdata[col] = CAIRO_BITSWAP8 (data[col]);
|
|
_cairo_output_stream_write (output, rowdata, (width+7)/8);
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_A8:
|
|
for (row = image->height; row--; ) {
|
|
_cairo_output_stream_write (output, data, width);
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_RGB24:
|
|
for (row = image->height; row--; ) {
|
|
uint8_t *src = data;
|
|
int col;
|
|
for (col = 0; col < width; col++) {
|
|
rowdata[3*col+2] = *src++;
|
|
rowdata[3*col+1] = *src++;
|
|
rowdata[3*col+0] = *src++;
|
|
src++;
|
|
}
|
|
_cairo_output_stream_write (output, rowdata, 3*width);
|
|
data += stride;
|
|
}
|
|
break;
|
|
case CAIRO_FORMAT_ARGB32:
|
|
for (row = image->height; row--; ) {
|
|
uint32_t *src = (uint32_t *) data;
|
|
uint32_t *dst = (uint32_t *) rowdata;
|
|
int col;
|
|
for (col = 0; col < width; col++)
|
|
dst[col] = bswap_32 (src[col]);
|
|
_cairo_output_stream_write (output, rowdata, 4*width);
|
|
data += stride;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT_NOT_REACHED;
|
|
break;
|
|
}
|
|
if (rowdata != row_stack)
|
|
free (rowdata);
|
|
#endif
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_emit_png_surface (cairo_script_surface_t *surface,
|
|
cairo_image_surface_t *image)
|
|
{
|
|
cairo_output_stream_t *base85_stream;
|
|
cairo_status_t status;
|
|
const uint8_t *mime_data;
|
|
unsigned int mime_data_length;
|
|
|
|
cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG,
|
|
&mime_data, &mime_data_length);
|
|
if (mime_data == NULL)
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"<< "
|
|
"/width %d "
|
|
"/height %d "
|
|
"/format //%s "
|
|
"/mime-type (image/png) "
|
|
"/source <~",
|
|
image->width, image->height,
|
|
_format_to_string (image->format));
|
|
|
|
base85_stream = _cairo_base85_stream_create (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, " >> image ");
|
|
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)
|
|
{
|
|
cairo_output_stream_t *base85_stream;
|
|
cairo_output_stream_t *zlib_stream;
|
|
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,
|
|
"<< "
|
|
"/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);
|
|
|
|
_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)
|
|
status = status2;
|
|
status2 = _cairo_output_stream_destroy (base85_stream);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
status = status2;
|
|
if (unlikely (status))
|
|
return status;
|
|
} 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;
|
|
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) <~",
|
|
CAIRO_MIME_TYPE_JPEG);
|
|
|
|
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_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);
|
|
|
|
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
|
|
_emit_image_surface_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_surface_pattern_t *surface_pattern;
|
|
cairo_image_surface_t *image;
|
|
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;
|
|
image = (cairo_image_surface_t *)
|
|
_cairo_surface_snapshot (surface_pattern->surface);
|
|
status = _emit_image_surface (surface, image);
|
|
cairo_surface_destroy (&image->base);
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_surface_pattern (cairo_script_surface_t *surface,
|
|
const cairo_pattern_t *pattern)
|
|
{
|
|
cairo_surface_pattern_t *surface_pattern;
|
|
cairo_surface_t *source;
|
|
|
|
surface_pattern = (cairo_surface_pattern_t *) pattern;
|
|
source = surface_pattern->surface;
|
|
|
|
switch ((int) source->type) {
|
|
case CAIRO_SURFACE_TYPE_META:
|
|
return _emit_meta_surface_pattern (surface, pattern);
|
|
case CAIRO_SURFACE_TYPE_SCRIPT:
|
|
return _emit_script_surface_pattern (surface, pattern);
|
|
default:
|
|
return _emit_image_surface_pattern (surface, pattern);
|
|
}
|
|
}
|
|
|
|
static cairo_status_t
|
|
_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:
|
|
/* solid colors do not need filter/extend/matrix */
|
|
return _emit_solid_pattern (surface, pattern);
|
|
|
|
case CAIRO_PATTERN_TYPE_LINEAR:
|
|
status = _emit_linear_pattern (surface, pattern);
|
|
is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT;
|
|
break;
|
|
case CAIRO_PATTERN_TYPE_RADIAL:
|
|
status = _emit_radial_pattern (surface, pattern);
|
|
is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT;
|
|
break;
|
|
case CAIRO_PATTERN_TYPE_SURFACE:
|
|
status = _emit_surface_pattern (surface, pattern);
|
|
is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT;
|
|
break;
|
|
|
|
default:
|
|
ASSERT_NOT_REACHED;
|
|
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
|
}
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (! _cairo_matrix_is_identity (&pattern->matrix)) {
|
|
if (need_newline) {
|
|
_cairo_output_stream_puts (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,
|
|
pattern->matrix.xy, pattern->matrix.yy,
|
|
pattern->matrix.x0, pattern->matrix.y0);
|
|
}
|
|
|
|
/* XXX need to discriminate the user explicitly setting the default */
|
|
if (pattern->filter != CAIRO_FILTER_DEFAULT) {
|
|
if (need_newline) {
|
|
_cairo_output_stream_puts (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;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_identity (cairo_script_surface_t *surface,
|
|
cairo_bool_t *matrix_updated)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (_cairo_matrix_is_identity (&surface->cr.current_ctm))
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
"identity set-matrix\n");
|
|
|
|
*matrix_updated = TRUE;
|
|
cairo_matrix_init_identity (&surface->cr.current_ctm);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_source (cairo_script_surface_t *surface,
|
|
cairo_operator_t op,
|
|
const cairo_pattern_t *source)
|
|
{
|
|
cairo_bool_t matrix_updated = FALSE;
|
|
cairo_status_t status;
|
|
|
|
assert (target_is_active (surface));
|
|
|
|
if (op == CAIRO_OPERATOR_CLEAR) {
|
|
/* the source is ignored, so don't change it */
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (_cairo_pattern_equal (&surface->cr.current_source.base, source))
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
_cairo_pattern_fini (&surface->cr.current_source.base);
|
|
status = _cairo_pattern_init_copy (&surface->cr.current_source.base,
|
|
source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_identity (surface, &matrix_updated);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_pattern (surface, source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
" set-source\n");
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_path_move_to (void *closure,
|
|
const cairo_point_t *point)
|
|
{
|
|
_cairo_output_stream_printf (closure,
|
|
" %f %f m",
|
|
_cairo_fixed_to_double (point->x),
|
|
_cairo_fixed_to_double (point->y));
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_path_line_to (void *closure,
|
|
const cairo_point_t *point)
|
|
{
|
|
_cairo_output_stream_printf (closure,
|
|
" %f %f l",
|
|
_cairo_fixed_to_double (point->x),
|
|
_cairo_fixed_to_double (point->y));
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_path_curve_to (void *closure,
|
|
const cairo_point_t *p1,
|
|
const cairo_point_t *p2,
|
|
const cairo_point_t *p3)
|
|
{
|
|
_cairo_output_stream_printf (closure,
|
|
" %f %f %f %f %f %f c",
|
|
_cairo_fixed_to_double (p1->x),
|
|
_cairo_fixed_to_double (p1->y),
|
|
_cairo_fixed_to_double (p2->x),
|
|
_cairo_fixed_to_double (p2->y),
|
|
_cairo_fixed_to_double (p3->x),
|
|
_cairo_fixed_to_double (p3->y));
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_path_close (void *closure)
|
|
{
|
|
_cairo_output_stream_printf (closure,
|
|
" h");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_path (cairo_script_surface_t *surface,
|
|
cairo_path_fixed_t *path)
|
|
{
|
|
cairo_box_t box;
|
|
cairo_status_t status;
|
|
|
|
assert (target_is_active (surface));
|
|
assert (_cairo_matrix_is_identity (&surface->cr.current_ctm));
|
|
|
|
if (_cairo_path_fixed_equal (&surface->cr.current_path, path))
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
_cairo_path_fixed_fini (&surface->cr.current_path);
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "n");
|
|
|
|
if (path == NULL) {
|
|
_cairo_path_fixed_init (&surface->cr.current_path);
|
|
} else if (_cairo_path_fixed_is_rectangle (path, &box)) {
|
|
double x1 = _cairo_fixed_to_double (box.p1.x);
|
|
double y1 = _cairo_fixed_to_double (box.p1.y);
|
|
double x2 = _cairo_fixed_to_double (box.p2.x);
|
|
double y2 = _cairo_fixed_to_double (box.p2.y);
|
|
|
|
status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" %f %f %f %f rectangle",
|
|
x1, y1, x2 - x1, y2 - y1);
|
|
} else {
|
|
cairo_status_t status;
|
|
|
|
status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _cairo_path_fixed_interpret (path,
|
|
CAIRO_DIRECTION_FORWARD,
|
|
_path_move_to,
|
|
_path_line_to,
|
|
_path_curve_to,
|
|
_path_close,
|
|
surface->ctx->stream);
|
|
if (unlikely (status))
|
|
return status;
|
|
}
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "\n");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_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));
|
|
|
|
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;
|
|
surface->cr.current_ctm = *ctm;
|
|
|
|
if (_cairo_matrix_is_identity (ctm)) {
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
"identity set-matrix\n");
|
|
} else {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"[%f %f %f %f %f %f] set-matrix\n",
|
|
ctm->xx, ctm->yx,
|
|
ctm->xy, ctm->yy,
|
|
ctm->x0, ctm->y0);
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_font_matrix (cairo_script_surface_t *surface,
|
|
const cairo_matrix_t *font_matrix)
|
|
{
|
|
assert (target_is_active (surface));
|
|
|
|
if (memcmp (&surface->cr.current_font_matrix,
|
|
font_matrix,
|
|
sizeof (cairo_matrix_t)) == 0)
|
|
{
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
surface->cr.current_font_matrix = *font_matrix;
|
|
|
|
if (_cairo_matrix_is_identity (font_matrix)) {
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
"identity set-font-matrix\n");
|
|
} else {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"[%f %f %f %f %f %f] set-font-matrix\n",
|
|
font_matrix->xx, font_matrix->yx,
|
|
font_matrix->xy, font_matrix->yy,
|
|
font_matrix->x0, font_matrix->y0);
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
_cairo_script_surface_create_similar (void *abstract_surface,
|
|
cairo_content_t content,
|
|
int width,
|
|
int height)
|
|
{
|
|
cairo_script_surface_t *surface, *other = abstract_surface;
|
|
cairo_surface_t *passthrough = NULL;
|
|
cairo_script_vmcontext_t *ctx;
|
|
cairo_status_t status;
|
|
|
|
ctx = other->ctx;
|
|
|
|
if (other->id == (unsigned long) -1) {
|
|
status = _emit_surface (other);
|
|
if (unlikely (status))
|
|
return _cairo_surface_create_in_error (status);
|
|
|
|
target_push (other);
|
|
}
|
|
|
|
if (_cairo_surface_wrapper_is_active (&other->wrapper)) {
|
|
passthrough =
|
|
_cairo_surface_wrapper_create_similar (&other->wrapper,
|
|
content, width, height);
|
|
if (unlikely (passthrough->status))
|
|
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,
|
|
&surface->id);
|
|
if (unlikely (status)) {
|
|
cairo_surface_destroy (&surface->base);
|
|
return _cairo_surface_create_in_error (status);
|
|
}
|
|
|
|
_get_target (other);
|
|
_cairo_output_stream_printf (ctx->stream,
|
|
"%u %u //%s similar dup /s%ld exch def context\n",
|
|
width, height,
|
|
_content_to_string (content),
|
|
surface->id);
|
|
surface->defined = TRUE;
|
|
target_push (surface);
|
|
|
|
return &surface->base;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_vmcontext_destroy (cairo_script_vmcontext_t *ctx)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
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;
|
|
_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);
|
|
|
|
return status;
|
|
}
|
|
|
|
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) {
|
|
if (cairo_list_is_first (&surface->operand,
|
|
&surface->ctx->operands))
|
|
{
|
|
_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);
|
|
} 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;
|
|
} else {
|
|
cairo_list_swap (&link->operand, &surface->operand);
|
|
cairo_list_add (&link->link, &surface->ctx->deferred);
|
|
}
|
|
}
|
|
|
|
if (surface->defined) {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"/s%ld undef\n",
|
|
surface->id);
|
|
}
|
|
|
|
_bitmap_release_id (&surface->ctx->surface_id, surface->id);
|
|
}
|
|
|
|
status2 = _vmcontext_destroy (surface->ctx);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
status = status2;
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_script_surface_copy_page (void *abstract_surface)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_status_t status;
|
|
|
|
status = _emit_context (surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "copy-page\n");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_script_surface_show_page (void *abstract_surface)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_status_t status;
|
|
|
|
status = _emit_context (surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "show-page\n");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
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) {
|
|
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_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;
|
|
|
|
status = _emit_fill_rule (surface, fill_rule);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (! path->is_rectilinear) {
|
|
status = _emit_tolerance (surface, tolerance, matrix_updated);
|
|
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
|
|
ctx_active (cairo_script_vmcontext_t *ctx)
|
|
{
|
|
ctx->active++;
|
|
}
|
|
|
|
static void
|
|
ctx_inactive (cairo_script_vmcontext_t *ctx)
|
|
{
|
|
if (--ctx->active > 0)
|
|
return;
|
|
|
|
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)
|
|
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);
|
|
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_clip_t *clip)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_status_t status;
|
|
|
|
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;
|
|
|
|
status = _emit_source (surface, op, source);
|
|
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;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_script_surface_mask (void *abstract_surface,
|
|
cairo_operator_t op,
|
|
const cairo_pattern_t *source,
|
|
const cairo_pattern_t *mask,
|
|
cairo_clip_t *clip)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_status_t status;
|
|
|
|
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;
|
|
|
|
status = _emit_source (surface, op, source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
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;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_script_surface_stroke (void *abstract_surface,
|
|
cairo_operator_t op,
|
|
const cairo_pattern_t *source,
|
|
cairo_path_fixed_t *path,
|
|
cairo_stroke_style_t *style,
|
|
cairo_matrix_t *ctm,
|
|
cairo_matrix_t *ctm_inverse,
|
|
double tolerance,
|
|
cairo_antialias_t antialias,
|
|
cairo_clip_t *clip)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_bool_t matrix_updated = FALSE;
|
|
cairo_status_t status;
|
|
|
|
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;
|
|
|
|
status = _emit_identity (surface, &matrix_updated);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_path (surface, path);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_source (surface, op, source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_scaling_matrix (surface, ctm, &matrix_updated);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_operator (surface, op);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_stroke_style (surface, style, 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;
|
|
|
|
_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;
|
|
}
|
|
|
|
static cairo_int_status_t
|
|
_cairo_script_surface_fill (void *abstract_surface,
|
|
cairo_operator_t op,
|
|
const cairo_pattern_t *source,
|
|
cairo_path_fixed_t *path,
|
|
cairo_fill_rule_t fill_rule,
|
|
double tolerance,
|
|
cairo_antialias_t antialias,
|
|
cairo_clip_t *clip)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_bool_t matrix_updated = FALSE;
|
|
cairo_status_t status;
|
|
|
|
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;
|
|
|
|
status = _emit_identity (surface, &matrix_updated);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_source (surface, op, source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_fill_rule (surface, fill_rule);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (! path->is_rectilinear) {
|
|
status = _emit_tolerance (surface, tolerance, matrix_updated);
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
static cairo_bool_t
|
|
_cairo_script_surface_has_show_text_glyphs (void *abstract_surface)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static const char *
|
|
_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order)
|
|
{
|
|
static const char *names[] = {
|
|
"SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */
|
|
"SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */
|
|
"SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */
|
|
"SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */
|
|
"SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */
|
|
};
|
|
return names[subpixel_order];
|
|
}
|
|
static const char *
|
|
_hint_style_to_string (cairo_hint_style_t hint_style)
|
|
{
|
|
static const char *names[] = {
|
|
"HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */
|
|
"HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */
|
|
"HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */
|
|
"HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */
|
|
"HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */
|
|
};
|
|
return names[hint_style];
|
|
}
|
|
static const char *
|
|
_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics)
|
|
{
|
|
static const char *names[] = {
|
|
"HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */
|
|
"HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */
|
|
"HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */
|
|
};
|
|
return names[hint_metrics];
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_font_options (cairo_script_surface_t *surface,
|
|
cairo_font_options_t *font_options)
|
|
{
|
|
if (cairo_font_options_equal (&surface->cr.current_font_options,
|
|
font_options))
|
|
{
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
_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",
|
|
_antialias_to_string (font_options->antialias));
|
|
}
|
|
|
|
if (font_options->subpixel_order !=
|
|
surface->cr.current_font_options.subpixel_order)
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" /subpixel-order //%s",
|
|
_subpixel_order_to_string (font_options->subpixel_order));
|
|
}
|
|
|
|
if (font_options->hint_style !=
|
|
surface->cr.current_font_options.hint_style)
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" /hint-style //%s",
|
|
_hint_style_to_string (font_options->hint_style));
|
|
}
|
|
|
|
if (font_options->hint_metrics !=
|
|
surface->cr.current_font_options.hint_metrics)
|
|
{
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" /hint-metrics //%s",
|
|
_hint_metrics_to_string (font_options->hint_metrics));
|
|
}
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" >> set-font-options\n");
|
|
|
|
surface->cr.current_font_options = *font_options;
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
|
|
font_private = scaled_font->surface_private;
|
|
if (font_private != NULL) {
|
|
_cairo_output_stream_printf (font_private->ctx->stream,
|
|
"/f%lu undef\n",
|
|
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;
|
|
|
|
free (font_private);
|
|
|
|
scaled_font->surface_private = NULL;
|
|
}
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_type42_font (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font)
|
|
{
|
|
const cairo_scaled_font_backend_t *backend;
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_output_stream_t *base85_stream;
|
|
cairo_output_stream_t *zlib_stream;
|
|
cairo_status_t status, status2;
|
|
unsigned long size;
|
|
unsigned int load_flags;
|
|
uint32_t len;
|
|
uint8_t *buf;
|
|
|
|
backend = scaled_font->backend;
|
|
if (backend->load_truetype_table == NULL)
|
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
|
size = 0;
|
|
status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
buf = malloc (size);
|
|
if (unlikely (buf == NULL))
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL);
|
|
if (unlikely (status)) {
|
|
free (buf);
|
|
return status;
|
|
}
|
|
|
|
load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font);
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"<< "
|
|
"/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);
|
|
free (buf);
|
|
|
|
status2 = _cairo_output_stream_destroy (zlib_stream);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
status = status2;
|
|
|
|
status2 = _cairo_output_stream_destroy (base85_stream);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
status = status2;
|
|
|
|
font_private = scaled_font->surface_private;
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" >> font dup /f%lu exch def set-font-face\n",
|
|
font_private->id);
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_font_init (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_status_t status;
|
|
|
|
font_private = malloc (sizeof (cairo_script_surface_font_private_t));
|
|
if (unlikely (font_private == NULL))
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
font_private->ctx = surface->ctx;
|
|
font_private->parent = scaled_font;
|
|
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;
|
|
|
|
status = _bitmap_next_id (&surface->ctx->font_id,
|
|
&font_private->id);
|
|
if (unlikely (status)) {
|
|
free (font_private);
|
|
return status;
|
|
}
|
|
|
|
scaled_font->surface_private = font_private;
|
|
scaled_font->surface_backend = &_cairo_script_surface_backend;
|
|
|
|
status = _emit_context (surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_type42_font (surface, scaled_font);
|
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
|
return status;
|
|
|
|
font_private->has_sfnt = FALSE;
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"dict\n"
|
|
" /type 3 set\n"
|
|
" /metrics [%f %f %f %f %f] set\n"
|
|
" /glyphs array set\n"
|
|
" font dup /f%lu exch def set-font-face\n",
|
|
scaled_font->fs_extents.ascent,
|
|
scaled_font->fs_extents.descent,
|
|
scaled_font->fs_extents.height,
|
|
scaled_font->fs_extents.max_x_advance,
|
|
scaled_font->fs_extents.max_y_advance,
|
|
font_private->id);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_font (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font)
|
|
{
|
|
cairo_matrix_t matrix;
|
|
cairo_font_options_t options;
|
|
cairo_bool_t matrix_updated = FALSE;
|
|
cairo_status_t status;
|
|
cairo_script_surface_font_private_t *font_private;
|
|
|
|
cairo_scaled_font_get_ctm (scaled_font, &matrix);
|
|
status = _emit_scaling_matrix (surface, &matrix, &matrix_updated);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (! matrix_updated && surface->cr.current_scaled_font == scaled_font)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
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);
|
|
|
|
font_private = scaled_font->surface_private;
|
|
if (font_private == NULL) {
|
|
status = _emit_scaled_font_init (surface, scaled_font);
|
|
if (unlikely (status))
|
|
return status;
|
|
} else {
|
|
status = _emit_context (surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"f%lu set-font-face\n",
|
|
font_private->id);
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_glyph_vector (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font,
|
|
cairo_scaled_glyph_t *scaled_glyph)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_script_implicit_context_t old_cr;
|
|
cairo_status_t status;
|
|
unsigned long index;
|
|
|
|
font_private = scaled_font->surface_private;
|
|
index = ++font_private->subset_glyph_index;
|
|
scaled_glyph->surface_private = (void *) index;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%lu <<\n"
|
|
" /metrics [%f %f %f %f %f %f]\n"
|
|
" /render {\n",
|
|
index,
|
|
scaled_glyph->fs_metrics.x_bearing,
|
|
scaled_glyph->fs_metrics.y_bearing,
|
|
scaled_glyph->fs_metrics.width,
|
|
scaled_glyph->fs_metrics.height,
|
|
scaled_glyph->fs_metrics.x_advance,
|
|
scaled_glyph->fs_metrics.y_advance);
|
|
|
|
if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"[%f %f %f %f %f %f] transform\n",
|
|
scaled_font->scale_inverse.xx,
|
|
scaled_font->scale_inverse.yx,
|
|
scaled_font->scale_inverse.xy,
|
|
scaled_font->scale_inverse.yy,
|
|
scaled_font->scale_inverse.x0,
|
|
scaled_font->scale_inverse.y0);
|
|
}
|
|
|
|
old_cr = surface->cr;
|
|
_cairo_script_implicit_context_init (&surface->cr);
|
|
status = cairo_meta_surface_replay (scaled_glyph->meta_surface,
|
|
&surface->base);
|
|
surface->cr = old_cr;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "} >> set\n");
|
|
|
|
return status;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font,
|
|
cairo_scaled_glyph_t *scaled_glyph)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_status_t status;
|
|
unsigned long index;
|
|
|
|
font_private = scaled_font->surface_private;
|
|
index = ++font_private->subset_glyph_index;
|
|
scaled_glyph->surface_private = (void *) index;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%lu <<\n"
|
|
" /metrics [%f %f %f %f %f %f]\n"
|
|
" /render {\n"
|
|
"%f %f translate\n",
|
|
index,
|
|
scaled_glyph->fs_metrics.x_bearing,
|
|
scaled_glyph->fs_metrics.y_bearing,
|
|
scaled_glyph->fs_metrics.width,
|
|
scaled_glyph->fs_metrics.height,
|
|
scaled_glyph->fs_metrics.x_advance,
|
|
scaled_glyph->fs_metrics.y_advance,
|
|
scaled_glyph->fs_metrics.x_bearing,
|
|
scaled_glyph->fs_metrics.y_bearing);
|
|
|
|
status = _emit_image_surface (surface, scaled_glyph->surface);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"\n [%f %f %f %f %f %f] set-matrix\n",
|
|
scaled_font->font_matrix.xx,
|
|
scaled_font->font_matrix.yx,
|
|
scaled_font->font_matrix.xy,
|
|
scaled_font->font_matrix.yy,
|
|
scaled_font->font_matrix.x0,
|
|
scaled_font->font_matrix.y0);
|
|
}
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
"mask\n} >> set\n");
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
|
|
assert (scaled_font->surface_backend == &_cairo_script_surface_backend);
|
|
|
|
font_private = scaled_font->surface_private;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"f%lu /glyphs get\n",
|
|
font_private->id);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_emit_scaled_glyphs (cairo_script_surface_t *surface,
|
|
cairo_scaled_font_t *scaled_font,
|
|
cairo_glyph_t *glyphs,
|
|
unsigned int num_glyphs)
|
|
{
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_status_t status;
|
|
unsigned int n;
|
|
cairo_bool_t have_glyph_prologue = FALSE;
|
|
|
|
if (num_glyphs == 0)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
font_private = scaled_font->surface_private;
|
|
if (font_private->has_sfnt)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
_cairo_scaled_font_freeze_cache (scaled_font);
|
|
for (n = 0; n < num_glyphs; n++) {
|
|
cairo_scaled_glyph_t *scaled_glyph;
|
|
|
|
status = _cairo_scaled_glyph_lookup (scaled_font,
|
|
glyphs[n].index,
|
|
CAIRO_SCALED_GLYPH_INFO_METRICS,
|
|
&scaled_glyph);
|
|
if (unlikely (status))
|
|
break;
|
|
|
|
if (scaled_glyph->surface_private != NULL)
|
|
continue;
|
|
|
|
status = _cairo_scaled_glyph_lookup (scaled_font,
|
|
glyphs[n].index,
|
|
CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
|
|
&scaled_glyph);
|
|
if (_cairo_status_is_error (status))
|
|
break;
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS) {
|
|
if (! have_glyph_prologue) {
|
|
status = _emit_scaled_glyph_prologue (surface, scaled_font);
|
|
if (unlikely (status))
|
|
break;
|
|
|
|
have_glyph_prologue = TRUE;
|
|
}
|
|
|
|
status = _emit_scaled_glyph_vector (surface,
|
|
scaled_font,
|
|
scaled_glyph);
|
|
if (unlikely (status))
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
|
|
status = _cairo_scaled_glyph_lookup (scaled_font,
|
|
glyphs[n].index,
|
|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
|
|
&scaled_glyph);
|
|
if (_cairo_status_is_error (status))
|
|
break;
|
|
|
|
if (status == CAIRO_STATUS_SUCCESS) {
|
|
if (! have_glyph_prologue) {
|
|
status = _emit_scaled_glyph_prologue (surface, scaled_font);
|
|
if (unlikely (status))
|
|
break;
|
|
|
|
have_glyph_prologue = TRUE;
|
|
}
|
|
|
|
status = _emit_scaled_glyph_bitmap (surface,
|
|
scaled_font,
|
|
scaled_glyph);
|
|
if (unlikely (status))
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
_cairo_scaled_font_thaw_cache (scaled_font);
|
|
|
|
if (have_glyph_prologue) {
|
|
_cairo_output_stream_puts (surface->ctx->stream, "pop pop\n");
|
|
}
|
|
|
|
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,
|
|
const cairo_pattern_t *source,
|
|
const char *utf8,
|
|
int utf8_len,
|
|
cairo_glyph_t *glyphs,
|
|
int num_glyphs,
|
|
const cairo_text_cluster_t *clusters,
|
|
int num_clusters,
|
|
cairo_text_cluster_flags_t backward,
|
|
cairo_scaled_font_t *scaled_font,
|
|
cairo_clip_t *clip)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
cairo_script_surface_font_private_t *font_private;
|
|
cairo_scaled_glyph_t *scaled_glyph;
|
|
cairo_matrix_t matrix;
|
|
cairo_status_t status;
|
|
double x, y, ix, iy;
|
|
int n;
|
|
cairo_output_stream_t *base85_stream = NULL;
|
|
|
|
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;
|
|
|
|
status = _emit_source (surface, op, source);
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
status = _emit_scaled_font (surface, scaled_font);
|
|
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;
|
|
|
|
/* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */
|
|
/* [cx cy [glyphs]] show_glyphs */
|
|
|
|
if (utf8 != NULL && clusters != NULL) {
|
|
_emit_string_literal (surface, utf8, utf8_len);
|
|
_cairo_output_stream_puts (surface->ctx->stream, " ");
|
|
}
|
|
|
|
matrix = surface->cr.current_ctm;
|
|
status = cairo_matrix_invert (&matrix);
|
|
assert (status == CAIRO_STATUS_SUCCESS);
|
|
|
|
ix = x = glyphs[0].x;
|
|
iy = y = glyphs[0].y;
|
|
cairo_matrix_transform_point (&matrix, &ix, &iy);
|
|
ix -= scaled_font->font_matrix.x0;
|
|
iy -= scaled_font->font_matrix.y0;
|
|
|
|
_cairo_scaled_font_freeze_cache (scaled_font);
|
|
font_private = scaled_font->surface_private;
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"[%f %f ",
|
|
ix, iy);
|
|
|
|
for (n = 0; n < num_glyphs; n++) {
|
|
if (font_private->has_sfnt) {
|
|
if (glyphs[n].index > 256)
|
|
break;
|
|
} else {
|
|
status = _cairo_scaled_glyph_lookup (scaled_font,
|
|
glyphs[n].index,
|
|
CAIRO_SCALED_GLYPH_INFO_METRICS,
|
|
&scaled_glyph);
|
|
if (unlikely (status)) {
|
|
_cairo_scaled_font_thaw_cache (scaled_font);
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (n == num_glyphs) {
|
|
_cairo_output_stream_puts (surface->ctx->stream, "<~");
|
|
base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
|
|
} else
|
|
_cairo_output_stream_puts (surface->ctx->stream, "[");
|
|
|
|
for (n = 0; n < num_glyphs; n++) {
|
|
double dx, dy;
|
|
|
|
status = _cairo_scaled_glyph_lookup (scaled_font,
|
|
glyphs[n].index,
|
|
CAIRO_SCALED_GLYPH_INFO_METRICS,
|
|
&scaled_glyph);
|
|
if (unlikely (status))
|
|
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;
|
|
}
|
|
|
|
_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) {
|
|
uint8_t c;
|
|
|
|
if (font_private->has_sfnt)
|
|
c = glyphs[n].index;
|
|
else
|
|
c = (uint8_t) (long unsigned) scaled_glyph->surface_private;
|
|
|
|
_cairo_output_stream_write (base85_stream, &c, 1);
|
|
} else {
|
|
if (font_private->has_sfnt)
|
|
_cairo_output_stream_printf (surface->ctx->stream, " %lu",
|
|
glyphs[n].index);
|
|
else
|
|
_cairo_output_stream_printf (surface->ctx->stream, " %lu",
|
|
(long unsigned) scaled_glyph->surface_private);
|
|
}
|
|
|
|
dx = scaled_glyph->metrics.x_advance;
|
|
dy = scaled_glyph->metrics.y_advance;
|
|
cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy);
|
|
x += dx;
|
|
y += dy;
|
|
}
|
|
_cairo_scaled_font_thaw_cache (scaled_font);
|
|
|
|
if (base85_stream != NULL) {
|
|
cairo_status_t status2;
|
|
|
|
status2 = _cairo_output_stream_destroy (base85_stream);
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
status = status2;
|
|
} else {
|
|
_cairo_output_stream_puts (surface->ctx->stream, " ]");
|
|
}
|
|
if (unlikely (status))
|
|
return status;
|
|
|
|
if (utf8 != NULL && clusters != NULL) {
|
|
for (n = 0; n < num_clusters; n++) {
|
|
if (clusters[n].num_bytes > UCHAR_MAX ||
|
|
clusters[n].num_glyphs > UCHAR_MAX)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (n < num_clusters) {
|
|
_cairo_output_stream_puts (surface->ctx->stream, "] [ ");
|
|
for (n = 0; n < num_clusters; n++) {
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
"%d %d ",
|
|
clusters[n].num_bytes,
|
|
clusters[n].num_glyphs);
|
|
}
|
|
_cairo_output_stream_puts (surface->ctx->stream, "]");
|
|
}
|
|
else
|
|
{
|
|
_cairo_output_stream_puts (surface->ctx->stream, "] <~");
|
|
base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
|
|
for (n = 0; n < num_clusters; n++) {
|
|
uint8_t c[2];
|
|
c[0] = clusters[n].num_bytes;
|
|
c[1] = clusters[n].num_glyphs;
|
|
_cairo_output_stream_write (base85_stream, c, 2);
|
|
}
|
|
status = _cairo_output_stream_destroy (base85_stream);
|
|
if (unlikely (status))
|
|
return status;
|
|
}
|
|
|
|
_cairo_output_stream_printf (surface->ctx->stream,
|
|
" //%s show-text-glyphs\n",
|
|
_direction_to_string (backward));
|
|
} else {
|
|
_cairo_output_stream_puts (surface->ctx->stream,
|
|
"] show-glyphs\n");
|
|
}
|
|
|
|
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_bool_t
|
|
_cairo_script_surface_get_extents (void *abstract_surface,
|
|
cairo_rectangle_int_t *rectangle)
|
|
{
|
|
cairo_script_surface_t *surface = abstract_surface;
|
|
|
|
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
|
|
return _cairo_surface_wrapper_get_extents (&surface->wrapper,
|
|
rectangle);
|
|
}
|
|
|
|
if (surface->width < 0 || surface->height < 0)
|
|
return FALSE;
|
|
|
|
rectangle->x = 0;
|
|
rectangle->y = 0;
|
|
rectangle->width = surface->width;
|
|
rectangle->height = surface->height;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const cairo_surface_backend_t
|
|
_cairo_script_surface_backend = {
|
|
CAIRO_SURFACE_TYPE_SCRIPT,
|
|
_cairo_script_surface_create_similar,
|
|
_cairo_script_surface_finish,
|
|
_cairo_script_surface_acquire_source_image,
|
|
_cairo_script_surface_release_source_image,
|
|
NULL, /* acquire_dest_image */
|
|
NULL, /* release_dest_image */
|
|
NULL, /* clone_similar */
|
|
NULL, /* composite */
|
|
NULL, /* fill_rectangles */
|
|
NULL, /* composite_trapezoids */
|
|
NULL, /* create_span_renderer */
|
|
NULL, /* check_span_renderer */
|
|
_cairo_script_surface_copy_page,
|
|
_cairo_script_surface_show_page,
|
|
_cairo_script_surface_get_extents,
|
|
NULL, /* old_show_glyphs */
|
|
NULL, /* get_font_options */
|
|
NULL, /* flush */
|
|
NULL, /* mark_dirty_rectangle */
|
|
_cairo_script_surface_scaled_font_fini,
|
|
NULL, /* scaled_glyph_fini */
|
|
|
|
/* The 5 high level operations */
|
|
_cairo_script_surface_paint,
|
|
_cairo_script_surface_mask,
|
|
_cairo_script_surface_stroke,
|
|
_cairo_script_surface_fill,
|
|
NULL,
|
|
|
|
NULL, /* _cairo_script_surface_snapshot, */
|
|
|
|
NULL, /* is_similar */
|
|
/* XXX need fill-stroke for passthrough */
|
|
NULL, /* fill_stroke */
|
|
NULL, /* create_solid_pattern_surface */
|
|
NULL, /* can_repaint_solid_pattern_surface */
|
|
|
|
/* The alternate high-level text operation */
|
|
_cairo_script_surface_has_show_text_glyphs,
|
|
_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));
|
|
|
|
cairo_list_init (&ctx->operands);
|
|
cairo_list_init (&ctx->deferred);
|
|
ctx->stream = stream;
|
|
ctx->mode = CAIRO_SCRIPT_MODE_ASCII;
|
|
|
|
cairo_list_init (&ctx->defines);
|
|
|
|
return ctx;
|
|
}
|
|
|
|
static void
|
|
_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr)
|
|
{
|
|
cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
|
|
cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
|
|
cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
|
|
cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT;
|
|
_cairo_stroke_style_init (&cr->current_style);
|
|
_cairo_pattern_init_solid (&cr->current_source.solid,
|
|
CAIRO_COLOR_BLACK,
|
|
CAIRO_CONTENT_COLOR);
|
|
_cairo_path_fixed_init (&cr->current_path);
|
|
cairo_matrix_init_identity (&cr->current_ctm);
|
|
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 cairo_script_surface_t *
|
|
_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
|
|
double width,
|
|
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));
|
|
|
|
surface = malloc (sizeof (cairo_script_surface_t));
|
|
if (unlikely (surface == NULL))
|
|
return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
|
|
|
_cairo_surface_init (&surface->base,
|
|
&_cairo_script_surface_backend,
|
|
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++;
|
|
|
|
surface->width = width;
|
|
surface->height = height;
|
|
|
|
surface->defined = FALSE;
|
|
surface->id = (unsigned long) -1;
|
|
cairo_list_init (&surface->operand);
|
|
|
|
_cairo_script_implicit_context_init (&surface->cr);
|
|
|
|
return surface;
|
|
}
|
|
|
|
cairo_surface_t *
|
|
cairo_script_surface_create (const char *filename,
|
|
double width,
|
|
double height)
|
|
{
|
|
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));
|
|
|
|
|
|
surface = _cairo_script_surface_create_internal
|
|
(_cairo_script_vmcontext_create (stream), width, height, NULL);
|
|
if (surface->base.status)
|
|
return &surface->base;
|
|
|
|
_cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n");
|
|
return &surface->base;
|
|
}
|
|
|
|
cairo_surface_t *
|
|
cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
|
|
void *closure,
|
|
double width,
|
|
double height)
|
|
{
|
|
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_surface_create_internal
|
|
(_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
|
|
cairo_script_surface_set_mode (cairo_surface_t *abstract_surface,
|
|
cairo_script_mode_t mode)
|
|
{
|
|
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;
|
|
surface->ctx->mode = mode;
|
|
}
|
|
|
|
cairo_script_mode_t
|
|
cairo_script_surface_get_mode (cairo_surface_t *abstract_surface)
|
|
{
|
|
cairo_script_surface_t *surface;
|
|
|
|
if (! _cairo_surface_is_script (abstract_surface) ||
|
|
abstract_surface->status)
|
|
{
|
|
return CAIRO_SCRIPT_MODE_ASCII;
|
|
}
|
|
|
|
surface = (cairo_script_surface_t *) abstract_surface;
|
|
return surface->ctx->mode;
|
|
}
|