2 * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
4 * This library is free software; you can redistribute it and/or
5 * modify it either under the terms of the GNU Lesser General Public
6 * License version 2.1 as published by the Free Software Foundation
7 * (the "LGPL") or, at your option, under the terms of the Mozilla
8 * Public License Version 1.1 (the "MPL"). If you do not alter this
9 * notice, a recipient may use your version of this file under either
10 * the MPL or the LGPL.
12 * You should have received a copy of the LGPL along with this library
13 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15 * You should have received a copy of the MPL along with this library
16 * in the file COPYING-MPL-1.1
18 * The contents of this file are subject to the Mozilla Public License
19 * Version 1.1 (the "License"); you may not use this file except in
20 * compliance with the License. You may obtain a copy of the License at
21 * http://www.mozilla.org/MPL/
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
24 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
25 * the specific language governing rights and limitations.
27 * The Original Code is the cairo graphics library.
29 * The Initial Developer of the Original Code is Chris Wilson.
32 * Chris Wilson <chris@chris-wilson.co.uk>
35 /* TODO real path type */
37 #include "cairo-script-private.h"
39 #if CAIRO_HAS_SCRIPT_SURFACE
40 #include "cairo-script.h"
43 #include <stdio.h> /* snprintf */
44 #include <stdlib.h> /* mkstemp */
48 #define _USE_MATH_DEFINES /* for M_LN2, M_PI and M_SQRT2 on win32 */
49 #define snprintf _snprintf
53 #include <limits.h> /* INT_MAX */
61 #include <lzo/lzo2a.h>
66 # include <sys/mman.h>
73 typedef struct _csi_proxy {
76 csi_dictionary_t *dictionary;
77 csi_destroy_func_t destroy_func;
81 typedef struct _csi_blob {
88 static const cairo_user_data_key_t _csi_proxy_key;
89 static const cairo_user_data_key_t _csi_blob_key;
96 #define check(CNT) do {\
97 if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \
98 return _csi_error (CSI_STATUS_INVALID_SCRIPT); \
100 #define pop(CNT) _csi_pop_ostack (ctx, (CNT))
101 #define push(OBJ) _csi_push_ostack (ctx, (OBJ))
104 _csi_proxy_create (csi_t *ctx,
106 csi_dictionary_t *dictionary,
107 csi_destroy_func_t destroy_func,
112 proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t));
116 proxy->ctx = cairo_script_interpreter_reference (ctx);
118 proxy->destroy_func = destroy_func;
119 proxy->destroy_data = destroy_data;
120 proxy->dictionary = dictionary;
121 if (dictionary != NULL)
122 dictionary->base.ref++;
128 _csi_proxy_destroy (void *closure)
130 csi_proxy_t *proxy = closure;
131 csi_t *ctx = proxy->ctx;
133 /* XXX this doesn't work because user_data_destroy is called too late.
134 * Considering another hook into the (cairo internal) object system.
136 if (proxy->destroy_func != NULL)
137 proxy->destroy_func (proxy->destroy_data, proxy->ptr);
139 if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0)
140 csi_dictionary_free (ctx, proxy->dictionary);
142 _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t));
143 cairo_script_interpreter_destroy (ctx);
147 _csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len)
149 unsigned long hash = blob->hash;
152 unsigned long c = *data++;
160 _csi_blob_equal (const csi_list_t *link, void *data)
164 A = csi_container_of (link, csi_blob_t, list);
167 if (A->len != B->len)
170 if (A->hash != B->hash)
173 return memcmp (A->bytes, B->bytes, A->len) == 0;
177 _csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len)
185 _csi_list_unlink (csi_list_t *head, csi_list_t *link)
187 if (link->next != NULL)
188 link->next->prev = link->prev;
189 if (link->prev != NULL)
190 link->prev->next = link->next;
197 _csi_list_prepend (csi_list_t *head, csi_list_t *link)
207 _csi_list_find (csi_list_t *head,
208 csi_boolean_t (*predicate) (const csi_list_t *link, void *data),
211 while (head != NULL) {
212 if (predicate (head, data))
221 _csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out)
226 obj = _csi_peek_ostack (ctx, i);
227 type = csi_object_get_type (obj);
229 case CSI_OBJECT_TYPE_BOOLEAN:
230 *out = obj->datum.boolean;
232 case CSI_OBJECT_TYPE_INTEGER:
233 *out = !! obj->datum.integer;
235 case CSI_OBJECT_TYPE_REAL:
236 *out = obj->datum.real != 0.;
239 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
241 return CSI_STATUS_SUCCESS;
245 _csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out)
250 obj = _csi_peek_ostack (ctx, i);
251 type = csi_object_get_type (obj);
253 case CSI_OBJECT_TYPE_BOOLEAN:
254 *out = obj->datum.boolean;
256 case CSI_OBJECT_TYPE_INTEGER:
257 *out = obj->datum.integer;
259 case CSI_OBJECT_TYPE_REAL:
260 *out = obj->datum.real;
263 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
265 return CSI_STATUS_SUCCESS;
269 _csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out)
274 obj = _csi_peek_ostack (ctx, i);
275 type = csi_object_get_type (obj);
277 case CSI_OBJECT_TYPE_BOOLEAN:
278 *out = obj->datum.boolean;
280 case CSI_OBJECT_TYPE_INTEGER:
281 *out = obj->datum.integer;
283 case CSI_OBJECT_TYPE_REAL:
284 *out = obj->datum.real;
287 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
289 return CSI_STATUS_SUCCESS;
293 _csi_object_as_real (csi_object_t *obj)
297 type = csi_object_get_type (obj);
299 case CSI_OBJECT_TYPE_BOOLEAN:
300 return obj->datum.boolean;
301 case CSI_OBJECT_TYPE_INTEGER:
302 return obj->datum.integer;
303 case CSI_OBJECT_TYPE_REAL:
304 return obj->datum.real;
311 _csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out)
315 obj = _csi_peek_ostack (ctx, i);
316 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME))
317 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
319 *out = obj->datum.name;
320 return CSI_STATUS_SUCCESS;
324 _csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out)
328 obj = _csi_peek_ostack (ctx, i);
329 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT))
330 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
332 *out = obj->datum.cr;
333 return CSI_STATUS_SUCCESS;
337 _csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out)
341 obj = _csi_peek_ostack (ctx, i);
342 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT))
343 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
345 *out = obj->datum.font_face;
346 return CSI_STATUS_SUCCESS;
350 _csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out)
354 obj = _csi_peek_ostack (ctx, i);
355 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN))
356 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
358 *out = obj->datum.pattern;
359 return CSI_STATUS_SUCCESS;
363 _csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i,
364 cairo_scaled_font_t **out)
368 obj = _csi_peek_ostack (ctx, i);
370 (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT))
372 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
375 *out = obj->datum.scaled_font;
376 return CSI_STATUS_SUCCESS;
380 _csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out)
385 obj = _csi_peek_ostack (ctx, i);
386 type = csi_object_get_type (obj);
388 case CSI_OBJECT_TYPE_CONTEXT:
389 *out = cairo_get_target (obj->datum.cr);
391 case CSI_OBJECT_TYPE_SURFACE:
392 *out = obj->datum.surface;
395 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
397 return CSI_STATUS_SUCCESS;
401 _csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out)
405 obj = _csi_peek_ostack (ctx, i);
406 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY))
407 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
409 *out = obj->datum.array;
410 return CSI_STATUS_SUCCESS;
414 _csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out)
418 obj = _csi_peek_ostack (ctx, i);
419 if (_csi_unlikely (! csi_object_is_procedure (obj)))
420 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
422 *out = obj->datum.array;
423 return CSI_STATUS_SUCCESS;
427 _csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out)
431 obj = _csi_peek_ostack (ctx, i);
433 (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY))
435 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
438 *out = obj->datum.dictionary;
439 return CSI_STATUS_SUCCESS;
443 _csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out)
448 obj = _csi_peek_ostack (ctx, i);
449 type = csi_object_get_type (obj);
451 case CSI_OBJECT_TYPE_MATRIX:
452 *out = obj->datum.matrix->matrix;
453 return CSI_STATUS_SUCCESS;
455 case CSI_OBJECT_TYPE_ARRAY:
456 if (obj->datum.array->stack.len == 6) {
457 cairo_matrix_init (out,
458 csi_number_get_value (&obj->datum.array->stack.objects[0]),
459 csi_number_get_value (&obj->datum.array->stack.objects[1]),
460 csi_number_get_value (&obj->datum.array->stack.objects[2]),
461 csi_number_get_value (&obj->datum.array->stack.objects[3]),
462 csi_number_get_value (&obj->datum.array->stack.objects[4]),
463 csi_number_get_value (&obj->datum.array->stack.objects[5]));
464 return CSI_STATUS_SUCCESS;
467 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
472 _csi_dictionary_get_integer (csi_t *ctx,
473 csi_dictionary_t *dict,
475 csi_boolean_t optional,
479 csi_object_t key, obj;
482 status = csi_name_new_static (ctx, &key, name);
483 if (_csi_unlikely (status))
486 if (optional && ! csi_dictionary_has (dict, key.datum.name))
487 return CSI_STATUS_SUCCESS;
489 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
490 if (_csi_unlikely (status))
493 type = csi_object_get_type (&obj);
495 case CSI_OBJECT_TYPE_BOOLEAN:
496 *value = obj.datum.boolean;
498 case CSI_OBJECT_TYPE_INTEGER:
499 *value = obj.datum.integer;
501 case CSI_OBJECT_TYPE_REAL:
502 *value = obj.datum.real;
505 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
507 return CSI_STATUS_SUCCESS;
511 _csi_dictionary_get_number (csi_t *ctx,
512 csi_dictionary_t *dict,
514 csi_boolean_t optional,
518 csi_object_t key, obj;
520 status = csi_name_new_static (ctx, &key, name);
521 if (_csi_unlikely (status))
524 if (optional && ! csi_dictionary_has (dict, key.datum.name))
525 return CSI_STATUS_SUCCESS;
527 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
528 if (_csi_unlikely (status))
531 *value = csi_number_get_value (&obj);
532 return CSI_STATUS_SUCCESS;
536 _csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out)
540 obj = _csi_peek_ostack (ctx, i);
541 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING))
542 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
544 *out = obj->datum.string;
545 return CSI_STATUS_SUCCESS;
549 _csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out)
554 obj = _csi_peek_ostack (ctx, i);
555 type = csi_object_get_type (obj);
557 case CSI_OBJECT_TYPE_NAME:
558 *out = (const char *) obj->datum.name;
560 case CSI_OBJECT_TYPE_STRING:
561 *out = obj->datum.string->string;
564 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
566 return CSI_STATUS_SUCCESS;
570 _do_cairo_op (csi_t *ctx, void (*op) (cairo_t *))
577 status = _csi_ostack_get_context (ctx, 0, &cr);
578 if (_csi_unlikely (status))
582 return CSI_STATUS_SUCCESS;
586 end_dict_construction (csi_t *ctx)
589 csi_dictionary_t *dict;
592 status = csi_dictionary_new (ctx, &obj);
593 if (_csi_unlikely (status))
596 dict = obj.datum.dictionary;
598 csi_object_t *name, *value;
602 value = _csi_peek_ostack (ctx, 0);
603 if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) {
610 name = _csi_peek_ostack (ctx, 1);
612 (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME))
614 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
617 status = csi_dictionary_put (ctx, dict, name->datum.name, value);
618 if (_csi_unlikely (status))
628 end_array_construction (csi_t *ctx)
637 if (csi_object_get_type (_csi_peek_ostack (ctx, len)) ==
638 CSI_OBJECT_TYPE_MARK)
646 status = csi_array_new (ctx, len, &obj);
647 if (_csi_unlikely (status))
653 array = obj.datum.array;
654 memcpy (array->stack.objects,
655 _csi_peek_ostack (ctx, len - 1),
656 sizeof (csi_object_t) * len);
657 array->stack.len = len;
659 ctx->ostack.len -= len + 1;
673 status = _csi_ostack_get_number (ctx, 0, &a);
674 if (_csi_unlikely (status))
679 obj.type = CSI_OBJECT_TYPE_PATTERN;
680 obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a);
689 csi_object_type_t type_a, type_b;
693 B = _csi_peek_ostack (ctx, 0);
694 A = _csi_peek_ostack (ctx, 1);
696 type_a = csi_object_get_type (A);
697 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
698 type_a == CSI_OBJECT_TYPE_REAL)))
700 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
703 type_b = csi_object_get_type (B);
704 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
705 type_b == CSI_OBJECT_TYPE_REAL)))
707 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
712 if (type_a == CSI_OBJECT_TYPE_REAL &&
713 type_b == CSI_OBJECT_TYPE_REAL)
715 return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real);
718 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
719 type_b == CSI_OBJECT_TYPE_INTEGER)
721 return _csi_push_ostack_integer (ctx,
722 A->datum.integer + B->datum.integer);
728 if (type_a == CSI_OBJECT_TYPE_REAL)
731 v = A->datum.integer;
733 if (type_b == CSI_OBJECT_TYPE_REAL)
736 v += B->datum.integer;
738 return _csi_push_ostack_real (ctx, v);
743 _add_color_stop (csi_t *ctx)
746 double offset, r, g, b, a;
747 cairo_pattern_t *pattern = NULL; /* silence the compiler */
751 status = _csi_ostack_get_number (ctx, 0, &a);
752 if (_csi_unlikely (status))
754 status = _csi_ostack_get_number (ctx, 1, &b);
755 if (_csi_unlikely (status))
757 status = _csi_ostack_get_number (ctx, 2, &g);
758 if (_csi_unlikely (status))
760 status = _csi_ostack_get_number (ctx, 3, &r);
761 if (_csi_unlikely (status))
763 status = _csi_ostack_get_number (ctx, 4, &offset);
764 if (_csi_unlikely (status))
766 status = _csi_ostack_get_pattern (ctx, 5, &pattern);
767 if (_csi_unlikely (status))
770 cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a);
773 return CSI_STATUS_SUCCESS;
784 a = _csi_peek_ostack (ctx, 0);
785 b = _csi_peek_ostack (ctx, 1);
786 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
787 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
790 type = csi_object_get_type (a);
792 case CSI_OBJECT_TYPE_INTEGER:
793 return _csi_push_ostack_integer (ctx,
794 a->datum.integer & b->datum.integer);
795 case CSI_OBJECT_TYPE_BOOLEAN:
796 return _csi_push_ostack_boolean (ctx,
797 a->datum.boolean & b->datum.boolean);
799 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
808 double theta1, theta2;
813 status = _csi_ostack_get_number (ctx, 0, &theta2);
814 if (_csi_unlikely (status))
816 status = _csi_ostack_get_number (ctx, 1, &theta1);
817 if (_csi_unlikely (status))
819 status = _csi_ostack_get_number (ctx, 2, &r);
820 if (_csi_unlikely (status))
822 status = _csi_ostack_get_number (ctx, 3, &y);
823 if (_csi_unlikely (status))
825 status = _csi_ostack_get_number (ctx, 4, &x);
826 if (_csi_unlikely (status))
828 status = _csi_ostack_get_context (ctx, 5, &cr);
829 if (_csi_unlikely (status))
832 /* XXX handle path object */
834 cairo_arc (cr, x, y, r, theta1, theta2);
836 return CSI_STATUS_SUCCESS;
840 _arc_negative (csi_t *ctx)
844 double theta1, theta2;
849 status = _csi_ostack_get_number (ctx, 0, &theta2);
850 if (_csi_unlikely (status))
852 status = _csi_ostack_get_number (ctx, 1, &theta1);
853 if (_csi_unlikely (status))
855 status = _csi_ostack_get_number (ctx, 2, &r);
856 if (_csi_unlikely (status))
858 status = _csi_ostack_get_number (ctx, 3, &y);
859 if (_csi_unlikely (status))
861 status = _csi_ostack_get_number (ctx, 4, &x);
862 if (_csi_unlikely (status))
864 status = _csi_ostack_get_context (ctx, 5, &cr);
865 if (_csi_unlikely (status))
868 /* XXX handle path object */
870 cairo_arc_negative (cr, x, y, r, theta1, theta2);
872 return CSI_STATUS_SUCCESS;
881 status = csi_array_new (ctx, 0, &obj);
882 if (_csi_unlikely (status))
889 _bind_substitute (csi_t *ctx, csi_array_t *array)
893 csi_dictionary_t *dict;
895 /* perform operator substitution on the executable array (procedure) */
896 dict = ctx->dstack.objects[0].datum.dictionary;
897 n = array->stack.len;
898 for (i = 0; i < n; i++) {
899 csi_object_t *obj = &array->stack.objects[i];
901 if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) {
902 csi_dictionary_entry_t *entry;
904 entry = _csi_hash_table_lookup (&dict->hash_table,
909 } else if (csi_object_is_procedure (obj)) {
910 status = _bind_substitute (ctx, obj->datum.array);
911 if (_csi_unlikely (status))
916 return CSI_STATUS_SUCCESS;
920 _idiom_substitute (csi_t *ctx, csi_array_t *array)
926 /* XXX substring search, build array once then search for
927 * longest matching idiom, repeat. */
929 /* scan the top-most array for sequences we can pre-compile */
931 /* now recurse for subroutines */
932 j = array->stack.len;
933 for (i = 0; i < j; i++) {
934 csi_object_t *obj = &array->stack.objects[i];
936 if (csi_object_is_procedure (obj)) {
937 status = _idiom_substitute (ctx, obj->datum.array);
938 if (_csi_unlikely (_cairo_is_error (status))
944 return CSI_STATUS_SUCCESS;
955 status = _csi_ostack_get_procedure (ctx, 0, &array);
956 if (_csi_unlikely (status))
959 status = _bind_substitute (ctx, array);
960 if (_csi_unlikely (status))
963 status = _idiom_substitute (ctx, array);
964 if (_csi_unlikely (status))
967 return CSI_STATUS_SUCCESS;
971 _bitshift (csi_t *ctx)
978 status = _csi_ostack_get_integer (ctx, 0, &shift);
979 if (_csi_unlikely (status))
981 status = _csi_ostack_get_integer (ctx, 1, &v);
982 if (_csi_unlikely (status))
992 _csi_peek_ostack (ctx, 0)->datum.integer = v;
994 return CSI_STATUS_SUCCESS;
1000 return _do_cairo_op (ctx, cairo_clip);
1004 _clip_preserve (csi_t *ctx)
1006 return _do_cairo_op (ctx, cairo_clip_preserve);
1010 _close_path (csi_t *ctx)
1012 return _do_cairo_op (ctx, cairo_close_path);
1016 _context (csi_t *ctx)
1019 csi_status_t status;
1020 cairo_surface_t *surface;
1022 csi_context_create_func_t hook;
1027 status = _csi_ostack_get_surface (ctx, 0, &surface);
1028 if (_csi_unlikely (status))
1031 hook = ctx->hooks.context_create;
1033 cr = hook (ctx->hooks.closure, surface);
1035 cr = cairo_create (surface);
1037 proxy = _csi_proxy_create (ctx, cr, NULL,
1038 ctx->hooks.context_destroy,
1039 ctx->hooks.closure);
1040 if (_csi_unlikely (proxy == NULL)) {
1042 return _csi_error (CSI_STATUS_NO_MEMORY);
1045 status = cairo_set_user_data (cr, &_csi_proxy_key,
1046 proxy, _csi_proxy_destroy);
1047 if (_csi_unlikely (status)) {
1048 _csi_proxy_destroy (proxy);
1054 obj.type = CSI_OBJECT_TYPE_CONTEXT;
1067 obj = csi_object_reference (_csi_peek_ostack (ctx, 0));
1070 type = csi_object_get_type (obj);
1072 /*XXX array, string, dictionary, etc */
1073 case CSI_OBJECT_TYPE_INTEGER:
1077 n = obj->datum.integer;
1078 if (_csi_unlikely (n < 0))
1079 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1082 for (i = n; i--; ) {
1083 csi_status_t status;
1085 status = _csi_push_ostack_copy (ctx,
1086 _csi_peek_ostack (ctx, n-1));
1087 if (_csi_unlikely (status))
1093 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1096 return CSI_STATUS_SUCCESS;
1100 _copy_page (csi_t *ctx)
1107 obj = _csi_peek_ostack (ctx, 0);
1108 type = csi_object_get_type (obj);
1110 case CSI_OBJECT_TYPE_CONTEXT:
1111 cairo_copy_page (obj->datum.cr);
1112 if (ctx->hooks.copy_page != NULL)
1113 ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
1115 case CSI_OBJECT_TYPE_SURFACE:
1116 cairo_surface_copy_page (obj->datum.surface);
1120 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1123 return CSI_STATUS_SUCCESS;
1127 _curve_to (csi_t *ctx)
1129 csi_status_t status;
1138 status = _csi_ostack_get_number (ctx, 0, &y3);
1139 if (_csi_unlikely (status))
1141 status = _csi_ostack_get_number (ctx, 1, &x3);
1142 if (_csi_unlikely (status))
1144 status = _csi_ostack_get_number (ctx, 2, &y2);
1145 if (_csi_unlikely (status))
1147 status = _csi_ostack_get_number (ctx, 3, &x2);
1148 if (_csi_unlikely (status))
1150 status = _csi_ostack_get_number (ctx, 4, &y1);
1151 if (_csi_unlikely (status))
1153 status = _csi_ostack_get_number (ctx, 5, &x1);
1154 if (_csi_unlikely (status))
1157 obj = _csi_peek_ostack (ctx, 6);
1158 type = csi_object_get_type (obj);
1160 case CSI_OBJECT_TYPE_CONTEXT:
1161 cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3);
1163 case CSI_OBJECT_TYPE_PATTERN:
1164 cairo_mesh_pattern_curve_to (obj->datum.pattern,
1165 x1, y1, x2, y2, x3, y3);
1167 /* XXX handle path object */
1171 return CSI_STATUS_SUCCESS;
1177 csi_object_t *val, obj;
1182 val = _csi_peek_ostack (ctx, 0);
1183 type = csi_object_get_type (val);
1185 case CSI_OBJECT_TYPE_INTEGER:
1186 return CSI_STATUS_SUCCESS;
1188 case CSI_OBJECT_TYPE_REAL:
1190 return _csi_push_ostack_integer (ctx, val->datum.real);
1192 case CSI_OBJECT_TYPE_STRING:
1193 if (! _csi_parse_number (&obj,
1194 val->datum.string->string,
1195 val->datum.string->len))
1197 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1201 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_INTEGER)
1204 return _csi_push_ostack_integer (ctx, obj.datum.real);
1207 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1214 csi_object_t *val, obj;
1219 val = _csi_peek_ostack (ctx, 0);
1220 type = csi_object_get_type (val);
1222 case CSI_OBJECT_TYPE_REAL:
1223 return CSI_STATUS_SUCCESS;
1225 case CSI_OBJECT_TYPE_INTEGER:
1227 return _csi_push_ostack_real (ctx, val->datum.integer);
1229 case CSI_OBJECT_TYPE_STRING:
1230 if (! _csi_parse_number (&obj,
1231 val->datum.string->string,
1232 val->datum.string->len))
1234 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1238 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_REAL)
1241 return _csi_push_ostack_real (ctx, obj.datum.integer);
1244 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1251 csi_name_t name = 0; /* silence the compiler */
1252 csi_status_t status;
1256 status = _csi_ostack_get_name (ctx, 1, &name);
1257 if (_csi_unlikely (status))
1260 status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0));
1261 if (_csi_unlikely (status))
1265 return CSI_STATUS_SUCCESS;
1272 csi_status_t status;
1274 status = csi_dictionary_new (ctx, &obj);
1275 if (_csi_unlikely (status))
1286 csi_object_type_t type_a, type_b;
1290 B = _csi_peek_ostack (ctx, 0);
1291 A = _csi_peek_ostack (ctx, 1);
1293 type_a = csi_object_get_type (A);
1294 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
1295 type_a == CSI_OBJECT_TYPE_REAL)))
1297 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1300 type_b = csi_object_get_type (B);
1301 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
1302 type_b == CSI_OBJECT_TYPE_REAL)))
1304 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1309 if (type_a == CSI_OBJECT_TYPE_REAL &&
1310 type_b == CSI_OBJECT_TYPE_REAL)
1312 return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real);
1315 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
1316 type_b == CSI_OBJECT_TYPE_INTEGER)
1318 return _csi_push_ostack_integer (ctx,
1319 A->datum.integer / B->datum.integer);
1325 if (type_a == CSI_OBJECT_TYPE_REAL)
1328 v = A->datum.integer;
1330 if (type_b == CSI_OBJECT_TYPE_REAL)
1333 v /= B->datum.integer;
1335 return _csi_push_ostack_real (ctx, v);
1340 _duplicate (csi_t *ctx)
1344 return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0));
1350 csi_object_t *a, *b;
1355 b = _csi_peek_ostack (ctx, 0);
1356 a = _csi_peek_ostack (ctx, 1);
1358 v = csi_object_eq (a, b);
1361 return _csi_push_ostack_boolean (ctx, v);
1367 return _csi_stack_exch (&ctx->ostack);
1373 return _csi_push_ostack_boolean (ctx, FALSE);
1379 return _do_cairo_op (ctx, cairo_fill);
1383 _fill_preserve (csi_t *ctx)
1385 return _do_cairo_op (ctx, cairo_fill_preserve);
1389 _filter (csi_t *ctx)
1392 csi_dictionary_t *dict = NULL;
1393 csi_status_t status;
1394 const char *name = NULL; /* silence the compiler */
1395 const struct filters {
1397 csi_status_t (*constructor) (csi_t *t,
1402 { "ascii85", csi_file_new_ascii85_decode },
1404 { "deflate", csi_file_new_deflate_decode },
1407 { "lzw", csi_file_new_lzw_decode },
1415 status = _csi_ostack_get_string_constant (ctx, 0, &name);
1416 if (_csi_unlikely (status))
1419 src = _csi_peek_ostack (ctx, 1);
1421 if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) {
1422 dict = src->datum.dictionary;
1426 src = _csi_peek_ostack (ctx, 2);
1430 for (filter = filters; filter->name != NULL; filter++) {
1431 if (strcmp (name, filter->name) == 0) {
1434 status = filter->constructor (ctx, &file, dict, src);
1435 if (_csi_unlikely (status))
1439 return push (&file);
1443 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1446 static cairo_status_t
1447 _type3_init (cairo_scaled_font_t *scaled_font,
1449 cairo_font_extents_t *metrics)
1451 cairo_font_face_t *face;
1454 csi_dictionary_t *font;
1458 csi_status_t status;
1460 face = cairo_scaled_font_get_font_face (scaled_font);
1461 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1462 if (_csi_unlikely (proxy == NULL))
1463 return CAIRO_STATUS_NO_MEMORY;
1466 font = proxy->dictionary;
1468 status = csi_name_new_static (ctx, &key, "metrics");
1469 if (_csi_unlikely (status))
1470 return CAIRO_STATUS_NO_MEMORY;
1472 if (! csi_dictionary_has (font, key.datum.name))
1473 return CAIRO_STATUS_SUCCESS;
1475 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1476 if (_csi_unlikely (status))
1479 if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)
1480 return CAIRO_STATUS_USER_FONT_ERROR;
1482 array = obj.datum.array;
1483 if (array->stack.len != 5)
1484 return CAIRO_STATUS_USER_FONT_ERROR;
1486 metrics->ascent = csi_number_get_value (&array->stack.objects[0]);
1487 metrics->descent = csi_number_get_value (&array->stack.objects[1]);
1488 metrics->height = csi_number_get_value (&array->stack.objects[2]);
1489 metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]);
1490 metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]);
1492 return CAIRO_STATUS_SUCCESS;
1495 static cairo_status_t
1496 _type3_lookup (cairo_scaled_font_t *scaled_font,
1497 unsigned long unicode,
1498 unsigned long *glyph)
1500 cairo_font_face_t *face;
1503 csi_dictionary_t *font;
1504 csi_object_t obj, key;
1508 cairo_status_t status;
1510 face = cairo_scaled_font_get_font_face (scaled_font);
1511 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1512 if (_csi_unlikely (proxy == NULL))
1513 return CAIRO_STATUS_USER_FONT_ERROR;
1516 font = proxy->dictionary;
1518 status = csi_name_new_static (ctx, &key, "encoding");
1519 if (_csi_unlikely (status))
1520 return CAIRO_STATUS_USER_FONT_ERROR;
1522 if (! csi_dictionary_has (font, key.datum.name)) {
1524 return CAIRO_STATUS_SUCCESS;
1527 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1528 if (_csi_unlikely (status))
1529 return CAIRO_STATUS_USER_FONT_ERROR;
1531 if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
1532 return CAIRO_STATUS_USER_FONT_ERROR;
1534 snprintf (buf, sizeof (buf), "uni%04lu", unicode);
1535 array = obj.datum.array;
1536 for (i = 0; i < array->stack.len; i++) {
1539 name = &array->stack.objects[i];
1540 if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)
1543 if (strcmp ((char *) name->datum.name, buf) == 0) {
1545 return CAIRO_STATUS_SUCCESS;
1549 return CAIRO_STATUS_USER_FONT_ERROR;
1552 static cairo_status_t
1553 _type3_render (cairo_scaled_font_t *scaled_font,
1554 unsigned long glyph_index,
1556 cairo_text_extents_t *metrics)
1558 cairo_font_face_t *face;
1561 csi_dictionary_t *font;
1562 csi_array_t *glyphs;
1563 csi_object_t *glyph;
1566 csi_object_t render;
1567 csi_status_t status;
1569 face = cairo_scaled_font_get_font_face (scaled_font);
1570 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1571 if (_csi_unlikely (proxy == NULL))
1572 return CAIRO_STATUS_USER_FONT_ERROR;
1575 font = proxy->dictionary;
1577 status = csi_name_new_static (ctx, &key, "glyphs");
1578 if (_csi_unlikely (status))
1579 return CAIRO_STATUS_USER_FONT_ERROR;
1581 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1582 if (_csi_unlikely (status))
1583 return CAIRO_STATUS_USER_FONT_ERROR;
1585 if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
1586 return CAIRO_STATUS_USER_FONT_ERROR;
1588 glyphs = obj.datum.array;
1589 glyph = &glyphs->stack.objects[glyph_index];
1590 if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL)
1591 return CAIRO_STATUS_SUCCESS; /* .notdef */
1593 if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY))
1594 return CAIRO_STATUS_USER_FONT_ERROR;
1596 status = csi_name_new_static (ctx, &key, "metrics");
1597 if (_csi_unlikely (status))
1598 return CAIRO_STATUS_USER_FONT_ERROR;
1600 font = glyph->datum.dictionary;
1601 if (csi_dictionary_has (font, key.datum.name)) {
1604 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1605 if (_csi_unlikely (status))
1606 return CAIRO_STATUS_USER_FONT_ERROR;
1608 if (_csi_unlikely (csi_object_get_type (&obj) !=
1609 CSI_OBJECT_TYPE_ARRAY))
1610 return CAIRO_STATUS_USER_FONT_ERROR;
1612 array = obj.datum.array;
1613 if (_csi_unlikely (array->stack.len != 6))
1614 return CAIRO_STATUS_USER_FONT_ERROR;
1616 metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]);
1617 metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]);
1618 metrics->width = csi_number_get_value (&array->stack.objects[2]);
1619 metrics->height = csi_number_get_value (&array->stack.objects[3]);
1620 metrics->x_advance = csi_number_get_value (&array->stack.objects[4]);
1621 metrics->y_advance = csi_number_get_value (&array->stack.objects[5]);
1624 status = csi_name_new_static (ctx, &key, "render");
1625 if (_csi_unlikely (status))
1626 return CAIRO_STATUS_USER_FONT_ERROR;
1628 status = csi_dictionary_get (ctx, font, key.datum.name, &render);
1629 if (_csi_unlikely (status))
1630 return CAIRO_STATUS_USER_FONT_ERROR;
1632 if (_csi_unlikely (! csi_object_is_procedure (&render)))
1633 return CAIRO_STATUS_USER_FONT_ERROR;
1635 obj.type = CSI_OBJECT_TYPE_CONTEXT;
1636 obj.datum.cr = cairo_reference (cr);
1637 status = push (&obj);
1638 if (_csi_unlikely (status)) {
1640 return CAIRO_STATUS_USER_FONT_ERROR;
1643 status = csi_object_execute (ctx, &render);
1645 return status ? CAIRO_STATUS_USER_FONT_ERROR : CAIRO_STATUS_SUCCESS;
1649 _font_type3 (csi_t *ctx,
1650 csi_dictionary_t *font,
1651 cairo_font_face_t **font_face_out)
1653 cairo_font_face_t *font_face;
1655 font_face = cairo_user_font_face_create ();
1656 cairo_user_font_face_set_init_func (font_face, _type3_init);
1657 cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup);
1658 cairo_user_font_face_set_render_glyph_func (font_face, _type3_render);
1660 *font_face_out = font_face;
1661 return CSI_STATUS_SUCCESS;
1664 #if CAIRO_HAS_FT_FONT
1665 #include <cairo-ft.h>
1666 #include <ft2build.h>
1667 #include FT_FREETYPE_H
1669 static FT_Library _ft_lib;
1671 struct _ft_face_data {
1675 csi_string_t *source;
1677 cairo_font_face_t *font_face;
1681 _ft_done_face (void *closure)
1683 struct _ft_face_data *data = closure;
1688 if (data->face != NULL)
1689 FT_Done_Face (data->face);
1691 ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list);
1693 if (data->source != NULL) {
1694 if (--data->source->base.ref == 0)
1695 csi_string_free (ctx, data->source);
1698 munmap (data->blob.bytes, data->blob.len);
1702 if (data->bytes != NULL)
1703 _csi_free (ctx, data->bytes);
1705 _csi_slab_free (ctx, data, sizeof (*data));
1707 cairo_script_interpreter_destroy (ctx);
1711 const uint8_t *bytes;
1716 /* manual form of swapping for swapless systems like tiny */
1718 _mmap_bytes (const struct mmap_vec *vec, int count)
1720 char template[] = "/tmp/csi-font.XXXXXX";
1725 fd = mkstemp (template);
1732 const uint8_t *bytes = vec->bytes;
1733 size_t len = vec->num_bytes;
1735 int ret = write (fd, bytes, len);
1744 num_bytes += vec->num_bytes;
1748 ptr = mmap (NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0);
1756 inflate_string (csi_t *ctx, csi_string_t *src)
1762 bytes = _csi_alloc (ctx, len + 1);
1766 switch (src->method) {
1774 if (uncompress ((Bytef *) bytes, &len,
1775 (Bytef *) src->string, src->len) != Z_OK)
1777 _csi_free (ctx, bytes);
1785 if (lzo2a_decompress ((Bytef *) src->string, src->len,
1786 (Bytef *) bytes, &len,
1789 _csi_free (ctx, bytes);
1801 _ft_create_for_source (csi_t *ctx,
1802 csi_string_t *source,
1803 int index, int load_flags,
1804 cairo_font_face_t **font_face_out)
1807 struct _ft_face_data *data;
1810 cairo_font_face_t *font_face;
1811 csi_status_t status;
1812 struct mmap_vec vec[2];
1817 /* check for an existing FT_Face (kept alive by the font cache) */
1818 /* XXX index/flags */
1819 _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len);
1820 _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t));
1821 link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
1823 if (--source->base.ref == 0)
1824 csi_string_free (ctx, source);
1825 data = csi_container_of (link, struct _ft_face_data, blob.list);
1826 *font_face_out = cairo_font_face_reference (data->font_face);
1827 return CSI_STATUS_SUCCESS;
1830 /* no existing font_face, create new FT_Face */
1831 if (_ft_lib == NULL) {
1832 err = FT_Init_FreeType (&_ft_lib);
1833 if (_csi_unlikely (err != FT_Err_Ok))
1834 return _csi_error (CSI_STATUS_NO_MEMORY);
1837 data = _csi_slab_alloc (ctx, sizeof (*data));
1839 return _csi_error (CSI_STATUS_NO_MEMORY);
1842 data->source = source;
1844 vec[0].bytes = tmpl.bytes;
1845 vec[0].num_bytes = tmpl.len;
1847 if (source->deflate) {
1848 len = source->deflate;
1849 bytes = inflate_string (ctx, source);
1850 if (_csi_unlikely (bytes == NULL))
1851 return _csi_error (CSI_STATUS_NO_MEMORY);
1853 vec[1].bytes = bytes;
1854 vec[1].num_bytes = len;
1855 data->bytes = bytes;
1864 ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
1865 data->ctx = cairo_script_interpreter_reference (ctx);
1866 data->blob.hash = tmpl.hash;
1867 data->blob.len = tmpl.len;
1869 data->blob.bytes = _mmap_bytes (vec, vec_count);
1870 if (data->blob.bytes != MAP_FAILED) {
1871 if (--source->base.ref == 0)
1872 csi_string_free (ctx, source);
1874 if (source->deflate) {
1875 _csi_free (ctx, bytes);
1876 bytes = data->blob.bytes + vec[0].num_bytes;
1878 bytes = data->blob.bytes;
1880 data->source = NULL;
1883 data->blob.bytes = tmpl.bytes;
1886 data->blob.bytes = tmpl.bytes;
1889 err = FT_New_Memory_Face (_ft_lib,
1893 if (_csi_unlikely (err != FT_Err_Ok)) {
1894 _ft_done_face (data);
1896 if (err == FT_Err_Out_Of_Memory)
1897 return _csi_error (CSI_STATUS_NO_MEMORY);
1899 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1902 font_face = cairo_ft_font_face_create_for_ft_face (data->face, load_flags);
1903 status = cairo_font_face_set_user_data (font_face,
1905 data, _ft_done_face);
1906 if (_csi_unlikely (status)) {
1907 _ft_done_face (data);
1908 cairo_font_face_destroy (font_face);
1912 data->font_face = font_face;
1913 *font_face_out = font_face;
1914 return CSI_STATUS_SUCCESS;
1918 _ft_create_for_pattern (csi_t *ctx,
1919 csi_string_t *string,
1920 cairo_font_face_t **font_face_out)
1922 #if CAIRO_HAS_FC_FONT
1924 struct _ft_face_data *data;
1926 cairo_font_face_t *font_face;
1927 FcPattern *pattern, *resolved;
1928 csi_status_t status;
1929 struct mmap_vec vec;
1932 _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len);
1933 _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t));
1934 link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
1936 if (--string->base.ref == 0)
1937 csi_string_free (ctx, string);
1938 data = csi_container_of (link, struct _ft_face_data, blob.list);
1939 *font_face_out = cairo_font_face_reference (data->font_face);
1940 return CSI_STATUS_SUCCESS;
1943 if (string->deflate) {
1944 bytes = inflate_string (ctx, string);
1945 if (_csi_unlikely (bytes == NULL))
1946 return _csi_error (CSI_STATUS_NO_MEMORY);
1951 pattern = FcNameParse (bytes);
1952 if (bytes != tmpl.bytes)
1953 _csi_free (ctx, bytes);
1957 if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) {
1958 /* prior to 1.9, you needed to pass a resolved pattern */
1959 resolved = FcFontMatch (NULL, pattern, NULL);
1960 if (_csi_unlikely (resolved == NULL)) {
1961 FcPatternDestroy (pattern);
1962 return _csi_error (CSI_STATUS_NO_MEMORY);
1966 font_face = cairo_ft_font_face_create_for_pattern (resolved);
1967 if (resolved != pattern)
1968 FcPatternDestroy (resolved);
1970 if (cairo_font_face_status (font_face)) {
1971 char *filename = NULL;
1973 /* Try a manual fallback process by eliminating specific requests */
1975 if (FcPatternGetString (pattern,
1977 (FcChar8 **) &filename) == FcResultMatch) {
1978 FcPatternDel (pattern, FC_FILE);
1980 cairo_font_face_destroy (font_face);
1985 FcPatternDestroy (pattern);
1987 data = _csi_slab_alloc (ctx, sizeof (*data));
1988 if (_csi_unlikely (data == NULL)) {
1990 cairo_font_face_destroy (font_face);
1991 return _csi_error (CSI_STATUS_NO_MEMORY);
1994 ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
1995 data->ctx = cairo_script_interpreter_reference (ctx);
1996 data->blob.hash = tmpl.hash;
1997 data->blob.len = tmpl.len;
2001 vec.bytes = tmpl.bytes;
2002 vec.num_bytes = tmpl.len;
2003 data->blob.bytes = _mmap_bytes (&vec, 1);
2004 if (data->blob.bytes != MAP_FAILED) {
2005 data->source = NULL;
2006 if (--string->base.ref == 0)
2007 csi_string_free (ctx, string);
2009 data->blob.bytes = tmpl.bytes;
2010 data->source = string;
2013 data->blob.bytes = tmpl.bytes;
2014 data->source = string;
2017 status = cairo_font_face_set_user_data (font_face,
2019 data, _ft_done_face);
2020 if (_csi_unlikely (status)) {
2021 _ft_done_face (data);
2022 cairo_font_face_destroy (font_face);
2026 data->font_face = font_face;
2027 *font_face_out = font_face;
2028 return CSI_STATUS_SUCCESS;
2030 if (--string->base.ref == 0)
2031 csi_string_free (ctx, string);
2032 return CSI_INT_STATUS_UNSUPPORTED;
2037 _ft_type42_create (csi_t *ctx,
2038 csi_dictionary_t *font,
2039 cairo_font_face_t **font_face_out)
2042 csi_status_t status;
2044 /* two basic sub-types, either an FcPattern or embedded font */
2045 status = csi_name_new_static (ctx, &key, "pattern");
2046 if (_csi_unlikely (status))
2049 if (csi_dictionary_has (font, key.datum.name)) {
2053 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2054 if (_csi_unlikely (status))
2057 type = csi_object_get_type (&obj);
2059 case CSI_OBJECT_TYPE_FILE:
2060 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2061 if (_csi_unlikely (status))
2064 case CSI_OBJECT_TYPE_STRING:
2065 obj.datum.object->ref++;
2068 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2071 return _ft_create_for_pattern (ctx,
2076 status = csi_name_new_static (ctx, &key, "source");
2077 if (_csi_unlikely (status))
2080 if (csi_dictionary_has (font, key.datum.name)) {
2086 status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index);
2087 if (_csi_unlikely (status))
2091 status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags);
2092 if (_csi_unlikely (status))
2095 status = csi_name_new_static (ctx, &key, "source");
2096 if (_csi_unlikely (status))
2098 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2099 if (_csi_unlikely (status))
2101 type = csi_object_get_type (&obj);
2103 case CSI_OBJECT_TYPE_FILE:
2104 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2105 if (_csi_unlikely (status))
2108 case CSI_OBJECT_TYPE_STRING:
2109 obj.datum.object->ref++;
2112 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2115 return _ft_create_for_source (ctx, obj.datum.string,
2120 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2123 #define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED
2127 _fc_strcpy (csi_t *ctx, const char *str)
2132 ret = strchr (str, ':');
2138 ret = _csi_alloc (ctx, len+1);
2139 if (_csi_unlikely (ret == NULL))
2142 memcpy (ret, str, len);
2148 static cairo_font_face_t *
2149 _select_font (const char *name)
2151 cairo_surface_t *surface;
2152 cairo_font_face_t *face;
2155 /* create a dummy context to choose a font */
2156 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
2157 cr = cairo_create (surface);
2158 cairo_surface_destroy (surface);
2160 cairo_select_font_face (cr, name,
2161 CAIRO_FONT_SLANT_NORMAL,
2162 CAIRO_FONT_WEIGHT_NORMAL);
2163 face = cairo_font_face_reference (cairo_get_font_face (cr));
2170 _ft_fallback_create_for_pattern (csi_t *ctx,
2171 csi_string_t *string,
2172 cairo_font_face_t **font_face_out)
2176 str = string->string;
2178 name = strstr (str, "fullname=");
2183 name = _fc_strcpy (ctx, str);
2184 if (_csi_unlikely (name == NULL))
2185 return _csi_error (CSI_STATUS_NO_MEMORY);
2187 *font_face_out = _select_font (name);
2188 _csi_free (ctx, name);
2190 return CSI_STATUS_SUCCESS;
2194 _ft_type42_fallback_create (csi_t *ctx,
2195 csi_dictionary_t *font,
2196 cairo_font_face_t **font_face_out)
2199 csi_status_t status;
2201 /* attempt to select a similar font */
2203 /* two basic sub-types, either an FcPattern or embedded font */
2204 status = csi_name_new_static (ctx, &key, "pattern");
2205 if (_csi_unlikely (status))
2208 if (csi_dictionary_has (font, key.datum.name)) {
2212 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2213 if (_csi_unlikely (status))
2216 type = csi_object_get_type (&obj);
2218 case CSI_OBJECT_TYPE_FILE:
2219 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2220 if (_csi_unlikely (status))
2223 case CSI_OBJECT_TYPE_STRING:
2224 obj.datum.object->ref++;
2227 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2230 return _ft_fallback_create_for_pattern (ctx,
2235 /* XXX: enable the trace to run */
2236 *font_face_out = _select_font ("Sans");
2237 return CSI_STATUS_SUCCESS;
2241 _font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face)
2243 csi_status_t status;
2245 status = _ft_type42_create (ctx, font, font_face);
2246 if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED))
2249 return _ft_type42_fallback_create (ctx, font, font_face);
2255 csi_dictionary_t *font;
2256 csi_status_t status;
2257 cairo_font_face_t *font_face = NULL; /* silence the compiler */
2264 status = _csi_ostack_get_dictionary (ctx, 0, &font);
2265 if (_csi_unlikely (status))
2268 status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type);
2269 if (_csi_unlikely (status))
2274 status = _font_type3 (ctx, font, &font_face);
2277 status = _font_type42 (ctx, font, &font_face);
2280 status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
2284 if (_csi_unlikely (status))
2287 /* transfer ownership of dictionary to cairo_font_face_t */
2288 proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL);
2289 if (_csi_unlikely (proxy == NULL)) {
2290 cairo_font_face_destroy (font_face);
2291 return _csi_error (CSI_STATUS_NO_MEMORY);
2294 status = cairo_font_face_set_user_data (font_face,
2296 proxy, _csi_proxy_destroy);
2297 if (_csi_unlikely (status)) {
2298 _csi_proxy_destroy (proxy);
2299 cairo_font_face_destroy (font_face);
2303 obj.type = CSI_OBJECT_TYPE_FONT;
2304 obj.datum.font_face = font_face;
2307 status = push (&obj);
2308 if (_csi_unlikely (status)) {
2309 cairo_font_face_destroy (font_face);
2313 return CSI_STATUS_SUCCESS;
2320 csi_status_t status;
2325 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2326 if (_csi_unlikely (status))
2328 status = _csi_ostack_get_integer (ctx, 1, &limit);
2329 if (_csi_unlikely (status))
2331 status = _csi_ostack_get_integer (ctx, 2, &inc);
2332 if (_csi_unlikely (status))
2334 status = _csi_ostack_get_integer (ctx, 3, &i);
2335 if (_csi_unlikely (status))
2341 for (; i <= limit; i += inc) {
2342 status = _csi_push_ostack_integer (ctx, i);
2343 if (_csi_unlikely (status))
2346 status = _csi_array_execute (ctx, proc);
2347 if (_csi_unlikely (status))
2351 if (--proc->base.ref == 0)
2352 csi_array_free (ctx, proc);
2359 csi_status_t status;
2360 csi_object_t *a, *b;
2365 b = _csi_peek_ostack (ctx, 0);
2366 a = _csi_peek_ostack (ctx, 1);
2368 status = csi_object_compare (a, b, &cmp);
2369 if (_csi_unlikely (status))
2373 return _csi_push_ostack_boolean (ctx, cmp >= 0);
2377 _proxy_get (csi_proxy_t *proxy,
2381 csi_status_t status;
2383 if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL))
2384 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2386 status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj);
2387 if (_csi_unlikely (status))
2390 return _csi_push_ostack_copy (proxy->ctx, &obj);
2394 _context_get (csi_t *ctx,
2398 csi_status_t status;
2401 if (strcmp ((char *) key, "current-point") == 0) {
2404 cairo_get_current_point (cr, &x, &y);
2406 status = _csi_push_ostack_real (ctx, x);
2407 if (_csi_unlikely (status))
2409 status = _csi_push_ostack_real (ctx, y);
2410 if (_csi_unlikely (status))
2413 return CSI_STATUS_SUCCESS;
2414 } else if (strcmp ((char *) key, "source") == 0) {
2415 obj.type = CSI_OBJECT_TYPE_PATTERN;
2416 obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr));
2417 } else if (strcmp ((char *) key, "target") == 0) {
2418 obj.type = CSI_OBJECT_TYPE_SURFACE;
2419 obj.datum.surface = cairo_surface_reference (cairo_get_target (cr));
2420 } else if (strcmp ((char *) key, "group-target") == 0) {
2421 obj.type = CSI_OBJECT_TYPE_SURFACE;
2422 obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr));
2423 } else if (strcmp ((char *) key, "scaled-font") == 0) {
2424 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
2425 obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr));
2426 } else if (strcmp ((char *) key, "font-face") == 0) {
2427 obj.type = CSI_OBJECT_TYPE_FONT;
2428 obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr));
2430 return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key);
2436 _font_get (csi_t *ctx,
2437 cairo_font_face_t *font_face,
2440 return _proxy_get (cairo_font_face_get_user_data (font_face,
2446 _pattern_get (csi_t *ctx,
2447 cairo_pattern_t *pattern,
2450 csi_status_t status;
2452 if (strcmp ((char *) key, "type") == 0)
2453 return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern));
2455 if (strcmp ((char *) key, "filter") == 0)
2456 return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern));
2458 if (strcmp ((char *) key, "extend") == 0)
2459 return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern));
2461 if (strcmp ((char *) key, "matrix") == 0) {
2465 cairo_pattern_get_matrix (pattern, &m);
2466 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
2467 if (_csi_unlikely (status))
2473 return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key),
2478 _scaled_font_get (csi_t *ctx,
2479 cairo_scaled_font_t *font,
2482 return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key),
2487 _surface_get (csi_t *ctx,
2488 cairo_surface_t *surface,
2491 if (strcmp ((char *) key, "type") == 0) {
2492 return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface));
2495 if (strcmp ((char *) key, "content") == 0) {
2496 return _csi_push_ostack_integer (ctx,
2497 cairo_surface_get_content (surface));
2500 return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key),
2507 csi_object_t *key, *src, obj;
2508 csi_status_t status;
2513 key = _csi_peek_ostack (ctx, 0);
2514 src = _csi_peek_ostack (ctx, 1);
2516 type = csi_object_get_type (src);
2518 case CSI_OBJECT_TYPE_DICTIONARY:
2519 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2520 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2522 status = csi_dictionary_get (ctx,
2523 src->datum.dictionary,
2527 case CSI_OBJECT_TYPE_ARRAY:
2528 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER))
2529 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2531 status = csi_array_get (ctx,
2537 case CSI_OBJECT_TYPE_STRING:
2538 status = csi_string_get (src, key, &obj);
2542 case CSI_OBJECT_TYPE_CONTEXT:
2543 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2544 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2545 return _context_get (ctx, src->datum.cr, key->datum.name);
2547 case CSI_OBJECT_TYPE_FONT:
2548 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2549 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2550 return _font_get (ctx, src->datum.font_face, key->datum.name);
2552 case CSI_OBJECT_TYPE_PATTERN:
2553 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2554 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2555 return _pattern_get (ctx, src->datum.pattern, key->datum.name);
2557 case CSI_OBJECT_TYPE_SCALED_FONT:
2558 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2559 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2560 return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name);
2562 case CSI_OBJECT_TYPE_SURFACE:
2563 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2564 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2565 return _surface_get (ctx, src->datum.surface, key->datum.name);
2568 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2571 if (_csi_unlikely (status))
2574 return _csi_push_ostack_copy (ctx, &obj);
2577 struct glyph_advance_cache {
2579 double glyph_advance[256][2];
2580 unsigned long have_glyph_advance[256];
2584 glyph_advance_cache_destroy (void *closure)
2586 struct glyph_advance_cache *cache = closure;
2587 _csi_free (cache->ctx, cache);
2591 _glyph_string (csi_t *ctx,
2593 cairo_scaled_font_t *scaled_font,
2594 cairo_glyph_t *glyphs)
2596 struct glyph_advance_cache uncached;
2597 struct glyph_advance_cache *cache;
2598 csi_integer_t nglyphs, i, j;
2600 cairo_status_t status;
2602 if (cairo_scaled_font_status (scaled_font))
2605 cache = cairo_scaled_font_get_user_data (scaled_font,
2606 (cairo_user_data_key_t *) ctx);
2607 if (cache == NULL) {
2608 cache = _csi_alloc (ctx, sizeof (*cache));
2609 if (_csi_likely (cache != NULL)) {
2611 memset (cache->have_glyph_advance, 0xff,
2612 sizeof (cache->have_glyph_advance));
2614 status = cairo_scaled_font_set_user_data (scaled_font,
2615 (cairo_user_data_key_t *) ctx,
2617 glyph_advance_cache_destroy);
2618 if (_csi_unlikely (status)) {
2619 _csi_free (ctx, cache);
2625 if (_csi_unlikely (cache == NULL)) {
2629 memset (cache->have_glyph_advance, 0xff,
2630 sizeof (cache->have_glyph_advance));
2635 for (i = 0; i < array->stack.len; i++) {
2636 const csi_object_t *obj = &array->stack.objects[i];
2637 int type = csi_object_get_type (obj);
2640 case CSI_OBJECT_TYPE_ARRAY: {
2641 const csi_array_t *glyph_array = obj->datum.array;
2642 for (j = 0; j < glyph_array->stack.len; j++) {
2646 obj = &glyph_array->stack.objects[j];
2647 if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
2649 g = obj->datum.integer;
2651 glyphs[nglyphs].index = g;
2652 glyphs[nglyphs].x = x;
2653 glyphs[nglyphs].y = y;
2655 gi = g % ARRAY_LENGTH (cache->have_glyph_advance);
2656 if (cache->have_glyph_advance[gi] != g) {
2657 cairo_text_extents_t extents;
2659 cairo_scaled_font_glyph_extents (scaled_font,
2660 &glyphs[nglyphs], 1,
2663 cache->glyph_advance[gi][0] = extents.x_advance;
2664 cache->glyph_advance[gi][1] = extents.y_advance;
2665 cache->have_glyph_advance[gi] = g;
2668 x += cache->glyph_advance[gi][0];
2669 y += cache->glyph_advance[gi][1];
2675 case CSI_OBJECT_TYPE_STRING: {
2676 const csi_string_t *glyph_string = obj->datum.string;
2677 for (j = 0; j < glyph_string->len; j++) {
2680 g = glyph_string->string[j];
2681 glyphs[nglyphs].index = g;
2682 glyphs[nglyphs].x = x;
2683 glyphs[nglyphs].y = y;
2685 if (cache->have_glyph_advance[g] != g) {
2686 cairo_text_extents_t extents;
2688 cairo_scaled_font_glyph_extents (scaled_font,
2689 &glyphs[nglyphs], 1,
2692 cache->glyph_advance[g][0] = extents.x_advance;
2693 cache->glyph_advance[g][1] = extents.y_advance;
2694 cache->have_glyph_advance[g] = g;
2697 x += cache->glyph_advance[g][0];
2698 y += cache->glyph_advance[g][1];
2704 case CSI_OBJECT_TYPE_INTEGER:
2705 case CSI_OBJECT_TYPE_REAL: /* dx or x*/
2706 dx = csi_number_get_value (obj);
2707 if (i+1 == array->stack.len)
2710 type = csi_object_get_type (&array->stack.objects[i+1]);
2712 case CSI_OBJECT_TYPE_INTEGER:
2713 case CSI_OBJECT_TYPE_REAL: /* y */
2714 y = csi_number_get_value (&array->stack.objects[i+1]);
2729 _glyph_path (csi_t *ctx)
2732 csi_status_t status;
2734 cairo_glyph_t stack_glyphs[256], *glyphs;
2735 csi_integer_t nglyphs, i;
2739 status = _csi_ostack_get_array (ctx, 0, &array);
2740 if (_csi_unlikely (status))
2742 status = _csi_ostack_get_context (ctx, 1, &cr);
2743 if (_csi_unlikely (status))
2748 for (i = 0; i < array->stack.len; i++) {
2749 csi_object_t *obj = &array->stack.objects[i];
2750 int type = csi_object_get_type (obj);
2752 case CSI_OBJECT_TYPE_ARRAY:
2753 nglyphs += obj->datum.array->stack.len;
2755 case CSI_OBJECT_TYPE_STRING:
2756 nglyphs += obj->datum.string->len;
2762 return CSI_STATUS_SUCCESS;
2765 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
2766 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
2767 return _csi_error (CSI_STATUS_NO_MEMORY);
2769 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
2770 if (_csi_unlikely (glyphs == NULL))
2771 return _csi_error (CSI_STATUS_NO_MEMORY);
2773 glyphs = stack_glyphs;
2775 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
2776 cairo_glyph_path (cr, glyphs, nglyphs);
2778 if (glyphs != stack_glyphs)
2779 _csi_free (ctx, glyphs);
2782 return CSI_STATUS_SUCCESS;
2789 csi_status_t status;
2794 status = _csi_ostack_get_number (ctx, 0, &g);
2795 if (_csi_unlikely (status))
2800 obj.type = CSI_OBJECT_TYPE_PATTERN;
2801 obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1);
2808 csi_status_t status;
2809 csi_object_t *a, *b;
2814 b = _csi_peek_ostack (ctx, 0);
2815 a = _csi_peek_ostack (ctx, 1);
2817 status = csi_object_compare (a, b, &cmp);
2818 if (_csi_unlikely (status))
2822 return _csi_push_ostack_boolean (ctx, cmp > 0);
2826 _identity (csi_t *ctx)
2829 csi_status_t status;
2831 status = csi_matrix_new (ctx, &obj);
2832 if (_csi_unlikely (status))
2842 csi_boolean_t predicate = FALSE; /* silence the compiler */
2843 csi_status_t status;
2847 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2848 if (_csi_unlikely (status))
2851 status = _csi_ostack_get_boolean (ctx, 1, &predicate);
2852 if (_csi_unlikely (status))
2859 status = _csi_array_execute (ctx, proc);
2861 if (--proc->base.ref == 0)
2862 csi_array_free (ctx, proc);
2868 _ifelse (csi_t *ctx)
2870 csi_array_t *true_proc, *false_proc;
2871 csi_boolean_t predicate = FALSE; /* silence the compiler */
2872 csi_status_t status;
2876 status = _csi_ostack_get_procedure (ctx, 0, &false_proc);
2877 if (_csi_unlikely (status))
2878 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2880 status = _csi_ostack_get_procedure (ctx, 1, &true_proc);
2881 if (_csi_unlikely (status))
2882 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2884 status = _csi_ostack_get_boolean (ctx, 2, &predicate);
2885 if (_csi_unlikely (status))
2888 true_proc->base.ref++;
2889 false_proc->base.ref++;
2893 status = _csi_array_execute (ctx, true_proc);
2895 status = _csi_array_execute (ctx, false_proc);
2897 if (--true_proc->base.ref == 0)
2898 csi_array_free (ctx, true_proc);
2899 if (--false_proc->base.ref == 0)
2900 csi_array_free (ctx, false_proc);
2906 _image_read_raw (csi_t *ctx,
2908 cairo_format_t format,
2909 int width, int height,
2910 cairo_surface_t **image_out)
2912 cairo_surface_t *image;
2914 int rem, len, ret, x, rowlen, instride, stride;
2915 cairo_status_t status;
2917 if (width == 0 || height == 0) {
2918 *image_out = cairo_image_surface_create (format, 0, 0);
2919 return CSI_STATUS_SUCCESS;
2922 if (ctx->hooks.create_source_image != NULL) {
2923 image = ctx->hooks.create_source_image (ctx->hooks.closure,
2924 format, width, height,
2927 stride = cairo_image_surface_get_stride (image);
2928 data = cairo_image_surface_get_data (image);
2930 return CAIRO_STATUS_NULL_POINTER;
2932 stride = cairo_format_stride_for_width (format, width);
2933 data = malloc (stride * height);
2935 return CAIRO_STATUS_NO_MEMORY;
2937 image = cairo_image_surface_create_for_data (data, format,
2938 width, height, stride);
2939 status = cairo_surface_set_user_data (image,
2940 (const cairo_user_data_key_t *) image,
2943 cairo_surface_destroy (image);
2950 case CAIRO_FORMAT_A1:
2951 instride = rowlen = (width+7)/8;
2953 case CAIRO_FORMAT_A8:
2954 instride = rowlen = width;
2956 case CAIRO_FORMAT_RGB16_565:
2957 instride = rowlen = 2 * width;
2959 case CAIRO_FORMAT_RGB24:
2961 instride = 4 *width;
2964 case CAIRO_FORMAT_RGB30:
2965 case CAIRO_FORMAT_INVALID:
2966 case CAIRO_FORMAT_ARGB32:
2967 instride = rowlen = 4 * width;
2970 len = rowlen * height;
2972 if (rowlen == instride &&
2973 src->type == CSI_OBJECT_TYPE_STRING &&
2974 len == src->datum.string->deflate)
2976 csi_string_t *s = src->datum.string;
2977 unsigned long out = s->deflate;
2979 switch (s->method) {
2983 cairo_surface_destroy (image);
2984 return _csi_error (CSI_STATUS_READ_ERROR);
2988 if (uncompress ((Bytef *) data, &out,
2989 (Bytef *) s->string, s->len) != Z_OK)
2990 goto err_decompress;
2996 if (lzo2a_decompress ((Bytef *) s->string, s->len,
2997 (Bytef *) data, &out,
2999 goto err_decompress;
3008 status = csi_object_as_file (ctx, src, &file);
3009 if (_csi_unlikely (status)) {
3010 cairo_surface_destroy (image);
3017 ret = csi_file_read (file.datum.file, bp, rem);
3018 if (_csi_unlikely (ret == 0)) {
3019 cairo_surface_destroy (image);
3020 return _csi_error (CSI_STATUS_READ_ERROR);
3026 if (len != height * stride) {
3028 uint8_t *row = data + height * stride;
3030 /* XXX pixel conversion */
3032 case CAIRO_FORMAT_A1:
3033 for (x = rowlen; x--; ) {
3034 uint8_t byte = *--bp;
3035 row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
3038 case CAIRO_FORMAT_A8:
3039 for (x = width; x--; )
3042 case CAIRO_FORMAT_RGB16_565:
3043 for (x = width; x--; ) {
3044 #ifdef WORDS_BIGENDIAN
3045 row[2*x + 1] = *--bp;
3046 row[2*x + 0] = *--bp;
3048 row[2*x + 0] = *--bp;
3049 row[2*x + 1] = *--bp;
3053 case CAIRO_FORMAT_RGB24:
3054 for (x = width; x--; ) {
3055 #ifdef WORDS_BIGENDIAN
3056 row[4*x + 3] = *--bp;
3057 row[4*x + 2] = *--bp;
3058 row[4*x + 1] = *--bp;
3059 row[4*x + 0] = 0xff;
3061 row[4*x + 0] = *--bp;
3062 row[4*x + 1] = *--bp;
3063 row[4*x + 2] = *--bp;
3064 row[4*x + 3] = 0xff;
3068 case CAIRO_FORMAT_RGB30:
3069 case CAIRO_FORMAT_INVALID:
3070 case CAIRO_FORMAT_ARGB32:
3071 /* stride == width */
3075 memset (row + instride, 0, stride - instride);
3078 /* need to treat last row carefully */
3080 case CAIRO_FORMAT_A1:
3081 for (x = rowlen; x--; ) {
3082 uint8_t byte = *--bp;
3083 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
3086 case CAIRO_FORMAT_A8:
3087 for (x = width; x--; )
3090 case CAIRO_FORMAT_RGB16_565:
3091 for (x = width; x--; ) {
3092 #ifdef WORDS_BIGENDIAN
3093 data[2*x + 1] = *--bp;
3094 data[2*x + 0] = *--bp;
3096 data[2*x + 0] = *--bp;
3097 data[2*x + 1] = *--bp;
3101 case CAIRO_FORMAT_RGB24:
3102 for (x = width; --x>1; ) {
3103 #ifdef WORDS_BIGENDIAN
3104 data[4*x + 3] = *--bp;
3105 data[4*x + 2] = *--bp;
3106 data[4*x + 1] = *--bp;
3107 data[4*x + 0] = 0xff;
3109 data[4*x + 0] = *--bp;
3110 data[4*x + 1] = *--bp;
3111 data[4*x + 2] = *--bp;
3112 data[4*x + 3] = 0xff;
3117 /* shuffle the last couple of overlapping pixels */
3118 rgb[1][0] = data[5];
3119 rgb[1][1] = data[4];
3120 rgb[1][2] = data[3];
3121 rgb[0][0] = data[2];
3122 rgb[0][1] = data[1];
3123 rgb[0][2] = data[0];
3124 #ifdef WORDS_BIGENDIAN
3126 data[5] = rgb[1][2];
3127 data[6] = rgb[1][1];
3128 data[7] = rgb[1][0];
3130 data[1] = rgb[0][2];
3131 data[2] = rgb[0][1];
3132 data[3] = rgb[0][0];
3135 data[6] = rgb[1][2];
3136 data[5] = rgb[1][1];
3137 data[4] = rgb[1][0];
3139 data[2] = rgb[0][2];
3140 data[1] = rgb[0][1];
3141 data[0] = rgb[0][0];
3144 #ifdef WORDS_BIGENDIAN
3157 case CAIRO_FORMAT_RGB30:
3158 case CAIRO_FORMAT_INVALID:
3159 case CAIRO_FORMAT_ARGB32:
3160 /* stride == width */
3163 memset (data + instride, 0, stride - instride);
3165 #ifndef WORDS_BIGENDIAN
3167 case CAIRO_FORMAT_A1:
3168 for (x = 0; x < len; x++) {
3169 uint8_t byte = data[x];
3170 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
3173 case CAIRO_FORMAT_RGB16_565:
3175 uint32_t *rgba = (uint32_t *) data;
3176 for (x = len/2; x--; rgba++) {
3177 *rgba = bswap_16 (*rgba);
3181 case CAIRO_FORMAT_ARGB32:
3183 uint32_t *rgba = (uint32_t *) data;
3184 for (x = len/4; x--; rgba++) {
3185 *rgba = bswap_32 (*rgba);
3190 case CAIRO_FORMAT_A8:
3193 case CAIRO_FORMAT_RGB30:
3194 case CAIRO_FORMAT_RGB24:
3195 case CAIRO_FORMAT_INVALID:
3201 csi_object_free (ctx, &file);
3204 cairo_surface_mark_dirty (image);
3206 return CSI_STATUS_SUCCESS;
3209 static cairo_status_t
3210 png_read_func (void *closure, uint8_t *data, unsigned int len)
3214 ret = csi_file_read (closure, data, len);
3215 if ((unsigned int) ret != len)
3216 return CAIRO_STATUS_READ_ERROR;
3218 return CAIRO_STATUS_SUCCESS;
3222 _image_read_png (csi_file_t *src, cairo_surface_t **out)
3224 #if CAIRO_HAS_PNG_FUNCTIONS
3225 *out = cairo_image_surface_create_from_png_stream (png_read_func, src);
3226 return cairo_surface_status (*out);
3228 return CAIRO_STATUS_READ_ERROR;
3235 cairo_surface_t *surface;
3239 _image_tag_done (void *closure)
3241 struct _image_tag *tag = closure;
3242 csi_t *ctx = tag->ctx;
3244 ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list);
3245 _csi_slab_free (ctx, tag, sizeof (*tag));
3246 cairo_script_interpreter_destroy (ctx);
3250 _image_hash (csi_blob_t *blob,
3251 cairo_surface_t *surface)
3255 value = cairo_image_surface_get_width (surface);
3256 _csi_blob_hash (blob, &value, 1);
3258 value = cairo_image_surface_get_height (surface);
3259 _csi_blob_hash (blob, &value, 1);
3261 value = cairo_image_surface_get_format (surface);
3262 _csi_blob_hash (blob, &value, 1);
3265 static cairo_surface_t *
3266 _image_cached (csi_t *ctx, cairo_surface_t *surface)
3272 struct _image_tag *tag;
3274 /* check for an existing image */
3276 data = cairo_image_surface_get_data (surface);
3277 stride = cairo_image_surface_get_stride (surface);
3278 height = cairo_image_surface_get_height (surface);
3279 _csi_blob_init (&tmpl, data, stride * height);
3280 _image_hash (&tmpl, surface);
3281 link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
3283 cairo_surface_destroy (surface);
3284 tag = csi_container_of (link, struct _image_tag, blob.list);
3285 return cairo_surface_reference (tag->surface);
3288 /* none found, insert a tag for this one */
3290 tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag));
3294 ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list);
3295 tag->ctx = cairo_script_interpreter_reference (ctx);
3296 tag->blob.hash = tmpl.hash;
3297 tag->blob.bytes = tmpl.bytes;
3298 tag->blob.len = tmpl.len;
3299 tag->surface = surface;
3301 if (cairo_surface_set_user_data (surface, &_csi_blob_key,
3302 tag, _image_tag_done))
3304 _image_tag_done (tag);
3311 _image_load_from_dictionary (csi_t *ctx,
3312 csi_dictionary_t *dict,
3313 cairo_surface_t **image_out)
3315 csi_object_t obj, key;
3319 cairo_surface_t *image = NULL; /* silence the compiler */
3320 csi_status_t status;
3322 /* check for "status? */
3324 status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width);
3325 if (_csi_unlikely (status))
3327 status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height);
3328 if (_csi_unlikely (status))
3331 format = CAIRO_FORMAT_ARGB32;
3332 status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format);
3333 if (_csi_unlikely (status))
3336 status = csi_name_new_static (ctx, &key, "source");
3337 if (_csi_unlikely (status))
3340 if (csi_dictionary_has (dict, key.datum.name)) {
3341 enum mime_type mime_type;
3344 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
3345 if (_csi_unlikely (status))
3348 status = csi_name_new_static (ctx, &key, "mime-type");
3349 if (_csi_unlikely (status))
3352 mime_type = MIME_TYPE_NONE;
3353 if (csi_dictionary_has (dict, key.datum.name)) {
3354 csi_object_t type_obj;
3355 const char *type_str;
3358 status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj);
3359 if (_csi_unlikely (status))
3362 type = csi_object_get_type (&type_obj);
3364 case CSI_OBJECT_TYPE_STRING:
3365 type_str = type_obj.datum.string->string;
3367 case CSI_OBJECT_TYPE_NAME:
3368 type_str = (char *) type_obj.datum.name;
3371 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3374 if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0)
3375 mime_type = MIME_TYPE_PNG;
3379 /* XXX hook for general mime-type decoder */
3381 switch (mime_type) {
3382 case MIME_TYPE_NONE:
3383 status = _image_read_raw (ctx, &obj, format, width, height, &image);
3386 status = csi_object_as_file (ctx, &obj, &file);
3387 if (_csi_unlikely (status))
3390 status = _image_read_png (file.datum.file, &image);
3391 csi_object_free (ctx, &file);
3394 if (_csi_unlikely (status)) {
3395 cairo_surface_destroy (image);
3398 image = _image_cached (ctx, image);
3400 image = cairo_image_surface_create (format, width, height);
3403 return CSI_STATUS_SUCCESS;
3409 csi_dictionary_t *dict;
3410 cairo_surface_t *image;
3411 csi_status_t status;
3416 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
3417 if (_csi_unlikely (status))
3420 status = _image_load_from_dictionary (ctx, dict, &image);
3421 if (_csi_unlikely (status)) {
3422 cairo_surface_destroy (image);
3427 obj.type = CSI_OBJECT_TYPE_SURFACE;
3428 obj.datum.surface = image;
3435 csi_status_t status;
3440 status = _csi_ostack_get_integer (ctx, 0, &n);
3441 if (_csi_unlikely (status))
3447 return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n));
3451 _integer (csi_t *ctx)
3458 obj = _csi_peek_ostack (ctx, 0);
3459 type = csi_object_get_type (obj);
3461 case CSI_OBJECT_TYPE_INTEGER:
3463 case CSI_OBJECT_TYPE_REAL:
3464 obj->datum.integer = obj->datum.real;
3467 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3469 obj->type = CSI_OBJECT_TYPE_INTEGER;
3471 return CSI_STATUS_SUCCESS;
3475 _invert (csi_t *ctx)
3478 csi_status_t status;
3483 status = _csi_ostack_get_matrix (ctx, 0, &m);
3484 if (_csi_unlikely (status))
3487 cairo_matrix_invert (&m);
3489 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
3490 if (_csi_unlikely (status))
3501 csi_status_t status;
3502 csi_object_t *a, *b;
3507 b = _csi_peek_ostack (ctx, 0);
3508 a = _csi_peek_ostack (ctx, 1);
3510 status = csi_object_compare (a, b, &cmp);
3511 if (_csi_unlikely (status))
3515 return _csi_push_ostack_boolean (ctx, cmp <= 0);
3519 _linear (csi_t *ctx)
3522 csi_status_t status;
3523 double x1, y1, x2, y2;
3527 status = _csi_ostack_get_number (ctx, 0, &y2);
3528 if (_csi_unlikely (status))
3530 status = _csi_ostack_get_number (ctx, 1, &x2);
3531 if (_csi_unlikely (status))
3533 status = _csi_ostack_get_number (ctx, 2, &y1);
3534 if (_csi_unlikely (status))
3536 status = _csi_ostack_get_number (ctx, 3, &x1);
3537 if (_csi_unlikely (status))
3542 obj.type = CSI_OBJECT_TYPE_PATTERN;
3543 obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
3548 _line_to (csi_t *ctx)
3550 csi_status_t status;
3557 status = _csi_ostack_get_number (ctx, 0, &y);
3558 if (_csi_unlikely (status))
3560 status = _csi_ostack_get_number (ctx, 1, &x);
3561 if (_csi_unlikely (status))
3564 /* XXX path object */
3566 obj = _csi_peek_ostack (ctx, 2);
3567 type = csi_object_get_type (obj);
3569 case CSI_OBJECT_TYPE_CONTEXT:
3570 cairo_line_to (obj->datum.cr, x, y);
3572 case CSI_OBJECT_TYPE_PATTERN:
3573 cairo_mesh_pattern_line_to (obj->datum.pattern, x, y);
3578 return CSI_STATUS_SUCCESS;
3584 csi_status_t status;
3585 csi_object_t *a, *b;
3590 b = _csi_peek_ostack (ctx, 0);
3591 a = _csi_peek_ostack (ctx, 1);
3593 status = csi_object_compare (a, b, &cmp);
3594 if (_csi_unlikely (status))
3598 return _csi_push_ostack_boolean (ctx, cmp < 0);
3604 return _csi_push_ostack_mark (ctx);
3610 csi_object_t *a, *b;
3615 b = _csi_peek_ostack (ctx, 0);
3616 a = _csi_peek_ostack (ctx, 1);
3618 v = ! csi_object_eq (a, b);
3621 return _csi_push_ostack_boolean (ctx, v);
3632 obj = _csi_peek_ostack (ctx, 0);
3633 type = csi_object_get_type (obj);
3635 case CSI_OBJECT_TYPE_INTEGER:
3636 obj->datum.integer = -obj->datum.integer;
3638 case CSI_OBJECT_TYPE_REAL:
3639 obj->datum.real = -obj->datum.real;
3642 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3645 return CSI_STATUS_SUCCESS;
3656 obj = _csi_peek_ostack (ctx, 0);
3657 type = csi_object_get_type (obj);
3659 case CSI_OBJECT_TYPE_BOOLEAN:
3660 obj->datum.boolean = ! obj->datum.boolean;
3662 case CSI_OBJECT_TYPE_INTEGER:
3663 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3664 obj->datum.boolean = ! obj->datum.integer;
3666 case CSI_OBJECT_TYPE_REAL:
3667 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3668 obj->datum.boolean = obj->datum.real == 0.0;
3671 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3674 return CSI_STATUS_SUCCESS;
3678 _new_path (csi_t *ctx)
3680 /* XXX handle path object */
3681 return _do_cairo_op (ctx, cairo_new_path);
3685 _new_sub_path (csi_t *ctx)
3687 /* XXX handle path object */
3688 return _do_cairo_op (ctx, cairo_new_sub_path);
3694 return _csi_push_ostack_null (ctx);
3701 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3702 csi_status_t status;
3706 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3707 if (_csi_unlikely (status))
3709 status = _csi_ostack_get_context (ctx, 1, &cr);
3710 if (_csi_unlikely (status))
3713 cairo_mask (cr, pattern);
3716 return CSI_STATUS_SUCCESS;
3720 _matrix (csi_t *ctx)
3722 csi_object_t *obj, matrix;
3724 csi_status_t status;
3729 obj = _csi_peek_ostack (ctx, 0);
3730 if (csi_object_is_number (obj)) {
3733 for (n = 6; n--; ) {
3734 status = _csi_ostack_get_number (ctx, 5-n, &v[n]);
3735 if (_csi_unlikely (status))
3738 status = csi_matrix_new_from_values (ctx, &matrix, v);
3739 if (_csi_unlikely (status))
3746 status = _csi_ostack_get_array (ctx, 0, &array);
3747 if (_csi_unlikely (status))
3750 status = csi_matrix_new_from_array (ctx, &matrix, array);
3751 if (_csi_unlikely (status))
3757 return push (&matrix);
3761 _map_to_image (csi_t *ctx)
3765 csi_status_t status;
3766 cairo_rectangle_int_t extents, *r;
3767 cairo_surface_t *surface;
3771 status = _csi_ostack_get_array (ctx, 0, &array);
3772 if (_csi_unlikely (status))
3775 status = _csi_ostack_get_surface (ctx, 1, &surface);
3776 if (_csi_unlikely (status))
3779 switch (array->stack.len) {
3784 extents.x = floor (_csi_object_as_real (&array->stack.objects[0]));
3785 extents.y = floor (_csi_object_as_real (&array->stack.objects[1]));
3786 extents.width = ceil (_csi_object_as_real (&array->stack.objects[2]));
3787 extents.height = ceil (_csi_object_as_real (&array->stack.objects[3]));
3791 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3794 obj.type = CSI_OBJECT_TYPE_SURFACE;
3795 obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r));
3801 _unmap_image (csi_t *ctx)
3803 cairo_surface_t *surface, *image;
3804 csi_status_t status;
3808 status = _csi_ostack_get_surface (ctx, 0, &image);
3809 if (_csi_unlikely (status))
3811 status = _csi_ostack_get_surface (ctx, 1, &surface);
3812 if (_csi_unlikely (status))
3815 cairo_surface_unmap_image (surface, image);
3818 return CSI_STATUS_SUCCESS;
3826 obj.type = CSI_OBJECT_TYPE_PATTERN;
3827 obj.datum.pattern = cairo_pattern_create_mesh ();
3832 _mesh_begin_patch (csi_t *ctx)
3834 csi_status_t status;
3835 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3839 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3840 if (_csi_unlikely (status))
3843 cairo_mesh_pattern_begin_patch (pattern);
3844 return CSI_STATUS_SUCCESS;
3848 _mesh_end_patch (csi_t *ctx)
3850 csi_status_t status;
3851 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3855 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3856 if (_csi_unlikely (status))
3859 cairo_mesh_pattern_end_patch (pattern);
3860 return CSI_STATUS_SUCCESS;
3864 _mesh_set_control_point (csi_t *ctx)
3866 csi_status_t status;
3868 csi_integer_t point;
3869 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3873 status = _csi_ostack_get_number (ctx, 0, &y);
3874 if (_csi_unlikely (status))
3876 status = _csi_ostack_get_number (ctx, 1, &x);
3877 if (_csi_unlikely (status))
3879 status = _csi_ostack_get_integer (ctx, 2, &point);
3880 if (_csi_unlikely (status))
3882 status = _csi_ostack_get_pattern (ctx, 3, &pattern);
3883 if (_csi_unlikely (status))
3886 cairo_mesh_pattern_set_control_point (pattern, point, x, y);
3889 return CSI_STATUS_SUCCESS;
3893 _mesh_set_corner_color (csi_t *ctx)
3895 csi_status_t status;
3897 csi_integer_t corner;
3898 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3902 status = _csi_ostack_get_number (ctx, 0, &a);
3903 if (_csi_unlikely (status))
3905 status = _csi_ostack_get_number (ctx, 1, &b);
3906 if (_csi_unlikely (status))
3908 status = _csi_ostack_get_number (ctx, 2, &g);
3909 if (_csi_unlikely (status))
3911 status = _csi_ostack_get_number (ctx, 3, &r);
3912 if (_csi_unlikely (status))
3914 status = _csi_ostack_get_integer (ctx, 4, &corner);
3915 if (_csi_unlikely (status))
3917 status = _csi_ostack_get_pattern (ctx, 5, &pattern);
3918 if (_csi_unlikely (status))
3921 cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a);
3924 return CSI_STATUS_SUCCESS;
3931 csi_status_t status;
3935 status = _csi_ostack_get_integer (ctx, 0, &y);
3936 if (_csi_unlikely (status))
3938 status = _csi_ostack_get_integer (ctx, 1, &x);
3939 if (_csi_unlikely (status))
3943 return _csi_push_ostack_integer (ctx, x % y);
3947 _move_to (csi_t *ctx)
3949 csi_status_t status;
3956 status = _csi_ostack_get_number (ctx, 0, &y);
3957 if (_csi_unlikely (status))
3959 status = _csi_ostack_get_number (ctx, 1, &x);
3960 if (_csi_unlikely (status))
3963 obj = _csi_peek_ostack (ctx, 2);
3964 type = csi_object_get_type (obj);
3966 case CSI_OBJECT_TYPE_CONTEXT:
3967 cairo_move_to (obj->datum.cr, x, y);
3969 case CSI_OBJECT_TYPE_PATTERN:
3970 cairo_mesh_pattern_move_to (obj->datum.pattern, x, y);
3973 /* XXX path object */
3977 return CSI_STATUS_SUCCESS;
3985 csi_object_type_t type_a, type_b;
3989 B = _csi_peek_ostack (ctx, 0);
3990 A = _csi_peek_ostack (ctx, 1);
3992 type_a = csi_object_get_type (A);
3993 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
3994 type_a == CSI_OBJECT_TYPE_REAL)))
3996 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3998 type_b = csi_object_get_type (B);
3999 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
4000 type_b == CSI_OBJECT_TYPE_REAL)))
4002 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4007 if (type_a == CSI_OBJECT_TYPE_REAL &&
4008 type_b == CSI_OBJECT_TYPE_REAL)
4010 return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real);
4013 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
4014 type_b == CSI_OBJECT_TYPE_INTEGER)
4016 return _csi_push_ostack_integer (ctx,
4017 A->datum.integer * B->datum.integer);
4023 if (type_a == CSI_OBJECT_TYPE_REAL)
4026 v = A->datum.integer;
4028 if (type_b == CSI_OBJECT_TYPE_REAL)
4031 v *= B->datum.integer;
4033 return _csi_push_ostack_real (ctx, v);
4040 csi_object_t *a, *b;
4045 a = _csi_peek_ostack (ctx, 0);
4046 b = _csi_peek_ostack (ctx, 1);
4047 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
4048 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4051 type = csi_object_get_type (a);
4053 case CSI_OBJECT_TYPE_INTEGER:
4054 return _csi_push_ostack_integer (ctx,
4055 a->datum.integer | b->datum.integer);
4056 case CSI_OBJECT_TYPE_BOOLEAN:
4057 return _csi_push_ostack_boolean (ctx,
4058 a->datum.boolean | b->datum.boolean);
4060 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4067 return _do_cairo_op (ctx, cairo_paint);
4071 _paint_with_alpha (csi_t *ctx)
4074 csi_status_t status;
4079 status = _csi_ostack_get_number (ctx, 0, &alpha);
4080 if (_csi_unlikely (status))
4083 status = _csi_ostack_get_context (ctx, 1, &cr);
4084 if (_csi_unlikely (status))
4087 cairo_paint_with_alpha (cr, alpha);
4089 return CSI_STATUS_SUCCESS;
4093 _pattern (csi_t *ctx)
4096 csi_status_t status;
4097 cairo_surface_t *surface;
4101 status = _csi_ostack_get_surface (ctx, 0, &surface);
4102 if (_csi_unlikely (status))
4105 obj.type = CSI_OBJECT_TYPE_PATTERN;
4106 obj.datum.pattern = cairo_pattern_create_for_surface (surface);
4118 return CSI_STATUS_SUCCESS;
4122 _pop_group (csi_t *ctx)
4125 csi_status_t status;
4130 status = _csi_ostack_get_context (ctx, 0, &cr);
4131 if (_csi_unlikely (status))
4134 obj.type = CSI_OBJECT_TYPE_PATTERN;
4135 obj.datum.pattern = cairo_pop_group (cr);
4141 _push_group (csi_t *ctx)
4143 csi_status_t status;
4149 status = _csi_ostack_get_integer (ctx, 0, &content);
4150 if (_csi_unlikely (status))
4153 status = _csi_ostack_get_context (ctx, 1, &cr);
4154 if (_csi_unlikely (status))
4157 cairo_push_group_with_content (cr, content);
4159 return CSI_STATUS_SUCCESS;
4163 _radial (csi_t *ctx)
4166 csi_status_t status;
4167 double x1, y1, r1, x2, y2, r2;
4171 status = _csi_ostack_get_number (ctx, 0, &r2);
4172 if (_csi_unlikely (status))
4174 status = _csi_ostack_get_number (ctx, 1, &y2);
4175 if (_csi_unlikely (status))
4177 status = _csi_ostack_get_number (ctx, 2, &x2);
4178 if (_csi_unlikely (status))
4180 status = _csi_ostack_get_number (ctx, 3, &r1);
4181 if (_csi_unlikely (status))
4183 status = _csi_ostack_get_number (ctx, 4, &y1);
4184 if (_csi_unlikely (status))
4186 status = _csi_ostack_get_number (ctx, 5, &x1);
4187 if (_csi_unlikely (status))
4190 obj.type = CSI_OBJECT_TYPE_PATTERN;
4191 obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2);
4197 _rectangle (csi_t *ctx)
4199 csi_status_t status;
4206 status = _csi_ostack_get_number (ctx, 0, &h);
4207 if (_csi_unlikely (status))
4209 status = _csi_ostack_get_number (ctx, 1, &w);
4210 if (_csi_unlikely (status))
4212 status = _csi_ostack_get_number (ctx, 2, &y);
4213 if (_csi_unlikely (status))
4215 status = _csi_ostack_get_number (ctx, 3, &x);
4216 if (_csi_unlikely (status))
4218 status = _csi_ostack_get_context (ctx, 4, &cr);
4219 if (_csi_unlikely (status))
4222 /* XXX path object */
4224 cairo_rectangle (cr, x, y, w, h);
4226 return CSI_STATUS_SUCCESS;
4230 _rel_curve_to (csi_t *ctx)
4232 csi_status_t status;
4240 status = _csi_ostack_get_number (ctx, 0, &y3);
4241 if (_csi_unlikely (status))
4243 status = _csi_ostack_get_number (ctx, 1, &x3);
4244 if (_csi_unlikely (status))
4246 status = _csi_ostack_get_number (ctx, 2, &y2);
4247 if (_csi_unlikely (status))
4249 status = _csi_ostack_get_number (ctx, 3, &x2);
4250 if (_csi_unlikely (status))
4252 status = _csi_ostack_get_number (ctx, 4, &y1);
4253 if (_csi_unlikely (status))
4255 status = _csi_ostack_get_number (ctx, 5, &x1);
4256 if (_csi_unlikely (status))
4258 status = _csi_ostack_get_context (ctx, 6, &cr);
4259 if (_csi_unlikely (status))
4262 /* XXX path object */
4264 cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3);
4266 return CSI_STATUS_SUCCESS;
4270 _rel_line_to (csi_t *ctx)
4272 csi_status_t status;
4278 status = _csi_ostack_get_number (ctx, 0, &y);
4279 if (_csi_unlikely (status))
4281 status = _csi_ostack_get_number (ctx, 1, &x);
4282 if (_csi_unlikely (status))
4284 status = _csi_ostack_get_context (ctx, 2, &cr);
4285 if (_csi_unlikely (status))
4288 /* XXX path object */
4290 cairo_rel_line_to (cr, x, y);
4292 return CSI_STATUS_SUCCESS;
4296 _rel_move_to (csi_t *ctx)
4298 csi_status_t status;
4304 status = _csi_ostack_get_number (ctx, 0, &y);
4305 if (_csi_unlikely (status))
4307 status = _csi_ostack_get_number (ctx, 1, &x);
4308 if (_csi_unlikely (status))
4310 status = _csi_ostack_get_context (ctx, 2, &cr);
4311 if (_csi_unlikely (status))
4314 /* XXX path object */
4315 cairo_rel_move_to (cr, x, y);
4317 return CSI_STATUS_SUCCESS;
4321 _repeat (csi_t *ctx)
4324 csi_integer_t count;
4325 csi_status_t status;
4329 status = _csi_ostack_get_procedure (ctx, 0, &proc);
4330 if (_csi_unlikely (status))
4333 status = _csi_ostack_get_integer (ctx, 1, &count);
4334 if (_csi_unlikely (status))
4337 if (_csi_unlikely (count < 0))
4338 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4344 status = _csi_array_execute (ctx, proc);
4345 if (_csi_unlikely (status))
4349 if (--proc->base.ref == 0)
4350 csi_array_free (ctx, proc);
4356 _reset_clip (csi_t *ctx)
4358 return _do_cairo_op (ctx, cairo_reset_clip);
4362 _restore (csi_t *ctx)
4364 return _do_cairo_op (ctx, cairo_restore);
4371 csi_status_t status;
4376 status = _csi_ostack_get_number (ctx, 0, &b);
4377 if (_csi_unlikely (status))
4379 status = _csi_ostack_get_number (ctx, 1, &g);
4380 if (_csi_unlikely (status))
4382 status = _csi_ostack_get_number (ctx, 2, &r);
4383 if (_csi_unlikely (status))
4386 obj.type = CSI_OBJECT_TYPE_PATTERN;
4387 obj.datum.pattern = cairo_pattern_create_rgb (r, g, b);
4396 csi_status_t status;
4401 status = _csi_ostack_get_number (ctx, 0, &a);
4402 if (_csi_unlikely (status))
4404 status = _csi_ostack_get_number (ctx, 1, &b);
4405 if (_csi_unlikely (status))
4407 status = _csi_ostack_get_number (ctx, 2, &g);
4408 if (_csi_unlikely (status))
4410 status = _csi_ostack_get_number (ctx, 3, &r);
4411 if (_csi_unlikely (status))
4414 obj.type = CSI_OBJECT_TYPE_PATTERN;
4415 obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a);
4423 csi_status_t status;
4428 status = _csi_ostack_get_integer (ctx, 0, &j);
4429 if (_csi_unlikely (status))
4431 status = _csi_ostack_get_integer (ctx, 1, &n);
4432 if (_csi_unlikely (status))
4437 return _csi_stack_roll (ctx, &ctx->ostack, j, n);
4441 _rotate (csi_t *ctx)
4444 csi_status_t status;
4450 status = _csi_ostack_get_number (ctx, 0, &theta);
4451 if (_csi_unlikely (status))
4454 obj = _csi_peek_ostack (ctx, 1);
4455 type = csi_object_get_type (obj);
4457 case CSI_OBJECT_TYPE_CONTEXT:
4458 cairo_rotate (obj->datum.cr, theta);
4461 case CSI_OBJECT_TYPE_PATTERN:
4464 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4465 cairo_matrix_rotate (&ctm, theta);
4466 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4471 case CSI_OBJECT_TYPE_MATRIX:
4472 cairo_matrix_rotate (&obj->datum.matrix->matrix, theta);
4476 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4480 return CSI_STATUS_SUCCESS;
4486 return _do_cairo_op (ctx, cairo_save);
4493 csi_status_t status;
4499 status = _csi_ostack_get_number (ctx, 0, &y);
4500 if (_csi_unlikely (status))
4502 status = _csi_ostack_get_number (ctx, 1, &x);
4503 if (_csi_unlikely (status))
4506 obj = _csi_peek_ostack (ctx, 2);
4507 type = csi_object_get_type (obj);
4509 case CSI_OBJECT_TYPE_CONTEXT:
4510 cairo_scale (obj->datum.cr, x, y);
4513 case CSI_OBJECT_TYPE_PATTERN:
4516 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4517 cairo_matrix_scale (&ctm, x, y);
4518 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4523 case CSI_OBJECT_TYPE_MATRIX:
4524 cairo_matrix_scale (&obj->datum.matrix->matrix, x, y);
4528 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4532 return CSI_STATUS_SUCCESS;
4536 _font_options_load_from_dictionary (csi_t *ctx,
4537 csi_dictionary_t *dict,
4538 cairo_font_options_t *options)
4542 void (*setter) (cairo_font_options_t *, int val);
4545 (void (*)(cairo_font_options_t *, int val))
4546 cairo_font_options_set_antialias },
4548 (void (*)(cairo_font_options_t *, int val))
4549 cairo_font_options_set_subpixel_order },
4551 (void (*)(cairo_font_options_t *, int val))
4552 cairo_font_options_set_hint_style },
4554 (void (*)(cairo_font_options_t *, int val))
4555 cairo_font_options_set_hint_metrics },
4557 }, *prop = properties;
4559 while (prop->key != NULL) {
4560 csi_object_t key, value;
4561 csi_status_t status;
4563 status = csi_name_new_static (ctx, &key, prop->key);
4564 if (_csi_unlikely (status))
4567 if (csi_dictionary_has (dict, key.datum.name)) {
4568 status = csi_dictionary_get (ctx, dict, key.datum.name, &value);
4569 if (_csi_unlikely (status))
4572 if (_csi_unlikely (csi_object_get_type (&value) !=
4573 CSI_OBJECT_TYPE_INTEGER))
4575 csi_object_free (ctx, &value);
4576 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4579 prop->setter (options, value.datum.integer);
4585 return CSI_STATUS_SUCCESS;
4589 _scaled_font (csi_t *ctx)
4592 csi_dictionary_t *dict;
4593 cairo_font_face_t *font_face = NULL; /* silence the compiler */
4594 cairo_matrix_t font_matrix, ctm;
4595 cairo_font_options_t *options;
4596 csi_status_t status;
4600 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
4601 if (_csi_unlikely (status))
4603 options = cairo_font_options_create ();
4604 status = _font_options_load_from_dictionary (ctx, dict, options);
4605 if (_csi_unlikely (status)) {
4606 cairo_font_options_destroy (options);
4610 status = _csi_ostack_get_matrix (ctx, 1, &ctm);
4611 if (_csi_unlikely (status)) {
4612 cairo_font_options_destroy (options);
4616 status = _csi_ostack_get_matrix (ctx, 2, &font_matrix);
4617 if (_csi_unlikely (status)) {
4618 cairo_font_options_destroy (options);
4622 status = _csi_ostack_get_font_face (ctx, 3, &font_face);
4623 if (_csi_unlikely (status)) {
4624 cairo_font_options_destroy (options);
4628 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
4629 obj.datum.scaled_font = cairo_scaled_font_create (font_face,
4633 cairo_font_options_destroy (options);
4639 _select_font_face (csi_t *ctx)
4644 csi_string_t *family;
4645 csi_status_t status;
4649 status = _csi_ostack_get_integer (ctx, 0, &weight);
4650 if (_csi_unlikely (status))
4652 status = _csi_ostack_get_integer (ctx, 1, &slant);
4653 if (_csi_unlikely (status))
4655 status = _csi_ostack_get_string (ctx, 2, &family);
4656 if (_csi_unlikely (status))
4658 status = _csi_ostack_get_context (ctx, 3, &cr);
4659 if (_csi_unlikely (status))
4662 cairo_select_font_face (cr, family->string, slant, weight);
4664 return CSI_STATUS_SUCCESS;
4668 _context_set (csi_t *ctx,
4673 if (strcmp ((char *) key, "source") == 0) {
4674 if (_csi_unlikely (csi_object_get_type (obj) !=
4675 CSI_OBJECT_TYPE_PATTERN))
4676 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4678 cairo_set_source (cr, obj->datum.pattern);
4679 return CSI_STATUS_SUCCESS;
4682 if (strcmp ((char *) key, "scaled-font") == 0) {
4683 if (_csi_unlikely (csi_object_get_type (obj) !=
4684 CSI_OBJECT_TYPE_SCALED_FONT))
4685 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4687 cairo_set_scaled_font (cr, obj->datum.scaled_font);
4688 return CSI_STATUS_SUCCESS;
4691 if (strcmp ((char *) key, "font-face") == 0) {
4692 if (_csi_unlikely (csi_object_get_type (obj) !=
4693 CSI_OBJECT_TYPE_FONT))
4694 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4696 cairo_set_font_face (cr, obj->datum.font_face);
4697 return CSI_STATUS_SUCCESS;
4700 /* return _proxy_set()? */
4701 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4707 csi_object_t *key, *value, *dst;
4708 csi_status_t status;
4713 value = _csi_peek_ostack (ctx, 0);
4714 key = _csi_peek_ostack (ctx, 1);
4715 dst = _csi_peek_ostack (ctx, 2);
4717 type = csi_object_get_type (dst);
4719 case CSI_OBJECT_TYPE_DICTIONARY:
4720 if (_csi_unlikely (csi_object_get_type (key) !=
4721 CSI_OBJECT_TYPE_NAME))
4722 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4724 status = csi_dictionary_put (ctx,
4725 dst->datum.dictionary,
4729 case CSI_OBJECT_TYPE_ARRAY:
4730 if (_csi_unlikely (csi_object_get_type (key) !=
4731 CSI_OBJECT_TYPE_INTEGER))
4732 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4734 status = csi_array_put (ctx,
4740 case CSI_OBJECT_TYPE_CONTEXT:
4741 if (_csi_unlikely (csi_object_get_type (key) !=
4742 CSI_OBJECT_TYPE_NAME))
4743 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4745 status = _context_set (ctx,
4751 case CSI_OBJECT_TYPE_STRING:
4753 status = csi_string_put (dst, key, value);
4757 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4765 _set_antialias (csi_t *ctx)
4767 csi_status_t status;
4773 status = _csi_ostack_get_integer (ctx, 0, &antialias);
4774 if (_csi_unlikely (status))
4776 status = _csi_ostack_get_context (ctx, 1, &cr);
4777 if (_csi_unlikely (status))
4780 cairo_set_antialias (cr, antialias);
4782 return CSI_STATUS_SUCCESS;
4786 _set_dash (csi_t *ctx)
4789 csi_status_t status;
4795 status = _csi_ostack_get_number (ctx, 0, &offset);
4796 if (_csi_unlikely (status))
4798 status = _csi_ostack_get_array (ctx, 1, &array);
4799 if (_csi_unlikely (status))
4801 status = _csi_ostack_get_context (ctx, 2, &cr);
4802 if (_csi_unlikely (status))
4805 if (array->stack.len == 0) {
4806 cairo_set_dash (cr, NULL, 0., 0.);
4808 double stack_dashes[8];
4812 if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) {
4813 dashes = stack_dashes;
4815 if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double)))
4816 return _csi_error (CSI_STATUS_NO_MEMORY);
4817 dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len);
4818 if (_csi_unlikely (dashes == NULL))
4819 return _csi_error (CSI_STATUS_NO_MEMORY);
4822 for (n = 0; n < array->stack.len; n++) {
4823 if (_csi_unlikely (! csi_object_is_number
4824 (&array->stack.objects[n])))
4826 if (dashes != stack_dashes)
4827 _csi_free (ctx, dashes);
4828 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4831 dashes[n] = csi_number_get_value (&array->stack.objects[n]);
4834 cairo_set_dash (cr, dashes, n, offset);
4836 if (dashes != stack_dashes)
4837 _csi_free (ctx, dashes);
4841 return CSI_STATUS_SUCCESS;
4845 _set_device_offset (csi_t *ctx)
4847 csi_status_t status;
4848 cairo_surface_t *surface;
4853 status = _csi_ostack_get_number (ctx, 0, &y);
4854 if (_csi_unlikely (status))
4856 status = _csi_ostack_get_number (ctx, 1, &x);
4857 if (_csi_unlikely (status))
4859 status = _csi_ostack_get_surface (ctx, 2, &surface);
4860 if (_csi_unlikely (status))
4863 cairo_surface_set_device_offset (surface, x, y);
4865 return CSI_STATUS_SUCCESS;
4869 _set_extend (csi_t *ctx)
4871 csi_status_t status;
4878 status = _csi_ostack_get_integer (ctx, 0, &extend);
4879 if (_csi_unlikely (status))
4882 obj = _csi_peek_ostack (ctx, 1);
4883 type = csi_object_get_type (obj);
4885 case CSI_OBJECT_TYPE_CONTEXT:
4886 cairo_pattern_set_extend (cairo_get_source (obj->datum.cr),
4889 case CSI_OBJECT_TYPE_PATTERN:
4890 cairo_pattern_set_extend (obj->datum.pattern, extend);
4893 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4897 return CSI_STATUS_SUCCESS;
4901 _set_fallback_resolution (csi_t *ctx)
4903 csi_status_t status;
4904 cairo_surface_t *surface;
4905 double dpi_x, dpi_y;
4909 status = _csi_ostack_get_number (ctx, 0, &dpi_y);
4910 if (_csi_unlikely (status))
4912 status = _csi_ostack_get_number (ctx, 1, &dpi_x);
4913 if (_csi_unlikely (status))
4915 status = _csi_ostack_get_surface (ctx, 2, &surface);
4916 if (_csi_unlikely (status))
4919 cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y);
4921 return CSI_STATUS_SUCCESS;
4925 _set_fill_rule (csi_t *ctx)
4927 csi_status_t status;
4933 status = _csi_ostack_get_integer (ctx, 0, &fill_rule);
4934 if (_csi_unlikely (status))
4936 status = _csi_ostack_get_context (ctx, 1, &cr);
4937 if (_csi_unlikely (status))
4940 cairo_set_fill_rule (cr, fill_rule);
4942 return CSI_STATUS_SUCCESS;
4946 _set_filter (csi_t *ctx)
4948 csi_status_t status;
4955 status = _csi_ostack_get_integer (ctx, 0, &filter);
4956 if (_csi_unlikely (status))
4959 obj = _csi_peek_ostack (ctx, 1);
4960 type = csi_object_get_type (obj);
4962 case CSI_OBJECT_TYPE_CONTEXT:
4963 cairo_pattern_set_filter (cairo_get_source (obj->datum.cr),
4966 case CSI_OBJECT_TYPE_PATTERN:
4967 cairo_pattern_set_filter (obj->datum.pattern, filter);
4970 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4974 return CSI_STATUS_SUCCESS;
4978 _set_font_face (csi_t *ctx)
4981 cairo_font_face_t *font = NULL; /* silence the compiler */
4982 csi_status_t status;
4986 status = _csi_ostack_get_font_face (ctx, 0, &font);
4987 if (_csi_unlikely (status))
4989 status = _csi_ostack_get_context (ctx, 1, &cr);
4990 if (_csi_unlikely (status))
4993 cairo_set_font_face (cr, font);
4995 return CSI_STATUS_SUCCESS;
4999 _set_font_options (csi_t *ctx)
5001 csi_status_t status;
5003 csi_dictionary_t *dict;
5004 cairo_font_options_t *options;
5008 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
5009 if (_csi_unlikely (status))
5011 status = _csi_ostack_get_context (ctx, 1, &cr);
5012 if (_csi_unlikely (status))
5015 options = cairo_font_options_create ();
5016 status = _font_options_load_from_dictionary (ctx, dict, options);
5017 if (_csi_unlikely (status))
5020 cairo_set_font_options (cr, options);
5021 cairo_font_options_destroy (options);
5023 return CSI_STATUS_SUCCESS;
5027 _set_font_matrix (csi_t *ctx)
5029 csi_status_t status;
5035 status = _csi_ostack_get_matrix (ctx, 0, &m);
5036 if (_csi_unlikely (status))
5038 status = _csi_ostack_get_context (ctx, 1, &cr);
5039 if (_csi_unlikely (status))
5042 cairo_set_font_matrix (cr, &m);
5044 return CSI_STATUS_SUCCESS;
5048 _set_font_size (csi_t *ctx)
5050 csi_status_t status;
5056 status = _csi_ostack_get_number (ctx, 0, &size);
5057 if (_csi_unlikely (status))
5059 status = _csi_ostack_get_context (ctx, 1, &cr);
5060 if (_csi_unlikely (status))
5063 cairo_set_font_size (cr, size);
5065 return CSI_STATUS_SUCCESS;
5069 _set_line_cap (csi_t *ctx)
5071 csi_status_t status;
5077 status = _csi_ostack_get_integer (ctx, 0, &line_cap);
5078 if (_csi_unlikely (status))
5080 status = _csi_ostack_get_context (ctx, 1, &cr);
5081 if (_csi_unlikely (status))
5084 cairo_set_line_cap (cr, line_cap);
5086 return CSI_STATUS_SUCCESS;
5090 _set_line_join (csi_t *ctx)
5092 csi_status_t status;
5096 status = _csi_ostack_get_integer (ctx, 0, &line_join);
5097 if (_csi_unlikely (status))
5099 status = _csi_ostack_get_context (ctx, 1, &cr);
5100 if (_csi_unlikely (status))
5103 cairo_set_line_join (cr, line_join);
5105 return CSI_STATUS_SUCCESS;
5109 _set_line_width (csi_t *ctx)
5111 csi_status_t status;
5117 status = _csi_ostack_get_number (ctx, 0, &line_width);
5118 if (_csi_unlikely (status))
5120 status = _csi_ostack_get_context (ctx, 1, &cr);
5121 if (_csi_unlikely (status))
5124 cairo_set_line_width (cr, line_width);
5126 return CSI_STATUS_SUCCESS;
5130 _set_matrix (csi_t *ctx)
5133 csi_status_t status;
5139 status = _csi_ostack_get_matrix (ctx, 0, &m);
5140 if (_csi_unlikely (status))
5143 obj = _csi_peek_ostack (ctx, 1);
5144 type = csi_object_get_type (obj);
5146 case CSI_OBJECT_TYPE_CONTEXT:
5147 cairo_set_matrix (obj->datum.cr, &m);
5149 case CSI_OBJECT_TYPE_PATTERN:
5150 cairo_pattern_set_matrix (obj->datum.pattern, &m);
5152 case CSI_OBJECT_TYPE_MATRIX:
5153 obj->datum.matrix->matrix = m;
5156 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5160 return CSI_STATUS_SUCCESS;
5165 csi_string_t *source;
5168 _mime_tag_destroy (void *closure)
5170 struct _mime_tag *tag = closure;
5172 if (--tag->source->base.ref)
5173 csi_string_free (tag->ctx, tag->source);
5175 _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag));
5179 _set_mime_data (csi_t *ctx)
5181 csi_status_t status;
5183 const char *mime = NULL; /* silence the compiler */
5184 csi_object_t source;
5185 cairo_surface_t *surface;
5186 struct _mime_tag *tag;
5191 obj = _csi_peek_ostack (ctx, 0);
5192 type = csi_object_get_type (obj);
5194 case CSI_OBJECT_TYPE_FILE:
5195 status = _csi_file_as_string (ctx, obj->datum.file, &source);
5196 if (_csi_unlikely (status))
5201 case CSI_OBJECT_TYPE_STRING:
5202 source = *csi_object_reference (obj);
5206 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5209 status = _csi_ostack_get_string_constant (ctx, 1, &mime);
5210 if (_csi_unlikely (status))
5213 status = _csi_ostack_get_surface (ctx, 2, &surface);
5214 if (_csi_unlikely (status))
5218 /* XXX free source */
5219 tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag));
5220 if (_csi_unlikely (tag == NULL))
5221 return _csi_error (CSI_STATUS_NO_MEMORY);
5222 tag->ctx = cairo_script_interpreter_reference (ctx);
5223 tag->source = source.datum.string;
5224 tag->source->base.ref++;
5226 status = cairo_surface_set_mime_data (surface,
5229 source.datum.string->string,
5230 source.datum.string->len,
5231 _mime_tag_destroy, tag);
5232 if (_csi_unlikely (status)) {
5233 _mime_tag_destroy (tag);
5238 return CSI_STATUS_SUCCESS;
5242 _set_miter_limit (csi_t *ctx)
5244 csi_status_t status;
5250 status = _csi_ostack_get_number (ctx, 0, &miter_limit);
5251 if (_csi_unlikely (status))
5253 status = _csi_ostack_get_context (ctx, 1, &cr);
5254 if (_csi_unlikely (status))
5257 cairo_set_miter_limit (cr, miter_limit);
5259 return CSI_STATUS_SUCCESS;
5263 _set_operator (csi_t *ctx)
5267 csi_status_t status;
5271 status = _csi_ostack_get_integer (ctx, 0, &val);
5272 if (_csi_unlikely (status))
5274 status = _csi_ostack_get_context (ctx, 1, &cr);
5275 if (_csi_unlikely (status))
5278 cairo_set_operator (cr, val);
5280 return CSI_STATUS_SUCCESS;
5284 _set_scaled_font (csi_t *ctx)
5287 cairo_scaled_font_t *font = NULL; /* silence the compiler */
5288 csi_status_t status;
5292 status = _csi_ostack_get_scaled_font (ctx, 0, &font);
5293 if (_csi_unlikely (status))
5295 status = _csi_ostack_get_context (ctx, 1, &cr);
5296 if (_csi_unlikely (status))
5299 cairo_set_scaled_font (cr, font);
5301 return CSI_STATUS_SUCCESS;
5305 _set_source (csi_t *ctx)
5308 cairo_pattern_t *pattern = NULL; /* silence the compiler */
5309 csi_status_t status;
5313 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
5314 if (_csi_unlikely (status))
5316 status = _csi_ostack_get_context (ctx, 1, &cr);
5317 if (_csi_unlikely (status))
5320 cairo_set_source (cr, pattern);
5322 return CSI_STATUS_SUCCESS;
5325 static csi_boolean_t
5326 _matching_images (cairo_surface_t *a, cairo_surface_t *b)
5328 cairo_format_t format_a, format_b;
5330 if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE)
5332 if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE)
5335 if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b))
5338 if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b))
5341 format_a = cairo_image_surface_get_format (a);
5342 if (format_a == CAIRO_FORMAT_RGB24)
5343 format_a = CAIRO_FORMAT_ARGB32;
5345 format_b = cairo_image_surface_get_format (b);
5346 if (format_b == CAIRO_FORMAT_RGB24)
5347 format_b = CAIRO_FORMAT_ARGB32;
5349 if (format_a != format_b)
5356 _set_source_image (csi_t *ctx)
5358 csi_status_t status;
5359 cairo_surface_t *surface;
5360 cairo_surface_t *source;
5361 unsigned char *image_surface_data;
5362 unsigned char *source_data;
5365 status = _csi_ostack_get_surface (ctx, 0, &source);
5366 if (_csi_unlikely (status))
5368 status = _csi_ostack_get_surface (ctx, 1, &surface);
5369 if (_csi_unlikely (status))
5372 /* Catch the most frequent use of simply uploading pixel data,
5373 * principally to remove the pixman ops from the profiles.
5375 if (_csi_likely (_matching_images (surface, source))) {
5376 if (cairo_surface_get_reference_count (surface) == 1 &&
5377 cairo_surface_get_reference_count (source) == 1)
5379 _csi_peek_ostack (ctx, 0)->datum.surface = surface;
5380 _csi_peek_ostack (ctx, 1)->datum.surface = source;
5384 cairo_surface_flush (surface);
5385 image_surface_data = cairo_image_surface_get_data (surface);
5386 if (image_surface_data == NULL)
5387 return _csi_error (CSI_STATUS_NULL_POINTER);
5389 source_data = cairo_image_surface_get_data (source);
5390 if (source_data == NULL)
5391 return _csi_error (CSI_STATUS_NULL_POINTER);
5393 memcpy (image_surface_data,
5395 cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
5396 cairo_surface_mark_dirty (surface);
5401 cr = cairo_create (surface);
5402 cairo_set_source_surface (cr, source, 0, 0);
5408 return CSI_STATUS_SUCCESS;
5412 _set_source_rgb (csi_t *ctx)
5414 csi_status_t status;
5420 status = _csi_ostack_get_number (ctx, 0, &b);
5421 if (_csi_unlikely (status))
5423 status = _csi_ostack_get_number (ctx, 1, &g);
5424 if (_csi_unlikely (status))
5426 status = _csi_ostack_get_number (ctx, 2, &r);
5427 if (_csi_unlikely (status))
5429 status = _csi_ostack_get_context (ctx, 3, &cr);
5430 if (_csi_unlikely (status))
5433 cairo_set_source_rgb (cr, r, g, b);
5435 return CSI_STATUS_SUCCESS;
5439 _set_source_rgba (csi_t *ctx)
5441 csi_status_t status;
5447 status = _csi_ostack_get_number (ctx, 0, &a);
5448 if (_csi_unlikely (status))
5450 status = _csi_ostack_get_number (ctx, 1, &b);
5451 if (_csi_unlikely (status))
5453 status = _csi_ostack_get_number (ctx, 2, &g);
5454 if (_csi_unlikely (status))
5456 status = _csi_ostack_get_number (ctx, 3, &r);
5457 if (_csi_unlikely (status))
5459 status = _csi_ostack_get_context (ctx, 4, &cr);
5460 if (_csi_unlikely (status))
5463 cairo_set_source_rgba (cr, r, g, b, a);
5465 return CSI_STATUS_SUCCESS;
5469 _set_tolerance (csi_t *ctx)
5471 csi_status_t status;
5477 status = _csi_ostack_get_number (ctx, 0, &tolerance);
5478 if (_csi_unlikely (status))
5480 status = _csi_ostack_get_context (ctx, 1, &cr);
5481 if (_csi_unlikely (status))
5484 cairo_set_tolerance (cr, tolerance);
5486 return CSI_STATUS_SUCCESS;
5490 _transform (csi_t *ctx)
5493 csi_status_t status;
5499 status = _csi_ostack_get_matrix (ctx, 0, &m);
5500 if (_csi_unlikely (status))
5503 obj = _csi_peek_ostack (ctx, 1);
5504 type = csi_object_get_type (obj);
5506 case CSI_OBJECT_TYPE_CONTEXT:
5507 cairo_transform (obj->datum.cr, &m);
5509 case CSI_OBJECT_TYPE_PATTERN:
5512 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5513 cairo_matrix_multiply (&ctm, &m, &ctm);
5514 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5517 case CSI_OBJECT_TYPE_MATRIX:
5518 cairo_matrix_multiply (&obj->datum.matrix->matrix,
5520 &obj->datum.matrix->matrix);
5523 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5527 return CSI_STATUS_SUCCESS;
5531 _translate (csi_t *ctx)
5534 csi_status_t status;
5540 status = _csi_ostack_get_number (ctx, 0, &y);
5541 if (_csi_unlikely (status))
5543 status = _csi_ostack_get_number (ctx, 1, &x);
5544 if (_csi_unlikely (status))
5547 obj = _csi_peek_ostack (ctx, 2);
5548 type = csi_object_get_type (obj);
5550 case CSI_OBJECT_TYPE_CONTEXT:
5551 cairo_translate (obj->datum.cr, x, y);
5554 case CSI_OBJECT_TYPE_PATTERN:
5557 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5558 cairo_matrix_translate (&ctm, x, y);
5559 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5564 case CSI_OBJECT_TYPE_MATRIX:
5565 cairo_matrix_translate (&obj->datum.matrix->matrix, x, y);
5569 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5573 return CSI_STATUS_SUCCESS;
5579 return _csi_push_ostack_boolean (ctx, TRUE);
5583 _show_page (csi_t *ctx)
5590 obj = _csi_peek_ostack (ctx, 0);
5591 type = csi_object_get_type (obj);
5593 case CSI_OBJECT_TYPE_CONTEXT:
5594 cairo_show_page (obj->datum.cr);
5595 if (ctx->hooks.copy_page != NULL)
5596 ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
5598 case CSI_OBJECT_TYPE_SURFACE:
5599 cairo_surface_show_page (obj->datum.surface);
5603 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5606 return CSI_STATUS_SUCCESS;
5610 _similar (csi_t *ctx)
5614 double width, height;
5615 cairo_surface_t *other;
5616 csi_status_t status;
5620 status = _csi_ostack_get_integer (ctx, 0, &content);
5621 if (_csi_unlikely (status))
5623 status = _csi_ostack_get_number (ctx, 1, &height);
5624 if (_csi_unlikely (status))
5626 status = _csi_ostack_get_number (ctx, 2, &width);
5627 if (_csi_unlikely (status))
5629 status = _csi_ostack_get_surface (ctx, 3, &other);
5630 if (_csi_unlikely (status))
5633 /* silently fix-up a common bug when writing CS */
5634 if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) {
5635 if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA))
5636 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5638 switch ((int) content) {
5640 case CAIRO_FORMAT_ARGB32:
5641 content = CAIRO_CONTENT_COLOR_ALPHA;
5643 case CAIRO_FORMAT_RGB16_565:
5644 case CAIRO_FORMAT_RGB24:
5645 content = CAIRO_CONTENT_COLOR;
5647 case CAIRO_FORMAT_A8:
5648 case CAIRO_FORMAT_A1:
5649 content = CAIRO_CONTENT_ALPHA;
5654 obj.type = CSI_OBJECT_TYPE_SURFACE;
5655 obj.datum.surface = cairo_surface_create_similar (other,
5656 content, width, height);
5662 _similar_image (csi_t *ctx)
5666 double width, height;
5667 cairo_surface_t *other;
5668 csi_status_t status;
5672 status = _csi_ostack_get_number (ctx, 0, &height);
5673 if (_csi_unlikely (status))
5675 status = _csi_ostack_get_number (ctx, 1, &width);
5676 if (_csi_unlikely (status))
5678 status = _csi_ostack_get_integer (ctx, 2, &format);
5679 if (_csi_unlikely (status))
5681 status = _csi_ostack_get_surface (ctx, 3, &other);
5682 if (_csi_unlikely (status))
5685 obj.type = CSI_OBJECT_TYPE_SURFACE;
5686 obj.datum.surface = cairo_surface_create_similar_image (other,
5694 _subsurface (csi_t *ctx)
5697 double x, y, width, height;
5698 cairo_surface_t *target;
5699 csi_status_t status;
5703 status = _csi_ostack_get_number (ctx, 0, &height);
5704 if (_csi_unlikely (status))
5706 status = _csi_ostack_get_number (ctx, 1, &width);
5707 if (_csi_unlikely (status))
5709 status = _csi_ostack_get_number (ctx, 2, &y);
5710 if (_csi_unlikely (status))
5712 status = _csi_ostack_get_number (ctx, 3, &x);
5713 if (_csi_unlikely (status))
5715 status = _csi_ostack_get_surface (ctx, 4, &target);
5716 if (_csi_unlikely (status))
5719 obj.type = CSI_OBJECT_TYPE_SURFACE;
5720 obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height);
5726 _show_text (csi_t *ctx)
5728 csi_status_t status;
5734 status = _csi_ostack_get_string (ctx, 0, &text);
5735 if (_csi_unlikely (status))
5737 status = _csi_ostack_get_context (ctx, 1, &cr);
5738 if (_csi_unlikely (status))
5741 cairo_show_text (cr, text->string);
5743 return CSI_STATUS_SUCCESS;
5747 _show_glyphs (csi_t *ctx)
5750 csi_status_t status;
5752 cairo_glyph_t stack_glyphs[256], *glyphs;
5753 csi_integer_t nglyphs, i;
5757 status = _csi_ostack_get_array (ctx, 0, &array);
5758 if (_csi_unlikely (status))
5760 status = _csi_ostack_get_context (ctx, 1, &cr);
5761 if (_csi_unlikely (status))
5766 for (i = 0; i < array->stack.len; i++) {
5767 csi_object_t *obj = &array->stack.objects[i];
5768 int type = csi_object_get_type (obj);
5770 case CSI_OBJECT_TYPE_ARRAY:
5771 nglyphs += obj->datum.array->stack.len;
5773 case CSI_OBJECT_TYPE_STRING:
5774 nglyphs += obj->datum.string->len;
5780 return CSI_STATUS_SUCCESS;
5783 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5784 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
5785 return _csi_error (CSI_STATUS_NO_MEMORY);
5787 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5788 if (_csi_unlikely (glyphs == NULL))
5789 return _csi_error (CSI_STATUS_NO_MEMORY);
5791 glyphs = stack_glyphs;
5793 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5794 cairo_show_glyphs (cr, glyphs, nglyphs);
5796 if (glyphs != stack_glyphs)
5797 _csi_free (ctx, glyphs);
5800 return CSI_STATUS_SUCCESS;
5804 _show_text_glyphs (csi_t *ctx)
5808 csi_string_t *string;
5809 csi_string_t *utf8_string;
5810 csi_status_t status;
5812 cairo_text_cluster_t stack_clusters[256], *clusters;
5813 cairo_glyph_t stack_glyphs[256], *glyphs;
5814 csi_integer_t nglyphs, nclusters, i;
5820 status = _csi_ostack_get_integer (ctx, 0, &direction);
5821 if (_csi_unlikely (status))
5824 obj = _csi_peek_ostack (ctx, 1);
5825 type = csi_object_get_type (obj);
5827 case CSI_OBJECT_TYPE_ARRAY:
5828 array = obj->datum.array;
5829 nclusters = array->stack.len / 2;
5830 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5831 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5832 return _csi_error (CSI_STATUS_NO_MEMORY);
5833 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5834 if (_csi_unlikely (clusters == NULL))
5835 return _csi_error (CSI_STATUS_NO_MEMORY);
5837 clusters = stack_clusters;
5839 for (i = 0; i < nclusters; i++) {
5840 clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]);
5841 clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]);
5845 case CSI_OBJECT_TYPE_STRING:
5846 string = obj->datum.string;
5847 nclusters = string->len / 2;
5848 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5849 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5850 return _csi_error (CSI_STATUS_NO_MEMORY);
5851 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5852 if (_csi_unlikely (clusters == NULL))
5853 return _csi_error (CSI_STATUS_NO_MEMORY);
5855 clusters = stack_clusters;
5857 for (i = 0; i < nclusters; i++) {
5858 clusters[i].num_bytes = string->string[2*i+0];
5859 clusters[i].num_glyphs = string->string[2*i+1];
5864 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5867 status = _csi_ostack_get_array (ctx, 2, &array);
5868 if (_csi_unlikely (status)) {
5869 if (clusters != stack_clusters)
5870 _csi_free (ctx, clusters);
5873 status = _csi_ostack_get_string (ctx, 3, &utf8_string);
5874 if (_csi_unlikely (status)) {
5875 if (clusters != stack_clusters)
5876 _csi_free (ctx, clusters);
5879 status = _csi_ostack_get_context (ctx, 4, &cr);
5880 if (_csi_unlikely (status)) {
5881 if (clusters != stack_clusters)
5882 _csi_free (ctx, clusters);
5888 for (i = 0; i < array->stack.len; i++) {
5889 obj = &array->stack.objects[i];
5890 type = csi_object_get_type (obj);
5892 case CSI_OBJECT_TYPE_ARRAY:
5893 nglyphs += obj->datum.array->stack.len;
5895 case CSI_OBJECT_TYPE_STRING:
5896 nglyphs += obj->datum.string->len;
5902 if (clusters != stack_clusters)
5903 _csi_free (ctx, clusters);
5904 return CSI_STATUS_SUCCESS;
5907 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5908 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) {
5909 if (clusters != stack_clusters)
5910 _csi_free (ctx, clusters);
5911 return _csi_error (CSI_STATUS_NO_MEMORY);
5914 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5915 if (_csi_unlikely (glyphs == NULL)) {
5916 if (clusters != stack_clusters)
5917 _csi_free (ctx, clusters);
5918 return _csi_error (CSI_STATUS_NO_MEMORY);
5921 glyphs = stack_glyphs;
5923 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5924 cairo_show_text_glyphs (cr,
5925 utf8_string->string, utf8_string->len,
5927 clusters, nclusters,
5930 if (clusters != stack_clusters)
5931 _csi_free (ctx, clusters);
5932 if (glyphs != stack_glyphs)
5933 _csi_free (ctx, glyphs);
5936 return CSI_STATUS_SUCCESS;
5940 _stroke (csi_t *ctx)
5942 return _do_cairo_op (ctx, cairo_stroke);
5946 _stroke_preserve (csi_t *ctx)
5948 return _do_cairo_op (ctx, cairo_stroke_preserve);
5956 csi_object_type_t type_a, type_b;
5960 B = _csi_peek_ostack (ctx, 0);
5961 A = _csi_peek_ostack (ctx, 1);
5963 type_a = csi_object_get_type (A);
5964 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
5965 type_a == CSI_OBJECT_TYPE_REAL)))
5967 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5970 type_b = csi_object_get_type (B);
5971 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
5972 type_b == CSI_OBJECT_TYPE_REAL)))
5974 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5979 if (type_a == CSI_OBJECT_TYPE_REAL &&
5980 type_b == CSI_OBJECT_TYPE_REAL)
5982 return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real);
5985 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
5986 type_b == CSI_OBJECT_TYPE_INTEGER)
5988 return _csi_push_ostack_integer (ctx,
5989 A->datum.integer - B->datum.integer);
5995 if (type_a == CSI_OBJECT_TYPE_REAL)
5998 v = A->datum.integer;
6000 if (type_b == CSI_OBJECT_TYPE_REAL)
6003 v -= B->datum.integer;
6005 return _csi_push_ostack_real (ctx, v);
6010 _surface (csi_t *ctx)
6013 csi_dictionary_t *dict;
6016 double width, height;
6017 csi_surface_create_func_t hook;
6019 cairo_surface_t *surface;
6021 csi_status_t status;
6025 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
6026 if (_csi_unlikely (status))
6029 status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width);
6030 if (_csi_unlikely (status))
6032 status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height);
6033 if (_csi_unlikely (status))
6036 content = CAIRO_CONTENT_COLOR_ALPHA;
6037 status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content);
6038 if (_csi_unlikely (status))
6042 status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid);
6043 if (_csi_unlikely (status))
6046 status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid);
6047 if (_csi_unlikely (status))
6051 hook = ctx->hooks.surface_create;
6052 assert (hook != NULL);
6054 surface = hook (ctx->hooks.closure, content, width, height, uid);
6055 if (_csi_unlikely (surface == NULL)) {
6056 return _csi_error (CSI_STATUS_NULL_POINTER);
6059 proxy = _csi_proxy_create (ctx, surface, dict,
6060 ctx->hooks.surface_destroy,
6061 ctx->hooks.closure);
6062 if (_csi_unlikely (proxy == NULL)) {
6063 cairo_surface_destroy (surface);
6064 return _csi_error (CSI_STATUS_NO_MEMORY);
6067 status = cairo_surface_set_user_data (surface,
6069 proxy, _csi_proxy_destroy);
6070 if (_csi_unlikely (status)) {
6071 _csi_proxy_destroy (proxy);
6072 cairo_surface_destroy (surface);
6076 status = csi_name_new_static (ctx, &key, "fallback-resolution");
6077 if (_csi_unlikely (status)) {
6078 cairo_surface_destroy (surface);
6081 if (csi_dictionary_has (dict, key.datum.name)) {
6082 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
6083 if (_csi_unlikely (status)) {
6084 cairo_surface_destroy (surface);
6087 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
6088 csi_array_t *array = obj.datum.array;
6089 if (array->stack.len == 2) {
6090 cairo_surface_set_fallback_resolution (surface,
6091 csi_number_get_value
6092 (&array->stack.objects[0]),
6093 csi_number_get_value
6094 (&array->stack.objects[1]));
6098 /* initialise surface to source */
6099 status = csi_name_new_static (ctx, &key, "source");
6100 if (_csi_unlikely (status)) {
6101 cairo_surface_destroy (surface);
6104 if (csi_dictionary_has (dict, key.datum.name)) {
6105 cairo_surface_t *image;
6108 status = _image_load_from_dictionary (ctx, dict, &image);
6109 if (_csi_unlikely (status)) {
6110 cairo_surface_destroy (surface);
6111 cairo_surface_destroy (image);
6115 cr = cairo_create (surface);
6116 cairo_set_source_surface (cr, image, 0, 0);
6117 cairo_surface_destroy (image);
6119 status = cairo_status (cr);
6122 if (_csi_unlikely (status))
6126 status = csi_name_new_static (ctx, &key, "device-offset");
6127 if (_csi_unlikely (status)) {
6128 cairo_surface_destroy (surface);
6131 if (csi_dictionary_has (dict, key.datum.name)) {
6132 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
6133 if (_csi_unlikely (status))
6136 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
6137 csi_array_t *array = obj.datum.array;
6139 if (array->stack.len == 2) {
6140 cairo_surface_set_device_offset (surface,
6141 csi_number_get_value
6142 (&array->stack.objects[0]),
6143 csi_number_get_value
6144 (&array->stack.objects[1]));
6149 obj.type = CSI_OBJECT_TYPE_SURFACE;
6150 obj.datum.surface = surface;
6156 _record (csi_t *ctx)
6161 csi_status_t status;
6162 cairo_rectangle_t extents;
6163 cairo_rectangle_t *r;
6167 status = _csi_ostack_get_array (ctx, 0, &array);
6168 if (_csi_unlikely (status))
6171 status = _csi_ostack_get_integer (ctx, 1, &content);
6172 if (_csi_unlikely (status))
6175 switch (array->stack.len) {
6180 extents.x = extents.y = 0;
6181 extents.width = _csi_object_as_real (&array->stack.objects[0]);
6182 extents.height = _csi_object_as_real (&array->stack.objects[1]);
6186 extents.x = _csi_object_as_real (&array->stack.objects[0]);
6187 extents.y = _csi_object_as_real (&array->stack.objects[1]);
6188 extents.width = _csi_object_as_real (&array->stack.objects[2]);
6189 extents.height = _csi_object_as_real (&array->stack.objects[3]);
6193 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6196 obj.type = CSI_OBJECT_TYPE_SURFACE;
6197 obj.datum.surface = cairo_recording_surface_create (content, r);
6203 _text_path (csi_t *ctx)
6205 csi_status_t status;
6211 status = _csi_ostack_get_string (ctx, 0, &text);
6212 if (_csi_unlikely (status))
6214 status = _csi_ostack_get_context (ctx, 1, &cr);
6215 if (_csi_unlikely (status))
6218 cairo_text_path (cr, text->string);
6220 return CSI_STATUS_SUCCESS;
6226 csi_name_t name = 0; /* silence the compiler */
6227 csi_status_t status;
6231 status = _csi_ostack_get_name (ctx, 0, &name);
6232 if (_csi_unlikely (status))
6235 status = _csi_name_undefine (ctx, name);
6236 if (_csi_unlikely (status))
6240 return CSI_STATUS_SUCCESS;
6247 csi_name_t name = 0; /* silence the compiler */
6248 csi_status_t status;
6253 status = _csi_ostack_get_name (ctx, 0, &name);
6254 if (_csi_unlikely (status))
6257 dst = _csi_peek_ostack (ctx, 1);
6258 type = csi_object_get_type (dst);
6260 case CSI_OBJECT_TYPE_DICTIONARY:
6261 csi_dictionary_remove (ctx, dst->datum.dictionary, name);
6263 case CSI_OBJECT_TYPE_STRING:
6264 case CSI_OBJECT_TYPE_ARRAY:
6266 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6270 return CSI_STATUS_SUCCESS;
6274 _write_to_png (csi_t *ctx)
6276 csi_status_t status;
6277 csi_string_t *filename;
6278 cairo_surface_t *surface;
6282 status = _csi_ostack_get_string (ctx, 0, &filename);
6283 if (_csi_unlikely (status))
6285 status = _csi_ostack_get_surface (ctx, 1, &surface);
6286 if (_csi_unlikely (status))
6289 #if CAIRO_HAS_PNG_FUNCTIONS
6290 status = cairo_surface_write_to_png (surface, filename->string);
6291 if (_csi_unlikely (status))
6294 return CAIRO_STATUS_WRITE_ERROR;
6298 return CSI_STATUS_SUCCESS;
6302 _write_to_script (csi_t *ctx)
6304 csi_status_t status;
6305 csi_string_t *filename;
6306 cairo_surface_t *record;
6310 status = _csi_ostack_get_string (ctx, 0, &filename);
6311 if (_csi_unlikely (status))
6313 status = _csi_ostack_get_surface (ctx, 1, &record);
6314 if (_csi_unlikely (status))
6317 if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING)
6318 return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
6320 #if CAIRO_HAS_SCRIPT_SURFACE
6322 cairo_device_t *script;
6324 script = cairo_script_create (filename->string);
6325 status = cairo_script_from_recording_surface (script, record);
6326 cairo_device_destroy (script);
6327 if (_csi_unlikely (status))
6331 return CAIRO_STATUS_WRITE_ERROR;
6335 return CSI_STATUS_SUCCESS;
6341 csi_object_t *a, *b;
6346 a = _csi_peek_ostack (ctx, 0);
6347 b = _csi_peek_ostack (ctx, 1);
6348 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
6349 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6352 type = csi_object_get_type (a);
6354 case CSI_OBJECT_TYPE_INTEGER:
6355 return _csi_push_ostack_integer (ctx,
6356 a->datum.integer ^ b->datum.integer);
6357 case CSI_OBJECT_TYPE_BOOLEAN:
6358 return _csi_push_ostack_boolean (ctx,
6359 a->datum.boolean ^ b->datum.boolean);
6361 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6366 _debug_print (csi_t *ctx)
6371 obj = _csi_peek_ostack (ctx, 0);
6372 switch (csi_object_get_type (obj)) {
6373 case CSI_OBJECT_TYPE_NULL:
6374 fprintf (stderr, "NULL\n");
6378 case CSI_OBJECT_TYPE_BOOLEAN:
6379 fprintf (stderr, "boolean: %s\n",
6380 obj->datum.boolean ? "true" : "false");
6382 case CSI_OBJECT_TYPE_INTEGER:
6383 fprintf (stderr, "integer: %ld\n", obj->datum.integer);
6385 case CSI_OBJECT_TYPE_MARK:
6386 fprintf (stderr, "mark\n");
6388 case CSI_OBJECT_TYPE_NAME:
6389 fprintf (stderr, "name: %s\n", (char *) obj->datum.name);
6391 case CSI_OBJECT_TYPE_OPERATOR:
6392 fprintf (stderr, "operator: %p\n", obj->datum.ptr);
6394 case CSI_OBJECT_TYPE_REAL:
6395 fprintf (stderr, "real: %g\n", obj->datum.real);
6399 case CSI_OBJECT_TYPE_ARRAY:
6400 fprintf (stderr, "array\n");
6402 case CSI_OBJECT_TYPE_DICTIONARY:
6403 fprintf (stderr, "dictionary\n");
6405 case CSI_OBJECT_TYPE_FILE:
6406 fprintf (stderr, "file\n");
6408 case CSI_OBJECT_TYPE_MATRIX:
6409 fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n",
6410 obj->datum.matrix->matrix.xx,
6411 obj->datum.matrix->matrix.yx,
6412 obj->datum.matrix->matrix.xy,
6413 obj->datum.matrix->matrix.yy,
6414 obj->datum.matrix->matrix.x0,
6415 obj->datum.matrix->matrix.y0);
6417 case CSI_OBJECT_TYPE_STRING:
6418 fprintf (stderr, "string: %s\n", obj->datum.string->string);
6422 case CSI_OBJECT_TYPE_CONTEXT:
6423 fprintf (stderr, "context\n");
6425 case CSI_OBJECT_TYPE_FONT:
6426 fprintf (stderr, "font\n");
6428 case CSI_OBJECT_TYPE_PATTERN:
6429 fprintf (stderr, "pattern\n");
6431 case CSI_OBJECT_TYPE_SCALED_FONT:
6432 fprintf (stderr, "scaled-font\n");
6434 case CSI_OBJECT_TYPE_SURFACE:
6435 fprintf (stderr, "surface\n");
6439 return CSI_STATUS_SUCCESS;
6442 static const csi_operator_def_t
6445 { ">>", end_dict_construction },
6447 { "]", end_array_construction },
6451 { "add-color-stop", _add_color_stop },
6454 { "arc-negative", _arc_negative },
6455 { "arc-", _arc_negative },
6457 { "array", _array },
6461 { "bitshift", _bitshift },
6463 { "C", _rel_curve_to },
6464 { "ceiling", NULL },
6466 { "clear-to-mark", NULL },
6468 { "clip-extents", NULL },
6469 { "clip-preserve", _clip_preserve },
6470 { "clip+", _clip_preserve },
6471 { "close-path", _close_path },
6472 { "context", _context },
6474 { "copy-page", _copy_page },
6477 { "count-to-mark", NULL },
6478 { "curve-to", _curve_to },
6482 { "device-to-user", NULL },
6483 { "device-to-user-distance", NULL },
6486 { "dup", _duplicate },
6491 { "false", _false },
6493 { "fill-extents", NULL },
6494 { "fill-preserve", _fill_preserve },
6495 { "fill+", _fill_preserve },
6496 { "filter", _filter },
6504 { "glyph-path", _glyph_path },
6506 { "h", _close_path },
6507 { "identity", _identity },
6509 { "ifelse", _ifelse },
6510 { "image", _image },
6511 { "index", _index },
6512 { "integer", _integer },
6513 { "invert", _invert },
6514 { "in-stroke", NULL },
6515 { "in-fill", NULL },
6518 { "L", _rel_line_to },
6519 { "languagelevel", NULL },
6522 { "linear", _linear },
6523 { "line-to", _line_to },
6530 { "M", _rel_move_to },
6531 { "map-to-image", _map_to_image },
6534 { "matrix", _matrix },
6537 { "begin-patch", _mesh_begin_patch },
6538 { "end-patch", _mesh_end_patch },
6539 { "set-control-point", _mesh_set_control_point },
6540 { "set-corner-color", _mesh_set_corner_color },
6543 { "move-to", _move_to },
6545 { "multiply", NULL },
6547 { "N", _new_sub_path },
6550 { "new-path", _new_path },
6551 { "new-sub-path", _new_sub_path },
6555 { "paint", _paint },
6556 { "paint-with-alpha", _paint_with_alpha },
6557 { "pattern", _pattern },
6559 { "pop-group", _pop_group },
6560 { "push-group", _push_group },
6561 { "radial", _radial },
6563 { "record", _record },
6564 { "rectangle", _rectangle },
6565 { "repeat", _repeat },
6566 { "restore", _restore },
6567 { "rel-curve-to", _rel_curve_to },
6568 { "rel-line-to", _rel_line_to },
6569 { "rel-move-to", _rel_move_to },
6570 { "reset-clip", _reset_clip },
6574 { "rotate", _rotate },
6578 { "scale", _scale },
6579 { "scaled-font", _scaled_font },
6580 { "select-font-face", _select_font_face },
6582 { "set-antialias", _set_antialias },
6583 { "set-dash", _set_dash },
6584 { "set-device-offset", _set_device_offset },
6585 { "set-extend", _set_extend },
6586 { "set-fallback-resolution", _set_fallback_resolution },
6587 { "set-fill-rule", _set_fill_rule },
6588 { "set-filter", _set_filter },
6589 { "set-font-face", _set_font_face },
6590 { "set-font-options", _set_font_options },
6591 { "set-font-matrix", _set_font_matrix },
6592 { "set-font-size", _set_font_size },
6593 { "set-line-cap", _set_line_cap },
6594 { "set-line-join", _set_line_join },
6595 { "set-line-width", _set_line_width },
6596 { "set-matrix", _set_matrix },
6597 { "set-miter-limit", _set_miter_limit },
6598 { "set-mime-data", _set_mime_data },
6599 { "set-operator", _set_operator },
6600 { "set-scaled-font", _set_scaled_font },
6601 { "set-source", _set_source },
6602 { "set-source-image", _set_source_image },
6603 { "set-source-rgb", _set_source_rgb },
6604 { "set-source-rgba", _set_source_rgba },
6605 { "set-tolerance", _set_tolerance },
6606 { "show-glyphs", _show_glyphs },
6607 { "show-text", _show_text },
6608 { "show-text-glyphs", _show_text_glyphs },
6609 { "show-page", _show_page },
6610 { "similar", _similar },
6611 { "similar-image", _similar_image },
6615 { "subsurface", _subsurface },
6616 { "surface", _surface },
6618 { "stroke", _stroke },
6619 { "stroke-extents", NULL },
6620 { "stroke-preserve", _stroke_preserve },
6621 { "stroke+", _stroke_preserve },
6622 { "text-path", _text_path },
6623 { "transform", _transform },
6624 { "transform-distance", NULL },
6625 { "transform-point", NULL },
6626 { "translate", _translate },
6629 { "undef", _undef },
6630 { "unmap-image", _unmap_image },
6631 { "unset", _unset },
6632 { "user-to-device", NULL },
6633 { "user-to-device-distance", NULL },
6635 { "write-to-png", _write_to_png },
6636 { "write-to-script", _write_to_script },
6639 { "=", _debug_print },
6644 const csi_operator_def_t *
6645 _csi_operators (void)
6650 static const csi_integer_constant_def_t
6651 _integer_constants[] = {
6652 { "CLEAR", CAIRO_OPERATOR_CLEAR },
6653 { "SOURCE", CAIRO_OPERATOR_SOURCE },
6654 { "OVER", CAIRO_OPERATOR_OVER },
6655 { "IN", CAIRO_OPERATOR_IN },
6656 { "OUT", CAIRO_OPERATOR_OUT },
6657 { "ATOP", CAIRO_OPERATOR_ATOP },
6658 { "DEST", CAIRO_OPERATOR_DEST },
6659 { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER },
6660 { "DEST_IN", CAIRO_OPERATOR_DEST_IN },
6661 { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT },
6662 { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP },
6663 { "XOR", CAIRO_OPERATOR_XOR },
6664 { "ADD", CAIRO_OPERATOR_ADD },
6665 { "SATURATE", CAIRO_OPERATOR_SATURATE },
6666 { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY },
6667 { "SCREEN", CAIRO_OPERATOR_SCREEN },
6668 { "OVERLAY", CAIRO_OPERATOR_OVERLAY },
6669 { "DARKEN", CAIRO_OPERATOR_DARKEN },
6670 { "LIGHTEN", CAIRO_OPERATOR_LIGHTEN },
6671 { "DODGE", CAIRO_OPERATOR_COLOR_DODGE },
6672 { "BURN", CAIRO_OPERATOR_COLOR_BURN },
6673 { "HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT },
6674 { "SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT },
6675 { "DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE },
6676 { "EXCLUSION", CAIRO_OPERATOR_EXCLUSION },
6677 { "HSL_HUE", CAIRO_OPERATOR_HSL_HUE },
6678 { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION },
6679 { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR },
6680 { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY },
6682 { "WINDING", CAIRO_FILL_RULE_WINDING },
6683 { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD },
6685 { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT },
6686 { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE },
6687 { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY },
6688 { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL },
6689 { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST },
6690 { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD },
6691 { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST },
6693 { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT },
6694 { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND },
6695 { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE },
6697 { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER },
6698 { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND },
6699 { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL },
6701 { "EXTEND_NONE", CAIRO_EXTEND_NONE },
6702 { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT },
6703 { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT },
6704 { "EXTEND_PAD", CAIRO_EXTEND_PAD },
6706 { "FILTER_FAST", CAIRO_FILTER_FAST },
6707 { "FILTER_GOOD", CAIRO_FILTER_GOOD },
6708 { "FILTER_BEST", CAIRO_FILTER_BEST },
6709 { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR },
6710 { "FILTER_NEAREST", CAIRO_FILTER_NEAREST },
6711 { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN },
6713 { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL },
6714 { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC },
6715 { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE },
6717 { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL },
6718 { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD },
6720 { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT },
6721 { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB },
6722 { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR },
6723 { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB },
6724 { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR },
6726 { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT },
6727 { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE },
6728 { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT },
6729 { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM },
6730 { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL },
6732 { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT },
6733 { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF },
6734 { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON },
6739 { "COLOR", CAIRO_CONTENT_COLOR },
6740 { "ALPHA", CAIRO_CONTENT_ALPHA },
6741 { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA },
6743 { "A1", CAIRO_FORMAT_A1 },
6744 { "A8", CAIRO_FORMAT_A8 },
6745 { "RGB16_565", CAIRO_FORMAT_RGB16_565 },
6746 { "RGB24", CAIRO_FORMAT_RGB24 },
6747 { "ARGB32", CAIRO_FORMAT_ARGB32 },
6748 { "INVALID", CAIRO_FORMAT_INVALID },
6754 const csi_integer_constant_def_t *
6755 _csi_integer_constants (void)
6757 return _integer_constants;
6760 static const csi_real_constant_def_t
6761 _real_constants[] = {
6762 { "math.pi", M_PI },
6763 { "math.2pi", 2 * M_PI },
6764 { "math.sqrt2", M_SQRT2 },
6765 { "math.ln2", M_LN2 },
6770 const csi_real_constant_def_t *
6771 _csi_real_constants (void)
6773 return _real_constants;