diff options
Diffstat (limited to 'libs/cairo-1.16.0/util/cairo-script/cairo-script-operators.c')
-rw-r--r-- | libs/cairo-1.16.0/util/cairo-script/cairo-script-operators.c | 6793 |
1 files changed, 0 insertions, 6793 deletions
diff --git a/libs/cairo-1.16.0/util/cairo-script/cairo-script-operators.c b/libs/cairo-1.16.0/util/cairo-script/cairo-script-operators.c deleted file mode 100644 index e493311..0000000 --- a/libs/cairo-1.16.0/util/cairo-script/cairo-script-operators.c +++ /dev/null @@ -1,6793 +0,0 @@ -/* - * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Chris Wilson. - * - * Contributor(s): - * Chris Wilson <chris@chris-wilson.co.uk> - */ - -#include "config.h" - -/* TODO real path type */ - -#include "cairo-script-private.h" - -#if CAIRO_HAS_SCRIPT_SURFACE -#include "cairo-script.h" -#endif - -#include <stdio.h> /* snprintf */ -#include <stdlib.h> /* mkstemp */ -#include <string.h> - -#ifdef _MSC_VER -#define _USE_MATH_DEFINES /* for M_LN2, M_PI and M_SQRT2 on win32 */ -#define snprintf _snprintf -#endif - -#include <math.h> -#include <limits.h> /* INT_MAX */ -#include <assert.h> - -#if HAVE_ZLIB -#include <zlib.h> -#endif - -#if HAVE_LZO -#include <lzo/lzo2a.h> -#endif - -#ifdef HAVE_MMAP -# ifdef HAVE_UNISTD_H -# include <sys/mman.h> -# include <unistd.h> -# else -# undef HAVE_MMAP -# endif -#endif - -typedef struct _csi_proxy { - csi_t *ctx; - void *ptr; - csi_dictionary_t *dictionary; - csi_destroy_func_t destroy_func; - void *destroy_data; -} csi_proxy_t; - -typedef struct _csi_blob { - csi_list_t list; - unsigned long hash; - uint8_t *bytes; - unsigned int len; -} csi_blob_t; - -static const cairo_user_data_key_t _csi_proxy_key; -static const cairo_user_data_key_t _csi_blob_key; - -enum mime_type { - MIME_TYPE_NONE = 0, - MIME_TYPE_PNG -}; - -#define check(CNT) do {\ - if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \ - return _csi_error (CSI_STATUS_INVALID_SCRIPT); \ -} while (0) -#define pop(CNT) _csi_pop_ostack (ctx, (CNT)) -#define push(OBJ) _csi_push_ostack (ctx, (OBJ)) - -static csi_proxy_t * -_csi_proxy_create (csi_t *ctx, - void *ptr, - csi_dictionary_t *dictionary, - csi_destroy_func_t destroy_func, - void *destroy_data) -{ - csi_proxy_t *proxy; - - proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t)); - if (proxy == NULL) - return NULL; - - proxy->ctx = cairo_script_interpreter_reference (ctx); - proxy->ptr = ptr; - proxy->destroy_func = destroy_func; - proxy->destroy_data = destroy_data; - proxy->dictionary = dictionary; - if (dictionary != NULL) - dictionary->base.ref++; - - return proxy; -} - -static void -_csi_proxy_destroy (void *closure) -{ - csi_proxy_t *proxy = closure; - csi_t *ctx = proxy->ctx; - - /* XXX this doesn't work because user_data_destroy is called too late. - * Considering another hook into the (cairo internal) object system. - */ - if (proxy->destroy_func != NULL) - proxy->destroy_func (proxy->destroy_data, proxy->ptr); - - if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0) - csi_dictionary_free (ctx, proxy->dictionary); - - _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t)); - cairo_script_interpreter_destroy (ctx); -} - -static void -_csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len) -{ - unsigned long hash = blob->hash; - /* very simple! */ - while (len--) { - unsigned long c = *data++; - hash *= 33; - hash ^= c; - } - blob->hash = hash; -} - -static csi_boolean_t -_csi_blob_equal (const csi_list_t *link, void *data) -{ - csi_blob_t *A, *B; - - A = csi_container_of (link, csi_blob_t, list); - B = data; - - if (A->len != B->len) - return FALSE; - - if (A->hash != B->hash) - return FALSE; - - return memcmp (A->bytes, B->bytes, A->len) == 0; -} - -static void -_csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len) -{ - blob->hash = 5381; - blob->len = len; - blob->bytes = bytes; -} - -static csi_list_t * -_csi_list_unlink (csi_list_t *head, csi_list_t *link) -{ - if (link->next != NULL) - link->next->prev = link->prev; - if (link->prev != NULL) - link->prev->next = link->next; - else - head = link->next; - return head; -} - -static csi_list_t * -_csi_list_prepend (csi_list_t *head, csi_list_t *link) -{ - if (head != NULL) - head->prev = link; - link->next = head; - link->prev = NULL; - return link; -} - -static csi_list_t * -_csi_list_find (csi_list_t *head, - csi_boolean_t (*predicate) (const csi_list_t *link, void *data), - void *data) -{ - while (head != NULL) { - if (predicate (head, data)) - return head; - head = head->next; - } - - return NULL; -} - -static csi_status_t -_csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - *out = obj->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - *out = !! obj->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - *out = obj->datum.real != 0.; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - *out = obj->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - *out = obj->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - *out = obj->datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - *out = obj->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - *out = obj->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - *out = obj->datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static double -_csi_object_as_real (csi_object_t *obj) -{ - int type; - - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - return obj->datum.boolean; - case CSI_OBJECT_TYPE_INTEGER: - return obj->datum.integer; - case CSI_OBJECT_TYPE_REAL: - return obj->datum.real; - default: - return 0; - } -} - -static csi_status_t -_csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.name; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.cr; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.font_face; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.pattern; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i, - cairo_scaled_font_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely - (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT)) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - *out = obj->datum.scaled_font; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - *out = cairo_get_target (obj->datum.cr); - break; - case CSI_OBJECT_TYPE_SURFACE: - *out = obj->datum.surface; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.array; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (! csi_object_is_procedure (obj))) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.array; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely - (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY)) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - *out = obj->datum.dictionary; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_MATRIX: - *out = obj->datum.matrix->matrix; - return CSI_STATUS_SUCCESS; - - case CSI_OBJECT_TYPE_ARRAY: - if (obj->datum.array->stack.len == 6) { - cairo_matrix_init (out, - csi_number_get_value (&obj->datum.array->stack.objects[0]), - csi_number_get_value (&obj->datum.array->stack.objects[1]), - csi_number_get_value (&obj->datum.array->stack.objects[2]), - csi_number_get_value (&obj->datum.array->stack.objects[3]), - csi_number_get_value (&obj->datum.array->stack.objects[4]), - csi_number_get_value (&obj->datum.array->stack.objects[5])); - return CSI_STATUS_SUCCESS; - } - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_csi_dictionary_get_integer (csi_t *ctx, - csi_dictionary_t *dict, - const char *name, - csi_boolean_t optional, - long *value) -{ - csi_status_t status; - csi_object_t key, obj; - int type; - - status = csi_name_new_static (ctx, &key, name); - if (_csi_unlikely (status)) - return status; - - if (optional && ! csi_dictionary_has (dict, key.datum.name)) - return CSI_STATUS_SUCCESS; - - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - type = csi_object_get_type (&obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - *value = obj.datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - *value = obj.datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - *value = obj.datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_dictionary_get_number (csi_t *ctx, - csi_dictionary_t *dict, - const char *name, - csi_boolean_t optional, - double *value) -{ - csi_status_t status; - csi_object_t key, obj; - - status = csi_name_new_static (ctx, &key, name); - if (_csi_unlikely (status)) - return status; - - if (optional && ! csi_dictionary_has (dict, key.datum.name)) - return CSI_STATUS_SUCCESS; - - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - *value = csi_number_get_value (&obj); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out) -{ - csi_object_t *obj; - - obj = _csi_peek_ostack (ctx, i); - if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - *out = obj->datum.string; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out) -{ - csi_object_t *obj; - int type; - - obj = _csi_peek_ostack (ctx, i); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_NAME: - *out = (const char *) obj->datum.name; - break; - case CSI_OBJECT_TYPE_STRING: - *out = obj->datum.string->string; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_do_cairo_op (csi_t *ctx, void (*op) (cairo_t *)) -{ - cairo_t *cr; - csi_status_t status; - - check (1); - - status = _csi_ostack_get_context (ctx, 0, &cr); - if (_csi_unlikely (status)) - return status; - - op (cr); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -end_dict_construction (csi_t *ctx) -{ - csi_object_t obj; - csi_dictionary_t *dict; - csi_status_t status; - - status = csi_dictionary_new (ctx, &obj); - if (_csi_unlikely (status)) - return status; - - dict = obj.datum.dictionary; - do { - csi_object_t *name, *value; - - check (1); - - value = _csi_peek_ostack (ctx, 0); - if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) { - pop (1); - break; - } - - check (2); - - name = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely - (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - status = csi_dictionary_put (ctx, dict, name->datum.name, value); - if (_csi_unlikely (status)) - return status; - - pop (2); - } while (TRUE); - - return push (&obj); -} - -static csi_status_t -end_array_construction (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - int len = 0; - - do { - check (len + 1); - - if (csi_object_get_type (_csi_peek_ostack (ctx, len)) == - CSI_OBJECT_TYPE_MARK) - { - break; - } - - len++; - } while (TRUE); - - status = csi_array_new (ctx, len, &obj); - if (_csi_unlikely (status)) - return status; - - if (len != 0) { - csi_array_t *array; - - array = obj.datum.array; - memcpy (array->stack.objects, - _csi_peek_ostack (ctx, len - 1), - sizeof (csi_object_t) * len); - array->stack.len = len; - } - ctx->ostack.len -= len + 1; - - return push (&obj); -} - -static csi_status_t -_alpha (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double a; - - check (1); - - status = _csi_ostack_get_number (ctx, 0, &a); - if (_csi_unlikely (status)) - return status; - - pop (1); - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a); - return push (&obj); -} - -static csi_status_t -_add (csi_t *ctx) -{ - csi_object_t *A; - csi_object_t *B; - csi_object_type_t type_a, type_b; - - check (2); - - B = _csi_peek_ostack (ctx, 0); - A = _csi_peek_ostack (ctx, 1); - - type_a = csi_object_get_type (A); - if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || - type_a == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - type_b = csi_object_get_type (B); - if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || - type_b == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - - if (type_a == CSI_OBJECT_TYPE_REAL && - type_b == CSI_OBJECT_TYPE_REAL) - { - return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real); - - } - else if (type_a == CSI_OBJECT_TYPE_INTEGER && - type_b == CSI_OBJECT_TYPE_INTEGER) - { - return _csi_push_ostack_integer (ctx, - A->datum.integer + B->datum.integer); - } - else - { - double v; - - if (type_a == CSI_OBJECT_TYPE_REAL) - v = A->datum.real; - else - v = A->datum.integer; - - if (type_b == CSI_OBJECT_TYPE_REAL) - v += B->datum.real; - else - v += B->datum.integer; - - return _csi_push_ostack_real (ctx, v); - } -} - -static csi_status_t -_add_color_stop (csi_t *ctx) -{ - csi_status_t status; - double offset, r, g, b, a; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - - check (6); - - status = _csi_ostack_get_number (ctx, 0, &a); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &offset); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_pattern (ctx, 5, &pattern); - if (_csi_unlikely (status)) - return status; - - cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a); - - pop (5); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_and (csi_t *ctx) -{ - csi_object_t *a, *b; - int type; - - check (2); - - a = _csi_peek_ostack (ctx, 0); - b = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - pop (2); - type = csi_object_get_type (a); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - return _csi_push_ostack_integer (ctx, - a->datum.integer & b->datum.integer); - case CSI_OBJECT_TYPE_BOOLEAN: - return _csi_push_ostack_boolean (ctx, - a->datum.boolean & b->datum.boolean); - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_arc (csi_t *ctx) -{ - csi_status_t status; - double x, y, r; - double theta1, theta2; - cairo_t *cr; - - check (6); - - status = _csi_ostack_get_number (ctx, 0, &theta2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &theta1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 5, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX handle path object */ - - cairo_arc (cr, x, y, r, theta1, theta2); - pop (5); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_arc_negative (csi_t *ctx) -{ - csi_status_t status; - double x, y, r; - double theta1, theta2; - cairo_t *cr; - - check (6); - - status = _csi_ostack_get_number (ctx, 0, &theta2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &theta1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 5, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX handle path object */ - - cairo_arc_negative (cr, x, y, r, theta1, theta2); - pop (5); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_array (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - - status = csi_array_new (ctx, 0, &obj); - if (_csi_unlikely (status)) - return status; - - return push (&obj); -} - -static csi_status_t -_bind_substitute (csi_t *ctx, csi_array_t *array) -{ - csi_status_t status; - csi_integer_t i, n; - csi_dictionary_t *dict; - - /* perform operator substitution on the executable array (procedure) */ - dict = ctx->dstack.objects[0].datum.dictionary; - n = array->stack.len; - for (i = 0; i < n; i++) { - csi_object_t *obj = &array->stack.objects[i]; - - if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) { - csi_dictionary_entry_t *entry; - - entry = _csi_hash_table_lookup (&dict->hash_table, - (csi_hash_entry_t *) - &obj->datum.name); - if (entry != NULL) - *obj = entry->value; - } else if (csi_object_is_procedure (obj)) { - status = _bind_substitute (ctx, obj->datum.array); - if (_csi_unlikely (status)) - return status; - } - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_idiom_substitute (csi_t *ctx, csi_array_t *array) -{ -#if 0 - csi_status_t status; - csi_integer_t i, j; - - /* XXX substring search, build array once then search for - * longest matching idiom, repeat. */ - - /* scan the top-most array for sequences we can pre-compile */ - - /* now recurse for subroutines */ - j = array->stack.len; - for (i = 0; i < j; i++) { - csi_object_t *obj = &array->stack.objects[i]; - - if (csi_object_is_procedure (obj)) { - status = _idiom_substitute (ctx, obj->datum.array); - if (_csi_unlikely (_cairo_is_error (status)) - return status; - } - } -#endif - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_bind (csi_t *ctx) -{ - csi_array_t *array; - csi_status_t status; - - check (1); - - status = _csi_ostack_get_procedure (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - - status = _bind_substitute (ctx, array); - if (_csi_unlikely (status)) - return status; - - status = _idiom_substitute (ctx, array); - if (_csi_unlikely (status)) - return status; - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_bitshift (csi_t *ctx) -{ - long v, shift; - csi_status_t status; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &shift); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 1, &v); - if (_csi_unlikely (status)) - return status; - - if (shift < 0) { - shift = -shift; - v >>= shift; - } else - v <<= shift; - - pop (1); - _csi_peek_ostack (ctx, 0)->datum.integer = v; - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_clip (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_clip); -} - -static csi_status_t -_clip_preserve (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_clip_preserve); -} - -static csi_status_t -_close_path (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_close_path); -} - -static csi_status_t -_context (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - cairo_surface_t *surface; - cairo_t *cr; - csi_context_create_func_t hook; - csi_proxy_t *proxy; - - check (1); - - status = _csi_ostack_get_surface (ctx, 0, &surface); - if (_csi_unlikely (status)) - return status; - - hook = ctx->hooks.context_create; - if (hook != NULL) - cr = hook (ctx->hooks.closure, surface); - else - cr = cairo_create (surface); - - proxy = _csi_proxy_create (ctx, cr, NULL, - ctx->hooks.context_destroy, - ctx->hooks.closure); - if (_csi_unlikely (proxy == NULL)) { - cairo_destroy (cr); - return _csi_error (CSI_STATUS_NO_MEMORY); - } - - status = cairo_set_user_data (cr, &_csi_proxy_key, - proxy, _csi_proxy_destroy); - if (_csi_unlikely (status)) { - _csi_proxy_destroy (proxy); - cairo_destroy (cr); - return status; - } - - pop (1); - obj.type = CSI_OBJECT_TYPE_CONTEXT; - obj.datum.cr = cr; - return push (&obj); -} - -static csi_status_t -_copy (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = csi_object_reference (_csi_peek_ostack (ctx, 0)); - pop (1); - - type = csi_object_get_type (obj); - switch (type) { - /*XXX array, string, dictionary, etc */ - case CSI_OBJECT_TYPE_INTEGER: - { - long i, n; - - n = obj->datum.integer; - if (_csi_unlikely (n < 0)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - check (n); - - for (i = n; i--; ) { - csi_status_t status; - - status = _csi_push_ostack_copy (ctx, - _csi_peek_ostack (ctx, n-1)); - if (_csi_unlikely (status)) - return status; - } - break; - } - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_copy_page (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_copy_page (obj->datum.cr); - if (ctx->hooks.copy_page != NULL) - ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); - break; - case CSI_OBJECT_TYPE_SURFACE: - cairo_surface_copy_page (obj->datum.surface); - /* XXX hook? */ - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_curve_to (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - int type; - double x1, y1; - double x2, y2; - double x3, y3; - - check (7); - - status = _csi_ostack_get_number (ctx, 0, &y3); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x3); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &y2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &x2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &y1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 5, &x1); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 6); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_mesh_pattern_curve_to (obj->datum.pattern, - x1, y1, x2, y2, x3, y3); - break; - /* XXX handle path object */ - } - - pop (6); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_cvi (csi_t *ctx) -{ - csi_object_t *val, obj; - int type; - - check (1); - - val = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (val); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - return CSI_STATUS_SUCCESS; - - case CSI_OBJECT_TYPE_REAL: - pop (1); - return _csi_push_ostack_integer (ctx, val->datum.real); - - case CSI_OBJECT_TYPE_STRING: - if (! _csi_parse_number (&obj, - val->datum.string->string, - val->datum.string->len)) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_INTEGER) - return push (&obj); - else - return _csi_push_ostack_integer (ctx, obj.datum.real); - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_cvr (csi_t *ctx) -{ - csi_object_t *val, obj; - int type; - - check (1); - - val = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (val); - switch (type) { - case CSI_OBJECT_TYPE_REAL: - return CSI_STATUS_SUCCESS; - - case CSI_OBJECT_TYPE_INTEGER: - pop (1); - return _csi_push_ostack_real (ctx, val->datum.integer); - - case CSI_OBJECT_TYPE_STRING: - if (! _csi_parse_number (&obj, - val->datum.string->string, - val->datum.string->len)) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_REAL) - return push (&obj); - else - return _csi_push_ostack_real (ctx, obj.datum.integer); - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_def (csi_t *ctx) -{ - csi_name_t name = 0; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_name (ctx, 1, &name); - if (_csi_unlikely (status)) - return status; - - status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0)); - if (_csi_unlikely (status)) - return status; - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_dict (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - - status = csi_dictionary_new (ctx, &obj); - if (_csi_unlikely (status)) - return status; - - return push (&obj); -} - -static csi_status_t -_div (csi_t *ctx) -{ - csi_object_t *A; - csi_object_t *B; - csi_object_type_t type_a, type_b; - - check (2); - - B = _csi_peek_ostack (ctx, 0); - A = _csi_peek_ostack (ctx, 1); - - type_a = csi_object_get_type (A); - if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || - type_a == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - type_b = csi_object_get_type (B); - if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || - type_b == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - - if (type_a == CSI_OBJECT_TYPE_REAL && - type_b == CSI_OBJECT_TYPE_REAL) - { - return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real); - - } - else if (type_a == CSI_OBJECT_TYPE_INTEGER && - type_b == CSI_OBJECT_TYPE_INTEGER) - { - return _csi_push_ostack_integer (ctx, - A->datum.integer / B->datum.integer); - } - else - { - double v; - - if (type_a == CSI_OBJECT_TYPE_REAL) - v = A->datum.real; - else - v = A->datum.integer; - - if (type_b == CSI_OBJECT_TYPE_REAL) - v /= B->datum.real; - else - v /= B->datum.integer; - - return _csi_push_ostack_real (ctx, v); - } -} - -static csi_status_t -_duplicate (csi_t *ctx) -{ - check (1); - - return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0)); -} - -static csi_status_t -_eq (csi_t *ctx) -{ - csi_object_t *a, *b; - csi_boolean_t v; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - v = csi_object_eq (a, b); - - pop (2); - return _csi_push_ostack_boolean (ctx, v); -} - -static csi_status_t -_exch (csi_t *ctx) -{ - return _csi_stack_exch (&ctx->ostack); -} - -static csi_status_t -_false (csi_t *ctx) -{ - return _csi_push_ostack_boolean (ctx, FALSE); -} - -static csi_status_t -_fill (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_fill); -} - -static csi_status_t -_fill_preserve (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_fill_preserve); -} - -static csi_status_t -_filter (csi_t *ctx) -{ - csi_object_t *src; - csi_dictionary_t *dict = NULL; - csi_status_t status; - const char *name = NULL; /* silence the compiler */ - const struct filters { - const char *name; - csi_status_t (*constructor) (csi_t *t, - csi_object_t *, - csi_dictionary_t *, - csi_object_t *); - } filters[] = { - { "ascii85", csi_file_new_ascii85_decode }, -#if HAVE_ZLIB - { "deflate", csi_file_new_deflate_decode }, -#endif -#if 0 - { "lzw", csi_file_new_lzw_decode }, -#endif - { NULL, NULL } - }, *filter; - int cnt; - - check (2); - - status = _csi_ostack_get_string_constant (ctx, 0, &name); - if (_csi_unlikely (status)) - return status; - - src = _csi_peek_ostack (ctx, 1); - cnt = 2; - if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) { - dict = src->datum.dictionary; - - check (3); - - src = _csi_peek_ostack (ctx, 2); - cnt = 3; - } - - for (filter = filters; filter->name != NULL; filter++) { - if (strcmp (name, filter->name) == 0) { - csi_object_t file; - - status = filter->constructor (ctx, &file, dict, src); - if (_csi_unlikely (status)) - return status; - - pop (cnt); - return push (&file); - } - } - - return _csi_error (CSI_STATUS_INVALID_SCRIPT); -} - -static cairo_status_t -_type3_init (cairo_scaled_font_t *scaled_font, - cairo_t *cr, - cairo_font_extents_t *metrics) -{ - cairo_font_face_t *face; - csi_proxy_t *proxy; - csi_t *ctx; - csi_dictionary_t *font; - csi_object_t key; - csi_object_t obj; - csi_array_t *array; - csi_status_t status; - - face = cairo_scaled_font_get_font_face (scaled_font); - proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); - if (_csi_unlikely (proxy == NULL)) - return CAIRO_STATUS_NO_MEMORY; - - ctx = proxy->ctx; - font = proxy->dictionary; - - status = csi_name_new_static (ctx, &key, "metrics"); - if (_csi_unlikely (status)) - return CAIRO_STATUS_NO_MEMORY; - - if (! csi_dictionary_has (font, key.datum.name)) - return CAIRO_STATUS_SUCCESS; - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY) - return CAIRO_STATUS_USER_FONT_ERROR; - - array = obj.datum.array; - if (array->stack.len != 5) - return CAIRO_STATUS_USER_FONT_ERROR; - - metrics->ascent = csi_number_get_value (&array->stack.objects[0]); - metrics->descent = csi_number_get_value (&array->stack.objects[1]); - metrics->height = csi_number_get_value (&array->stack.objects[2]); - metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]); - metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_type3_lookup (cairo_scaled_font_t *scaled_font, - unsigned long unicode, - unsigned long *glyph) -{ - cairo_font_face_t *face; - csi_proxy_t *proxy; - csi_t *ctx; - csi_dictionary_t *font; - csi_object_t obj, key; - csi_array_t *array; - char buf[12]; - csi_integer_t i; - cairo_status_t status; - - face = cairo_scaled_font_get_font_face (scaled_font); - proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); - if (_csi_unlikely (proxy == NULL)) - return CAIRO_STATUS_USER_FONT_ERROR; - - ctx = proxy->ctx; - font = proxy->dictionary; - - status = csi_name_new_static (ctx, &key, "encoding"); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - if (! csi_dictionary_has (font, key.datum.name)) { - *glyph = unicode; - return CAIRO_STATUS_SUCCESS; - } - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) - return CAIRO_STATUS_USER_FONT_ERROR; - - snprintf (buf, sizeof (buf), "uni%04lu", unicode); - array = obj.datum.array; - for (i = 0; i < array->stack.len; i++) { - csi_object_t *name; - - name = &array->stack.objects[i]; - if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME) - continue; - - if (strcmp ((char *) name->datum.name, buf) == 0) { - *glyph = i; - return CAIRO_STATUS_SUCCESS; - } - } - - return CAIRO_STATUS_USER_FONT_ERROR; -} - -static cairo_status_t -_type3_render (cairo_scaled_font_t *scaled_font, - unsigned long glyph_index, - cairo_t *cr, - cairo_text_extents_t *metrics) -{ - cairo_font_face_t *face; - csi_proxy_t *proxy; - csi_t *ctx; - csi_dictionary_t *font; - csi_array_t *glyphs; - csi_object_t *glyph; - csi_object_t key; - csi_object_t obj; - csi_object_t render; - csi_status_t status; - - face = cairo_scaled_font_get_font_face (scaled_font); - proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); - if (_csi_unlikely (proxy == NULL)) - return CAIRO_STATUS_USER_FONT_ERROR; - - ctx = proxy->ctx; - font = proxy->dictionary; - - status = csi_name_new_static (ctx, &key, "glyphs"); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) - return CAIRO_STATUS_USER_FONT_ERROR; - - glyphs = obj.datum.array; - glyph = &glyphs->stack.objects[glyph_index]; - if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL) - return CAIRO_STATUS_SUCCESS; /* .notdef */ - - if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY)) - return CAIRO_STATUS_USER_FONT_ERROR; - - status = csi_name_new_static (ctx, &key, "metrics"); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - font = glyph->datum.dictionary; - if (csi_dictionary_has (font, key.datum.name)) { - csi_array_t *array; - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - if (_csi_unlikely (csi_object_get_type (&obj) != - CSI_OBJECT_TYPE_ARRAY)) - return CAIRO_STATUS_USER_FONT_ERROR; - - array = obj.datum.array; - if (_csi_unlikely (array->stack.len != 6)) - return CAIRO_STATUS_USER_FONT_ERROR; - - metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]); - metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]); - metrics->width = csi_number_get_value (&array->stack.objects[2]); - metrics->height = csi_number_get_value (&array->stack.objects[3]); - metrics->x_advance = csi_number_get_value (&array->stack.objects[4]); - metrics->y_advance = csi_number_get_value (&array->stack.objects[5]); - } - - status = csi_name_new_static (ctx, &key, "render"); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - status = csi_dictionary_get (ctx, font, key.datum.name, &render); - if (_csi_unlikely (status)) - return CAIRO_STATUS_USER_FONT_ERROR; - - if (_csi_unlikely (! csi_object_is_procedure (&render))) - return CAIRO_STATUS_USER_FONT_ERROR; - - obj.type = CSI_OBJECT_TYPE_CONTEXT; - obj.datum.cr = cairo_reference (cr); - status = push (&obj); - if (_csi_unlikely (status)) { - cairo_destroy (cr); - return CAIRO_STATUS_USER_FONT_ERROR; - } - - status = csi_object_execute (ctx, &render); - pop (1); - return status ? CAIRO_STATUS_USER_FONT_ERROR : CAIRO_STATUS_SUCCESS; -} - -static csi_status_t -_font_type3 (csi_t *ctx, - csi_dictionary_t *font, - cairo_font_face_t **font_face_out) -{ - cairo_font_face_t *font_face; - - font_face = cairo_user_font_face_create (); - cairo_user_font_face_set_init_func (font_face, _type3_init); - cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup); - cairo_user_font_face_set_render_glyph_func (font_face, _type3_render); - - *font_face_out = font_face; - return CSI_STATUS_SUCCESS; -} - -#if CAIRO_HAS_FT_FONT -#include <cairo-ft.h> -#include <ft2build.h> -#include FT_FREETYPE_H - -static FT_Library _ft_lib; - -struct _ft_face_data { - csi_t *ctx; - csi_blob_t blob; - FT_Face face; - csi_string_t *source; - void *bytes; - cairo_font_face_t *font_face; -}; - -static void -_ft_done_face (void *closure) -{ - struct _ft_face_data *data = closure; - csi_t *ctx; - - ctx = data->ctx; - - if (data->face != NULL) - FT_Done_Face (data->face); - - ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list); - - if (data->source != NULL) { - if (--data->source->base.ref == 0) - csi_string_free (ctx, data->source); - } else { -#ifdef HAVE_MMAP - munmap (data->blob.bytes, data->blob.len); -#endif - } - - if (data->bytes != NULL) - _csi_free (ctx, data->bytes); - - _csi_slab_free (ctx, data, sizeof (*data)); - - cairo_script_interpreter_destroy (ctx); -} - -struct mmap_vec { - const uint8_t *bytes; - size_t num_bytes; -}; - -#ifdef HAVE_MMAP -/* manual form of swapping for swapless systems like tiny */ -static void * -_mmap_bytes (const struct mmap_vec *vec, int count) -{ - char template[] = "/tmp/csi-font.XXXXXX"; - void *ptr; - int fd; - int num_bytes; - - fd = mkstemp (template); - if (fd == -1) - return MAP_FAILED; - - unlink (template); - num_bytes = 0; - while (count--) { - const uint8_t *bytes = vec->bytes; - size_t len = vec->num_bytes; - while (len) { - int ret = write (fd, bytes, len); - if (ret < 0) { - close (fd); - return MAP_FAILED; - } - len -= ret; - bytes += ret; - } - - num_bytes += vec->num_bytes; - vec++; - } - - ptr = mmap (NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0); - close (fd); - - return ptr; -} -#endif - -static void * -inflate_string (csi_t *ctx, csi_string_t *src) -{ - uLongf len; - uint8_t *bytes; - - len = src->deflate; - bytes = _csi_alloc (ctx, len + 1); - if (bytes == NULL) - return NULL; - - switch (src->method) { - default: - case NONE: - free (bytes); - return NULL; - - case ZLIB: -#if HAVE_ZLIB - if (uncompress ((Bytef *) bytes, &len, - (Bytef *) src->string, src->len) != Z_OK) -#endif - { - _csi_free (ctx, bytes); - return NULL; - } - break; - - case LZO: -#if HAVE_LZO - if (lzo2a_decompress ((Bytef *) src->string, src->len, - (Bytef *) bytes, &len, - NULL)) -#endif - { - _csi_free (ctx, bytes); - return NULL; - } - break; - } - - bytes[len] = '\0'; - return bytes; -} - -static csi_status_t -_ft_create_for_source (csi_t *ctx, - csi_string_t *source, - int index, int load_flags, - cairo_font_face_t **font_face_out) -{ - csi_blob_t tmpl; - struct _ft_face_data *data; - csi_list_t *link; - FT_Error err; - cairo_font_face_t *font_face; - csi_status_t status; - struct mmap_vec vec[2]; - int vec_count; - void *bytes; - int len; - - /* check for an existing FT_Face (kept alive by the font cache) */ - /* XXX index/flags */ - _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len); - _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t)); - link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); - if (link) { - if (--source->base.ref == 0) - csi_string_free (ctx, source); - data = csi_container_of (link, struct _ft_face_data, blob.list); - *font_face_out = cairo_font_face_reference (data->font_face); - return CSI_STATUS_SUCCESS; - } - - /* no existing font_face, create new FT_Face */ - if (_ft_lib == NULL) { - err = FT_Init_FreeType (&_ft_lib); - if (_csi_unlikely (err != FT_Err_Ok)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } - - data = _csi_slab_alloc (ctx, sizeof (*data)); - data->bytes = NULL; - data->source = source; - - vec[0].bytes = tmpl.bytes; - vec[0].num_bytes = tmpl.len; - - if (source->deflate) { - len = source->deflate; - bytes = inflate_string (ctx, source); - if (_csi_unlikely (bytes == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - - vec[1].bytes = bytes; - vec[1].num_bytes = len; - data->bytes = bytes; - vec_count = 2; - } else { - bytes = tmpl.bytes; - len = tmpl.len; - vec_count = 1; - } - - data->face = NULL; - ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); - data->ctx = cairo_script_interpreter_reference (ctx); - data->blob.hash = tmpl.hash; - data->blob.len = tmpl.len; -#ifdef HAVE_MMAP - data->blob.bytes = _mmap_bytes (vec, vec_count); - if (data->blob.bytes != MAP_FAILED) { - if (--source->base.ref == 0) - csi_string_free (ctx, source); - - if (source->deflate) { - _csi_free (ctx, bytes); - bytes = data->blob.bytes + vec[0].num_bytes; - } else - bytes = data->blob.bytes; - - data->source = NULL; - data->bytes = NULL; - } else { - data->blob.bytes = tmpl.bytes; - } -#else - data->blob.bytes = tmpl.bytes; -#endif - - err = FT_New_Memory_Face (_ft_lib, - bytes, len, - index, - &data->face); - if (_csi_unlikely (err != FT_Err_Ok)) { - _ft_done_face (data); - - if (err == FT_Err_Out_Of_Memory) - return _csi_error (CSI_STATUS_NO_MEMORY); - - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - font_face = cairo_ft_font_face_create_for_ft_face (data->face, load_flags); - status = cairo_font_face_set_user_data (font_face, - &_csi_blob_key, - data, _ft_done_face); - if (_csi_unlikely (status)) { - _ft_done_face (data); - cairo_font_face_destroy (font_face); - return status; - } - - data->font_face = font_face; - *font_face_out = font_face; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_ft_create_for_pattern (csi_t *ctx, - csi_string_t *string, - cairo_font_face_t **font_face_out) -{ -#if CAIRO_HAS_FC_FONT - csi_blob_t tmpl; - struct _ft_face_data *data; - csi_list_t *link; - cairo_font_face_t *font_face; - FcPattern *pattern, *resolved; - csi_status_t status; - struct mmap_vec vec; - void *bytes; - - _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len); - _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t)); - link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); - if (link) { - if (--string->base.ref == 0) - csi_string_free (ctx, string); - data = csi_container_of (link, struct _ft_face_data, blob.list); - *font_face_out = cairo_font_face_reference (data->font_face); - return CSI_STATUS_SUCCESS; - } - - if (string->deflate) { - bytes = inflate_string (ctx, string); - if (_csi_unlikely (bytes == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else { - bytes = tmpl.bytes; - } - - pattern = FcNameParse (bytes); - if (!pattern) - { - /* Fontconfig's representation of charset changed mid 2014; - * We used to record charset before that. Remove everything - * after charset if that's present, and try again. */ - char *s = strstr ((char *) bytes, ":charset="); - if (s) - { - *s = '\0'; - pattern = FcNameParse (bytes); - } - } - if (bytes != tmpl.bytes) - _csi_free (ctx, bytes); - -retry: - resolved = pattern; - if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) { - /* prior to 1.9, you needed to pass a resolved pattern */ - resolved = FcFontMatch (NULL, pattern, NULL); - if (_csi_unlikely (resolved == NULL)) { - FcPatternDestroy (pattern); - return _csi_error (CSI_STATUS_NO_MEMORY); - } - } - - font_face = cairo_ft_font_face_create_for_pattern (resolved); - if (resolved != pattern) - FcPatternDestroy (resolved); - - if (cairo_font_face_status (font_face)) { - char *filename = NULL; - - /* Try a manual fallback process by eliminating specific requests */ - - if (FcPatternGetString (pattern, - FC_FILE, 0, - (FcChar8 **) &filename) == FcResultMatch) { - FcPatternDel (pattern, FC_FILE); - goto retry; - } - } - - FcPatternDestroy (pattern); - - data = _csi_slab_alloc (ctx, sizeof (*data)); - ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); - data->ctx = cairo_script_interpreter_reference (ctx); - data->blob.hash = tmpl.hash; - data->blob.len = tmpl.len; - data->bytes = NULL; - data->face = NULL; -#ifdef HAVE_MMAP - vec.bytes = tmpl.bytes; - vec.num_bytes = tmpl.len; - data->blob.bytes = _mmap_bytes (&vec, 1); - if (data->blob.bytes != MAP_FAILED) { - data->source = NULL; - if (--string->base.ref == 0) - csi_string_free (ctx, string); - } else { - data->blob.bytes = tmpl.bytes; - data->source = string; - } -#else - data->blob.bytes = tmpl.bytes; - data->source = string; -#endif - - status = cairo_font_face_set_user_data (font_face, - &_csi_blob_key, - data, _ft_done_face); - if (_csi_unlikely (status)) { - _ft_done_face (data); - cairo_font_face_destroy (font_face); - return status; - } - - data->font_face = font_face; - *font_face_out = font_face; - return CSI_STATUS_SUCCESS; -#else - if (--string->base.ref == 0) - csi_string_free (ctx, string); - return CSI_INT_STATUS_UNSUPPORTED; -#endif -} - -static csi_status_t -_ft_type42_create (csi_t *ctx, - csi_dictionary_t *font, - cairo_font_face_t **font_face_out) -{ - csi_object_t key; - csi_status_t status; - - /* two basic sub-types, either an FcPattern or embedded font */ - status = csi_name_new_static (ctx, &key, "pattern"); - if (_csi_unlikely (status)) - return status; - - if (csi_dictionary_has (font, key.datum.name)) { - csi_object_t obj; - int type; - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - type = csi_object_get_type (&obj); - switch (type) { - case CSI_OBJECT_TYPE_FILE: - status = _csi_file_as_string (ctx, obj.datum.file, &obj); - if (_csi_unlikely (status)) - return status; - break; - case CSI_OBJECT_TYPE_STRING: - obj.datum.object->ref++; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return _ft_create_for_pattern (ctx, - obj.datum.string, - font_face_out); - } - - status = csi_name_new_static (ctx, &key, "source"); - if (_csi_unlikely (status)) - return status; - - if (csi_dictionary_has (font, key.datum.name)) { - csi_object_t obj; - long index, flags; - int type; - - index = 0; - status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index); - if (_csi_unlikely (status)) - return status; - - flags = 0; - status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags); - if (_csi_unlikely (status)) - return status; - - status = csi_name_new_static (ctx, &key, "source"); - if (_csi_unlikely (status)) - return status; - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - type = csi_object_get_type (&obj); - switch (type) { - case CSI_OBJECT_TYPE_FILE: - status = _csi_file_as_string (ctx, obj.datum.file, &obj); - if (_csi_unlikely (status)) - return status; - break; - case CSI_OBJECT_TYPE_STRING: - obj.datum.object->ref++; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return _ft_create_for_source (ctx, obj.datum.string, - index, flags, - font_face_out); - } - - return _csi_error (CSI_STATUS_INVALID_SCRIPT); -} -#else -#define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED -#endif - -static char * -_fc_strcpy (csi_t *ctx, const char *str) -{ - char *ret; - int len; - - ret = strchr (str, ':'); - if (ret != NULL) - len = ret - str; - else - len = strlen (str); - - ret = _csi_alloc (ctx, len+1); - if (_csi_unlikely (ret == NULL)) - return NULL; - - memcpy (ret, str, len); - ret[len] = '\0'; - - return ret; -} - -static cairo_font_face_t * -_select_font (const char *name) -{ - cairo_surface_t *surface; - cairo_font_face_t *face; - cairo_t *cr; - - /* create a dummy context to choose a font */ - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); - cr = cairo_create (surface); - cairo_surface_destroy (surface); - - cairo_select_font_face (cr, name, - CAIRO_FONT_SLANT_NORMAL, - CAIRO_FONT_WEIGHT_NORMAL); - face = cairo_font_face_reference (cairo_get_font_face (cr)); - cairo_destroy (cr); - - return face; -} - -static csi_status_t -_ft_fallback_create_for_pattern (csi_t *ctx, - csi_string_t *string, - cairo_font_face_t **font_face_out) -{ - char *str, *name; - - str = string->string; -#if 0 - name = strstr (str, "fullname="); - if (name != NULL) - str = name + 9; -#endif - - name = _fc_strcpy (ctx, str); - if (_csi_unlikely (name == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - - *font_face_out = _select_font (name); - _csi_free (ctx, name); - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_ft_type42_fallback_create (csi_t *ctx, - csi_dictionary_t *font, - cairo_font_face_t **font_face_out) -{ - csi_object_t key; - csi_status_t status; - - /* attempt to select a similar font */ - - /* two basic sub-types, either an FcPattern or embedded font */ - status = csi_name_new_static (ctx, &key, "pattern"); - if (_csi_unlikely (status)) - return status; - - if (csi_dictionary_has (font, key.datum.name)) { - csi_object_t obj; - int type; - - status = csi_dictionary_get (ctx, font, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - type = csi_object_get_type (&obj); - switch (type) { - case CSI_OBJECT_TYPE_FILE: - status = _csi_file_as_string (ctx, obj.datum.file, &obj); - if (_csi_unlikely (status)) - return status; - break; - case CSI_OBJECT_TYPE_STRING: - obj.datum.object->ref++; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return _ft_fallback_create_for_pattern (ctx, - obj.datum.string, - font_face_out); - } - - /* XXX: enable the trace to run */ - *font_face_out = _select_font ("Sans"); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face) -{ - csi_status_t status; - - status = _ft_type42_create (ctx, font, font_face); - if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED)) - return status; - - return _ft_type42_fallback_create (ctx, font, font_face); -} - -static csi_status_t -_font (csi_t *ctx) -{ - csi_dictionary_t *font; - csi_status_t status; - cairo_font_face_t *font_face = NULL; /* silence the compiler */ - csi_proxy_t *proxy; - csi_object_t obj; - long type; - - check (1); - - status = _csi_ostack_get_dictionary (ctx, 0, &font); - if (_csi_unlikely (status)) - return status; - - status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type); - if (_csi_unlikely (status)) - return status; - - switch (type) { - case 3: - status = _font_type3 (ctx, font, &font_face); - break; - case 42: - status = _font_type42 (ctx, font, &font_face); - break; - default: - status = _csi_error (CSI_STATUS_INVALID_SCRIPT); - break; - } - - if (_csi_unlikely (status)) - return status; - - /* transfer ownership of dictionary to cairo_font_face_t */ - proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL); - if (_csi_unlikely (proxy == NULL)) { - cairo_font_face_destroy (font_face); - return _csi_error (CSI_STATUS_NO_MEMORY); - } - - status = cairo_font_face_set_user_data (font_face, - &_csi_proxy_key, - proxy, _csi_proxy_destroy); - if (_csi_unlikely (status)) { - _csi_proxy_destroy (proxy); - cairo_font_face_destroy (font_face); - return status; - } - - obj.type = CSI_OBJECT_TYPE_FONT; - obj.datum.font_face = font_face; - - pop (1); - status = push (&obj); - if (_csi_unlikely (status)) { - cairo_font_face_destroy (font_face); - return status; - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_for (csi_t *ctx) -{ - csi_array_t *proc; - csi_status_t status; - long i, inc, limit; - - check (4); - - status = _csi_ostack_get_procedure (ctx, 0, &proc); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 1, &limit); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 2, &inc); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 3, &i); - if (_csi_unlikely (status)) - return status; - - proc->base.ref++; - pop (4); - - for (; i <= limit; i += inc) { - status = _csi_push_ostack_integer (ctx, i); - if (_csi_unlikely (status)) - break; - - status = _csi_array_execute (ctx, proc); - if (_csi_unlikely (status)) - break; - } - - if (--proc->base.ref == 0) - csi_array_free (ctx, proc); - return status; -} - -static csi_status_t -_ge (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *a, *b; - int cmp; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - status = csi_object_compare (a, b, &cmp); - if (_csi_unlikely (status)) - return status; - - pop (2); - return _csi_push_ostack_boolean (ctx, cmp >= 0); -} - -static csi_status_t -_proxy_get (csi_proxy_t *proxy, - csi_name_t key) -{ - csi_object_t obj; - csi_status_t status; - - if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj); - if (_csi_unlikely (status)) - return status; - - return _csi_push_ostack_copy (proxy->ctx, &obj); -} - -static csi_status_t -_context_get (csi_t *ctx, - cairo_t *cr, - csi_name_t key) -{ - csi_status_t status; - csi_object_t obj; - - if (strcmp ((char *) key, "current-point") == 0) { - double x, y; - - cairo_get_current_point (cr, &x, &y); - - status = _csi_push_ostack_real (ctx, x); - if (_csi_unlikely (status)) - return status; - status = _csi_push_ostack_real (ctx, y); - if (_csi_unlikely (status)) - return status; - - return CSI_STATUS_SUCCESS; - } else if (strcmp ((char *) key, "source") == 0) { - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr)); - } else if (strcmp ((char *) key, "target") == 0) { - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_reference (cairo_get_target (cr)); - } else if (strcmp ((char *) key, "group-target") == 0) { - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr)); - } else if (strcmp ((char *) key, "scaled-font") == 0) { - obj.type = CSI_OBJECT_TYPE_SCALED_FONT; - obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr)); - } else if (strcmp ((char *) key, "font-face") == 0) { - obj.type = CSI_OBJECT_TYPE_FONT; - obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr)); - } else - return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key); - - return push (&obj); -} - -static csi_status_t -_font_get (csi_t *ctx, - cairo_font_face_t *font_face, - csi_name_t key) -{ - return _proxy_get (cairo_font_face_get_user_data (font_face, - &_csi_proxy_key), - key); -} - -static csi_status_t -_pattern_get (csi_t *ctx, - cairo_pattern_t *pattern, - csi_name_t key) -{ - csi_status_t status; - - if (strcmp ((char *) key, "type") == 0) - return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern)); - - if (strcmp ((char *) key, "filter") == 0) - return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern)); - - if (strcmp ((char *) key, "extend") == 0) - return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern)); - - if (strcmp ((char *) key, "matrix") == 0) { - csi_object_t obj; - cairo_matrix_t m; - - cairo_pattern_get_matrix (pattern, &m); - status = csi_matrix_new_from_matrix (ctx, &obj, &m); - if (_csi_unlikely (status)) - return status; - - return push (&obj); - } - - return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key), - key); -} - -static csi_status_t -_scaled_font_get (csi_t *ctx, - cairo_scaled_font_t *font, - csi_name_t key) -{ - return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key), - key); -} - -static csi_status_t -_surface_get (csi_t *ctx, - cairo_surface_t *surface, - csi_name_t key) -{ - if (strcmp ((char *) key, "type") == 0) { - return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface)); - } - - if (strcmp ((char *) key, "content") == 0) { - return _csi_push_ostack_integer (ctx, - cairo_surface_get_content (surface)); - } - - return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key), - key); -} - -static csi_status_t -_get (csi_t *ctx) -{ - csi_object_t *key, *src, obj; - csi_status_t status; - int type; - - check (2); - - key = _csi_peek_ostack (ctx, 0); - src = _csi_peek_ostack (ctx, 1); - pop (1); - type = csi_object_get_type (src); - switch (type) { - case CSI_OBJECT_TYPE_DICTIONARY: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = csi_dictionary_get (ctx, - src->datum.dictionary, - key->datum.name, - &obj); - break; - case CSI_OBJECT_TYPE_ARRAY: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = csi_array_get (ctx, - src->datum.array, - key->datum.integer, - &obj); - break; -#if 0 - case CSI_OBJECT_TYPE_STRING: - status = csi_string_get (src, key, &obj); - break; -#endif - - case CSI_OBJECT_TYPE_CONTEXT: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - return _context_get (ctx, src->datum.cr, key->datum.name); - - case CSI_OBJECT_TYPE_FONT: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - return _font_get (ctx, src->datum.font_face, key->datum.name); - - case CSI_OBJECT_TYPE_PATTERN: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - return _pattern_get (ctx, src->datum.pattern, key->datum.name); - - case CSI_OBJECT_TYPE_SCALED_FONT: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name); - - case CSI_OBJECT_TYPE_SURFACE: - if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - return _surface_get (ctx, src->datum.surface, key->datum.name); - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - if (_csi_unlikely (status)) - return status; - - return _csi_push_ostack_copy (ctx, &obj); -} - -struct glyph_advance_cache { - csi_t *ctx; - double glyph_advance[256][2]; - unsigned long have_glyph_advance[256]; -}; - -static void -glyph_advance_cache_destroy (void *closure) -{ - struct glyph_advance_cache *cache = closure; - _csi_free (cache->ctx, cache); -} - -static int -_glyph_string (csi_t *ctx, - csi_array_t *array, - cairo_scaled_font_t *scaled_font, - cairo_glyph_t *glyphs) -{ - struct glyph_advance_cache uncached; - struct glyph_advance_cache *cache; - csi_integer_t nglyphs, i, j; - double x, y, dx; - cairo_status_t status; - - if (cairo_scaled_font_status (scaled_font)) - return 0; - - cache = cairo_scaled_font_get_user_data (scaled_font, - (cairo_user_data_key_t *) ctx); - if (cache == NULL) { - cache = _csi_alloc (ctx, sizeof (*cache)); - if (_csi_likely (cache != NULL)) { - cache->ctx = ctx; - memset (cache->have_glyph_advance, 0xff, - sizeof (cache->have_glyph_advance)); - - status = cairo_scaled_font_set_user_data (scaled_font, - (cairo_user_data_key_t *) ctx, - cache, - glyph_advance_cache_destroy); - if (_csi_unlikely (status)) { - _csi_free (ctx, cache); - cache = NULL; - } - } - } - - if (_csi_unlikely (cache == NULL)) { - cache = &uncached; - - cache->ctx = ctx; - memset (cache->have_glyph_advance, 0xff, - sizeof (cache->have_glyph_advance)); - } - - nglyphs = 0; - x = y = 0; - for (i = 0; i < array->stack.len; i++) { - const csi_object_t *obj = &array->stack.objects[i]; - int type = csi_object_get_type (obj); - - switch (type) { - case CSI_OBJECT_TYPE_ARRAY: { - const csi_array_t *glyph_array = obj->datum.array; - for (j = 0; j < glyph_array->stack.len; j++) { - unsigned long g; - int gi; - - obj = &glyph_array->stack.objects[j]; - if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER) - break; - g = obj->datum.integer; - - glyphs[nglyphs].index = g; - glyphs[nglyphs].x = x; - glyphs[nglyphs].y = y; - - gi = g % ARRAY_LENGTH (cache->have_glyph_advance); - if (cache->have_glyph_advance[gi] != g) { - cairo_text_extents_t extents; - - cairo_scaled_font_glyph_extents (scaled_font, - &glyphs[nglyphs], 1, - &extents); - - cache->glyph_advance[gi][0] = extents.x_advance; - cache->glyph_advance[gi][1] = extents.y_advance; - cache->have_glyph_advance[gi] = g; - } - - x += cache->glyph_advance[gi][0]; - y += cache->glyph_advance[gi][1]; - nglyphs++; - } - break; - } - - case CSI_OBJECT_TYPE_STRING: { - const csi_string_t *glyph_string = obj->datum.string; - for (j = 0; j < glyph_string->len; j++) { - uint8_t g; - - g = glyph_string->string[j]; - glyphs[nglyphs].index = g; - glyphs[nglyphs].x = x; - glyphs[nglyphs].y = y; - - if (cache->have_glyph_advance[g] != g) { - cairo_text_extents_t extents; - - cairo_scaled_font_glyph_extents (scaled_font, - &glyphs[nglyphs], 1, - &extents); - - cache->glyph_advance[g][0] = extents.x_advance; - cache->glyph_advance[g][1] = extents.y_advance; - cache->have_glyph_advance[g] = g; - } - - x += cache->glyph_advance[g][0]; - y += cache->glyph_advance[g][1]; - nglyphs++; - } - break; - } - - case CSI_OBJECT_TYPE_INTEGER: - case CSI_OBJECT_TYPE_REAL: /* dx or x*/ - dx = csi_number_get_value (obj); - if (i+1 == array->stack.len) - break; - - type = csi_object_get_type (&array->stack.objects[i+1]); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - case CSI_OBJECT_TYPE_REAL: /* y */ - y = csi_number_get_value (&array->stack.objects[i+1]); - x = dx; - i++; - break; - - default: - x += dx; - } - } - } - - return nglyphs; -} - -static csi_status_t -_glyph_path (csi_t *ctx) -{ - csi_array_t *array; - csi_status_t status; - cairo_t *cr; - cairo_glyph_t stack_glyphs[256], *glyphs; - csi_integer_t nglyphs, i; - - check (2); - - status = _csi_ostack_get_array (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - /* count glyphs */ - nglyphs = 0; - for (i = 0; i < array->stack.len; i++) { - csi_object_t *obj = &array->stack.objects[i]; - int type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_ARRAY: - nglyphs += obj->datum.array->stack.len; - break; - case CSI_OBJECT_TYPE_STRING: - nglyphs += obj->datum.string->len; - break; - } - } - if (nglyphs == 0) { - pop (1); - return CSI_STATUS_SUCCESS; - } - - if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { - if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) - return _csi_error (CSI_STATUS_NO_MEMORY); - - glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); - if (_csi_unlikely (glyphs == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else - glyphs = stack_glyphs; - - nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); - cairo_glyph_path (cr, glyphs, nglyphs); - - if (glyphs != stack_glyphs) - _csi_free (ctx, glyphs); - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_gray (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double g; - - check (1); - - status = _csi_ostack_get_number (ctx, 0, &g); - if (_csi_unlikely (status)) - return status; - - pop (1); - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1); - return push (&obj); -} - -static csi_status_t -_gt (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *a, *b; - int cmp; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - status = csi_object_compare (a, b, &cmp); - if (_csi_unlikely (status)) - return status; - - pop (2); - return _csi_push_ostack_boolean (ctx, cmp > 0); -} - -static csi_status_t -_identity (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - - status = csi_matrix_new (ctx, &obj); - if (_csi_unlikely (status)) - return status; - - return push (&obj); -} - -static csi_status_t -_if (csi_t *ctx) -{ - csi_array_t *proc; - csi_boolean_t predicate = FALSE; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_procedure (ctx, 0, &proc); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_boolean (ctx, 1, &predicate); - if (_csi_unlikely (status)) - return status; - - proc->base.ref++; - pop (2); - - if (predicate) - status = _csi_array_execute (ctx, proc); - - if (--proc->base.ref == 0) - csi_array_free (ctx, proc); - - return status; -} - -static csi_status_t -_ifelse (csi_t *ctx) -{ - csi_array_t *true_proc, *false_proc; - csi_boolean_t predicate = FALSE; /* silence the compiler */ - csi_status_t status; - - check (3); - - status = _csi_ostack_get_procedure (ctx, 0, &false_proc); - if (_csi_unlikely (status)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = _csi_ostack_get_procedure (ctx, 1, &true_proc); - if (_csi_unlikely (status)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = _csi_ostack_get_boolean (ctx, 2, &predicate); - if (_csi_unlikely (status)) - return status; - - true_proc->base.ref++; - false_proc->base.ref++; - pop (3); - - if (predicate) - status = _csi_array_execute (ctx, true_proc); - else - status = _csi_array_execute (ctx, false_proc); - - if (--true_proc->base.ref == 0) - csi_array_free (ctx, true_proc); - if (--false_proc->base.ref == 0) - csi_array_free (ctx, false_proc); - - return status; -} - -static csi_status_t -_image_read_raw (csi_t *ctx, - csi_object_t *src, - cairo_format_t format, - int width, int height, - cairo_surface_t **image_out) -{ - cairo_surface_t *image; - uint8_t *bp, *data; - int rem, len, ret, x, rowlen, instride, stride; - cairo_status_t status; - - if (width == 0 || height == 0) { - *image_out = cairo_image_surface_create (format, 0, 0); - return CSI_STATUS_SUCCESS; - } - - if (ctx->hooks.create_source_image != NULL) { - image = ctx->hooks.create_source_image (ctx->hooks.closure, - format, width, height, - 0); - - stride = cairo_image_surface_get_stride (image); - data = cairo_image_surface_get_data (image); - } else { - stride = cairo_format_stride_for_width (format, width); - data = malloc (stride * height); - if (data == NULL) - return CAIRO_STATUS_NO_MEMORY; - - image = cairo_image_surface_create_for_data (data, format, - width, height, stride); - status = cairo_surface_set_user_data (image, - (const cairo_user_data_key_t *) image, - data, free); - if (status) { - cairo_surface_destroy (image); - free (image); - return status; - } - } - - switch (format) { - case CAIRO_FORMAT_A1: - instride = rowlen = (width+7)/8; - break; - case CAIRO_FORMAT_A8: - instride = rowlen = width; - break; - case CAIRO_FORMAT_RGB16_565: - instride = rowlen = 2 * width; - break; - case CAIRO_FORMAT_RGB24: - rowlen = 3 * width; - instride = 4 *width; - break; - default: - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_ARGB32: - instride = rowlen = 4 * width; - break; - } - len = rowlen * height; - - if (rowlen == instride && - src->type == CSI_OBJECT_TYPE_STRING && - len == src->datum.string->deflate) - { - csi_string_t *s = src->datum.string; - unsigned long out = s->deflate; - - switch (s->method) { - default: - case NONE: -err_decompress: - cairo_surface_destroy (image); - return _csi_error (CSI_STATUS_READ_ERROR); - - case ZLIB: -#if HAVE_ZLIB - if (uncompress ((Bytef *) data, &out, - (Bytef *) s->string, s->len) != Z_OK) -#endif - goto err_decompress; - break; - - case LZO: -#if HAVE_LZO - if (lzo2a_decompress ((Bytef *) s->string, s->len, - (Bytef *) data, &out, - NULL)) -#endif - goto err_decompress; - break; - } - } - else - { - csi_object_t file; - - status = csi_object_as_file (ctx, src, &file); - if (_csi_unlikely (status)) { - cairo_surface_destroy (image); - return status; - } - - bp = data; - rem = len; - while (rem) { - ret = csi_file_read (file.datum.file, bp, rem); - if (_csi_unlikely (ret == 0)) { - cairo_surface_destroy (image); - return _csi_error (CSI_STATUS_READ_ERROR); - } - rem -= ret; - bp += ret; - } - - if (len != height * stride) { - while (--height) { - uint8_t *row = data + height * stride; - - /* XXX pixel conversion */ - switch (format) { - case CAIRO_FORMAT_A1: - for (x = rowlen; x--; ) { - uint8_t byte = *--bp; - row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); - } - break; - case CAIRO_FORMAT_A8: - for (x = width; x--; ) - row[x] = *--bp; - break; - case CAIRO_FORMAT_RGB16_565: - for (x = width; x--; ) { -#ifdef WORDS_BIGENDIAN - row[2*x + 1] = *--bp; - row[2*x + 0] = *--bp; -#else - row[2*x + 0] = *--bp; - row[2*x + 1] = *--bp; -#endif - } - break; - case CAIRO_FORMAT_RGB24: - for (x = width; x--; ) { -#ifdef WORDS_BIGENDIAN - row[4*x + 3] = *--bp; - row[4*x + 2] = *--bp; - row[4*x + 1] = *--bp; - row[4*x + 0] = 0xff; -#else - row[4*x + 0] = *--bp; - row[4*x + 1] = *--bp; - row[4*x + 2] = *--bp; - row[4*x + 3] = 0xff; -#endif - } - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_ARGB32: - /* stride == width */ - break; - } - - memset (row + instride, 0, stride - instride); - } - - /* need to treat last row carefully */ - switch (format) { - case CAIRO_FORMAT_A1: - for (x = rowlen; x--; ) { - uint8_t byte = *--bp; - data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); - } - break; - case CAIRO_FORMAT_A8: - for (x = width; x--; ) - data[x] = *--bp; - break; - case CAIRO_FORMAT_RGB16_565: - for (x = width; x--; ) { -#ifdef WORDS_BIGENDIAN - data[2*x + 1] = *--bp; - data[2*x + 0] = *--bp; -#else - data[2*x + 0] = *--bp; - data[2*x + 1] = *--bp; -#endif - } - break; - case CAIRO_FORMAT_RGB24: - for (x = width; --x>1; ) { -#ifdef WORDS_BIGENDIAN - data[4*x + 3] = *--bp; - data[4*x + 2] = *--bp; - data[4*x + 1] = *--bp; - data[4*x + 0] = 0xff; -#else - data[4*x + 0] = *--bp; - data[4*x + 1] = *--bp; - data[4*x + 2] = *--bp; - data[4*x + 3] = 0xff; -#endif - } - if (width > 1) { - uint8_t rgb[2][3]; - /* shuffle the last couple of overlapping pixels */ - rgb[1][0] = data[5]; - rgb[1][1] = data[4]; - rgb[1][2] = data[3]; - rgb[0][0] = data[2]; - rgb[0][1] = data[1]; - rgb[0][2] = data[0]; -#ifdef WORDS_BIGENDIAN - data[4] = 0xff; - data[5] = rgb[1][2]; - data[6] = rgb[1][1]; - data[7] = rgb[1][0]; - data[0] = 0xff; - data[1] = rgb[0][2]; - data[2] = rgb[0][1]; - data[3] = rgb[0][0]; -#else - data[7] = 0xff; - data[6] = rgb[1][2]; - data[5] = rgb[1][1]; - data[4] = rgb[1][0]; - data[3] = 0xff; - data[2] = rgb[0][2]; - data[1] = rgb[0][1]; - data[0] = rgb[0][0]; -#endif - } else { -#ifdef WORDS_BIGENDIAN - data[0] = 0xff; - data[1] = data[0]; - data[2] = data[1]; - data[3] = data[2]; -#else - data[3] = data[0]; - data[0] = data[2]; - data[2] = data[3]; - data[3] = 0xff; -#endif - } - break; - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_INVALID: - case CAIRO_FORMAT_ARGB32: - /* stride == width */ - break; - } - memset (data + instride, 0, stride - instride); - } else { -#ifndef WORDS_BIGENDIAN - switch (format) { - case CAIRO_FORMAT_A1: - for (x = 0; x < len; x++) { - uint8_t byte = data[x]; - data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); - } - break; - case CAIRO_FORMAT_RGB16_565: - { - uint32_t *rgba = (uint32_t *) data; - for (x = len/2; x--; rgba++) { - *rgba = bswap_16 (*rgba); - } - } - break; - case CAIRO_FORMAT_ARGB32: - { - uint32_t *rgba = (uint32_t *) data; - for (x = len/4; x--; rgba++) { - *rgba = bswap_32 (*rgba); - } - } - break; - - case CAIRO_FORMAT_A8: - break; - - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_INVALID: - default: - break; - } -#endif - } - csi_object_free (ctx, &file); - } - - cairo_surface_mark_dirty (image); - *image_out = image; - return CSI_STATUS_SUCCESS; -} - -static cairo_status_t -png_read_func (void *closure, uint8_t *data, unsigned int len) -{ - int ret; - - ret = csi_file_read (closure, data, len); - if ((unsigned int) ret != len) - return CAIRO_STATUS_READ_ERROR; - - return CAIRO_STATUS_SUCCESS; -} - -static csi_status_t -_image_read_png (csi_file_t *src, cairo_surface_t **out) -{ -#if CAIRO_HAS_PNG_FUNCTIONS - *out = cairo_image_surface_create_from_png_stream (png_read_func, src); - return cairo_surface_status (*out); -#else - return CAIRO_STATUS_READ_ERROR; -#endif -} - -struct _image_tag { - csi_t *ctx; - csi_blob_t blob; - cairo_surface_t *surface; -}; - -static void -_image_tag_done (void *closure) -{ - struct _image_tag *tag = closure; - csi_t *ctx = tag->ctx; - - ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list); - _csi_slab_free (ctx, tag, sizeof (*tag)); - cairo_script_interpreter_destroy (ctx); -} - -static void -_image_hash (csi_blob_t *blob, - cairo_surface_t *surface) -{ - uint32_t value; - - value = cairo_image_surface_get_width (surface); - _csi_blob_hash (blob, &value, 1); - - value = cairo_image_surface_get_height (surface); - _csi_blob_hash (blob, &value, 1); - - value = cairo_image_surface_get_format (surface); - _csi_blob_hash (blob, &value, 1); -} - -static cairo_surface_t * -_image_cached (csi_t *ctx, cairo_surface_t *surface) -{ - csi_blob_t tmpl; - csi_list_t *link; - uint8_t *data; - int stride, height; - struct _image_tag *tag; - - /* check for an existing image */ - - data = cairo_image_surface_get_data (surface); - stride = cairo_image_surface_get_stride (surface); - height = cairo_image_surface_get_height (surface); - _csi_blob_init (&tmpl, data, stride * height); - _image_hash (&tmpl, surface); - link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl); - if (link) { - cairo_surface_destroy (surface); - tag = csi_container_of (link, struct _image_tag, blob.list); - return cairo_surface_reference (tag->surface); - } - - /* none found, insert a tag for this one */ - - tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag)); - if (tag == NULL) - return surface; - - ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list); - tag->ctx = cairo_script_interpreter_reference (ctx); - tag->blob.hash = tmpl.hash; - tag->blob.bytes = tmpl.bytes; - tag->blob.len = tmpl.len; - tag->surface = surface; - - if (cairo_surface_set_user_data (surface, &_csi_blob_key, - tag, _image_tag_done)) - { - _image_tag_done (tag); - } - - return surface; -} - -static csi_status_t -_image_load_from_dictionary (csi_t *ctx, - csi_dictionary_t *dict, - cairo_surface_t **image_out) -{ - csi_object_t obj, key; - long width; - long height; - long format; - cairo_surface_t *image = NULL; /* silence the compiler */ - csi_status_t status; - - /* check for "status? */ - - status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width); - if (_csi_unlikely (status)) - return status; - status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height); - if (_csi_unlikely (status)) - return status; - - format = CAIRO_FORMAT_ARGB32; - status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format); - if (_csi_unlikely (status)) - return status; - - status = csi_name_new_static (ctx, &key, "source"); - if (_csi_unlikely (status)) - return status; - - if (csi_dictionary_has (dict, key.datum.name)) { - enum mime_type mime_type; - csi_object_t file; - - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - status = csi_name_new_static (ctx, &key, "mime-type"); - if (_csi_unlikely (status)) - return status; - - mime_type = MIME_TYPE_NONE; - if (csi_dictionary_has (dict, key.datum.name)) { - csi_object_t type_obj; - const char *type_str; - int type; - - status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj); - if (_csi_unlikely (status)) - return status; - - type = csi_object_get_type (&type_obj); - switch (type) { - case CSI_OBJECT_TYPE_STRING: - type_str = type_obj.datum.string->string; - break; - case CSI_OBJECT_TYPE_NAME: - type_str = (char *) type_obj.datum.name; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0) - mime_type = MIME_TYPE_PNG; - } - - - /* XXX hook for general mime-type decoder */ - - switch (mime_type) { - case MIME_TYPE_NONE: - status = _image_read_raw (ctx, &obj, format, width, height, &image); - break; - case MIME_TYPE_PNG: - status = csi_object_as_file (ctx, &obj, &file); - if (_csi_unlikely (status)) - return status; - - status = _image_read_png (file.datum.file, &image); - csi_object_free (ctx, &file); - break; - } - if (_csi_unlikely (status)) - return status; - - image = _image_cached (ctx, image); - } else - image = cairo_image_surface_create (format, width, height); - - *image_out = image; - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_image (csi_t *ctx) -{ - csi_dictionary_t *dict; - cairo_surface_t *image; - csi_status_t status; - csi_object_t obj; - - check (1); - - status = _csi_ostack_get_dictionary (ctx, 0, &dict); - if (_csi_unlikely (status)) - return status; - - status = _image_load_from_dictionary (ctx, dict, &image); - if (_csi_unlikely (status)) - return status; - - pop (1); - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = image; - return push (&obj); -} - -static csi_status_t -_index (csi_t *ctx) -{ - csi_status_t status; - long n; - - check (1); - - status = _csi_ostack_get_integer (ctx, 0, &n); - if (_csi_unlikely (status)) - return status; - - pop (1); - - check (n); - return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n)); -} - -static csi_status_t -_integer (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - break; - case CSI_OBJECT_TYPE_REAL: - obj->datum.integer = obj->datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - obj->type = CSI_OBJECT_TYPE_INTEGER; - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_invert (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - cairo_matrix_t m; - - check (1); - - status = _csi_ostack_get_matrix (ctx, 0, &m); - if (_csi_unlikely (status)) - return status; - - cairo_matrix_invert (&m); - - status = csi_matrix_new_from_matrix (ctx, &obj, &m); - if (_csi_unlikely (status)) - return status; - - pop (1); - - return push (&obj); -} - -static csi_status_t -_le (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *a, *b; - int cmp; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - status = csi_object_compare (a, b, &cmp); - if (_csi_unlikely (status)) - return status; - - pop (2); - return _csi_push_ostack_boolean (ctx, cmp <= 0); -} - -static csi_status_t -_linear (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double x1, y1, x2, y2; - - check (4); - - status = _csi_ostack_get_number (ctx, 0, &y2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &y1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &x1); - if (_csi_unlikely (status)) - return status; - - pop (4); - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2); - return push (&obj); -} - -static csi_status_t -_line_to (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - int type; - double x, y; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - - /* XXX path object */ - - obj = _csi_peek_ostack (ctx, 2); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_line_to (obj->datum.cr, x, y); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_mesh_pattern_line_to (obj->datum.pattern, x, y); - break; - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_lt (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *a, *b; - int cmp; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - status = csi_object_compare (a, b, &cmp); - if (_csi_unlikely (status)) - return status; - - pop (2); - return _csi_push_ostack_boolean (ctx, cmp < 0); -} - -static csi_status_t -_mark (csi_t *ctx) -{ - return _csi_push_ostack_mark (ctx); -} - -static csi_status_t -_ne (csi_t *ctx) -{ - csi_object_t *a, *b; - csi_boolean_t v; - - check (2); - - b = _csi_peek_ostack (ctx, 0); - a = _csi_peek_ostack (ctx, 1); - - v = ! csi_object_eq (a, b); - - pop (2); - return _csi_push_ostack_boolean (ctx, v); -} - -static csi_status_t -_neg (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - obj->datum.integer = -obj->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - obj->datum.real = -obj->datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_not (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_BOOLEAN: - obj->datum.boolean = ! obj->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - obj->type = CSI_OBJECT_TYPE_BOOLEAN; - obj->datum.boolean = ! obj->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - obj->type = CSI_OBJECT_TYPE_BOOLEAN; - obj->datum.boolean = obj->datum.real == 0.0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_new_path (csi_t *ctx) -{ - /* XXX handle path object */ - return _do_cairo_op (ctx, cairo_new_path); -} - -static csi_status_t -_new_sub_path (csi_t *ctx) -{ - /* XXX handle path object */ - return _do_cairo_op (ctx, cairo_new_sub_path); -} - -static csi_status_t -_null (csi_t *ctx) -{ - return _csi_push_ostack_null (ctx); -} - -static csi_status_t -_mask (csi_t *ctx) -{ - cairo_t *cr; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_pattern (ctx, 0, &pattern); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_mask (cr, pattern); - pop (1); - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_matrix (csi_t *ctx) -{ - csi_object_t *obj, matrix; - double v[6]; - csi_status_t status; - int n; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - if (csi_object_is_number (obj)) { - check (6); - - for (n = 6; n--; ) { - status = _csi_ostack_get_number (ctx, 5-n, &v[n]); - if (_csi_unlikely (status)) - return status; - } - status = csi_matrix_new_from_values (ctx, &matrix, v); - if (_csi_unlikely (status)) - return status; - - pop (6); - } else { - csi_array_t *array; - - status = _csi_ostack_get_array (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - - status = csi_matrix_new_from_array (ctx, &matrix, array); - if (_csi_unlikely (status)) - return status; - - pop (1); - } - - return push (&matrix); -} - -static csi_status_t -_map_to_image (csi_t *ctx) -{ - csi_object_t obj; - csi_array_t *array; - csi_status_t status; - cairo_rectangle_int_t extents, *r; - cairo_surface_t *surface; - - check (2); - - status = _csi_ostack_get_array (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_surface (ctx, 1, &surface); - if (_csi_unlikely (status)) - return status; - - switch (array->stack.len) { - case 0: - r = NULL; - break; - case 4: - extents.x = floor (_csi_object_as_real (&array->stack.objects[0])); - extents.y = floor (_csi_object_as_real (&array->stack.objects[1])); - extents.width = ceil (_csi_object_as_real (&array->stack.objects[2])); - extents.height = ceil (_csi_object_as_real (&array->stack.objects[3])); - r = &extents; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r)); - pop (1); - return push (&obj); -} - -static csi_status_t -_unmap_image (csi_t *ctx) -{ - cairo_surface_t *surface, *image; - csi_status_t status; - - check (2); - - status = _csi_ostack_get_surface (ctx, 0, &image); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 1, &surface); - if (_csi_unlikely (status)) - return status; - - cairo_surface_unmap_image (surface, image); - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mesh (csi_t *ctx) -{ - csi_object_t obj; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_mesh (); - return push (&obj); -} - -static csi_status_t -_mesh_begin_patch (csi_t *ctx) -{ - csi_status_t status; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - - check (1); - - status = _csi_ostack_get_pattern (ctx, 0, &pattern); - if (_csi_unlikely (status)) - return status; - - cairo_mesh_pattern_begin_patch (pattern); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mesh_end_patch (csi_t *ctx) -{ - csi_status_t status; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - - check (1); - - status = _csi_ostack_get_pattern (ctx, 0, &pattern); - if (_csi_unlikely (status)) - return status; - - cairo_mesh_pattern_end_patch (pattern); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mesh_set_control_point (csi_t *ctx) -{ - csi_status_t status; - double x, y; - csi_integer_t point; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - - check (4); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 2, &point); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_pattern (ctx, 3, &pattern); - if (_csi_unlikely (status)) - return status; - - cairo_mesh_pattern_set_control_point (pattern, point, x, y); - - pop (3); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mesh_set_corner_color (csi_t *ctx) -{ - csi_status_t status; - double r, g, b, a; - csi_integer_t corner; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - - check (6); - - status = _csi_ostack_get_number (ctx, 0, &a); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 4, &corner); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_pattern (ctx, 5, &pattern); - if (_csi_unlikely (status)) - return status; - - cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a); - - pop (5); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mod (csi_t *ctx) -{ - csi_integer_t x, y; - csi_status_t status; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - - pop (2); - return _csi_push_ostack_integer (ctx, x % y); -} - -static csi_status_t -_move_to (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - int type; - double x, y; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 2); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_move_to (obj->datum.cr, x, y); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_mesh_pattern_move_to (obj->datum.pattern, x, y); - break; - - /* XXX path object */ - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_mul (csi_t *ctx) -{ - csi_object_t *A; - csi_object_t *B; - csi_object_type_t type_a, type_b; - - check (2); - - B = _csi_peek_ostack (ctx, 0); - A = _csi_peek_ostack (ctx, 1); - - type_a = csi_object_get_type (A); - if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || - type_a == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - type_b = csi_object_get_type (B); - if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || - type_b == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - - if (type_a == CSI_OBJECT_TYPE_REAL && - type_b == CSI_OBJECT_TYPE_REAL) - { - return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real); - - } - else if (type_a == CSI_OBJECT_TYPE_INTEGER && - type_b == CSI_OBJECT_TYPE_INTEGER) - { - return _csi_push_ostack_integer (ctx, - A->datum.integer * B->datum.integer); - } - else - { - double v; - - if (type_a == CSI_OBJECT_TYPE_REAL) - v = A->datum.real; - else - v = A->datum.integer; - - if (type_b == CSI_OBJECT_TYPE_REAL) - v *= B->datum.real; - else - v *= B->datum.integer; - - return _csi_push_ostack_real (ctx, v); - } -} - -static csi_status_t -_or (csi_t *ctx) -{ - csi_object_t *a, *b; - int type; - - check (2); - - a = _csi_peek_ostack (ctx, 0); - b = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - pop (2); - type = csi_object_get_type (a); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - return _csi_push_ostack_integer (ctx, - a->datum.integer | b->datum.integer); - case CSI_OBJECT_TYPE_BOOLEAN: - return _csi_push_ostack_boolean (ctx, - a->datum.boolean | b->datum.boolean); - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_paint (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_paint); -} - -static csi_status_t -_paint_with_alpha (csi_t *ctx) -{ - cairo_t *cr; - csi_status_t status; - double alpha; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &alpha); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_paint_with_alpha (cr, alpha); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_pattern (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - cairo_surface_t *surface; - - check (1); - - status = _csi_ostack_get_surface (ctx, 0, &surface); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_for_surface (surface); - - pop (1); - return push (&obj); -} - -static csi_status_t -_pop (csi_t *ctx) -{ - check (1); - pop (1); - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_pop_group (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - cairo_t *cr; - - check (1); - - status = _csi_ostack_get_context (ctx, 0, &cr); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pop_group (cr); - - return push (&obj); -} - -static csi_status_t -_push_group (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - long content; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &content); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_push_group_with_content (cr, content); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_radial (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double x1, y1, r1, x2, y2, r2; - - check (6); - - status = _csi_ostack_get_number (ctx, 0, &r2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &y2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &x2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &r1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &y1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 5, &x1); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2); - pop (6); - return push (&obj); -} - -static csi_status_t -_rectangle (csi_t *ctx) -{ - csi_status_t status; - double x, y; - double w, h; - cairo_t *cr; - - check (5); - - status = _csi_ostack_get_number (ctx, 0, &h); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &w); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 4, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX path object */ - - cairo_rectangle (cr, x, y, w, h); - pop(4); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_rel_curve_to (csi_t *ctx) -{ - csi_status_t status; - double x1, y1; - double x2, y2; - double x3, y3; - cairo_t *cr; - - check (7); - - status = _csi_ostack_get_number (ctx, 0, &y3); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x3); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &y2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &x2); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 4, &y1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 5, &x1); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 6, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX path object */ - - cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3); - pop (6); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_rel_line_to (csi_t *ctx) -{ - csi_status_t status; - double x, y; - cairo_t *cr; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 2, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX path object */ - - cairo_rel_line_to (cr, x, y); - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_rel_move_to (csi_t *ctx) -{ - csi_status_t status; - double x, y; - cairo_t *cr; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 2, &cr); - if (_csi_unlikely (status)) - return status; - - /* XXX path object */ - cairo_rel_move_to (cr, x, y); - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_repeat (csi_t *ctx) -{ - csi_array_t *proc; - csi_integer_t count; - csi_status_t status; - - check (2); - - status = _csi_ostack_get_procedure (ctx, 0, &proc); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_integer (ctx, 1, &count); - if (_csi_unlikely (status)) - return status; - - if (_csi_unlikely (count < 0)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - proc->base.ref++; - pop (2); - - while (count--) { - status = _csi_array_execute (ctx, proc); - if (_csi_unlikely (status)) - break; - } - - if (--proc->base.ref == 0) - csi_array_free (ctx, proc); - - return status; -} - -static csi_status_t -_reset_clip (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_reset_clip); -} - -static csi_status_t -_restore (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_restore); -} - -static csi_status_t -_rgb (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double r,g,b; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &r); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_rgb (r, g, b); - pop (3); - return push (&obj); -} - -static csi_status_t -_rgba (csi_t *ctx) -{ - csi_object_t obj; - csi_status_t status; - double r,g,b,a; - - check (4); - - status = _csi_ostack_get_number (ctx, 0, &a); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &r); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_PATTERN; - obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a); - pop (4); - return push (&obj); -} - -static csi_status_t -_roll (csi_t *ctx) -{ - csi_status_t status; - long j, n; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &j); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 1, &n); - if (_csi_unlikely (status)) - return status; - - pop (2); - check (n); - return _csi_stack_roll (ctx, &ctx->ostack, j, n); -} - -static csi_status_t -_rotate (csi_t *ctx) -{ - csi_object_t *obj; - csi_status_t status; - double theta; - int type; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &theta); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_rotate (obj->datum.cr, theta); - break; - - case CSI_OBJECT_TYPE_PATTERN: - { - cairo_matrix_t ctm; - cairo_pattern_get_matrix (obj->datum.pattern, &ctm); - cairo_matrix_rotate (&ctm, theta); - cairo_pattern_set_matrix (obj->datum.pattern, &ctm); - } - break; - - - case CSI_OBJECT_TYPE_MATRIX: - cairo_matrix_rotate (&obj->datum.matrix->matrix, theta); - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_save (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_save); -} - -static csi_status_t -_scale (csi_t *ctx) -{ - csi_object_t *obj; - csi_status_t status; - double x, y; - int type; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 2); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_scale (obj->datum.cr, x, y); - break; - - case CSI_OBJECT_TYPE_PATTERN: - { - cairo_matrix_t ctm; - cairo_pattern_get_matrix (obj->datum.pattern, &ctm); - cairo_matrix_scale (&ctm, x, y); - cairo_pattern_set_matrix (obj->datum.pattern, &ctm); - } - break; - - - case CSI_OBJECT_TYPE_MATRIX: - cairo_matrix_scale (&obj->datum.matrix->matrix, x, y); - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_font_options_load_from_dictionary (csi_t *ctx, - csi_dictionary_t *dict, - cairo_font_options_t *options) -{ - const struct { - const char *key; - void (*setter) (cairo_font_options_t *, int val); - } properties[] = { - { "antialias", - (void (*)(cairo_font_options_t *, int val)) - cairo_font_options_set_antialias }, - { "subpixel-order", - (void (*)(cairo_font_options_t *, int val)) - cairo_font_options_set_subpixel_order }, - { "hint-style", - (void (*)(cairo_font_options_t *, int val)) - cairo_font_options_set_hint_style }, - { "hint-metrics", - (void (*)(cairo_font_options_t *, int val)) - cairo_font_options_set_hint_metrics }, - { NULL, NULL }, - }, *prop = properties; - - while (prop->key != NULL) { - csi_object_t key, value; - csi_status_t status; - - status = csi_name_new_static (ctx, &key, prop->key); - if (_csi_unlikely (status)) - return status; - - if (csi_dictionary_has (dict, key.datum.name)) { - status = csi_dictionary_get (ctx, dict, key.datum.name, &value); - if (_csi_unlikely (status)) - return status; - - if (_csi_unlikely (csi_object_get_type (&value) != - CSI_OBJECT_TYPE_INTEGER)) - { - csi_object_free (ctx, &value); - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - prop->setter (options, value.datum.integer); - } - - prop++; - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_scaled_font (csi_t *ctx) -{ - csi_object_t obj; - csi_dictionary_t *dict; - cairo_font_face_t *font_face = NULL; /* silence the compiler */ - cairo_matrix_t font_matrix, ctm; - cairo_font_options_t *options; - csi_status_t status; - - check (4); - - status = _csi_ostack_get_dictionary (ctx, 0, &dict); - if (_csi_unlikely (status)) - return status; - options = cairo_font_options_create (); - status = _font_options_load_from_dictionary (ctx, dict, options); - if (_csi_unlikely (status)) { - cairo_font_options_destroy (options); - return status; - } - - status = _csi_ostack_get_matrix (ctx, 1, &ctm); - if (_csi_unlikely (status)) { - cairo_font_options_destroy (options); - return status; - } - - status = _csi_ostack_get_matrix (ctx, 2, &font_matrix); - if (_csi_unlikely (status)) { - cairo_font_options_destroy (options); - return status; - } - - status = _csi_ostack_get_font_face (ctx, 3, &font_face); - if (_csi_unlikely (status)) { - cairo_font_options_destroy (options); - return status; - } - - obj.type = CSI_OBJECT_TYPE_SCALED_FONT; - obj.datum.scaled_font = cairo_scaled_font_create (font_face, - &font_matrix, - &ctm, - options); - cairo_font_options_destroy (options); - pop (4); - return push (&obj); -} - -static csi_status_t -_select_font_face (csi_t *ctx) -{ - cairo_t *cr; - long weight; - long slant; - csi_string_t *family; - csi_status_t status; - - check (4); - - status = _csi_ostack_get_integer (ctx, 0, &weight); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 1, &slant); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_string (ctx, 2, &family); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 3, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_select_font_face (cr, family->string, slant, weight); - pop (3); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_context_set (csi_t *ctx, - cairo_t *cr, - csi_name_t key, - csi_object_t *obj) -{ - if (strcmp ((char *) key, "source") == 0) { - if (_csi_unlikely (csi_object_get_type (obj) != - CSI_OBJECT_TYPE_PATTERN)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - cairo_set_source (cr, obj->datum.pattern); - return CSI_STATUS_SUCCESS; - } - - if (strcmp ((char *) key, "scaled-font") == 0) { - if (_csi_unlikely (csi_object_get_type (obj) != - CSI_OBJECT_TYPE_SCALED_FONT)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - cairo_set_scaled_font (cr, obj->datum.scaled_font); - return CSI_STATUS_SUCCESS; - } - - if (strcmp ((char *) key, "font-face") == 0) { - if (_csi_unlikely (csi_object_get_type (obj) != - CSI_OBJECT_TYPE_FONT)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - cairo_set_font_face (cr, obj->datum.font_face); - return CSI_STATUS_SUCCESS; - } - - /* return _proxy_set()? */ - return _csi_error (CSI_STATUS_INVALID_SCRIPT); -} - -static csi_status_t -_set (csi_t *ctx) -{ - csi_object_t *key, *value, *dst; - csi_status_t status; - int type; - - check (3); - - value = _csi_peek_ostack (ctx, 0); - key = _csi_peek_ostack (ctx, 1); - dst = _csi_peek_ostack (ctx, 2); - - type = csi_object_get_type (dst); - switch (type) { - case CSI_OBJECT_TYPE_DICTIONARY: - if (_csi_unlikely (csi_object_get_type (key) != - CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = csi_dictionary_put (ctx, - dst->datum.dictionary, - key->datum.name, - value); - break; - case CSI_OBJECT_TYPE_ARRAY: - if (_csi_unlikely (csi_object_get_type (key) != - CSI_OBJECT_TYPE_INTEGER)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = csi_array_put (ctx, - dst->datum.array, - key->datum.integer, - value); - break; - - case CSI_OBJECT_TYPE_CONTEXT: - if (_csi_unlikely (csi_object_get_type (key) != - CSI_OBJECT_TYPE_NAME)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - status = _context_set (ctx, - dst->datum.cr, - key->datum.name, - value); - break; - - case CSI_OBJECT_TYPE_STRING: -#if 0 - status = csi_string_put (dst, key, value); - break; -#endif - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - return status; -} - -static csi_status_t -_set_antialias (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - long antialias; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &antialias); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_antialias (cr, antialias); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_dash (csi_t *ctx) -{ - csi_array_t *array; - csi_status_t status; - cairo_t *cr; - double offset; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &offset); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_array (ctx, 1, &array); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 2, &cr); - if (_csi_unlikely (status)) - return status; - - if (array->stack.len == 0) { - cairo_set_dash (cr, NULL, 0., 0.); - } else { - double stack_dashes[8]; - double *dashes; - csi_integer_t n; - - if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) { - dashes = stack_dashes; - } else { - if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double))) - return _csi_error (CSI_STATUS_NO_MEMORY); - dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len); - if (_csi_unlikely (dashes == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } - - for (n = 0; n < array->stack.len; n++) { - if (_csi_unlikely (! csi_object_is_number - (&array->stack.objects[n]))) - { - if (dashes != stack_dashes) - _csi_free (ctx, dashes); - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - dashes[n] = csi_number_get_value (&array->stack.objects[n]); - } - - cairo_set_dash (cr, dashes, n, offset); - - if (dashes != stack_dashes) - _csi_free (ctx, dashes); - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_device_offset (csi_t *ctx) -{ - csi_status_t status; - cairo_surface_t *surface; - double x, y; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 2, &surface); - if (_csi_unlikely (status)) - return status; - - cairo_surface_set_device_offset (surface, x, y); - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_device_scale (csi_t *ctx) -{ - csi_status_t status; - cairo_surface_t *surface; - double x, y; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 2, &surface); - if (_csi_unlikely (status)) - return status; - - cairo_surface_set_device_scale (surface, x, y); - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_extend (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - long extend; - int type; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &extend); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_pattern_set_extend (cairo_get_source (obj->datum.cr), - extend); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_pattern_set_extend (obj->datum.pattern, extend); - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_fallback_resolution (csi_t *ctx) -{ - csi_status_t status; - cairo_surface_t *surface; - double dpi_x, dpi_y; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &dpi_y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &dpi_x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 2, &surface); - if (_csi_unlikely (status)) - return status; - - cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y); - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_fill_rule (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - long fill_rule; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &fill_rule); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_fill_rule (cr, fill_rule); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_filter (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - long filter; - int type; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &filter); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_pattern_set_filter (cairo_get_source (obj->datum.cr), - filter); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_pattern_set_filter (obj->datum.pattern, filter); - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_font_face (csi_t *ctx) -{ - cairo_t *cr; - cairo_font_face_t *font = NULL; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_font_face (ctx, 0, &font); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_font_face (cr, font); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_font_options (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - csi_dictionary_t *dict; - cairo_font_options_t *options; - - check (2); - - status = _csi_ostack_get_dictionary (ctx, 0, &dict); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - options = cairo_font_options_create (); - status = _font_options_load_from_dictionary (ctx, dict, options); - if (_csi_unlikely (status)) - return status; - - cairo_set_font_options (cr, options); - cairo_font_options_destroy (options); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_font_matrix (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - cairo_matrix_t m; - - check (2); - - status = _csi_ostack_get_matrix (ctx, 0, &m); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_font_matrix (cr, &m); - pop(1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_font_size (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - double size; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &size); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_font_size (cr, size); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_line_cap (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - long line_cap; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &line_cap); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_line_cap (cr, line_cap); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_line_join (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - long line_join; - - status = _csi_ostack_get_integer (ctx, 0, &line_join); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_line_join (cr, line_join); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_line_width (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - double line_width; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &line_width); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_line_width (cr, line_width); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_matrix (csi_t *ctx) -{ - csi_object_t *obj; - csi_status_t status; - cairo_matrix_t m; - int type; - - check (2); - - status = _csi_ostack_get_matrix (ctx, 0, &m); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_set_matrix (obj->datum.cr, &m); - break; - case CSI_OBJECT_TYPE_PATTERN: - cairo_pattern_set_matrix (obj->datum.pattern, &m); - break; - case CSI_OBJECT_TYPE_MATRIX: - obj->datum.matrix->matrix = m; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -struct _mime_tag { - csi_t *ctx; - csi_string_t *source; -}; -static void -_mime_tag_destroy (void *closure) -{ - struct _mime_tag *tag = closure; - - if (--tag->source->base.ref) - csi_string_free (tag->ctx, tag->source); - - _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag)); -} - -static csi_status_t -_set_mime_data (csi_t *ctx) -{ - csi_status_t status; - csi_object_t *obj; - const char *mime = NULL; /* silence the compiler */ - csi_object_t source; - cairo_surface_t *surface; - struct _mime_tag *tag; - int type; - - check (3); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_FILE: - status = _csi_file_as_string (ctx, obj->datum.file, &source); - if (_csi_unlikely (status)) - return status; - - break; - - case CSI_OBJECT_TYPE_STRING: - source = *csi_object_reference (obj); - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - status = _csi_ostack_get_string_constant (ctx, 1, &mime); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_surface (ctx, 2, &surface); - if (_csi_unlikely (status)) - return status; - - - /* XXX free source */ - tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag)); - if (_csi_unlikely (tag == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - tag->ctx = cairo_script_interpreter_reference (ctx); - tag->source = source.datum.string; - tag->source->base.ref++; - - status = cairo_surface_set_mime_data (surface, - mime, - (uint8_t *) - source.datum.string->string, - source.datum.string->len, - _mime_tag_destroy, tag); - if (_csi_unlikely (status)) { - _mime_tag_destroy (tag); - return status; - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_miter_limit (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - double miter_limit; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &miter_limit); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_miter_limit (cr, miter_limit); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_operator (csi_t *ctx) -{ - cairo_t *cr; - long val; - csi_status_t status; - - check (2); - - status = _csi_ostack_get_integer (ctx, 0, &val); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_operator (cr, val); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_scaled_font (csi_t *ctx) -{ - cairo_t *cr; - cairo_scaled_font_t *font = NULL; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_scaled_font (ctx, 0, &font); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_scaled_font (cr, font); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_source (csi_t *ctx) -{ - cairo_t *cr; - cairo_pattern_t *pattern = NULL; /* silence the compiler */ - csi_status_t status; - - check (2); - - status = _csi_ostack_get_pattern (ctx, 0, &pattern); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_source (cr, pattern); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_boolean_t -_matching_images (cairo_surface_t *a, cairo_surface_t *b) -{ - cairo_format_t format_a, format_b; - - if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE) - return FALSE; - if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE) - return FALSE; - - if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b)) - return FALSE; - - if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b)) - return FALSE; - - format_a = cairo_image_surface_get_format (a); - if (format_a == CAIRO_FORMAT_RGB24) - format_a = CAIRO_FORMAT_ARGB32; - - format_b = cairo_image_surface_get_format (b); - if (format_b == CAIRO_FORMAT_RGB24) - format_b = CAIRO_FORMAT_ARGB32; - - if (format_a != format_b) - return FALSE; - - return TRUE; -} - -static csi_status_t -_set_source_image (csi_t *ctx) -{ - csi_status_t status; - cairo_surface_t *surface; - cairo_surface_t *source; - - check (2); - - status = _csi_ostack_get_surface (ctx, 0, &source); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 1, &surface); - if (_csi_unlikely (status)) - return status; - - /* Catch the most frequent use of simply uploading pixel data, - * principally to remove the pixman ops from the profiles. - */ - if (_csi_likely (_matching_images (surface, source))) { - if (cairo_surface_get_reference_count (surface) == 1 && - cairo_surface_get_reference_count (source) == 1) - { - _csi_peek_ostack (ctx, 0)->datum.surface = surface; - _csi_peek_ostack (ctx, 1)->datum.surface = source; - } - else - { - cairo_surface_flush (surface); - memcpy (cairo_image_surface_get_data (surface), - cairo_image_surface_get_data (source), - cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source)); - cairo_surface_mark_dirty (surface); - } - } else { - cairo_t *cr; - - cr = cairo_create (surface); - cairo_set_source_surface (cr, source, 0, 0); - cairo_paint (cr); - cairo_destroy (cr); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_source_rgb (csi_t *ctx) -{ - csi_status_t status; - double r,g,b; - cairo_t *cr; - - check (4); - - status = _csi_ostack_get_number (ctx, 0, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 3, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_source_rgb (cr, r, g, b); - pop (3); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_source_rgba (csi_t *ctx) -{ - csi_status_t status; - double r,g,b,a; - cairo_t *cr; - - check (5); - - status = _csi_ostack_get_number (ctx, 0, &a); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &b); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &g); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &r); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 4, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_source_rgba (cr, r, g, b, a); - pop (4); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_set_tolerance (csi_t *ctx) -{ - csi_status_t status; - cairo_t *cr; - double tolerance; - - check (2); - - status = _csi_ostack_get_number (ctx, 0, &tolerance); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_set_tolerance (cr, tolerance); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_transform (csi_t *ctx) -{ - csi_object_t *obj; - csi_status_t status; - cairo_matrix_t m; - int type; - - check (2); - - status = _csi_ostack_get_matrix (ctx, 0, &m); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_transform (obj->datum.cr, &m); - break; - case CSI_OBJECT_TYPE_PATTERN: - { - cairo_matrix_t ctm; - cairo_pattern_get_matrix (obj->datum.pattern, &ctm); - cairo_matrix_multiply (&ctm, &m, &ctm); - cairo_pattern_set_matrix (obj->datum.pattern, &ctm); - } - break; - case CSI_OBJECT_TYPE_MATRIX: - cairo_matrix_multiply (&obj->datum.matrix->matrix, - &m, - &obj->datum.matrix->matrix); - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_translate (csi_t *ctx) -{ - csi_object_t *obj; - csi_status_t status; - double x, y; - int type; - - check (3); - - status = _csi_ostack_get_number (ctx, 0, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &x); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 2); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_translate (obj->datum.cr, x, y); - break; - - case CSI_OBJECT_TYPE_PATTERN: - { - cairo_matrix_t ctm; - cairo_pattern_get_matrix (obj->datum.pattern, &ctm); - cairo_matrix_translate (&ctm, x, y); - cairo_pattern_set_matrix (obj->datum.pattern, &ctm); - } - break; - - - case CSI_OBJECT_TYPE_MATRIX: - cairo_matrix_translate (&obj->datum.matrix->matrix, x, y); - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_true (csi_t *ctx) -{ - return _csi_push_ostack_boolean (ctx, TRUE); -} - -static csi_status_t -_show_page (csi_t *ctx) -{ - csi_object_t *obj; - int type; - - check (1); - - obj = _csi_peek_ostack (ctx, 0); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_CONTEXT: - cairo_show_page (obj->datum.cr); - if (ctx->hooks.copy_page != NULL) - ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); - break; - case CSI_OBJECT_TYPE_SURFACE: - cairo_surface_show_page (obj->datum.surface); - /* XXX hook? */ - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_similar (csi_t *ctx) -{ - csi_object_t obj; - long content; - double width, height; - cairo_surface_t *other; - csi_status_t status; - - check (4); - - status = _csi_ostack_get_integer (ctx, 0, &content); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &height); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &width); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 3, &other); - if (_csi_unlikely (status)) - return status; - - /* silently fix-up a common bug when writing CS */ - if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) { - if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA)) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - switch ((int) content) { - default: - case CAIRO_FORMAT_ARGB32: - content = CAIRO_CONTENT_COLOR_ALPHA; - break; - case CAIRO_FORMAT_RGB16_565: - case CAIRO_FORMAT_RGB24: - content = CAIRO_CONTENT_COLOR; - break; - case CAIRO_FORMAT_A8: - case CAIRO_FORMAT_A1: - content = CAIRO_CONTENT_ALPHA; - break; - } - } - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_create_similar (other, - content, width, height); - pop (4); - return push (&obj); -} - -static csi_status_t -_similar_image (csi_t *ctx) -{ - csi_object_t obj; - long format; - double width, height; - cairo_surface_t *other; - csi_status_t status; - - check (4); - - status = _csi_ostack_get_number (ctx, 0, &height); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &width); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_integer (ctx, 2, &format); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 3, &other); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_create_similar_image (other, - format, - width, height); - pop (4); - return push (&obj); -} - -static csi_status_t -_subsurface (csi_t *ctx) -{ - csi_object_t obj; - double x, y, width, height; - cairo_surface_t *target; - csi_status_t status; - - check (5); - - status = _csi_ostack_get_number (ctx, 0, &height); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 1, &width); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 2, &y); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_number (ctx, 3, &x); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 4, &target); - if (_csi_unlikely (status)) - return status; - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height); - pop (5); - return push (&obj); -} - -static csi_status_t -_show_text (csi_t *ctx) -{ - csi_status_t status; - csi_string_t *text; - cairo_t *cr; - - check (2); - - status = _csi_ostack_get_string (ctx, 0, &text); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_show_text (cr, text->string); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_show_glyphs (csi_t *ctx) -{ - csi_array_t *array; - csi_status_t status; - cairo_t *cr; - cairo_glyph_t stack_glyphs[256], *glyphs; - csi_integer_t nglyphs, i; - - check (2); - - status = _csi_ostack_get_array (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - /* count glyphs */ - nglyphs = 0; - for (i = 0; i < array->stack.len; i++) { - csi_object_t *obj = &array->stack.objects[i]; - int type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_ARRAY: - nglyphs += obj->datum.array->stack.len; - break; - case CSI_OBJECT_TYPE_STRING: - nglyphs += obj->datum.string->len; - break; - } - } - if (nglyphs == 0) { - pop (1); - return CSI_STATUS_SUCCESS; - } - - if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { - if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) - return _csi_error (CSI_STATUS_NO_MEMORY); - - glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); - if (_csi_unlikely (glyphs == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else - glyphs = stack_glyphs; - - nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); - cairo_show_glyphs (cr, glyphs, nglyphs); - - if (glyphs != stack_glyphs) - _csi_free (ctx, glyphs); - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_show_text_glyphs (csi_t *ctx) -{ - csi_object_t *obj; - csi_array_t *array; - csi_string_t *string; - csi_string_t *utf8_string; - csi_status_t status; - cairo_t *cr; - cairo_text_cluster_t stack_clusters[256], *clusters; - cairo_glyph_t stack_glyphs[256], *glyphs; - csi_integer_t nglyphs, nclusters, i; - long direction; - int type; - - check (5); - - status = _csi_ostack_get_integer (ctx, 0, &direction); - if (_csi_unlikely (status)) - return status; - - obj = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_ARRAY: - array = obj->datum.array; - nclusters = array->stack.len / 2; - if (nclusters > ARRAY_LENGTH (stack_clusters)) { - if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t))) - return _csi_error (CSI_STATUS_NO_MEMORY); - clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); - if (_csi_unlikely (clusters == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else - clusters = stack_clusters; - - for (i = 0; i < nclusters; i++) { - clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]); - clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]); - } - break; - - case CSI_OBJECT_TYPE_STRING: - string = obj->datum.string; - nclusters = string->len / 2; - if (nclusters > ARRAY_LENGTH (stack_clusters)) { - if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t))) - return _csi_error (CSI_STATUS_NO_MEMORY); - clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); - if (_csi_unlikely (clusters == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else - clusters = stack_clusters; - - for (i = 0; i < nclusters; i++) { - clusters[i].num_bytes = string->string[2*i+0]; - clusters[i].num_glyphs = string->string[2*i+1]; - } - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - status = _csi_ostack_get_array (ctx, 2, &array); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_string (ctx, 3, &utf8_string); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 4, &cr); - if (_csi_unlikely (status)) - return status; - - /* count glyphs */ - nglyphs = 0; - for (i = 0; i < array->stack.len; i++) { - obj = &array->stack.objects[i]; - type = csi_object_get_type (obj); - switch (type) { - case CSI_OBJECT_TYPE_ARRAY: - nglyphs += obj->datum.array->stack.len; - break; - case CSI_OBJECT_TYPE_STRING: - nglyphs += obj->datum.string->len; - break; - } - } - if (nglyphs == 0) { - pop (4); - return CSI_STATUS_SUCCESS; - } - - if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { - if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) - return _csi_error (CSI_STATUS_NO_MEMORY); - - glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); - if (_csi_unlikely (glyphs == NULL)) - return _csi_error (CSI_STATUS_NO_MEMORY); - } else - glyphs = stack_glyphs; - - nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); - cairo_show_text_glyphs (cr, - utf8_string->string, utf8_string->len, - glyphs, nglyphs, - clusters, nclusters, - direction); - - if (clusters != stack_clusters) - _csi_free (ctx, clusters); - if (glyphs != stack_glyphs) - _csi_free (ctx, glyphs); - - pop (4); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_stroke (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_stroke); -} - -static csi_status_t -_stroke_preserve (csi_t *ctx) -{ - return _do_cairo_op (ctx, cairo_stroke_preserve); -} - -static csi_status_t -_sub (csi_t *ctx) -{ - csi_object_t *A; - csi_object_t *B; - csi_object_type_t type_a, type_b; - - check (2); - - B = _csi_peek_ostack (ctx, 0); - A = _csi_peek_ostack (ctx, 1); - - type_a = csi_object_get_type (A); - if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || - type_a == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - type_b = csi_object_get_type (B); - if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || - type_b == CSI_OBJECT_TYPE_REAL))) - { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (2); - - if (type_a == CSI_OBJECT_TYPE_REAL && - type_b == CSI_OBJECT_TYPE_REAL) - { - return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real); - - } - else if (type_a == CSI_OBJECT_TYPE_INTEGER && - type_b == CSI_OBJECT_TYPE_INTEGER) - { - return _csi_push_ostack_integer (ctx, - A->datum.integer - B->datum.integer); - } - else - { - double v; - - if (type_a == CSI_OBJECT_TYPE_REAL) - v = A->datum.real; - else - v = A->datum.integer; - - if (type_b == CSI_OBJECT_TYPE_REAL) - v -= B->datum.real; - else - v -= B->datum.integer; - - return _csi_push_ostack_real (ctx, v); - } -} - -static csi_status_t -_surface (csi_t *ctx) -{ - csi_object_t obj; - csi_dictionary_t *dict; - csi_proxy_t *proxy; - csi_object_t key; - double width, height; - csi_surface_create_func_t hook; - long content; - cairo_surface_t *surface; - long uid; - csi_status_t status; - - check (1); - - status = _csi_ostack_get_dictionary (ctx, 0, &dict); - if (_csi_unlikely (status)) - return status; - - status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width); - if (_csi_unlikely (status)) - return status; - status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height); - if (_csi_unlikely (status)) - return status; - - content = CAIRO_CONTENT_COLOR_ALPHA; - status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content); - if (_csi_unlikely (status)) - return status; - - uid = 0; - status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid); - if (_csi_unlikely (status)) - return status; - if (uid == 0) { - status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid); - if (_csi_unlikely (status)) - return status; - } - - hook = ctx->hooks.surface_create; - assert (hook != NULL); - - surface = hook (ctx->hooks.closure, content, width, height, uid); - if (_csi_unlikely (surface == NULL)) { - return _csi_error (CSI_STATUS_NULL_POINTER); - } - - proxy = _csi_proxy_create (ctx, surface, dict, - ctx->hooks.surface_destroy, - ctx->hooks.closure); - if (_csi_unlikely (proxy == NULL)) { - cairo_surface_destroy (surface); - return _csi_error (CSI_STATUS_NO_MEMORY); - } - - status = cairo_surface_set_user_data (surface, - &_csi_proxy_key, - proxy, _csi_proxy_destroy); - if (_csi_unlikely (status)) { - _csi_proxy_destroy (proxy); - cairo_surface_destroy (surface); - return status; - } - - status = csi_name_new_static (ctx, &key, "fallback-resolution"); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - if (csi_dictionary_has (dict, key.datum.name)) { - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { - csi_array_t *array = obj.datum.array; - if (array->stack.len == 2) { - cairo_surface_set_fallback_resolution (surface, - csi_number_get_value - (&array->stack.objects[0]), - csi_number_get_value - (&array->stack.objects[1])); - } - } - } - /* initialise surface to source */ - status = csi_name_new_static (ctx, &key, "source"); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - if (csi_dictionary_has (dict, key.datum.name)) { - cairo_surface_t *image; - cairo_t *cr; - - status = _image_load_from_dictionary (ctx, dict, &image); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - - cr = cairo_create (surface); - cairo_set_source_surface (cr, image, 0, 0); - cairo_surface_destroy (image); - cairo_paint (cr); - status = cairo_status (cr); - cairo_destroy (cr); - - if (_csi_unlikely (status)) - return status; - } - - status = csi_name_new_static (ctx, &key, "device-offset"); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - if (csi_dictionary_has (dict, key.datum.name)) { - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { - csi_array_t *array = obj.datum.array; - - if (array->stack.len == 2) { - cairo_surface_set_device_offset (surface, - csi_number_get_value - (&array->stack.objects[0]), - csi_number_get_value - (&array->stack.objects[1])); - } - } - } - - status = csi_name_new_static (ctx, &key, "device-scale"); - if (_csi_unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } - if (csi_dictionary_has (dict, key.datum.name)) { - status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); - if (_csi_unlikely (status)) - return status; - - if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { - csi_array_t *array = obj.datum.array; - - if (array->stack.len == 2) { - cairo_surface_set_device_scale (surface, - csi_number_get_value - (&array->stack.objects[0]), - csi_number_get_value - (&array->stack.objects[1])); - } - } - } - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = surface; - pop (1); - return push (&obj); -} - -static csi_status_t -_record (csi_t *ctx) -{ - csi_object_t obj; - long content; - csi_array_t *array; - csi_status_t status; - cairo_rectangle_t extents; - cairo_rectangle_t *r; - - check (2); - - status = _csi_ostack_get_array (ctx, 0, &array); - if (_csi_unlikely (status)) - return status; - - status = _csi_ostack_get_integer (ctx, 1, &content); - if (_csi_unlikely (status)) - return status; - - switch (array->stack.len) { - case 0: - r = NULL; - break; - case 2: - extents.x = extents.y = 0; - extents.width = _csi_object_as_real (&array->stack.objects[0]); - extents.height = _csi_object_as_real (&array->stack.objects[1]); - r = &extents; - break; - case 4: - extents.x = _csi_object_as_real (&array->stack.objects[0]); - extents.y = _csi_object_as_real (&array->stack.objects[1]); - extents.width = _csi_object_as_real (&array->stack.objects[2]); - extents.height = _csi_object_as_real (&array->stack.objects[3]); - r = &extents; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - obj.type = CSI_OBJECT_TYPE_SURFACE; - obj.datum.surface = cairo_recording_surface_create (content, r); - pop (2); - return push (&obj); -} - -static csi_status_t -_text_path (csi_t *ctx) -{ - csi_status_t status; - csi_string_t *text; - cairo_t *cr; - - check (2); - - status = _csi_ostack_get_string (ctx, 0, &text); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_context (ctx, 1, &cr); - if (_csi_unlikely (status)) - return status; - - cairo_text_path (cr, text->string); - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_undef (csi_t *ctx) -{ - csi_name_t name = 0; /* silence the compiler */ - csi_status_t status; - - check (1); - - status = _csi_ostack_get_name (ctx, 0, &name); - if (_csi_unlikely (status)) - return status; - - status = _csi_name_undefine (ctx, name); - if (_csi_unlikely (status)) - return status; - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_unset (csi_t *ctx) -{ - csi_object_t *dst; - csi_name_t name = 0; /* silence the compiler */ - csi_status_t status; - int type; - - check (2); - - status = _csi_ostack_get_name (ctx, 0, &name); - if (_csi_unlikely (status)) - return status; - - dst = _csi_peek_ostack (ctx, 1); - type = csi_object_get_type (dst); - switch (type) { - case CSI_OBJECT_TYPE_DICTIONARY: - csi_dictionary_remove (ctx, dst->datum.dictionary, name); - break; - case CSI_OBJECT_TYPE_STRING: - case CSI_OBJECT_TYPE_ARRAY: - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_write_to_png (csi_t *ctx) -{ - csi_status_t status; - csi_string_t *filename; - cairo_surface_t *surface; - - check (2); - - status = _csi_ostack_get_string (ctx, 0, &filename); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 1, &surface); - if (_csi_unlikely (status)) - return status; - -#if CAIRO_HAS_PNG_FUNCTIONS - status = cairo_surface_write_to_png (surface, filename->string); - if (_csi_unlikely (status)) - return status; -#else - return CAIRO_STATUS_WRITE_ERROR; -#endif - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_write_to_script (csi_t *ctx) -{ - csi_status_t status; - csi_string_t *filename; - cairo_surface_t *record; - - check (2); - - status = _csi_ostack_get_string (ctx, 0, &filename); - if (_csi_unlikely (status)) - return status; - status = _csi_ostack_get_surface (ctx, 1, &record); - if (_csi_unlikely (status)) - return status; - - if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING) - return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; - -#if CAIRO_HAS_SCRIPT_SURFACE - { - cairo_device_t *script; - - script = cairo_script_create (filename->string); - status = cairo_script_from_recording_surface (script, record); - cairo_device_destroy (script); - if (_csi_unlikely (status)) - return status; - } -#else - return CAIRO_STATUS_WRITE_ERROR; -#endif - - pop (1); - return CSI_STATUS_SUCCESS; -} - -static csi_status_t -_xor (csi_t *ctx) -{ - csi_object_t *a, *b; - int type; - - check (2); - - a = _csi_peek_ostack (ctx, 0); - b = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - - pop (2); - type = csi_object_get_type (a); - switch (type) { - case CSI_OBJECT_TYPE_INTEGER: - return _csi_push_ostack_integer (ctx, - a->datum.integer ^ b->datum.integer); - case CSI_OBJECT_TYPE_BOOLEAN: - return _csi_push_ostack_boolean (ctx, - a->datum.boolean ^ b->datum.boolean); - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } -} - -static csi_status_t -_debug_print (csi_t *ctx) -{ - csi_object_t *obj; - - check (1); - obj = _csi_peek_ostack (ctx, 0); - switch (csi_object_get_type (obj)) { - case CSI_OBJECT_TYPE_NULL: - fprintf (stderr, "NULL\n"); - break; - - /* atomics */ - case CSI_OBJECT_TYPE_BOOLEAN: - fprintf (stderr, "boolean: %s\n", - obj->datum.boolean ? "true" : "false"); - break; - case CSI_OBJECT_TYPE_INTEGER: - fprintf (stderr, "integer: %ld\n", obj->datum.integer); - break; - case CSI_OBJECT_TYPE_MARK: - fprintf (stderr, "mark\n"); - break; - case CSI_OBJECT_TYPE_NAME: - fprintf (stderr, "name: %s\n", (char *) obj->datum.name); - break; - case CSI_OBJECT_TYPE_OPERATOR: - fprintf (stderr, "operator: %p\n", obj->datum.ptr); - break; - case CSI_OBJECT_TYPE_REAL: - fprintf (stderr, "real: %g\n", obj->datum.real); - break; - - /* compound */ - case CSI_OBJECT_TYPE_ARRAY: - fprintf (stderr, "array\n"); - break; - case CSI_OBJECT_TYPE_DICTIONARY: - fprintf (stderr, "dictionary\n"); - break; - case CSI_OBJECT_TYPE_FILE: - fprintf (stderr, "file\n"); - break; - case CSI_OBJECT_TYPE_MATRIX: - fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n", - obj->datum.matrix->matrix.xx, - obj->datum.matrix->matrix.yx, - obj->datum.matrix->matrix.xy, - obj->datum.matrix->matrix.yy, - obj->datum.matrix->matrix.x0, - obj->datum.matrix->matrix.y0); - break; - case CSI_OBJECT_TYPE_STRING: - fprintf (stderr, "string: %s\n", obj->datum.string->string); - break; - - /* cairo */ - case CSI_OBJECT_TYPE_CONTEXT: - fprintf (stderr, "context\n"); - break; - case CSI_OBJECT_TYPE_FONT: - fprintf (stderr, "font\n"); - break; - case CSI_OBJECT_TYPE_PATTERN: - fprintf (stderr, "pattern\n"); - break; - case CSI_OBJECT_TYPE_SCALED_FONT: - fprintf (stderr, "scaled-font\n"); - break; - case CSI_OBJECT_TYPE_SURFACE: - fprintf (stderr, "surface\n"); - break; - } - pop (1); - return CSI_STATUS_SUCCESS; -} - -static const csi_operator_def_t -_defs[] = { - { "<<", _mark }, - { ">>", end_dict_construction }, - { "[", _mark }, - { "]", end_array_construction }, - { "a", _alpha }, - { "abs", NULL }, - { "add", _add }, - { "add-color-stop", _add_color_stop }, - { "and", _and }, - { "arc", _arc }, - { "arc-negative", _arc_negative }, - { "arc-", _arc_negative }, - { "arc-to", NULL }, - { "array", _array }, - { "astore", NULL }, - { "atan", NULL }, - { "bind", _bind }, - { "bitshift", _bitshift }, - { "c", _curve_to }, - { "C", _rel_curve_to }, - { "ceiling", NULL }, - { "clear", NULL }, - { "clear-to-mark", NULL }, - { "clip", _clip }, - { "clip-extents", NULL }, - { "clip-preserve", _clip_preserve }, - { "clip+", _clip_preserve }, - { "close-path", _close_path }, - { "context", _context }, - { "copy", _copy }, - { "copy-page", _copy_page }, - { "cos", NULL }, - { "count", NULL }, - { "count-to-mark", NULL }, - { "curve-to", _curve_to }, - { "cvi", _cvi }, - { "cvr", _cvr }, - { "def", _def }, - { "device-to-user", NULL }, - { "device-to-user-distance", NULL }, - { "dict", _dict }, - { "div", _div }, - { "dup", _duplicate }, - { "eq", _eq }, - { "exch", _exch }, - { "exec", NULL }, - { "exp", NULL }, - { "false", _false }, - { "fill", _fill }, - { "fill-extents", NULL }, - { "fill-preserve", _fill_preserve }, - { "fill+", _fill_preserve }, - { "filter", _filter }, - { "floor", NULL }, - { "font", _font }, - { "for", _for }, - { "forall", NULL }, - { "g", _gray }, - { "ge", _ge }, - { "get", _get }, - { "glyph-path", _glyph_path }, - { "gt", _gt }, - { "h", _close_path }, - { "identity", _identity }, - { "if", _if }, - { "ifelse", _ifelse }, - { "image", _image }, - { "index", _index }, - { "integer", _integer }, - { "invert", _invert }, - { "in-stroke", NULL }, - { "in-fill", NULL }, - { "known", NULL }, - { "l", _line_to }, - { "L", _rel_line_to }, - { "languagelevel", NULL }, - { "le", _le }, - { "length", NULL }, - { "linear", _linear }, - { "line-to", _line_to }, - { "ln", NULL }, - { "load", NULL }, - { "log", NULL }, - { "loop", NULL }, - { "lt", _lt }, - { "m", _move_to }, - { "M", _rel_move_to }, - { "map-to-image", _map_to_image }, - { "mark", _mark }, - { "mask", _mask }, - { "matrix", _matrix }, - - { "mesh", _mesh }, - { "begin-patch", _mesh_begin_patch }, - { "end-patch", _mesh_end_patch }, - { "set-control-point", _mesh_set_control_point }, - { "set-corner-color", _mesh_set_corner_color }, - - { "mod", _mod }, - { "move-to", _move_to }, - { "mul", _mul }, - { "multiply", NULL }, - { "n", _new_path }, - { "N", _new_sub_path }, - { "ne", _ne }, - { "neg", _neg }, - { "new-path", _new_path }, - { "new-sub-path", _new_sub_path }, - { "not", _not }, - { "null", _null }, - { "or", _or }, - { "paint", _paint }, - { "paint-with-alpha", _paint_with_alpha }, - { "pattern", _pattern }, - { "pop", _pop }, - { "pop-group", _pop_group }, - { "push-group", _push_group }, - { "radial", _radial }, - { "rand", NULL }, - { "record", _record }, - { "rectangle", _rectangle }, - { "repeat", _repeat }, - { "restore", _restore }, - { "rel-curve-to", _rel_curve_to }, - { "rel-line-to", _rel_line_to }, - { "rel-move-to", _rel_move_to }, - { "reset-clip", _reset_clip }, - { "rgb", _rgb }, - { "rgba", _rgba }, - { "roll", _roll }, - { "rotate", _rotate }, - { "round", NULL }, - { "run", NULL }, - { "save", _save }, - { "scale", _scale }, - { "scaled-font", _scaled_font }, - { "select-font-face", _select_font_face }, - { "set", _set }, - { "set-antialias", _set_antialias }, - { "set-dash", _set_dash }, - { "set-device-offset", _set_device_offset }, - { "set-device-scale", _set_device_scale }, - { "set-extend", _set_extend }, - { "set-fallback-resolution", _set_fallback_resolution }, - { "set-fill-rule", _set_fill_rule }, - { "set-filter", _set_filter }, - { "set-font-face", _set_font_face }, - { "set-font-options", _set_font_options }, - { "set-font-matrix", _set_font_matrix }, - { "set-font-size", _set_font_size }, - { "set-line-cap", _set_line_cap }, - { "set-line-join", _set_line_join }, - { "set-line-width", _set_line_width }, - { "set-matrix", _set_matrix }, - { "set-miter-limit", _set_miter_limit }, - { "set-mime-data", _set_mime_data }, - { "set-operator", _set_operator }, - { "set-scaled-font", _set_scaled_font }, - { "set-source", _set_source }, - { "set-source-image", _set_source_image }, - { "set-source-rgb", _set_source_rgb }, - { "set-source-rgba", _set_source_rgba }, - { "set-tolerance", _set_tolerance }, - { "show-glyphs", _show_glyphs }, - { "show-text", _show_text }, - { "show-text-glyphs", _show_text_glyphs }, - { "show-page", _show_page }, - { "similar", _similar }, - { "similar-image", _similar_image }, - { "sin", NULL }, - { "sqrt", NULL }, - { "sub", _sub }, - { "subsurface", _subsurface }, - { "surface", _surface }, - { "string", NULL }, - { "stroke", _stroke }, - { "stroke-extents", NULL }, - { "stroke-preserve", _stroke_preserve }, - { "stroke+", _stroke_preserve }, - { "text-path", _text_path }, - { "transform", _transform }, - { "transform-distance", NULL }, - { "transform-point", NULL }, - { "translate", _translate }, - { "true", _true }, - { "type", NULL }, - { "undef", _undef }, - { "unmap-image", _unmap_image }, - { "unset", _unset }, - { "user-to-device", NULL }, - { "user-to-device-distance", NULL }, - { "where", NULL }, - { "write-to-png", _write_to_png }, - { "write-to-script", _write_to_script }, - { "xor", _xor }, - - { "=", _debug_print }, - - { NULL, NULL }, -}; - -const csi_operator_def_t * -_csi_operators (void) -{ - return _defs; -} - -static const csi_integer_constant_def_t -_integer_constants[] = { - { "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 }, - - { "WINDING", CAIRO_FILL_RULE_WINDING }, - { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD }, - - { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT }, - { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE }, - { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY }, - { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL }, - { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST }, - { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD }, - { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST }, - - { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT }, - { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND }, - { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE }, - - { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER }, - { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND }, - { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL }, - - { "EXTEND_NONE", CAIRO_EXTEND_NONE }, - { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT }, - { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT }, - { "EXTEND_PAD", CAIRO_EXTEND_PAD }, - - { "FILTER_FAST", CAIRO_FILTER_FAST }, - { "FILTER_GOOD", CAIRO_FILTER_GOOD }, - { "FILTER_BEST", CAIRO_FILTER_BEST }, - { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR }, - { "FILTER_NEAREST", CAIRO_FILTER_NEAREST }, - { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN }, - - { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL }, - { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC }, - { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE }, - - { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL }, - { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD }, - - { "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 }, - - { "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 }, - - { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT }, - { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF }, - { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON }, - - { "FORWARD", 0 }, - { "BACKWARD", 1 }, - - { "COLOR", CAIRO_CONTENT_COLOR }, - { "ALPHA", CAIRO_CONTENT_ALPHA }, - { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA }, - - { "A1", CAIRO_FORMAT_A1 }, - { "A8", CAIRO_FORMAT_A8 }, - { "RGB16_565", CAIRO_FORMAT_RGB16_565 }, - { "RGB24", CAIRO_FORMAT_RGB24 }, - { "ARGB32", CAIRO_FORMAT_ARGB32 }, - { "INVALID", CAIRO_FORMAT_INVALID }, - - { NULL, 0 } -}; - - -const csi_integer_constant_def_t * -_csi_integer_constants (void) -{ - return _integer_constants; -} - -static const csi_real_constant_def_t -_real_constants[] = { - { "math.pi", M_PI }, - { "math.2pi", 2 * M_PI }, - { "math.sqrt2", M_SQRT2 }, - { "math.ln2", M_LN2 }, - - { NULL, 0 } -}; - -const csi_real_constant_def_t * -_csi_real_constants (void) -{ - return _real_constants; -} |