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 */
59 # include <sys/mman.h>
66 typedef struct _csi_proxy {
69 csi_dictionary_t *dictionary;
70 csi_destroy_func_t destroy_func;
74 typedef struct _csi_blob {
81 static const cairo_user_data_key_t _csi_proxy_key;
82 static const cairo_user_data_key_t _csi_blob_key;
89 #define check(CNT) do {\
90 if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \
91 return _csi_error (CSI_STATUS_INVALID_SCRIPT); \
93 #define pop(CNT) _csi_pop_ostack (ctx, (CNT))
94 #define push(OBJ) _csi_push_ostack (ctx, (OBJ))
97 _csi_proxy_create (csi_t *ctx,
99 csi_dictionary_t *dictionary,
100 csi_destroy_func_t destroy_func,
105 proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t));
109 proxy->ctx = cairo_script_interpreter_reference (ctx);
111 proxy->destroy_func = destroy_func;
112 proxy->destroy_data = destroy_data;
113 proxy->dictionary = dictionary;
114 if (dictionary != NULL)
115 dictionary->base.ref++;
121 _csi_proxy_destroy (void *closure)
123 csi_proxy_t *proxy = closure;
124 csi_t *ctx = proxy->ctx;
126 /* XXX this doesn't work because user_data_destroy is called too late.
127 * Considering another hook into the (cairo internal) object system.
129 if (proxy->destroy_func != NULL)
130 proxy->destroy_func (proxy->destroy_data, proxy->ptr);
132 if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0)
133 csi_dictionary_free (ctx, proxy->dictionary);
135 _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t));
136 cairo_script_interpreter_destroy (ctx);
140 _csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len)
142 unsigned long hash = blob->hash;
145 unsigned long c = *data++;
153 _csi_blob_equal (const csi_list_t *link, void *data)
157 A = csi_container_of (link, csi_blob_t, list);
160 if (A->len != B->len)
163 if (A->hash != B->hash)
166 return memcmp (A->bytes, B->bytes, A->len) == 0;
170 _csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len)
178 _csi_list_unlink (csi_list_t *head, csi_list_t *link)
180 if (link->next != NULL)
181 link->next->prev = link->prev;
182 if (link->prev != NULL)
183 link->prev->next = link->next;
190 _csi_list_prepend (csi_list_t *head, csi_list_t *link)
200 _csi_list_find (csi_list_t *head,
201 csi_boolean_t (*predicate) (const csi_list_t *link, void *data),
204 while (head != NULL) {
205 if (predicate (head, data))
214 _csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out)
219 obj = _csi_peek_ostack (ctx, i);
220 type = csi_object_get_type (obj);
222 case CSI_OBJECT_TYPE_BOOLEAN:
223 *out = obj->datum.boolean;
225 case CSI_OBJECT_TYPE_INTEGER:
226 *out = !! obj->datum.integer;
228 case CSI_OBJECT_TYPE_REAL:
229 *out = obj->datum.real != 0.;
232 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
234 return CSI_STATUS_SUCCESS;
238 _csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out)
243 obj = _csi_peek_ostack (ctx, i);
244 type = csi_object_get_type (obj);
246 case CSI_OBJECT_TYPE_BOOLEAN:
247 *out = obj->datum.boolean;
249 case CSI_OBJECT_TYPE_INTEGER:
250 *out = obj->datum.integer;
252 case CSI_OBJECT_TYPE_REAL:
253 *out = obj->datum.real;
256 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
258 return CSI_STATUS_SUCCESS;
262 _csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out)
267 obj = _csi_peek_ostack (ctx, i);
268 type = csi_object_get_type (obj);
270 case CSI_OBJECT_TYPE_BOOLEAN:
271 *out = obj->datum.boolean;
273 case CSI_OBJECT_TYPE_INTEGER:
274 *out = obj->datum.integer;
276 case CSI_OBJECT_TYPE_REAL:
277 *out = obj->datum.real;
280 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
282 return CSI_STATUS_SUCCESS;
286 _csi_object_as_real (csi_object_t *obj)
290 type = csi_object_get_type (obj);
292 case CSI_OBJECT_TYPE_BOOLEAN:
293 return obj->datum.boolean;
294 case CSI_OBJECT_TYPE_INTEGER:
295 return obj->datum.integer;
296 case CSI_OBJECT_TYPE_REAL:
297 return obj->datum.real;
304 _csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out)
308 obj = _csi_peek_ostack (ctx, i);
309 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME))
310 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
312 *out = obj->datum.name;
313 return CSI_STATUS_SUCCESS;
317 _csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out)
321 obj = _csi_peek_ostack (ctx, i);
322 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT))
323 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
325 *out = obj->datum.cr;
326 return CSI_STATUS_SUCCESS;
330 _csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out)
334 obj = _csi_peek_ostack (ctx, i);
335 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT))
336 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
338 *out = obj->datum.font_face;
339 return CSI_STATUS_SUCCESS;
343 _csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out)
347 obj = _csi_peek_ostack (ctx, i);
348 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN))
349 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
351 *out = obj->datum.pattern;
352 return CSI_STATUS_SUCCESS;
356 _csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i,
357 cairo_scaled_font_t **out)
361 obj = _csi_peek_ostack (ctx, i);
363 (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT))
365 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
368 *out = obj->datum.scaled_font;
369 return CSI_STATUS_SUCCESS;
373 _csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out)
378 obj = _csi_peek_ostack (ctx, i);
379 type = csi_object_get_type (obj);
381 case CSI_OBJECT_TYPE_CONTEXT:
382 *out = cairo_get_target (obj->datum.cr);
384 case CSI_OBJECT_TYPE_SURFACE:
385 *out = obj->datum.surface;
388 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
390 return CSI_STATUS_SUCCESS;
394 _csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out)
398 obj = _csi_peek_ostack (ctx, i);
399 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY))
400 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
402 *out = obj->datum.array;
403 return CSI_STATUS_SUCCESS;
407 _csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out)
411 obj = _csi_peek_ostack (ctx, i);
412 if (_csi_unlikely (! csi_object_is_procedure (obj)))
413 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
415 *out = obj->datum.array;
416 return CSI_STATUS_SUCCESS;
420 _csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out)
424 obj = _csi_peek_ostack (ctx, i);
426 (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY))
428 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
431 *out = obj->datum.dictionary;
432 return CSI_STATUS_SUCCESS;
436 _csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out)
441 obj = _csi_peek_ostack (ctx, i);
442 type = csi_object_get_type (obj);
444 case CSI_OBJECT_TYPE_MATRIX:
445 *out = obj->datum.matrix->matrix;
446 return CSI_STATUS_SUCCESS;
448 case CSI_OBJECT_TYPE_ARRAY:
449 if (obj->datum.array->stack.len == 6) {
450 cairo_matrix_init (out,
451 csi_number_get_value (&obj->datum.array->stack.objects[0]),
452 csi_number_get_value (&obj->datum.array->stack.objects[1]),
453 csi_number_get_value (&obj->datum.array->stack.objects[2]),
454 csi_number_get_value (&obj->datum.array->stack.objects[3]),
455 csi_number_get_value (&obj->datum.array->stack.objects[4]),
456 csi_number_get_value (&obj->datum.array->stack.objects[5]));
457 return CSI_STATUS_SUCCESS;
460 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
465 _csi_dictionary_get_integer (csi_t *ctx,
466 csi_dictionary_t *dict,
468 csi_boolean_t optional,
472 csi_object_t key, obj;
475 status = csi_name_new_static (ctx, &key, name);
476 if (_csi_unlikely (status))
479 if (optional && ! csi_dictionary_has (dict, key.datum.name))
480 return CSI_STATUS_SUCCESS;
482 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
483 if (_csi_unlikely (status))
486 type = csi_object_get_type (&obj);
488 case CSI_OBJECT_TYPE_BOOLEAN:
489 *value = obj.datum.boolean;
491 case CSI_OBJECT_TYPE_INTEGER:
492 *value = obj.datum.integer;
494 case CSI_OBJECT_TYPE_REAL:
495 *value = obj.datum.real;
498 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
500 return CSI_STATUS_SUCCESS;
504 _csi_dictionary_get_number (csi_t *ctx,
505 csi_dictionary_t *dict,
507 csi_boolean_t optional,
511 csi_object_t key, obj;
513 status = csi_name_new_static (ctx, &key, name);
514 if (_csi_unlikely (status))
517 if (optional && ! csi_dictionary_has (dict, key.datum.name))
518 return CSI_STATUS_SUCCESS;
520 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
521 if (_csi_unlikely (status))
524 *value = csi_number_get_value (&obj);
525 return CSI_STATUS_SUCCESS;
529 _csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out)
533 obj = _csi_peek_ostack (ctx, i);
534 if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING))
535 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
537 *out = obj->datum.string;
538 return CSI_STATUS_SUCCESS;
542 _csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out)
547 obj = _csi_peek_ostack (ctx, i);
548 type = csi_object_get_type (obj);
550 case CSI_OBJECT_TYPE_NAME:
551 *out = (const char *) obj->datum.name;
553 case CSI_OBJECT_TYPE_STRING:
554 *out = obj->datum.string->string;
557 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
559 return CSI_STATUS_SUCCESS;
563 _do_cairo_op (csi_t *ctx, void (*op) (cairo_t *))
570 status = _csi_ostack_get_context (ctx, 0, &cr);
571 if (_csi_unlikely (status))
575 return CSI_STATUS_SUCCESS;
579 end_dict_construction (csi_t *ctx)
582 csi_dictionary_t *dict;
585 status = csi_dictionary_new (ctx, &obj);
586 if (_csi_unlikely (status))
589 dict = obj.datum.dictionary;
591 csi_object_t *name, *value;
595 value = _csi_peek_ostack (ctx, 0);
596 if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) {
603 name = _csi_peek_ostack (ctx, 1);
605 (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME))
607 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
610 status = csi_dictionary_put (ctx, dict, name->datum.name, value);
611 if (_csi_unlikely (status))
621 end_array_construction (csi_t *ctx)
630 if (csi_object_get_type (_csi_peek_ostack (ctx, len)) ==
631 CSI_OBJECT_TYPE_MARK)
639 status = csi_array_new (ctx, len, &obj);
640 if (_csi_unlikely (status))
646 array = obj.datum.array;
647 memcpy (array->stack.objects,
648 _csi_peek_ostack (ctx, len - 1),
649 sizeof (csi_object_t) * len);
650 array->stack.len = len;
652 ctx->ostack.len -= len + 1;
666 status = _csi_ostack_get_number (ctx, 0, &a);
667 if (_csi_unlikely (status))
672 obj.type = CSI_OBJECT_TYPE_PATTERN;
673 obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a);
682 csi_object_type_t type_a, type_b;
686 B = _csi_peek_ostack (ctx, 0);
687 A = _csi_peek_ostack (ctx, 1);
689 type_a = csi_object_get_type (A);
690 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
691 type_a == CSI_OBJECT_TYPE_REAL)))
693 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
696 type_b = csi_object_get_type (B);
697 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
698 type_b == CSI_OBJECT_TYPE_REAL)))
700 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
705 if (type_a == CSI_OBJECT_TYPE_REAL &&
706 type_b == CSI_OBJECT_TYPE_REAL)
708 return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real);
711 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
712 type_b == CSI_OBJECT_TYPE_INTEGER)
714 return _csi_push_ostack_integer (ctx,
715 A->datum.integer + B->datum.integer);
721 if (type_a == CSI_OBJECT_TYPE_REAL)
724 v = A->datum.integer;
726 if (type_b == CSI_OBJECT_TYPE_REAL)
729 v += B->datum.integer;
731 return _csi_push_ostack_real (ctx, v);
736 _add_color_stop (csi_t *ctx)
739 double offset, r, g, b, a;
740 cairo_pattern_t *pattern = NULL; /* silence the compiler */
744 status = _csi_ostack_get_number (ctx, 0, &a);
745 if (_csi_unlikely (status))
747 status = _csi_ostack_get_number (ctx, 1, &b);
748 if (_csi_unlikely (status))
750 status = _csi_ostack_get_number (ctx, 2, &g);
751 if (_csi_unlikely (status))
753 status = _csi_ostack_get_number (ctx, 3, &r);
754 if (_csi_unlikely (status))
756 status = _csi_ostack_get_number (ctx, 4, &offset);
757 if (_csi_unlikely (status))
759 status = _csi_ostack_get_pattern (ctx, 5, &pattern);
760 if (_csi_unlikely (status))
763 cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a);
766 return CSI_STATUS_SUCCESS;
777 a = _csi_peek_ostack (ctx, 0);
778 b = _csi_peek_ostack (ctx, 1);
779 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
780 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
783 type = csi_object_get_type (a);
785 case CSI_OBJECT_TYPE_INTEGER:
786 return _csi_push_ostack_integer (ctx,
787 a->datum.integer & b->datum.integer);
788 case CSI_OBJECT_TYPE_BOOLEAN:
789 return _csi_push_ostack_boolean (ctx,
790 a->datum.boolean & b->datum.boolean);
792 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
801 double theta1, theta2;
806 status = _csi_ostack_get_number (ctx, 0, &theta2);
807 if (_csi_unlikely (status))
809 status = _csi_ostack_get_number (ctx, 1, &theta1);
810 if (_csi_unlikely (status))
812 status = _csi_ostack_get_number (ctx, 2, &r);
813 if (_csi_unlikely (status))
815 status = _csi_ostack_get_number (ctx, 3, &y);
816 if (_csi_unlikely (status))
818 status = _csi_ostack_get_number (ctx, 4, &x);
819 if (_csi_unlikely (status))
821 status = _csi_ostack_get_context (ctx, 5, &cr);
822 if (_csi_unlikely (status))
825 /* XXX handle path object */
827 cairo_arc (cr, x, y, r, theta1, theta2);
829 return CSI_STATUS_SUCCESS;
833 _arc_negative (csi_t *ctx)
837 double theta1, theta2;
842 status = _csi_ostack_get_number (ctx, 0, &theta2);
843 if (_csi_unlikely (status))
845 status = _csi_ostack_get_number (ctx, 1, &theta1);
846 if (_csi_unlikely (status))
848 status = _csi_ostack_get_number (ctx, 2, &r);
849 if (_csi_unlikely (status))
851 status = _csi_ostack_get_number (ctx, 3, &y);
852 if (_csi_unlikely (status))
854 status = _csi_ostack_get_number (ctx, 4, &x);
855 if (_csi_unlikely (status))
857 status = _csi_ostack_get_context (ctx, 5, &cr);
858 if (_csi_unlikely (status))
861 /* XXX handle path object */
863 cairo_arc_negative (cr, x, y, r, theta1, theta2);
865 return CSI_STATUS_SUCCESS;
874 status = csi_array_new (ctx, 0, &obj);
875 if (_csi_unlikely (status))
882 _bind_substitute (csi_t *ctx, csi_array_t *array)
886 csi_dictionary_t *dict;
888 /* perform operator substitution on the executable array (procedure) */
889 dict = ctx->dstack.objects[0].datum.dictionary;
890 n = array->stack.len;
891 for (i = 0; i < n; i++) {
892 csi_object_t *obj = &array->stack.objects[i];
894 if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) {
895 csi_dictionary_entry_t *entry;
897 entry = _csi_hash_table_lookup (&dict->hash_table,
902 } else if (csi_object_is_procedure (obj)) {
903 status = _bind_substitute (ctx, obj->datum.array);
904 if (_csi_unlikely (status))
909 return CSI_STATUS_SUCCESS;
913 _idiom_substitute (csi_t *ctx, csi_array_t *array)
919 /* XXX substring search, build array once then search for
920 * longest matching idiom, repeat. */
922 /* scan the top-most array for sequences we can pre-compile */
924 /* now recurse for subroutines */
925 j = array->stack.len;
926 for (i = 0; i < j; i++) {
927 csi_object_t *obj = &array->stack.objects[i];
929 if (csi_object_is_procedure (obj)) {
930 status = _idiom_substitute (ctx, obj->datum.array);
931 if (_csi_unlikely (_cairo_is_error (status))
937 return CSI_STATUS_SUCCESS;
948 status = _csi_ostack_get_procedure (ctx, 0, &array);
949 if (_csi_unlikely (status))
952 status = _bind_substitute (ctx, array);
953 if (_csi_unlikely (status))
956 status = _idiom_substitute (ctx, array);
957 if (_csi_unlikely (status))
960 return CSI_STATUS_SUCCESS;
964 _bitshift (csi_t *ctx)
971 status = _csi_ostack_get_integer (ctx, 0, &shift);
972 if (_csi_unlikely (status))
974 status = _csi_ostack_get_integer (ctx, 1, &v);
975 if (_csi_unlikely (status))
985 _csi_peek_ostack (ctx, 0)->datum.integer = v;
987 return CSI_STATUS_SUCCESS;
993 return _do_cairo_op (ctx, cairo_clip);
997 _clip_preserve (csi_t *ctx)
999 return _do_cairo_op (ctx, cairo_clip_preserve);
1003 _close_path (csi_t *ctx)
1005 return _do_cairo_op (ctx, cairo_close_path);
1009 _context (csi_t *ctx)
1012 csi_status_t status;
1013 cairo_surface_t *surface;
1015 csi_context_create_func_t hook;
1020 status = _csi_ostack_get_surface (ctx, 0, &surface);
1021 if (_csi_unlikely (status))
1024 hook = ctx->hooks.context_create;
1026 cr = hook (ctx->hooks.closure, surface);
1028 cr = cairo_create (surface);
1030 proxy = _csi_proxy_create (ctx, cr, NULL,
1031 ctx->hooks.context_destroy,
1032 ctx->hooks.closure);
1033 if (_csi_unlikely (proxy == NULL)) {
1035 return _csi_error (CSI_STATUS_NO_MEMORY);
1038 status = cairo_set_user_data (cr, &_csi_proxy_key,
1039 proxy, _csi_proxy_destroy);
1040 if (_csi_unlikely (status)) {
1041 _csi_proxy_destroy (proxy);
1047 obj.type = CSI_OBJECT_TYPE_CONTEXT;
1060 obj = csi_object_reference (_csi_peek_ostack (ctx, 0));
1063 type = csi_object_get_type (obj);
1065 /*XXX array, string, dictionary, etc */
1066 case CSI_OBJECT_TYPE_INTEGER:
1070 n = obj->datum.integer;
1071 if (_csi_unlikely (n < 0))
1072 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1075 for (i = n; i--; ) {
1076 csi_status_t status;
1078 status = _csi_push_ostack_copy (ctx,
1079 _csi_peek_ostack (ctx, n-1));
1080 if (_csi_unlikely (status))
1086 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1089 return CSI_STATUS_SUCCESS;
1093 _copy_page (csi_t *ctx)
1100 obj = _csi_peek_ostack (ctx, 0);
1101 type = csi_object_get_type (obj);
1103 case CSI_OBJECT_TYPE_CONTEXT:
1104 cairo_copy_page (obj->datum.cr);
1105 if (ctx->hooks.copy_page != NULL)
1106 ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
1108 case CSI_OBJECT_TYPE_SURFACE:
1109 cairo_surface_copy_page (obj->datum.surface);
1113 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1116 return CSI_STATUS_SUCCESS;
1120 _curve_to (csi_t *ctx)
1122 csi_status_t status;
1131 status = _csi_ostack_get_number (ctx, 0, &y3);
1132 if (_csi_unlikely (status))
1134 status = _csi_ostack_get_number (ctx, 1, &x3);
1135 if (_csi_unlikely (status))
1137 status = _csi_ostack_get_number (ctx, 2, &y2);
1138 if (_csi_unlikely (status))
1140 status = _csi_ostack_get_number (ctx, 3, &x2);
1141 if (_csi_unlikely (status))
1143 status = _csi_ostack_get_number (ctx, 4, &y1);
1144 if (_csi_unlikely (status))
1146 status = _csi_ostack_get_number (ctx, 5, &x1);
1147 if (_csi_unlikely (status))
1150 obj = _csi_peek_ostack (ctx, 6);
1151 type = csi_object_get_type (obj);
1153 case CSI_OBJECT_TYPE_CONTEXT:
1154 cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3);
1156 case CSI_OBJECT_TYPE_PATTERN:
1157 cairo_mesh_pattern_curve_to (obj->datum.pattern,
1158 x1, y1, x2, y2, x3, y3);
1160 /* XXX handle path object */
1164 return CSI_STATUS_SUCCESS;
1170 csi_object_t *val, obj;
1175 val = _csi_peek_ostack (ctx, 0);
1176 type = csi_object_get_type (val);
1178 case CSI_OBJECT_TYPE_INTEGER:
1179 return CSI_STATUS_SUCCESS;
1181 case CSI_OBJECT_TYPE_REAL:
1183 return _csi_push_ostack_integer (ctx, val->datum.real);
1185 case CSI_OBJECT_TYPE_STRING:
1186 if (! _csi_parse_number (&obj,
1187 val->datum.string->string,
1188 val->datum.string->len))
1190 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1194 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_INTEGER)
1197 return _csi_push_ostack_integer (ctx, obj.datum.real);
1200 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1207 csi_object_t *val, obj;
1212 val = _csi_peek_ostack (ctx, 0);
1213 type = csi_object_get_type (val);
1215 case CSI_OBJECT_TYPE_REAL:
1216 return CSI_STATUS_SUCCESS;
1218 case CSI_OBJECT_TYPE_INTEGER:
1220 return _csi_push_ostack_real (ctx, val->datum.integer);
1222 case CSI_OBJECT_TYPE_STRING:
1223 if (! _csi_parse_number (&obj,
1224 val->datum.string->string,
1225 val->datum.string->len))
1227 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1231 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_REAL)
1234 return _csi_push_ostack_real (ctx, obj.datum.integer);
1237 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1244 csi_name_t name = 0; /* silence the compiler */
1245 csi_status_t status;
1249 status = _csi_ostack_get_name (ctx, 1, &name);
1250 if (_csi_unlikely (status))
1253 status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0));
1254 if (_csi_unlikely (status))
1258 return CSI_STATUS_SUCCESS;
1265 csi_status_t status;
1267 status = csi_dictionary_new (ctx, &obj);
1268 if (_csi_unlikely (status))
1279 csi_object_type_t type_a, type_b;
1283 B = _csi_peek_ostack (ctx, 0);
1284 A = _csi_peek_ostack (ctx, 1);
1286 type_a = csi_object_get_type (A);
1287 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
1288 type_a == CSI_OBJECT_TYPE_REAL)))
1290 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1293 type_b = csi_object_get_type (B);
1294 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
1295 type_b == CSI_OBJECT_TYPE_REAL)))
1297 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1302 if (type_a == CSI_OBJECT_TYPE_REAL &&
1303 type_b == CSI_OBJECT_TYPE_REAL)
1305 return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real);
1308 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
1309 type_b == CSI_OBJECT_TYPE_INTEGER)
1311 return _csi_push_ostack_integer (ctx,
1312 A->datum.integer / B->datum.integer);
1318 if (type_a == CSI_OBJECT_TYPE_REAL)
1321 v = A->datum.integer;
1323 if (type_b == CSI_OBJECT_TYPE_REAL)
1326 v /= B->datum.integer;
1328 return _csi_push_ostack_real (ctx, v);
1333 _duplicate (csi_t *ctx)
1337 return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0));
1343 csi_object_t *a, *b;
1348 b = _csi_peek_ostack (ctx, 0);
1349 a = _csi_peek_ostack (ctx, 1);
1351 v = csi_object_eq (a, b);
1354 return _csi_push_ostack_boolean (ctx, v);
1360 return _csi_stack_exch (&ctx->ostack);
1366 return _csi_push_ostack_boolean (ctx, FALSE);
1372 return _do_cairo_op (ctx, cairo_fill);
1376 _fill_preserve (csi_t *ctx)
1378 return _do_cairo_op (ctx, cairo_fill_preserve);
1382 _filter (csi_t *ctx)
1385 csi_dictionary_t *dict = NULL;
1386 csi_status_t status;
1387 const char *name = NULL; /* silence the compiler */
1388 const struct filters {
1390 csi_status_t (*constructor) (csi_t *t,
1395 { "ascii85", csi_file_new_ascii85_decode },
1397 { "deflate", csi_file_new_deflate_decode },
1400 { "lzw", csi_file_new_lzw_decode },
1408 status = _csi_ostack_get_string_constant (ctx, 0, &name);
1409 if (_csi_unlikely (status))
1412 src = _csi_peek_ostack (ctx, 1);
1414 if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) {
1415 dict = src->datum.dictionary;
1419 src = _csi_peek_ostack (ctx, 2);
1423 for (filter = filters; filter->name != NULL; filter++) {
1424 if (strcmp (name, filter->name) == 0) {
1427 status = filter->constructor (ctx, &file, dict, src);
1428 if (_csi_unlikely (status))
1432 return push (&file);
1436 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1439 static cairo_status_t
1440 _type3_init (cairo_scaled_font_t *scaled_font,
1442 cairo_font_extents_t *metrics)
1444 cairo_font_face_t *face;
1447 csi_dictionary_t *font;
1451 csi_status_t status;
1453 face = cairo_scaled_font_get_font_face (scaled_font);
1454 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1455 if (_csi_unlikely (proxy == NULL))
1456 return CAIRO_STATUS_NO_MEMORY;
1459 font = proxy->dictionary;
1461 status = csi_name_new_static (ctx, &key, "metrics");
1462 if (_csi_unlikely (status))
1463 return CAIRO_STATUS_NO_MEMORY;
1465 if (! csi_dictionary_has (font, key.datum.name))
1466 return CAIRO_STATUS_SUCCESS;
1468 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1469 if (_csi_unlikely (status))
1472 if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)
1473 return CAIRO_STATUS_USER_FONT_ERROR;
1475 array = obj.datum.array;
1476 if (array->stack.len != 5)
1477 return CAIRO_STATUS_USER_FONT_ERROR;
1479 metrics->ascent = csi_number_get_value (&array->stack.objects[0]);
1480 metrics->descent = csi_number_get_value (&array->stack.objects[1]);
1481 metrics->height = csi_number_get_value (&array->stack.objects[2]);
1482 metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]);
1483 metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]);
1485 return CAIRO_STATUS_SUCCESS;
1488 static cairo_status_t
1489 _type3_lookup (cairo_scaled_font_t *scaled_font,
1490 unsigned long unicode,
1491 unsigned long *glyph)
1493 cairo_font_face_t *face;
1496 csi_dictionary_t *font;
1497 csi_object_t obj, key;
1501 cairo_status_t status;
1503 face = cairo_scaled_font_get_font_face (scaled_font);
1504 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1505 if (_csi_unlikely (proxy == NULL))
1506 return CAIRO_STATUS_USER_FONT_ERROR;
1509 font = proxy->dictionary;
1511 status = csi_name_new_static (ctx, &key, "encoding");
1512 if (_csi_unlikely (status))
1513 return CAIRO_STATUS_USER_FONT_ERROR;
1515 if (! csi_dictionary_has (font, key.datum.name)) {
1517 return CAIRO_STATUS_SUCCESS;
1520 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1521 if (_csi_unlikely (status))
1522 return CAIRO_STATUS_USER_FONT_ERROR;
1524 if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
1525 return CAIRO_STATUS_USER_FONT_ERROR;
1527 snprintf (buf, sizeof (buf), "uni%04lu", unicode);
1528 array = obj.datum.array;
1529 for (i = 0; i < array->stack.len; i++) {
1532 name = &array->stack.objects[i];
1533 if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)
1536 if (strcmp ((char *) name->datum.name, buf) == 0) {
1538 return CAIRO_STATUS_SUCCESS;
1542 return CAIRO_STATUS_USER_FONT_ERROR;
1545 static cairo_status_t
1546 _type3_render (cairo_scaled_font_t *scaled_font,
1547 unsigned long glyph_index,
1549 cairo_text_extents_t *metrics)
1551 cairo_font_face_t *face;
1554 csi_dictionary_t *font;
1555 csi_array_t *glyphs;
1556 csi_object_t *glyph;
1559 csi_object_t render;
1560 csi_status_t status;
1562 face = cairo_scaled_font_get_font_face (scaled_font);
1563 proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
1564 if (_csi_unlikely (proxy == NULL))
1565 return CAIRO_STATUS_USER_FONT_ERROR;
1568 font = proxy->dictionary;
1570 status = csi_name_new_static (ctx, &key, "glyphs");
1571 if (_csi_unlikely (status))
1572 return CAIRO_STATUS_USER_FONT_ERROR;
1574 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1575 if (_csi_unlikely (status))
1576 return CAIRO_STATUS_USER_FONT_ERROR;
1578 if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
1579 return CAIRO_STATUS_USER_FONT_ERROR;
1581 glyphs = obj.datum.array;
1582 glyph = &glyphs->stack.objects[glyph_index];
1583 if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL)
1584 return CAIRO_STATUS_SUCCESS; /* .notdef */
1586 if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY))
1587 return CAIRO_STATUS_USER_FONT_ERROR;
1589 status = csi_name_new_static (ctx, &key, "metrics");
1590 if (_csi_unlikely (status))
1591 return CAIRO_STATUS_USER_FONT_ERROR;
1593 font = glyph->datum.dictionary;
1594 if (csi_dictionary_has (font, key.datum.name)) {
1597 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
1598 if (_csi_unlikely (status))
1599 return CAIRO_STATUS_USER_FONT_ERROR;
1601 if (_csi_unlikely (csi_object_get_type (&obj) !=
1602 CSI_OBJECT_TYPE_ARRAY))
1603 return CAIRO_STATUS_USER_FONT_ERROR;
1605 array = obj.datum.array;
1606 if (_csi_unlikely (array->stack.len != 6))
1607 return CAIRO_STATUS_USER_FONT_ERROR;
1609 metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]);
1610 metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]);
1611 metrics->width = csi_number_get_value (&array->stack.objects[2]);
1612 metrics->height = csi_number_get_value (&array->stack.objects[3]);
1613 metrics->x_advance = csi_number_get_value (&array->stack.objects[4]);
1614 metrics->y_advance = csi_number_get_value (&array->stack.objects[5]);
1617 status = csi_name_new_static (ctx, &key, "render");
1618 if (_csi_unlikely (status))
1619 return CAIRO_STATUS_USER_FONT_ERROR;
1621 status = csi_dictionary_get (ctx, font, key.datum.name, &render);
1622 if (_csi_unlikely (status))
1623 return CAIRO_STATUS_USER_FONT_ERROR;
1625 if (_csi_unlikely (! csi_object_is_procedure (&render)))
1626 return CAIRO_STATUS_USER_FONT_ERROR;
1628 obj.type = CSI_OBJECT_TYPE_CONTEXT;
1629 obj.datum.cr = cairo_reference (cr);
1630 status = push (&obj);
1631 if (_csi_unlikely (status)) {
1633 return CAIRO_STATUS_USER_FONT_ERROR;
1636 status = csi_object_execute (ctx, &render);
1638 return status ? CAIRO_STATUS_USER_FONT_ERROR : CAIRO_STATUS_SUCCESS;
1642 _font_type3 (csi_t *ctx,
1643 csi_dictionary_t *font,
1644 cairo_font_face_t **font_face_out)
1646 cairo_font_face_t *font_face;
1648 font_face = cairo_user_font_face_create ();
1649 cairo_user_font_face_set_init_func (font_face, _type3_init);
1650 cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup);
1651 cairo_user_font_face_set_render_glyph_func (font_face, _type3_render);
1653 *font_face_out = font_face;
1654 return CSI_STATUS_SUCCESS;
1657 #if CAIRO_HAS_FT_FONT
1658 #include <cairo-ft.h>
1659 #include <ft2build.h>
1660 #include FT_FREETYPE_H
1662 static FT_Library _ft_lib;
1664 struct _ft_face_data {
1668 csi_string_t *source;
1670 cairo_font_face_t *font_face;
1674 _ft_done_face (void *closure)
1676 struct _ft_face_data *data = closure;
1681 if (data->face != NULL)
1682 FT_Done_Face (data->face);
1684 ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list);
1686 if (data->source != NULL) {
1687 if (--data->source->base.ref == 0)
1688 csi_string_free (ctx, data->source);
1691 munmap (data->blob.bytes, data->blob.len);
1695 if (data->bytes != NULL)
1696 _csi_free (ctx, data->bytes);
1698 _csi_slab_free (ctx, data, sizeof (*data));
1700 cairo_script_interpreter_destroy (ctx);
1704 const uint8_t *bytes;
1709 /* manual form of swapping for swapless systems like tiny */
1711 _mmap_bytes (const struct mmap_vec *vec, int count)
1713 char template[] = "/tmp/csi-font.XXXXXX";
1718 fd = mkstemp (template);
1725 const uint8_t *bytes = vec->bytes;
1726 size_t len = vec->num_bytes;
1728 int ret = write (fd, bytes, len);
1737 num_bytes += vec->num_bytes;
1741 ptr = mmap (NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0);
1749 inflate_string (csi_t *ctx, csi_string_t *src)
1755 bytes = _csi_alloc (ctx, len + 1);
1759 if (uncompress ((Bytef *) bytes, &len,
1760 (Bytef *) src->string, src->len) != Z_OK)
1762 _csi_free (ctx, bytes);
1774 _ft_create_for_source (csi_t *ctx,
1775 csi_string_t *source,
1776 int index, int load_flags,
1777 cairo_font_face_t **font_face_out)
1780 struct _ft_face_data *data;
1783 cairo_font_face_t *font_face;
1784 csi_status_t status;
1785 struct mmap_vec vec[2];
1790 /* check for an existing FT_Face (kept alive by the font cache) */
1791 /* XXX index/flags */
1792 _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len);
1793 _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t));
1794 link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
1796 if (--source->base.ref == 0)
1797 csi_string_free (ctx, source);
1798 data = csi_container_of (link, struct _ft_face_data, blob.list);
1799 *font_face_out = cairo_font_face_reference (data->font_face);
1800 return CSI_STATUS_SUCCESS;
1803 /* no existing font_face, create new FT_Face */
1804 if (_ft_lib == NULL) {
1805 err = FT_Init_FreeType (&_ft_lib);
1806 if (_csi_unlikely (err != FT_Err_Ok))
1807 return _csi_error (CSI_STATUS_NO_MEMORY);
1810 data = _csi_slab_alloc (ctx, sizeof (*data));
1812 data->source = source;
1814 vec[0].bytes = tmpl.bytes;
1815 vec[0].num_bytes = tmpl.len;
1817 if (source->deflate) {
1818 len = source->deflate;
1819 bytes = inflate_string (ctx, source);
1820 if (_csi_unlikely (bytes == NULL))
1821 return _csi_error (CSI_STATUS_NO_MEMORY);
1823 vec[1].bytes = bytes;
1824 vec[1].num_bytes = len;
1825 data->bytes = bytes;
1834 ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
1835 data->ctx = cairo_script_interpreter_reference (ctx);
1836 data->blob.hash = tmpl.hash;
1837 data->blob.len = tmpl.len;
1839 data->blob.bytes = _mmap_bytes (vec, vec_count);
1840 if (data->blob.bytes != MAP_FAILED) {
1841 if (--source->base.ref == 0)
1842 csi_string_free (ctx, source);
1844 if (source->deflate) {
1845 _csi_free (ctx, bytes);
1846 bytes = data->blob.bytes + vec[0].num_bytes;
1848 bytes = data->blob.bytes;
1850 data->source = NULL;
1853 data->blob.bytes = tmpl.bytes;
1856 data->blob.bytes = tmpl.bytes;
1859 err = FT_New_Memory_Face (_ft_lib,
1863 if (_csi_unlikely (err != FT_Err_Ok)) {
1864 _ft_done_face (data);
1866 if (err == FT_Err_Out_Of_Memory)
1867 return _csi_error (CSI_STATUS_NO_MEMORY);
1869 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1872 font_face = cairo_ft_font_face_create_for_ft_face (data->face, load_flags);
1873 status = cairo_font_face_set_user_data (font_face,
1875 data, _ft_done_face);
1876 if (_csi_unlikely (status)) {
1877 _ft_done_face (data);
1878 cairo_font_face_destroy (font_face);
1882 data->font_face = font_face;
1883 *font_face_out = font_face;
1884 return CSI_STATUS_SUCCESS;
1888 _ft_create_for_pattern (csi_t *ctx,
1889 csi_string_t *string,
1890 cairo_font_face_t **font_face_out)
1892 #if CAIRO_HAS_FC_FONT
1894 struct _ft_face_data *data;
1896 cairo_font_face_t *font_face;
1897 FcPattern *pattern, *resolved;
1898 csi_status_t status;
1899 struct mmap_vec vec;
1902 _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len);
1903 _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t));
1904 link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
1906 if (--string->base.ref == 0)
1907 csi_string_free (ctx, string);
1908 data = csi_container_of (link, struct _ft_face_data, blob.list);
1909 *font_face_out = cairo_font_face_reference (data->font_face);
1910 return CSI_STATUS_SUCCESS;
1913 if (string->deflate) {
1914 bytes = inflate_string (ctx, string);
1915 if (_csi_unlikely (bytes == NULL))
1916 return _csi_error (CSI_STATUS_NO_MEMORY);
1921 pattern = FcNameParse (bytes);
1922 if (bytes != tmpl.bytes)
1923 _csi_free (ctx, bytes);
1927 if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) {
1928 /* prior to 1.9, you needed to pass a resolved pattern */
1929 resolved = FcFontMatch (NULL, pattern, NULL);
1930 if (_csi_unlikely (resolved == NULL)) {
1931 FcPatternDestroy (pattern);
1932 return _csi_error (CSI_STATUS_NO_MEMORY);
1936 font_face = cairo_ft_font_face_create_for_pattern (resolved);
1937 if (resolved != pattern)
1938 FcPatternDestroy (resolved);
1940 if (cairo_font_face_status (font_face)) {
1941 char *filename = NULL;
1943 /* Try a manual fallback process by eliminating specific requests */
1945 if (FcPatternGetString (pattern,
1947 (FcChar8 **) &filename) == FcResultMatch) {
1948 FcPatternDel (pattern, FC_FILE);
1953 FcPatternDestroy (pattern);
1955 data = _csi_slab_alloc (ctx, sizeof (*data));
1956 ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
1957 data->ctx = cairo_script_interpreter_reference (ctx);
1958 data->blob.hash = tmpl.hash;
1959 data->blob.len = tmpl.len;
1963 vec.bytes = tmpl.bytes;
1964 vec.num_bytes = tmpl.len;
1965 data->blob.bytes = _mmap_bytes (&vec, 1);
1966 if (data->blob.bytes != MAP_FAILED) {
1967 data->source = NULL;
1968 if (--string->base.ref == 0)
1969 csi_string_free (ctx, string);
1971 data->blob.bytes = tmpl.bytes;
1972 data->source = string;
1975 data->blob.bytes = tmpl.bytes;
1976 data->source = string;
1979 status = cairo_font_face_set_user_data (font_face,
1981 data, _ft_done_face);
1982 if (_csi_unlikely (status)) {
1983 _ft_done_face (data);
1984 cairo_font_face_destroy (font_face);
1988 data->font_face = font_face;
1989 *font_face_out = font_face;
1990 return CSI_STATUS_SUCCESS;
1992 if (--string->base.ref == 0)
1993 csi_string_free (ctx, string);
1994 return CSI_INT_STATUS_UNSUPPORTED;
1999 _ft_type42_create (csi_t *ctx,
2000 csi_dictionary_t *font,
2001 cairo_font_face_t **font_face_out)
2004 csi_status_t status;
2006 /* two basic sub-types, either an FcPattern or embedded font */
2007 status = csi_name_new_static (ctx, &key, "pattern");
2008 if (_csi_unlikely (status))
2011 if (csi_dictionary_has (font, key.datum.name)) {
2015 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2016 if (_csi_unlikely (status))
2019 type = csi_object_get_type (&obj);
2021 case CSI_OBJECT_TYPE_FILE:
2022 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2023 if (_csi_unlikely (status))
2026 case CSI_OBJECT_TYPE_STRING:
2027 obj.datum.object->ref++;
2030 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2033 return _ft_create_for_pattern (ctx,
2038 status = csi_name_new_static (ctx, &key, "source");
2039 if (_csi_unlikely (status))
2042 if (csi_dictionary_has (font, key.datum.name)) {
2048 status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index);
2049 if (_csi_unlikely (status))
2053 status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags);
2054 if (_csi_unlikely (status))
2057 status = csi_name_new_static (ctx, &key, "source");
2058 if (_csi_unlikely (status))
2060 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2061 if (_csi_unlikely (status))
2063 type = csi_object_get_type (&obj);
2065 case CSI_OBJECT_TYPE_FILE:
2066 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2067 if (_csi_unlikely (status))
2070 case CSI_OBJECT_TYPE_STRING:
2071 obj.datum.object->ref++;
2074 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2077 return _ft_create_for_source (ctx, obj.datum.string,
2082 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2085 #define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED
2089 _fc_strcpy (csi_t *ctx, const char *str)
2094 ret = strchr (str, ':');
2100 ret = _csi_alloc (ctx, len+1);
2101 if (_csi_unlikely (ret == NULL))
2104 memcpy (ret, str, len);
2110 static cairo_font_face_t *
2111 _select_font (const char *name)
2113 cairo_surface_t *surface;
2114 cairo_font_face_t *face;
2117 /* create a dummy context to choose a font */
2118 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
2119 cr = cairo_create (surface);
2120 cairo_surface_destroy (surface);
2122 cairo_select_font_face (cr, name,
2123 CAIRO_FONT_SLANT_NORMAL,
2124 CAIRO_FONT_WEIGHT_NORMAL);
2125 face = cairo_font_face_reference (cairo_get_font_face (cr));
2132 _ft_fallback_create_for_pattern (csi_t *ctx,
2133 csi_string_t *string,
2134 cairo_font_face_t **font_face_out)
2138 str = string->string;
2140 name = strstr (str, "fullname=");
2145 name = _fc_strcpy (ctx, str);
2146 if (_csi_unlikely (name == NULL))
2147 return _csi_error (CSI_STATUS_NO_MEMORY);
2149 *font_face_out = _select_font (name);
2150 _csi_free (ctx, name);
2152 return CSI_STATUS_SUCCESS;
2156 _ft_type42_fallback_create (csi_t *ctx,
2157 csi_dictionary_t *font,
2158 cairo_font_face_t **font_face_out)
2161 csi_status_t status;
2163 /* attempt to select a similar font */
2165 /* two basic sub-types, either an FcPattern or embedded font */
2166 status = csi_name_new_static (ctx, &key, "pattern");
2167 if (_csi_unlikely (status))
2170 if (csi_dictionary_has (font, key.datum.name)) {
2174 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2175 if (_csi_unlikely (status))
2178 type = csi_object_get_type (&obj);
2180 case CSI_OBJECT_TYPE_FILE:
2181 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2182 if (_csi_unlikely (status))
2185 case CSI_OBJECT_TYPE_STRING:
2186 obj.datum.object->ref++;
2189 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2192 return _ft_fallback_create_for_pattern (ctx,
2197 /* XXX: enable the trace to run */
2198 *font_face_out = _select_font ("Sans");
2199 return CSI_STATUS_SUCCESS;
2203 _font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face)
2205 csi_status_t status;
2207 status = _ft_type42_create (ctx, font, font_face);
2208 if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED))
2211 return _ft_type42_fallback_create (ctx, font, font_face);
2217 csi_dictionary_t *font;
2218 csi_status_t status;
2219 cairo_font_face_t *font_face = NULL; /* silence the compiler */
2226 status = _csi_ostack_get_dictionary (ctx, 0, &font);
2227 if (_csi_unlikely (status))
2230 status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type);
2231 if (_csi_unlikely (status))
2236 status = _font_type3 (ctx, font, &font_face);
2239 status = _font_type42 (ctx, font, &font_face);
2242 status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
2246 if (_csi_unlikely (status))
2249 /* transfer ownership of dictionary to cairo_font_face_t */
2250 proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL);
2251 if (_csi_unlikely (proxy == NULL)) {
2252 cairo_font_face_destroy (font_face);
2253 return _csi_error (CSI_STATUS_NO_MEMORY);
2256 status = cairo_font_face_set_user_data (font_face,
2258 proxy, _csi_proxy_destroy);
2259 if (_csi_unlikely (status)) {
2260 _csi_proxy_destroy (proxy);
2261 cairo_font_face_destroy (font_face);
2265 obj.type = CSI_OBJECT_TYPE_FONT;
2266 obj.datum.font_face = font_face;
2269 status = push (&obj);
2270 if (_csi_unlikely (status)) {
2271 cairo_font_face_destroy (font_face);
2275 return CSI_STATUS_SUCCESS;
2282 csi_status_t status;
2287 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2288 if (_csi_unlikely (status))
2290 status = _csi_ostack_get_integer (ctx, 1, &limit);
2291 if (_csi_unlikely (status))
2293 status = _csi_ostack_get_integer (ctx, 2, &inc);
2294 if (_csi_unlikely (status))
2296 status = _csi_ostack_get_integer (ctx, 3, &i);
2297 if (_csi_unlikely (status))
2303 for (; i <= limit; i += inc) {
2304 status = _csi_push_ostack_integer (ctx, i);
2305 if (_csi_unlikely (status))
2308 status = _csi_array_execute (ctx, proc);
2309 if (_csi_unlikely (status))
2313 if (--proc->base.ref == 0)
2314 csi_array_free (ctx, proc);
2321 csi_status_t status;
2322 csi_object_t *a, *b;
2327 b = _csi_peek_ostack (ctx, 0);
2328 a = _csi_peek_ostack (ctx, 1);
2330 status = csi_object_compare (a, b, &cmp);
2331 if (_csi_unlikely (status))
2335 return _csi_push_ostack_boolean (ctx, cmp >= 0);
2339 _proxy_get (csi_proxy_t *proxy,
2343 csi_status_t status;
2345 if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL))
2346 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2348 status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj);
2349 if (_csi_unlikely (status))
2352 return _csi_push_ostack_copy (proxy->ctx, &obj);
2356 _context_get (csi_t *ctx,
2360 csi_status_t status;
2363 if (strcmp ((char *) key, "current-point") == 0) {
2366 cairo_get_current_point (cr, &x, &y);
2368 status = _csi_push_ostack_real (ctx, x);
2369 if (_csi_unlikely (status))
2371 status = _csi_push_ostack_real (ctx, y);
2372 if (_csi_unlikely (status))
2375 return CSI_STATUS_SUCCESS;
2376 } else if (strcmp ((char *) key, "source") == 0) {
2377 obj.type = CSI_OBJECT_TYPE_PATTERN;
2378 obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr));
2379 } else if (strcmp ((char *) key, "target") == 0) {
2380 obj.type = CSI_OBJECT_TYPE_SURFACE;
2381 obj.datum.surface = cairo_surface_reference (cairo_get_target (cr));
2382 } else if (strcmp ((char *) key, "group-target") == 0) {
2383 obj.type = CSI_OBJECT_TYPE_SURFACE;
2384 obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr));
2385 } else if (strcmp ((char *) key, "scaled-font") == 0) {
2386 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
2387 obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr));
2388 } else if (strcmp ((char *) key, "font-face") == 0) {
2389 obj.type = CSI_OBJECT_TYPE_FONT;
2390 obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr));
2392 return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key);
2398 _font_get (csi_t *ctx,
2399 cairo_font_face_t *font_face,
2402 return _proxy_get (cairo_font_face_get_user_data (font_face,
2408 _pattern_get (csi_t *ctx,
2409 cairo_pattern_t *pattern,
2412 csi_status_t status;
2414 if (strcmp ((char *) key, "type") == 0)
2415 return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern));
2417 if (strcmp ((char *) key, "filter") == 0)
2418 return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern));
2420 if (strcmp ((char *) key, "extend") == 0)
2421 return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern));
2423 if (strcmp ((char *) key, "matrix") == 0) {
2427 cairo_pattern_get_matrix (pattern, &m);
2428 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
2429 if (_csi_unlikely (status))
2435 return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key),
2440 _scaled_font_get (csi_t *ctx,
2441 cairo_scaled_font_t *font,
2444 return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key),
2449 _surface_get (csi_t *ctx,
2450 cairo_surface_t *surface,
2453 if (strcmp ((char *) key, "type") == 0) {
2454 return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface));
2457 if (strcmp ((char *) key, "content") == 0) {
2458 return _csi_push_ostack_integer (ctx,
2459 cairo_surface_get_content (surface));
2462 return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key),
2469 csi_object_t *key, *src, obj;
2470 csi_status_t status;
2475 key = _csi_peek_ostack (ctx, 0);
2476 src = _csi_peek_ostack (ctx, 1);
2478 type = csi_object_get_type (src);
2480 case CSI_OBJECT_TYPE_DICTIONARY:
2481 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2482 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2484 status = csi_dictionary_get (ctx,
2485 src->datum.dictionary,
2489 case CSI_OBJECT_TYPE_ARRAY:
2490 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER))
2491 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2493 status = csi_array_get (ctx,
2499 case CSI_OBJECT_TYPE_STRING:
2500 status = csi_string_get (src, key, &obj);
2504 case CSI_OBJECT_TYPE_CONTEXT:
2505 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2506 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2507 return _context_get (ctx, src->datum.cr, key->datum.name);
2509 case CSI_OBJECT_TYPE_FONT:
2510 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2511 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2512 return _font_get (ctx, src->datum.font_face, key->datum.name);
2514 case CSI_OBJECT_TYPE_PATTERN:
2515 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2516 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2517 return _pattern_get (ctx, src->datum.pattern, key->datum.name);
2519 case CSI_OBJECT_TYPE_SCALED_FONT:
2520 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2521 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2522 return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name);
2524 case CSI_OBJECT_TYPE_SURFACE:
2525 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2526 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2527 return _surface_get (ctx, src->datum.surface, key->datum.name);
2530 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2533 if (_csi_unlikely (status))
2536 return _csi_push_ostack_copy (ctx, &obj);
2539 struct glyph_advance_cache {
2541 double glyph_advance[256][2];
2542 unsigned long have_glyph_advance[256];
2546 glyph_advance_cache_destroy (void *closure)
2548 struct glyph_advance_cache *cache = closure;
2549 _csi_free (cache->ctx, cache);
2553 _glyph_string (csi_t *ctx,
2555 cairo_scaled_font_t *scaled_font,
2556 cairo_glyph_t *glyphs)
2558 struct glyph_advance_cache uncached;
2559 struct glyph_advance_cache *cache;
2560 csi_integer_t nglyphs, i, j;
2562 cairo_status_t status;
2564 if (cairo_scaled_font_status (scaled_font))
2567 cache = cairo_scaled_font_get_user_data (scaled_font,
2568 (cairo_user_data_key_t *) ctx);
2569 if (cache == NULL) {
2570 cache = _csi_alloc (ctx, sizeof (*cache));
2571 if (_csi_likely (cache != NULL)) {
2573 memset (cache->have_glyph_advance, 0xff,
2574 sizeof (cache->have_glyph_advance));
2576 status = cairo_scaled_font_set_user_data (scaled_font,
2577 (cairo_user_data_key_t *) ctx,
2579 glyph_advance_cache_destroy);
2580 if (_csi_unlikely (status)) {
2581 _csi_free (ctx, cache);
2587 if (_csi_unlikely (cache == NULL)) {
2591 memset (cache->have_glyph_advance, 0xff,
2592 sizeof (cache->have_glyph_advance));
2597 for (i = 0; i < array->stack.len; i++) {
2598 const csi_object_t *obj = &array->stack.objects[i];
2599 int type = csi_object_get_type (obj);
2602 case CSI_OBJECT_TYPE_ARRAY: {
2603 const csi_array_t *glyph_array = obj->datum.array;
2604 for (j = 0; j < glyph_array->stack.len; j++) {
2608 obj = &glyph_array->stack.objects[j];
2609 if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
2611 g = obj->datum.integer;
2613 glyphs[nglyphs].index = g;
2614 glyphs[nglyphs].x = x;
2615 glyphs[nglyphs].y = y;
2617 gi = g % ARRAY_LENGTH (cache->have_glyph_advance);
2618 if (cache->have_glyph_advance[gi] != g) {
2619 cairo_text_extents_t extents;
2621 cairo_scaled_font_glyph_extents (scaled_font,
2622 &glyphs[nglyphs], 1,
2625 cache->glyph_advance[gi][0] = extents.x_advance;
2626 cache->glyph_advance[gi][1] = extents.y_advance;
2627 cache->have_glyph_advance[gi] = g;
2630 x += cache->glyph_advance[gi][0];
2631 y += cache->glyph_advance[gi][1];
2637 case CSI_OBJECT_TYPE_STRING: {
2638 const csi_string_t *glyph_string = obj->datum.string;
2639 for (j = 0; j < glyph_string->len; j++) {
2642 g = glyph_string->string[j];
2643 glyphs[nglyphs].index = g;
2644 glyphs[nglyphs].x = x;
2645 glyphs[nglyphs].y = y;
2647 if (cache->have_glyph_advance[g] != g) {
2648 cairo_text_extents_t extents;
2650 cairo_scaled_font_glyph_extents (scaled_font,
2651 &glyphs[nglyphs], 1,
2654 cache->glyph_advance[g][0] = extents.x_advance;
2655 cache->glyph_advance[g][1] = extents.y_advance;
2656 cache->have_glyph_advance[g] = g;
2659 x += cache->glyph_advance[g][0];
2660 y += cache->glyph_advance[g][1];
2666 case CSI_OBJECT_TYPE_INTEGER:
2667 case CSI_OBJECT_TYPE_REAL: /* dx or x*/
2668 dx = csi_number_get_value (obj);
2669 if (i+1 == array->stack.len)
2672 type = csi_object_get_type (&array->stack.objects[i+1]);
2674 case CSI_OBJECT_TYPE_INTEGER:
2675 case CSI_OBJECT_TYPE_REAL: /* y */
2676 y = csi_number_get_value (&array->stack.objects[i+1]);
2691 _glyph_path (csi_t *ctx)
2694 csi_status_t status;
2696 cairo_glyph_t stack_glyphs[256], *glyphs;
2697 csi_integer_t nglyphs, i;
2701 status = _csi_ostack_get_array (ctx, 0, &array);
2702 if (_csi_unlikely (status))
2704 status = _csi_ostack_get_context (ctx, 1, &cr);
2705 if (_csi_unlikely (status))
2710 for (i = 0; i < array->stack.len; i++) {
2711 csi_object_t *obj = &array->stack.objects[i];
2712 int type = csi_object_get_type (obj);
2714 case CSI_OBJECT_TYPE_ARRAY:
2715 nglyphs += obj->datum.array->stack.len;
2717 case CSI_OBJECT_TYPE_STRING:
2718 nglyphs += obj->datum.string->len;
2724 return CSI_STATUS_SUCCESS;
2727 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
2728 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
2729 return _csi_error (CSI_STATUS_NO_MEMORY);
2731 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
2732 if (_csi_unlikely (glyphs == NULL))
2733 return _csi_error (CSI_STATUS_NO_MEMORY);
2735 glyphs = stack_glyphs;
2737 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
2738 cairo_glyph_path (cr, glyphs, nglyphs);
2740 if (glyphs != stack_glyphs)
2741 _csi_free (ctx, glyphs);
2744 return CSI_STATUS_SUCCESS;
2751 csi_status_t status;
2756 status = _csi_ostack_get_number (ctx, 0, &g);
2757 if (_csi_unlikely (status))
2762 obj.type = CSI_OBJECT_TYPE_PATTERN;
2763 obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1);
2770 csi_status_t status;
2771 csi_object_t *a, *b;
2776 b = _csi_peek_ostack (ctx, 0);
2777 a = _csi_peek_ostack (ctx, 1);
2779 status = csi_object_compare (a, b, &cmp);
2780 if (_csi_unlikely (status))
2784 return _csi_push_ostack_boolean (ctx, cmp > 0);
2788 _identity (csi_t *ctx)
2791 csi_status_t status;
2793 status = csi_matrix_new (ctx, &obj);
2794 if (_csi_unlikely (status))
2804 csi_boolean_t predicate = FALSE; /* silence the compiler */
2805 csi_status_t status;
2809 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2810 if (_csi_unlikely (status))
2813 status = _csi_ostack_get_boolean (ctx, 1, &predicate);
2814 if (_csi_unlikely (status))
2821 status = _csi_array_execute (ctx, proc);
2823 if (--proc->base.ref == 0)
2824 csi_array_free (ctx, proc);
2830 _ifelse (csi_t *ctx)
2832 csi_array_t *true_proc, *false_proc;
2833 csi_boolean_t predicate = FALSE; /* silence the compiler */
2834 csi_status_t status;
2838 status = _csi_ostack_get_procedure (ctx, 0, &false_proc);
2839 if (_csi_unlikely (status))
2840 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2842 status = _csi_ostack_get_procedure (ctx, 1, &true_proc);
2843 if (_csi_unlikely (status))
2844 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2846 status = _csi_ostack_get_boolean (ctx, 2, &predicate);
2847 if (_csi_unlikely (status))
2850 true_proc->base.ref++;
2851 false_proc->base.ref++;
2855 status = _csi_array_execute (ctx, true_proc);
2857 status = _csi_array_execute (ctx, false_proc);
2859 if (--true_proc->base.ref == 0)
2860 csi_array_free (ctx, true_proc);
2861 if (--false_proc->base.ref == 0)
2862 csi_array_free (ctx, false_proc);
2868 _image_read_raw (csi_file_t *src,
2869 cairo_format_t format,
2870 int width, int height,
2871 cairo_surface_t **image_out)
2873 cairo_surface_t *image;
2875 int rem, len, ret, x, rowlen, instride, stride;
2876 cairo_status_t status;
2878 stride = cairo_format_stride_for_width (format, width);
2879 data = malloc (stride * height);
2881 return CAIRO_STATUS_NO_MEMORY;
2883 image = cairo_image_surface_create_for_data (data, format,
2884 width, height, stride);
2885 status = cairo_surface_set_user_data (image,
2886 (const cairo_user_data_key_t *) image,
2889 cairo_surface_destroy (image);
2895 case CAIRO_FORMAT_A1:
2896 instride = rowlen = (width+7)/8;
2898 case CAIRO_FORMAT_A8:
2899 instride = rowlen = width;
2901 case CAIRO_FORMAT_RGB16_565:
2902 instride = rowlen = 2 * width;
2904 case CAIRO_FORMAT_RGB24:
2906 instride = 4 *width;
2909 case CAIRO_FORMAT_RGB30:
2910 case CAIRO_FORMAT_INVALID:
2911 case CAIRO_FORMAT_ARGB32:
2912 instride = rowlen = 4 * width;
2915 len = rowlen * height;
2920 ret = csi_file_read (src, bp, rem);
2921 if (_csi_unlikely (ret == 0)) {
2922 cairo_surface_destroy (image);
2923 return _csi_error (CSI_STATUS_READ_ERROR);
2929 if (len != height * stride) {
2931 uint8_t *row = data + height * stride;
2933 /* XXX pixel conversion */
2935 case CAIRO_FORMAT_A1:
2936 for (x = rowlen; x--; ) {
2937 uint8_t byte = *--bp;
2938 row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2941 case CAIRO_FORMAT_A8:
2942 for (x = width; x--; )
2945 case CAIRO_FORMAT_RGB16_565:
2946 for (x = width; x--; ) {
2947 #ifdef WORDS_BIGENDIAN
2948 row[2*x + 1] = *--bp;
2949 row[2*x + 0] = *--bp;
2951 row[2*x + 0] = *--bp;
2952 row[2*x + 1] = *--bp;
2956 case CAIRO_FORMAT_RGB24:
2957 for (x = width; x--; ) {
2958 #ifdef WORDS_BIGENDIAN
2959 row[4*x + 3] = *--bp;
2960 row[4*x + 2] = *--bp;
2961 row[4*x + 1] = *--bp;
2962 row[4*x + 0] = 0xff;
2964 row[4*x + 0] = *--bp;
2965 row[4*x + 1] = *--bp;
2966 row[4*x + 2] = *--bp;
2967 row[4*x + 3] = 0xff;
2971 case CAIRO_FORMAT_RGB30:
2972 case CAIRO_FORMAT_INVALID:
2973 case CAIRO_FORMAT_ARGB32:
2974 /* stride == width */
2978 memset (row + instride, 0, stride - instride);
2981 /* need to treat last row carefully */
2983 case CAIRO_FORMAT_A1:
2984 for (x = rowlen; x--; ) {
2985 uint8_t byte = *--bp;
2986 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2989 case CAIRO_FORMAT_A8:
2990 for (x = width; x--; )
2993 case CAIRO_FORMAT_RGB16_565:
2994 for (x = width; x--; ) {
2995 #ifdef WORDS_BIGENDIAN
2996 data[2*x + 1] = *--bp;
2997 data[2*x + 0] = *--bp;
2999 data[2*x + 0] = *--bp;
3000 data[2*x + 1] = *--bp;
3004 case CAIRO_FORMAT_RGB24:
3005 for (x = width; --x>1; ) {
3006 #ifdef WORDS_BIGENDIAN
3007 data[4*x + 3] = *--bp;
3008 data[4*x + 2] = *--bp;
3009 data[4*x + 1] = *--bp;
3010 data[4*x + 0] = 0xff;
3012 data[4*x + 0] = *--bp;
3013 data[4*x + 1] = *--bp;
3014 data[4*x + 2] = *--bp;
3015 data[4*x + 3] = 0xff;
3020 /* shuffle the last couple of overlapping pixels */
3021 rgb[1][0] = data[5];
3022 rgb[1][1] = data[4];
3023 rgb[1][2] = data[3];
3024 rgb[0][0] = data[2];
3025 rgb[0][1] = data[1];
3026 rgb[0][2] = data[0];
3027 #ifdef WORDS_BIGENDIAN
3029 data[5] = rgb[1][2];
3030 data[6] = rgb[1][1];
3031 data[7] = rgb[1][0];
3033 data[1] = rgb[0][2];
3034 data[2] = rgb[0][1];
3035 data[3] = rgb[0][0];
3038 data[6] = rgb[1][2];
3039 data[5] = rgb[1][1];
3040 data[4] = rgb[1][0];
3042 data[2] = rgb[0][2];
3043 data[1] = rgb[0][1];
3044 data[0] = rgb[0][0];
3047 #ifdef WORDS_BIGENDIAN
3060 case CAIRO_FORMAT_RGB30:
3061 case CAIRO_FORMAT_INVALID:
3062 case CAIRO_FORMAT_ARGB32:
3063 /* stride == width */
3066 memset (data + instride, 0, stride - instride);
3068 #ifndef WORDS_BIGENDIAN
3070 case CAIRO_FORMAT_A1:
3071 for (x = 0; x < len; x++) {
3072 uint8_t byte = data[x];
3073 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
3076 case CAIRO_FORMAT_RGB16_565:
3078 uint32_t *rgba = (uint32_t *) data;
3079 for (x = len/2; x--; rgba++) {
3080 *rgba = bswap_16 (*rgba);
3084 case CAIRO_FORMAT_ARGB32:
3086 uint32_t *rgba = (uint32_t *) data;
3087 for (x = len/4; x--; rgba++) {
3088 *rgba = bswap_32 (*rgba);
3093 case CAIRO_FORMAT_A8:
3096 case CAIRO_FORMAT_RGB30:
3097 case CAIRO_FORMAT_RGB24:
3098 case CAIRO_FORMAT_INVALID:
3105 cairo_surface_mark_dirty (image);
3107 return CSI_STATUS_SUCCESS;
3110 static cairo_status_t
3111 png_read_func (void *closure, uint8_t *data, unsigned int len)
3115 ret = csi_file_read (closure, data, len);
3116 if ((unsigned int) ret != len)
3117 return CAIRO_STATUS_READ_ERROR;
3119 return CAIRO_STATUS_SUCCESS;
3123 _image_read_png (csi_file_t *src, cairo_surface_t **out)
3125 #if CAIRO_HAS_PNG_FUNCTIONS
3126 *out = cairo_image_surface_create_from_png_stream (png_read_func, src);
3127 return cairo_surface_status (*out);
3129 return CAIRO_STATUS_READ_ERROR;
3136 cairo_surface_t *surface;
3140 _image_tag_done (void *closure)
3142 struct _image_tag *tag = closure;
3143 csi_t *ctx = tag->ctx;
3145 ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list);
3146 _csi_slab_free (ctx, tag, sizeof (*tag));
3147 cairo_script_interpreter_destroy (ctx);
3151 _image_hash (csi_blob_t *blob,
3152 cairo_surface_t *surface)
3156 value = cairo_image_surface_get_width (surface);
3157 _csi_blob_hash (blob, &value, 1);
3159 value = cairo_image_surface_get_height (surface);
3160 _csi_blob_hash (blob, &value, 1);
3162 value = cairo_image_surface_get_format (surface);
3163 _csi_blob_hash (blob, &value, 1);
3166 static cairo_surface_t *
3167 _image_cached (csi_t *ctx, cairo_surface_t *surface)
3173 struct _image_tag *tag;
3175 /* check for an existing image */
3177 data = cairo_image_surface_get_data (surface);
3178 stride = cairo_image_surface_get_stride (surface);
3179 height = cairo_image_surface_get_height (surface);
3180 _csi_blob_init (&tmpl, data, stride * height);
3181 _image_hash (&tmpl, surface);
3182 link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
3184 cairo_surface_destroy (surface);
3185 tag = csi_container_of (link, struct _image_tag, blob.list);
3186 return cairo_surface_reference (tag->surface);
3189 /* none found, insert a tag for this one */
3191 tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag));
3195 ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list);
3196 tag->ctx = cairo_script_interpreter_reference (ctx);
3197 tag->blob.hash = tmpl.hash;
3198 tag->blob.bytes = tmpl.bytes;
3199 tag->blob.len = tmpl.len;
3200 tag->surface = surface;
3202 if (cairo_surface_set_user_data (surface, &_csi_blob_key,
3203 tag, _image_tag_done))
3205 _image_tag_done (tag);
3212 _image_load_from_dictionary (csi_t *ctx,
3213 csi_dictionary_t *dict,
3214 cairo_surface_t **image_out)
3216 csi_object_t obj, key;
3220 cairo_surface_t *image = NULL; /* silence the compiler */
3221 csi_status_t status;
3223 /* check for "status? */
3225 status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width);
3226 if (_csi_unlikely (status))
3228 status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height);
3229 if (_csi_unlikely (status))
3232 format = CAIRO_FORMAT_ARGB32;
3233 status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format);
3234 if (_csi_unlikely (status))
3237 status = csi_name_new_static (ctx, &key, "source");
3238 if (_csi_unlikely (status))
3241 if (csi_dictionary_has (dict, key.datum.name)) {
3242 enum mime_type mime_type;
3245 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
3246 if (_csi_unlikely (status))
3249 status = csi_name_new_static (ctx, &key, "mime-type");
3250 if (_csi_unlikely (status))
3253 mime_type = MIME_TYPE_NONE;
3254 if (csi_dictionary_has (dict, key.datum.name)) {
3255 csi_object_t type_obj;
3256 const char *type_str;
3259 status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj);
3260 if (_csi_unlikely (status))
3263 type = csi_object_get_type (&type_obj);
3265 case CSI_OBJECT_TYPE_STRING:
3266 type_str = type_obj.datum.string->string;
3268 case CSI_OBJECT_TYPE_NAME:
3269 type_str = (char *) type_obj.datum.name;
3272 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3275 if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0)
3276 mime_type = MIME_TYPE_PNG;
3279 status = csi_object_as_file (ctx, &obj, &file);
3280 if (_csi_unlikely (status))
3283 /* XXX hook for general mime-type decoder */
3285 switch (mime_type) {
3286 case MIME_TYPE_NONE:
3287 status = _image_read_raw (file.datum.file,
3288 format, width, height, &image);
3291 status = _image_read_png (file.datum.file, &image);
3294 csi_object_free (ctx, &file);
3295 if (_csi_unlikely (status))
3298 image = _image_cached (ctx, image);
3300 image = cairo_image_surface_create (format, width, height);
3303 return CSI_STATUS_SUCCESS;
3309 csi_dictionary_t *dict;
3310 cairo_surface_t *image;
3311 csi_status_t status;
3316 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
3317 if (_csi_unlikely (status))
3320 status = _image_load_from_dictionary (ctx, dict, &image);
3321 if (_csi_unlikely (status))
3325 obj.type = CSI_OBJECT_TYPE_SURFACE;
3326 obj.datum.surface = image;
3333 csi_status_t status;
3338 status = _csi_ostack_get_integer (ctx, 0, &n);
3339 if (_csi_unlikely (status))
3345 return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n));
3349 _integer (csi_t *ctx)
3356 obj = _csi_peek_ostack (ctx, 0);
3357 type = csi_object_get_type (obj);
3359 case CSI_OBJECT_TYPE_INTEGER:
3361 case CSI_OBJECT_TYPE_REAL:
3362 obj->datum.integer = obj->datum.real;
3365 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3367 obj->type = CSI_OBJECT_TYPE_INTEGER;
3369 return CSI_STATUS_SUCCESS;
3373 _invert (csi_t *ctx)
3376 csi_status_t status;
3381 status = _csi_ostack_get_matrix (ctx, 0, &m);
3382 if (_csi_unlikely (status))
3385 cairo_matrix_invert (&m);
3387 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
3388 if (_csi_unlikely (status))
3399 csi_status_t status;
3400 csi_object_t *a, *b;
3405 b = _csi_peek_ostack (ctx, 0);
3406 a = _csi_peek_ostack (ctx, 1);
3408 status = csi_object_compare (a, b, &cmp);
3409 if (_csi_unlikely (status))
3413 return _csi_push_ostack_boolean (ctx, cmp <= 0);
3417 _linear (csi_t *ctx)
3420 csi_status_t status;
3421 double x1, y1, x2, y2;
3425 status = _csi_ostack_get_number (ctx, 0, &y2);
3426 if (_csi_unlikely (status))
3428 status = _csi_ostack_get_number (ctx, 1, &x2);
3429 if (_csi_unlikely (status))
3431 status = _csi_ostack_get_number (ctx, 2, &y1);
3432 if (_csi_unlikely (status))
3434 status = _csi_ostack_get_number (ctx, 3, &x1);
3435 if (_csi_unlikely (status))
3440 obj.type = CSI_OBJECT_TYPE_PATTERN;
3441 obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
3446 _line_to (csi_t *ctx)
3448 csi_status_t status;
3455 status = _csi_ostack_get_number (ctx, 0, &y);
3456 if (_csi_unlikely (status))
3458 status = _csi_ostack_get_number (ctx, 1, &x);
3459 if (_csi_unlikely (status))
3462 /* XXX path object */
3464 obj = _csi_peek_ostack (ctx, 2);
3465 type = csi_object_get_type (obj);
3467 case CSI_OBJECT_TYPE_CONTEXT:
3468 cairo_line_to (obj->datum.cr, x, y);
3470 case CSI_OBJECT_TYPE_PATTERN:
3471 cairo_mesh_pattern_line_to (obj->datum.pattern, x, y);
3476 return CSI_STATUS_SUCCESS;
3482 csi_status_t status;
3483 csi_object_t *a, *b;
3488 b = _csi_peek_ostack (ctx, 0);
3489 a = _csi_peek_ostack (ctx, 1);
3491 status = csi_object_compare (a, b, &cmp);
3492 if (_csi_unlikely (status))
3496 return _csi_push_ostack_boolean (ctx, cmp < 0);
3502 return _csi_push_ostack_mark (ctx);
3508 csi_object_t *a, *b;
3513 b = _csi_peek_ostack (ctx, 0);
3514 a = _csi_peek_ostack (ctx, 1);
3516 v = ! csi_object_eq (a, b);
3519 return _csi_push_ostack_boolean (ctx, v);
3530 obj = _csi_peek_ostack (ctx, 0);
3531 type = csi_object_get_type (obj);
3533 case CSI_OBJECT_TYPE_INTEGER:
3534 obj->datum.integer = -obj->datum.integer;
3536 case CSI_OBJECT_TYPE_REAL:
3537 obj->datum.real = -obj->datum.real;
3540 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3543 return CSI_STATUS_SUCCESS;
3554 obj = _csi_peek_ostack (ctx, 0);
3555 type = csi_object_get_type (obj);
3557 case CSI_OBJECT_TYPE_BOOLEAN:
3558 obj->datum.boolean = ! obj->datum.boolean;
3560 case CSI_OBJECT_TYPE_INTEGER:
3561 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3562 obj->datum.boolean = ! obj->datum.integer;
3564 case CSI_OBJECT_TYPE_REAL:
3565 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3566 obj->datum.boolean = obj->datum.real == 0.0;
3569 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3572 return CSI_STATUS_SUCCESS;
3576 _new_path (csi_t *ctx)
3578 /* XXX handle path object */
3579 return _do_cairo_op (ctx, cairo_new_path);
3583 _new_sub_path (csi_t *ctx)
3585 /* XXX handle path object */
3586 return _do_cairo_op (ctx, cairo_new_sub_path);
3592 return _csi_push_ostack_null (ctx);
3599 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3600 csi_status_t status;
3604 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3605 if (_csi_unlikely (status))
3607 status = _csi_ostack_get_context (ctx, 1, &cr);
3608 if (_csi_unlikely (status))
3611 cairo_mask (cr, pattern);
3614 return CSI_STATUS_SUCCESS;
3618 _matrix (csi_t *ctx)
3620 csi_object_t *obj, matrix;
3622 csi_status_t status;
3627 obj = _csi_peek_ostack (ctx, 0);
3628 if (csi_object_is_number (obj)) {
3631 for (n = 6; n--; ) {
3632 status = _csi_ostack_get_number (ctx, 5-n, &v[n]);
3633 if (_csi_unlikely (status))
3636 status = csi_matrix_new_from_values (ctx, &matrix, v);
3637 if (_csi_unlikely (status))
3644 status = _csi_ostack_get_array (ctx, 0, &array);
3645 if (_csi_unlikely (status))
3648 status = csi_matrix_new_from_array (ctx, &matrix, array);
3649 if (_csi_unlikely (status))
3655 return push (&matrix);
3659 _map_to_image (csi_t *ctx)
3663 csi_status_t status;
3664 cairo_rectangle_int_t extents, *r;
3665 cairo_surface_t *surface;
3669 status = _csi_ostack_get_array (ctx, 0, &array);
3670 if (_csi_unlikely (status))
3673 status = _csi_ostack_get_surface (ctx, 1, &surface);
3674 if (_csi_unlikely (status))
3677 switch (array->stack.len) {
3682 extents.x = floor (_csi_object_as_real (&array->stack.objects[0]));
3683 extents.y = floor (_csi_object_as_real (&array->stack.objects[1]));
3684 extents.width = ceil (_csi_object_as_real (&array->stack.objects[2]));
3685 extents.height = ceil (_csi_object_as_real (&array->stack.objects[3]));
3689 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3692 obj.type = CSI_OBJECT_TYPE_SURFACE;
3693 obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r));
3699 _unmap_image (csi_t *ctx)
3701 cairo_surface_t *surface, *image;
3702 csi_status_t status;
3706 status = _csi_ostack_get_surface (ctx, 0, &image);
3707 if (_csi_unlikely (status))
3709 status = _csi_ostack_get_surface (ctx, 1, &surface);
3710 if (_csi_unlikely (status))
3713 cairo_surface_unmap_image (surface, image);
3716 return CSI_STATUS_SUCCESS;
3724 obj.type = CSI_OBJECT_TYPE_PATTERN;
3725 obj.datum.pattern = cairo_pattern_create_mesh ();
3730 _mesh_begin_patch (csi_t *ctx)
3732 csi_status_t status;
3733 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3737 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3738 if (_csi_unlikely (status))
3741 cairo_mesh_pattern_begin_patch (pattern);
3742 return CSI_STATUS_SUCCESS;
3746 _mesh_end_patch (csi_t *ctx)
3748 csi_status_t status;
3749 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3753 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3754 if (_csi_unlikely (status))
3757 cairo_mesh_pattern_end_patch (pattern);
3758 return CSI_STATUS_SUCCESS;
3762 _mesh_set_control_point (csi_t *ctx)
3764 csi_status_t status;
3766 csi_integer_t point;
3767 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3771 status = _csi_ostack_get_number (ctx, 0, &y);
3772 if (_csi_unlikely (status))
3774 status = _csi_ostack_get_number (ctx, 1, &x);
3775 if (_csi_unlikely (status))
3777 status = _csi_ostack_get_integer (ctx, 2, &point);
3778 if (_csi_unlikely (status))
3780 status = _csi_ostack_get_pattern (ctx, 3, &pattern);
3781 if (_csi_unlikely (status))
3784 cairo_mesh_pattern_set_control_point (pattern, point, x, y);
3787 return CSI_STATUS_SUCCESS;
3791 _mesh_set_corner_color (csi_t *ctx)
3793 csi_status_t status;
3795 csi_integer_t corner;
3796 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3800 status = _csi_ostack_get_number (ctx, 0, &a);
3801 if (_csi_unlikely (status))
3803 status = _csi_ostack_get_number (ctx, 1, &b);
3804 if (_csi_unlikely (status))
3806 status = _csi_ostack_get_number (ctx, 2, &g);
3807 if (_csi_unlikely (status))
3809 status = _csi_ostack_get_number (ctx, 3, &r);
3810 if (_csi_unlikely (status))
3812 status = _csi_ostack_get_integer (ctx, 4, &corner);
3813 if (_csi_unlikely (status))
3815 status = _csi_ostack_get_pattern (ctx, 5, &pattern);
3816 if (_csi_unlikely (status))
3819 cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a);
3822 return CSI_STATUS_SUCCESS;
3829 csi_status_t status;
3833 status = _csi_ostack_get_integer (ctx, 0, &y);
3834 if (_csi_unlikely (status))
3836 status = _csi_ostack_get_integer (ctx, 1, &x);
3837 if (_csi_unlikely (status))
3841 return _csi_push_ostack_integer (ctx, x % y);
3845 _move_to (csi_t *ctx)
3847 csi_status_t status;
3854 status = _csi_ostack_get_number (ctx, 0, &y);
3855 if (_csi_unlikely (status))
3857 status = _csi_ostack_get_number (ctx, 1, &x);
3858 if (_csi_unlikely (status))
3861 obj = _csi_peek_ostack (ctx, 2);
3862 type = csi_object_get_type (obj);
3864 case CSI_OBJECT_TYPE_CONTEXT:
3865 cairo_move_to (obj->datum.cr, x, y);
3867 case CSI_OBJECT_TYPE_PATTERN:
3868 cairo_mesh_pattern_move_to (obj->datum.pattern, x, y);
3871 /* XXX path object */
3875 return CSI_STATUS_SUCCESS;
3883 csi_object_type_t type_a, type_b;
3887 B = _csi_peek_ostack (ctx, 0);
3888 A = _csi_peek_ostack (ctx, 1);
3890 type_a = csi_object_get_type (A);
3891 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
3892 type_a == CSI_OBJECT_TYPE_REAL)))
3894 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3896 type_b = csi_object_get_type (B);
3897 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
3898 type_b == CSI_OBJECT_TYPE_REAL)))
3900 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3905 if (type_a == CSI_OBJECT_TYPE_REAL &&
3906 type_b == CSI_OBJECT_TYPE_REAL)
3908 return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real);
3911 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
3912 type_b == CSI_OBJECT_TYPE_INTEGER)
3914 return _csi_push_ostack_integer (ctx,
3915 A->datum.integer * B->datum.integer);
3921 if (type_a == CSI_OBJECT_TYPE_REAL)
3924 v = A->datum.integer;
3926 if (type_b == CSI_OBJECT_TYPE_REAL)
3929 v *= B->datum.integer;
3931 return _csi_push_ostack_real (ctx, v);
3938 csi_object_t *a, *b;
3943 a = _csi_peek_ostack (ctx, 0);
3944 b = _csi_peek_ostack (ctx, 1);
3945 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
3946 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3949 type = csi_object_get_type (a);
3951 case CSI_OBJECT_TYPE_INTEGER:
3952 return _csi_push_ostack_integer (ctx,
3953 a->datum.integer | b->datum.integer);
3954 case CSI_OBJECT_TYPE_BOOLEAN:
3955 return _csi_push_ostack_boolean (ctx,
3956 a->datum.boolean | b->datum.boolean);
3958 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3965 return _do_cairo_op (ctx, cairo_paint);
3969 _paint_with_alpha (csi_t *ctx)
3972 csi_status_t status;
3977 status = _csi_ostack_get_number (ctx, 0, &alpha);
3978 if (_csi_unlikely (status))
3981 status = _csi_ostack_get_context (ctx, 1, &cr);
3982 if (_csi_unlikely (status))
3985 cairo_paint_with_alpha (cr, alpha);
3987 return CSI_STATUS_SUCCESS;
3991 _pattern (csi_t *ctx)
3994 csi_status_t status;
3995 cairo_surface_t *surface;
3999 status = _csi_ostack_get_surface (ctx, 0, &surface);
4000 if (_csi_unlikely (status))
4003 obj.type = CSI_OBJECT_TYPE_PATTERN;
4004 obj.datum.pattern = cairo_pattern_create_for_surface (surface);
4016 return CSI_STATUS_SUCCESS;
4020 _pop_group (csi_t *ctx)
4023 csi_status_t status;
4028 status = _csi_ostack_get_context (ctx, 0, &cr);
4029 if (_csi_unlikely (status))
4032 obj.type = CSI_OBJECT_TYPE_PATTERN;
4033 obj.datum.pattern = cairo_pop_group (cr);
4039 _push_group (csi_t *ctx)
4041 csi_status_t status;
4047 status = _csi_ostack_get_integer (ctx, 0, &content);
4048 if (_csi_unlikely (status))
4051 status = _csi_ostack_get_context (ctx, 1, &cr);
4052 if (_csi_unlikely (status))
4055 cairo_push_group_with_content (cr, content);
4057 return CSI_STATUS_SUCCESS;
4061 _radial (csi_t *ctx)
4064 csi_status_t status;
4065 double x1, y1, r1, x2, y2, r2;
4069 status = _csi_ostack_get_number (ctx, 0, &r2);
4070 if (_csi_unlikely (status))
4072 status = _csi_ostack_get_number (ctx, 1, &y2);
4073 if (_csi_unlikely (status))
4075 status = _csi_ostack_get_number (ctx, 2, &x2);
4076 if (_csi_unlikely (status))
4078 status = _csi_ostack_get_number (ctx, 3, &r1);
4079 if (_csi_unlikely (status))
4081 status = _csi_ostack_get_number (ctx, 4, &y1);
4082 if (_csi_unlikely (status))
4084 status = _csi_ostack_get_number (ctx, 5, &x1);
4085 if (_csi_unlikely (status))
4088 obj.type = CSI_OBJECT_TYPE_PATTERN;
4089 obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2);
4095 _rectangle (csi_t *ctx)
4097 csi_status_t status;
4104 status = _csi_ostack_get_number (ctx, 0, &h);
4105 if (_csi_unlikely (status))
4107 status = _csi_ostack_get_number (ctx, 1, &w);
4108 if (_csi_unlikely (status))
4110 status = _csi_ostack_get_number (ctx, 2, &y);
4111 if (_csi_unlikely (status))
4113 status = _csi_ostack_get_number (ctx, 3, &x);
4114 if (_csi_unlikely (status))
4116 status = _csi_ostack_get_context (ctx, 4, &cr);
4117 if (_csi_unlikely (status))
4120 /* XXX path object */
4122 cairo_rectangle (cr, x, y, w, h);
4124 return CSI_STATUS_SUCCESS;
4128 _rel_curve_to (csi_t *ctx)
4130 csi_status_t status;
4138 status = _csi_ostack_get_number (ctx, 0, &y3);
4139 if (_csi_unlikely (status))
4141 status = _csi_ostack_get_number (ctx, 1, &x3);
4142 if (_csi_unlikely (status))
4144 status = _csi_ostack_get_number (ctx, 2, &y2);
4145 if (_csi_unlikely (status))
4147 status = _csi_ostack_get_number (ctx, 3, &x2);
4148 if (_csi_unlikely (status))
4150 status = _csi_ostack_get_number (ctx, 4, &y1);
4151 if (_csi_unlikely (status))
4153 status = _csi_ostack_get_number (ctx, 5, &x1);
4154 if (_csi_unlikely (status))
4156 status = _csi_ostack_get_context (ctx, 6, &cr);
4157 if (_csi_unlikely (status))
4160 /* XXX path object */
4162 cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3);
4164 return CSI_STATUS_SUCCESS;
4168 _rel_line_to (csi_t *ctx)
4170 csi_status_t status;
4176 status = _csi_ostack_get_number (ctx, 0, &y);
4177 if (_csi_unlikely (status))
4179 status = _csi_ostack_get_number (ctx, 1, &x);
4180 if (_csi_unlikely (status))
4182 status = _csi_ostack_get_context (ctx, 2, &cr);
4183 if (_csi_unlikely (status))
4186 /* XXX path object */
4188 cairo_rel_line_to (cr, x, y);
4190 return CSI_STATUS_SUCCESS;
4194 _rel_move_to (csi_t *ctx)
4196 csi_status_t status;
4202 status = _csi_ostack_get_number (ctx, 0, &y);
4203 if (_csi_unlikely (status))
4205 status = _csi_ostack_get_number (ctx, 1, &x);
4206 if (_csi_unlikely (status))
4208 status = _csi_ostack_get_context (ctx, 2, &cr);
4209 if (_csi_unlikely (status))
4212 /* XXX path object */
4213 cairo_rel_move_to (cr, x, y);
4215 return CSI_STATUS_SUCCESS;
4219 _repeat (csi_t *ctx)
4222 csi_integer_t count;
4223 csi_status_t status;
4227 status = _csi_ostack_get_procedure (ctx, 0, &proc);
4228 if (_csi_unlikely (status))
4231 status = _csi_ostack_get_integer (ctx, 1, &count);
4232 if (_csi_unlikely (status))
4235 if (_csi_unlikely (count < 0))
4236 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4242 status = _csi_array_execute (ctx, proc);
4243 if (_csi_unlikely (status))
4247 if (--proc->base.ref == 0)
4248 csi_array_free (ctx, proc);
4254 _reset_clip (csi_t *ctx)
4256 return _do_cairo_op (ctx, cairo_reset_clip);
4260 _restore (csi_t *ctx)
4262 return _do_cairo_op (ctx, cairo_restore);
4269 csi_status_t status;
4274 status = _csi_ostack_get_number (ctx, 0, &b);
4275 if (_csi_unlikely (status))
4277 status = _csi_ostack_get_number (ctx, 1, &g);
4278 if (_csi_unlikely (status))
4280 status = _csi_ostack_get_number (ctx, 2, &r);
4281 if (_csi_unlikely (status))
4284 obj.type = CSI_OBJECT_TYPE_PATTERN;
4285 obj.datum.pattern = cairo_pattern_create_rgb (r, g, b);
4294 csi_status_t status;
4299 status = _csi_ostack_get_number (ctx, 0, &a);
4300 if (_csi_unlikely (status))
4302 status = _csi_ostack_get_number (ctx, 1, &b);
4303 if (_csi_unlikely (status))
4305 status = _csi_ostack_get_number (ctx, 2, &g);
4306 if (_csi_unlikely (status))
4308 status = _csi_ostack_get_number (ctx, 3, &r);
4309 if (_csi_unlikely (status))
4312 obj.type = CSI_OBJECT_TYPE_PATTERN;
4313 obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a);
4321 csi_status_t status;
4326 status = _csi_ostack_get_integer (ctx, 0, &j);
4327 if (_csi_unlikely (status))
4329 status = _csi_ostack_get_integer (ctx, 1, &n);
4330 if (_csi_unlikely (status))
4335 return _csi_stack_roll (ctx, &ctx->ostack, j, n);
4339 _rotate (csi_t *ctx)
4342 csi_status_t status;
4348 status = _csi_ostack_get_number (ctx, 0, &theta);
4349 if (_csi_unlikely (status))
4352 obj = _csi_peek_ostack (ctx, 1);
4353 type = csi_object_get_type (obj);
4355 case CSI_OBJECT_TYPE_CONTEXT:
4356 cairo_rotate (obj->datum.cr, theta);
4359 case CSI_OBJECT_TYPE_PATTERN:
4362 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4363 cairo_matrix_rotate (&ctm, theta);
4364 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4369 case CSI_OBJECT_TYPE_MATRIX:
4370 cairo_matrix_rotate (&obj->datum.matrix->matrix, theta);
4374 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4378 return CSI_STATUS_SUCCESS;
4384 return _do_cairo_op (ctx, cairo_save);
4391 csi_status_t status;
4397 status = _csi_ostack_get_number (ctx, 0, &y);
4398 if (_csi_unlikely (status))
4400 status = _csi_ostack_get_number (ctx, 1, &x);
4401 if (_csi_unlikely (status))
4404 obj = _csi_peek_ostack (ctx, 2);
4405 type = csi_object_get_type (obj);
4407 case CSI_OBJECT_TYPE_CONTEXT:
4408 cairo_scale (obj->datum.cr, x, y);
4411 case CSI_OBJECT_TYPE_PATTERN:
4414 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4415 cairo_matrix_scale (&ctm, x, y);
4416 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4421 case CSI_OBJECT_TYPE_MATRIX:
4422 cairo_matrix_scale (&obj->datum.matrix->matrix, x, y);
4426 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4430 return CSI_STATUS_SUCCESS;
4434 _font_options_load_from_dictionary (csi_t *ctx,
4435 csi_dictionary_t *dict,
4436 cairo_font_options_t *options)
4440 void (*setter) (cairo_font_options_t *, int val);
4443 (void (*)(cairo_font_options_t *, int val))
4444 cairo_font_options_set_antialias },
4446 (void (*)(cairo_font_options_t *, int val))
4447 cairo_font_options_set_subpixel_order },
4449 (void (*)(cairo_font_options_t *, int val))
4450 cairo_font_options_set_hint_style },
4452 (void (*)(cairo_font_options_t *, int val))
4453 cairo_font_options_set_hint_metrics },
4455 }, *prop = properties;
4457 while (prop->key != NULL) {
4458 csi_object_t key, value;
4459 csi_status_t status;
4461 status = csi_name_new_static (ctx, &key, prop->key);
4462 if (_csi_unlikely (status))
4465 if (csi_dictionary_has (dict, key.datum.name)) {
4466 status = csi_dictionary_get (ctx, dict, key.datum.name, &value);
4467 if (_csi_unlikely (status))
4470 if (_csi_unlikely (csi_object_get_type (&value) !=
4471 CSI_OBJECT_TYPE_INTEGER))
4473 csi_object_free (ctx, &value);
4474 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4477 prop->setter (options, value.datum.integer);
4483 return CSI_STATUS_SUCCESS;
4487 _scaled_font (csi_t *ctx)
4490 csi_dictionary_t *dict;
4491 cairo_font_face_t *font_face = NULL; /* silence the compiler */
4492 cairo_matrix_t font_matrix, ctm;
4493 cairo_font_options_t *options;
4494 csi_status_t status;
4498 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
4499 if (_csi_unlikely (status))
4501 options = cairo_font_options_create ();
4502 status = _font_options_load_from_dictionary (ctx, dict, options);
4503 if (_csi_unlikely (status)) {
4504 cairo_font_options_destroy (options);
4508 status = _csi_ostack_get_matrix (ctx, 1, &ctm);
4509 if (_csi_unlikely (status)) {
4510 cairo_font_options_destroy (options);
4514 status = _csi_ostack_get_matrix (ctx, 2, &font_matrix);
4515 if (_csi_unlikely (status)) {
4516 cairo_font_options_destroy (options);
4520 status = _csi_ostack_get_font_face (ctx, 3, &font_face);
4521 if (_csi_unlikely (status)) {
4522 cairo_font_options_destroy (options);
4526 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
4527 obj.datum.scaled_font = cairo_scaled_font_create (font_face,
4531 cairo_font_options_destroy (options);
4537 _select_font_face (csi_t *ctx)
4542 csi_string_t *family;
4543 csi_status_t status;
4547 status = _csi_ostack_get_integer (ctx, 0, &weight);
4548 if (_csi_unlikely (status))
4550 status = _csi_ostack_get_integer (ctx, 1, &slant);
4551 if (_csi_unlikely (status))
4553 status = _csi_ostack_get_string (ctx, 2, &family);
4554 if (_csi_unlikely (status))
4556 status = _csi_ostack_get_context (ctx, 3, &cr);
4557 if (_csi_unlikely (status))
4560 cairo_select_font_face (cr, family->string, slant, weight);
4562 return CSI_STATUS_SUCCESS;
4566 _context_set (csi_t *ctx,
4571 if (strcmp ((char *) key, "source") == 0) {
4572 if (_csi_unlikely (csi_object_get_type (obj) !=
4573 CSI_OBJECT_TYPE_PATTERN))
4574 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4576 cairo_set_source (cr, obj->datum.pattern);
4577 return CSI_STATUS_SUCCESS;
4580 if (strcmp ((char *) key, "scaled-font") == 0) {
4581 if (_csi_unlikely (csi_object_get_type (obj) !=
4582 CSI_OBJECT_TYPE_SCALED_FONT))
4583 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4585 cairo_set_scaled_font (cr, obj->datum.scaled_font);
4586 return CSI_STATUS_SUCCESS;
4589 if (strcmp ((char *) key, "font-face") == 0) {
4590 if (_csi_unlikely (csi_object_get_type (obj) !=
4591 CSI_OBJECT_TYPE_FONT))
4592 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4594 cairo_set_font_face (cr, obj->datum.font_face);
4595 return CSI_STATUS_SUCCESS;
4598 /* return _proxy_set()? */
4599 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4605 csi_object_t *key, *value, *dst;
4606 csi_status_t status;
4611 value = _csi_peek_ostack (ctx, 0);
4612 key = _csi_peek_ostack (ctx, 1);
4613 dst = _csi_peek_ostack (ctx, 2);
4615 type = csi_object_get_type (dst);
4617 case CSI_OBJECT_TYPE_DICTIONARY:
4618 if (_csi_unlikely (csi_object_get_type (key) !=
4619 CSI_OBJECT_TYPE_NAME))
4620 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4622 status = csi_dictionary_put (ctx,
4623 dst->datum.dictionary,
4627 case CSI_OBJECT_TYPE_ARRAY:
4628 if (_csi_unlikely (csi_object_get_type (key) !=
4629 CSI_OBJECT_TYPE_INTEGER))
4630 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4632 status = csi_array_put (ctx,
4638 case CSI_OBJECT_TYPE_CONTEXT:
4639 if (_csi_unlikely (csi_object_get_type (key) !=
4640 CSI_OBJECT_TYPE_NAME))
4641 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4643 status = _context_set (ctx,
4649 case CSI_OBJECT_TYPE_STRING:
4651 status = csi_string_put (dst, key, value);
4655 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4663 _set_antialias (csi_t *ctx)
4665 csi_status_t status;
4671 status = _csi_ostack_get_integer (ctx, 0, &antialias);
4672 if (_csi_unlikely (status))
4674 status = _csi_ostack_get_context (ctx, 1, &cr);
4675 if (_csi_unlikely (status))
4678 cairo_set_antialias (cr, antialias);
4680 return CSI_STATUS_SUCCESS;
4684 _set_dash (csi_t *ctx)
4687 csi_status_t status;
4693 status = _csi_ostack_get_number (ctx, 0, &offset);
4694 if (_csi_unlikely (status))
4696 status = _csi_ostack_get_array (ctx, 1, &array);
4697 if (_csi_unlikely (status))
4699 status = _csi_ostack_get_context (ctx, 2, &cr);
4700 if (_csi_unlikely (status))
4703 if (array->stack.len == 0) {
4704 cairo_set_dash (cr, NULL, 0., 0.);
4706 double stack_dashes[8];
4710 if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) {
4711 dashes = stack_dashes;
4713 if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double)))
4714 return _csi_error (CSI_STATUS_NO_MEMORY);
4715 dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len);
4716 if (_csi_unlikely (dashes == NULL))
4717 return _csi_error (CSI_STATUS_NO_MEMORY);
4720 for (n = 0; n < array->stack.len; n++) {
4721 if (_csi_unlikely (! csi_object_is_number
4722 (&array->stack.objects[n])))
4724 if (dashes != stack_dashes)
4725 _csi_free (ctx, dashes);
4726 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4729 dashes[n] = csi_number_get_value (&array->stack.objects[n]);
4732 cairo_set_dash (cr, dashes, n, offset);
4734 if (dashes != stack_dashes)
4735 _csi_free (ctx, dashes);
4739 return CSI_STATUS_SUCCESS;
4743 _set_device_offset (csi_t *ctx)
4745 csi_status_t status;
4746 cairo_surface_t *surface;
4751 status = _csi_ostack_get_number (ctx, 0, &y);
4752 if (_csi_unlikely (status))
4754 status = _csi_ostack_get_number (ctx, 1, &x);
4755 if (_csi_unlikely (status))
4757 status = _csi_ostack_get_surface (ctx, 2, &surface);
4758 if (_csi_unlikely (status))
4761 cairo_surface_set_device_offset (surface, x, y);
4763 return CSI_STATUS_SUCCESS;
4767 _set_extend (csi_t *ctx)
4769 csi_status_t status;
4776 status = _csi_ostack_get_integer (ctx, 0, &extend);
4777 if (_csi_unlikely (status))
4780 obj = _csi_peek_ostack (ctx, 1);
4781 type = csi_object_get_type (obj);
4783 case CSI_OBJECT_TYPE_CONTEXT:
4784 cairo_pattern_set_extend (cairo_get_source (obj->datum.cr),
4787 case CSI_OBJECT_TYPE_PATTERN:
4788 cairo_pattern_set_extend (obj->datum.pattern, extend);
4791 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4795 return CSI_STATUS_SUCCESS;
4799 _set_fallback_resolution (csi_t *ctx)
4801 csi_status_t status;
4802 cairo_surface_t *surface;
4803 double dpi_x, dpi_y;
4807 status = _csi_ostack_get_number (ctx, 0, &dpi_y);
4808 if (_csi_unlikely (status))
4810 status = _csi_ostack_get_number (ctx, 1, &dpi_x);
4811 if (_csi_unlikely (status))
4813 status = _csi_ostack_get_surface (ctx, 2, &surface);
4814 if (_csi_unlikely (status))
4817 cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y);
4819 return CSI_STATUS_SUCCESS;
4823 _set_fill_rule (csi_t *ctx)
4825 csi_status_t status;
4831 status = _csi_ostack_get_integer (ctx, 0, &fill_rule);
4832 if (_csi_unlikely (status))
4834 status = _csi_ostack_get_context (ctx, 1, &cr);
4835 if (_csi_unlikely (status))
4838 cairo_set_fill_rule (cr, fill_rule);
4840 return CSI_STATUS_SUCCESS;
4844 _set_filter (csi_t *ctx)
4846 csi_status_t status;
4853 status = _csi_ostack_get_integer (ctx, 0, &filter);
4854 if (_csi_unlikely (status))
4857 obj = _csi_peek_ostack (ctx, 1);
4858 type = csi_object_get_type (obj);
4860 case CSI_OBJECT_TYPE_CONTEXT:
4861 cairo_pattern_set_filter (cairo_get_source (obj->datum.cr),
4864 case CSI_OBJECT_TYPE_PATTERN:
4865 cairo_pattern_set_filter (obj->datum.pattern, filter);
4868 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4872 return CSI_STATUS_SUCCESS;
4876 _set_font_face (csi_t *ctx)
4879 cairo_font_face_t *font = NULL; /* silence the compiler */
4880 csi_status_t status;
4884 status = _csi_ostack_get_font_face (ctx, 0, &font);
4885 if (_csi_unlikely (status))
4887 status = _csi_ostack_get_context (ctx, 1, &cr);
4888 if (_csi_unlikely (status))
4891 cairo_set_font_face (cr, font);
4893 return CSI_STATUS_SUCCESS;
4897 _set_font_options (csi_t *ctx)
4899 csi_status_t status;
4901 csi_dictionary_t *dict;
4902 cairo_font_options_t *options;
4906 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
4907 if (_csi_unlikely (status))
4909 status = _csi_ostack_get_context (ctx, 1, &cr);
4910 if (_csi_unlikely (status))
4913 options = cairo_font_options_create ();
4914 status = _font_options_load_from_dictionary (ctx, dict, options);
4915 if (_csi_unlikely (status))
4918 cairo_set_font_options (cr, options);
4919 cairo_font_options_destroy (options);
4921 return CSI_STATUS_SUCCESS;
4925 _set_font_matrix (csi_t *ctx)
4927 csi_status_t status;
4933 status = _csi_ostack_get_matrix (ctx, 0, &m);
4934 if (_csi_unlikely (status))
4936 status = _csi_ostack_get_context (ctx, 1, &cr);
4937 if (_csi_unlikely (status))
4940 cairo_set_font_matrix (cr, &m);
4942 return CSI_STATUS_SUCCESS;
4946 _set_font_size (csi_t *ctx)
4948 csi_status_t status;
4954 status = _csi_ostack_get_number (ctx, 0, &size);
4955 if (_csi_unlikely (status))
4957 status = _csi_ostack_get_context (ctx, 1, &cr);
4958 if (_csi_unlikely (status))
4961 cairo_set_font_size (cr, size);
4963 return CSI_STATUS_SUCCESS;
4967 _set_line_cap (csi_t *ctx)
4969 csi_status_t status;
4975 status = _csi_ostack_get_integer (ctx, 0, &line_cap);
4976 if (_csi_unlikely (status))
4978 status = _csi_ostack_get_context (ctx, 1, &cr);
4979 if (_csi_unlikely (status))
4982 cairo_set_line_cap (cr, line_cap);
4984 return CSI_STATUS_SUCCESS;
4988 _set_line_join (csi_t *ctx)
4990 csi_status_t status;
4994 status = _csi_ostack_get_integer (ctx, 0, &line_join);
4995 if (_csi_unlikely (status))
4997 status = _csi_ostack_get_context (ctx, 1, &cr);
4998 if (_csi_unlikely (status))
5001 cairo_set_line_join (cr, line_join);
5003 return CSI_STATUS_SUCCESS;
5007 _set_line_width (csi_t *ctx)
5009 csi_status_t status;
5015 status = _csi_ostack_get_number (ctx, 0, &line_width);
5016 if (_csi_unlikely (status))
5018 status = _csi_ostack_get_context (ctx, 1, &cr);
5019 if (_csi_unlikely (status))
5022 cairo_set_line_width (cr, line_width);
5024 return CSI_STATUS_SUCCESS;
5028 _set_matrix (csi_t *ctx)
5031 csi_status_t status;
5037 status = _csi_ostack_get_matrix (ctx, 0, &m);
5038 if (_csi_unlikely (status))
5041 obj = _csi_peek_ostack (ctx, 1);
5042 type = csi_object_get_type (obj);
5044 case CSI_OBJECT_TYPE_CONTEXT:
5045 cairo_set_matrix (obj->datum.cr, &m);
5047 case CSI_OBJECT_TYPE_PATTERN:
5048 cairo_pattern_set_matrix (obj->datum.pattern, &m);
5050 case CSI_OBJECT_TYPE_MATRIX:
5051 obj->datum.matrix->matrix = m;
5054 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5058 return CSI_STATUS_SUCCESS;
5063 csi_string_t *source;
5066 _mime_tag_destroy (void *closure)
5068 struct _mime_tag *tag = closure;
5070 if (--tag->source->base.ref)
5071 csi_string_free (tag->ctx, tag->source);
5073 _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag));
5077 _set_mime_data (csi_t *ctx)
5079 csi_status_t status;
5081 const char *mime = NULL; /* silence the compiler */
5082 csi_object_t source;
5083 cairo_surface_t *surface;
5084 struct _mime_tag *tag;
5089 obj = _csi_peek_ostack (ctx, 0);
5090 type = csi_object_get_type (obj);
5092 case CSI_OBJECT_TYPE_FILE:
5093 status = _csi_file_as_string (ctx, obj->datum.file, &source);
5094 if (_csi_unlikely (status))
5099 case CSI_OBJECT_TYPE_STRING:
5100 source = *csi_object_reference (obj);
5104 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5107 status = _csi_ostack_get_string_constant (ctx, 1, &mime);
5108 if (_csi_unlikely (status))
5111 status = _csi_ostack_get_surface (ctx, 2, &surface);
5112 if (_csi_unlikely (status))
5116 /* XXX free source */
5117 tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag));
5118 if (_csi_unlikely (tag == NULL))
5119 return _csi_error (CSI_STATUS_NO_MEMORY);
5120 tag->ctx = cairo_script_interpreter_reference (ctx);
5121 tag->source = source.datum.string;
5122 tag->source->base.ref++;
5124 status = cairo_surface_set_mime_data (surface,
5127 source.datum.string->string,
5128 source.datum.string->len,
5129 _mime_tag_destroy, tag);
5130 if (_csi_unlikely (status)) {
5131 _mime_tag_destroy (tag);
5136 return CSI_STATUS_SUCCESS;
5140 _set_miter_limit (csi_t *ctx)
5142 csi_status_t status;
5148 status = _csi_ostack_get_number (ctx, 0, &miter_limit);
5149 if (_csi_unlikely (status))
5151 status = _csi_ostack_get_context (ctx, 1, &cr);
5152 if (_csi_unlikely (status))
5155 cairo_set_miter_limit (cr, miter_limit);
5157 return CSI_STATUS_SUCCESS;
5161 _set_operator (csi_t *ctx)
5165 csi_status_t status;
5169 status = _csi_ostack_get_integer (ctx, 0, &val);
5170 if (_csi_unlikely (status))
5172 status = _csi_ostack_get_context (ctx, 1, &cr);
5173 if (_csi_unlikely (status))
5176 cairo_set_operator (cr, val);
5178 return CSI_STATUS_SUCCESS;
5182 _set_scaled_font (csi_t *ctx)
5185 cairo_scaled_font_t *font = NULL; /* silence the compiler */
5186 csi_status_t status;
5190 status = _csi_ostack_get_scaled_font (ctx, 0, &font);
5191 if (_csi_unlikely (status))
5193 status = _csi_ostack_get_context (ctx, 1, &cr);
5194 if (_csi_unlikely (status))
5197 cairo_set_scaled_font (cr, font);
5199 return CSI_STATUS_SUCCESS;
5203 _set_source (csi_t *ctx)
5206 cairo_pattern_t *pattern = NULL; /* silence the compiler */
5207 csi_status_t status;
5211 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
5212 if (_csi_unlikely (status))
5214 status = _csi_ostack_get_context (ctx, 1, &cr);
5215 if (_csi_unlikely (status))
5218 cairo_set_source (cr, pattern);
5220 return CSI_STATUS_SUCCESS;
5223 static csi_boolean_t
5224 _matching_images (cairo_surface_t *a, cairo_surface_t *b)
5226 cairo_format_t format_a, format_b;
5228 if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE)
5230 if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE)
5233 if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b))
5236 if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b))
5239 format_a = cairo_image_surface_get_format (a);
5240 if (format_a == CAIRO_FORMAT_RGB24)
5241 format_a = CAIRO_FORMAT_ARGB32;
5243 format_b = cairo_image_surface_get_format (b);
5244 if (format_b == CAIRO_FORMAT_RGB24)
5245 format_b = CAIRO_FORMAT_ARGB32;
5247 if (format_a != format_b)
5254 _set_source_image (csi_t *ctx)
5256 csi_status_t status;
5257 cairo_surface_t *surface;
5258 cairo_surface_t *source;
5262 status = _csi_ostack_get_surface (ctx, 0, &source);
5263 if (_csi_unlikely (status))
5265 status = _csi_ostack_get_surface (ctx, 1, &surface);
5266 if (_csi_unlikely (status))
5269 /* Catch the most frequent use of simply uploading pixel data,
5270 * principally to remove the pixman ops from the profiles.
5272 if (_csi_likely (_matching_images (surface, source))) {
5273 cairo_surface_flush (surface);
5274 memcpy (cairo_image_surface_get_data (surface),
5275 cairo_image_surface_get_data (source),
5276 cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
5277 cairo_surface_mark_dirty (surface);
5281 cr = cairo_create (surface);
5282 cairo_set_source_surface (cr, source, 0, 0);
5288 return CSI_STATUS_SUCCESS;
5292 _set_source_rgb (csi_t *ctx)
5294 csi_status_t status;
5300 status = _csi_ostack_get_number (ctx, 0, &b);
5301 if (_csi_unlikely (status))
5303 status = _csi_ostack_get_number (ctx, 1, &g);
5304 if (_csi_unlikely (status))
5306 status = _csi_ostack_get_number (ctx, 2, &r);
5307 if (_csi_unlikely (status))
5309 status = _csi_ostack_get_context (ctx, 3, &cr);
5310 if (_csi_unlikely (status))
5313 cairo_set_source_rgb (cr, r, g, b);
5315 return CSI_STATUS_SUCCESS;
5319 _set_source_rgba (csi_t *ctx)
5321 csi_status_t status;
5327 status = _csi_ostack_get_number (ctx, 0, &a);
5328 if (_csi_unlikely (status))
5330 status = _csi_ostack_get_number (ctx, 1, &b);
5331 if (_csi_unlikely (status))
5333 status = _csi_ostack_get_number (ctx, 2, &g);
5334 if (_csi_unlikely (status))
5336 status = _csi_ostack_get_number (ctx, 3, &r);
5337 if (_csi_unlikely (status))
5339 status = _csi_ostack_get_context (ctx, 4, &cr);
5340 if (_csi_unlikely (status))
5343 cairo_set_source_rgba (cr, r, g, b, a);
5345 return CSI_STATUS_SUCCESS;
5349 _set_tolerance (csi_t *ctx)
5351 csi_status_t status;
5357 status = _csi_ostack_get_number (ctx, 0, &tolerance);
5358 if (_csi_unlikely (status))
5360 status = _csi_ostack_get_context (ctx, 1, &cr);
5361 if (_csi_unlikely (status))
5364 cairo_set_tolerance (cr, tolerance);
5366 return CSI_STATUS_SUCCESS;
5370 _transform (csi_t *ctx)
5373 csi_status_t status;
5379 status = _csi_ostack_get_matrix (ctx, 0, &m);
5380 if (_csi_unlikely (status))
5383 obj = _csi_peek_ostack (ctx, 1);
5384 type = csi_object_get_type (obj);
5386 case CSI_OBJECT_TYPE_CONTEXT:
5387 cairo_transform (obj->datum.cr, &m);
5389 case CSI_OBJECT_TYPE_PATTERN:
5392 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5393 cairo_matrix_multiply (&ctm, &m, &ctm);
5394 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5397 case CSI_OBJECT_TYPE_MATRIX:
5398 cairo_matrix_multiply (&obj->datum.matrix->matrix,
5400 &obj->datum.matrix->matrix);
5403 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5407 return CSI_STATUS_SUCCESS;
5411 _translate (csi_t *ctx)
5414 csi_status_t status;
5420 status = _csi_ostack_get_number (ctx, 0, &y);
5421 if (_csi_unlikely (status))
5423 status = _csi_ostack_get_number (ctx, 1, &x);
5424 if (_csi_unlikely (status))
5427 obj = _csi_peek_ostack (ctx, 2);
5428 type = csi_object_get_type (obj);
5430 case CSI_OBJECT_TYPE_CONTEXT:
5431 cairo_translate (obj->datum.cr, x, y);
5434 case CSI_OBJECT_TYPE_PATTERN:
5437 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5438 cairo_matrix_translate (&ctm, x, y);
5439 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5444 case CSI_OBJECT_TYPE_MATRIX:
5445 cairo_matrix_translate (&obj->datum.matrix->matrix, x, y);
5449 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5453 return CSI_STATUS_SUCCESS;
5459 return _csi_push_ostack_boolean (ctx, TRUE);
5463 _show_page (csi_t *ctx)
5470 obj = _csi_peek_ostack (ctx, 0);
5471 type = csi_object_get_type (obj);
5473 case CSI_OBJECT_TYPE_CONTEXT:
5474 cairo_show_page (obj->datum.cr);
5475 if (ctx->hooks.copy_page != NULL)
5476 ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
5478 case CSI_OBJECT_TYPE_SURFACE:
5479 cairo_surface_show_page (obj->datum.surface);
5483 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5486 return CSI_STATUS_SUCCESS;
5490 _similar (csi_t *ctx)
5494 double width, height;
5495 cairo_surface_t *other;
5496 csi_status_t status;
5500 status = _csi_ostack_get_integer (ctx, 0, &content);
5501 if (_csi_unlikely (status))
5503 status = _csi_ostack_get_number (ctx, 1, &height);
5504 if (_csi_unlikely (status))
5506 status = _csi_ostack_get_number (ctx, 2, &width);
5507 if (_csi_unlikely (status))
5509 status = _csi_ostack_get_surface (ctx, 3, &other);
5510 if (_csi_unlikely (status))
5513 /* silently fix-up a common bug when writing CS */
5514 if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) {
5515 if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA))
5516 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5518 switch ((int) content) {
5520 case CAIRO_FORMAT_ARGB32:
5521 content = CAIRO_CONTENT_COLOR_ALPHA;
5523 case CAIRO_FORMAT_RGB16_565:
5524 case CAIRO_FORMAT_RGB24:
5525 content = CAIRO_CONTENT_COLOR;
5527 case CAIRO_FORMAT_A8:
5528 case CAIRO_FORMAT_A1:
5529 content = CAIRO_CONTENT_ALPHA;
5534 obj.type = CSI_OBJECT_TYPE_SURFACE;
5535 obj.datum.surface = cairo_surface_create_similar (other,
5536 content, width, height);
5542 _similar_image (csi_t *ctx)
5546 double width, height;
5547 cairo_surface_t *other;
5548 csi_status_t status;
5552 status = _csi_ostack_get_number (ctx, 0, &height);
5553 if (_csi_unlikely (status))
5555 status = _csi_ostack_get_number (ctx, 1, &width);
5556 if (_csi_unlikely (status))
5558 status = _csi_ostack_get_integer (ctx, 2, &format);
5559 if (_csi_unlikely (status))
5561 status = _csi_ostack_get_surface (ctx, 3, &other);
5562 if (_csi_unlikely (status))
5565 obj.type = CSI_OBJECT_TYPE_SURFACE;
5566 obj.datum.surface = cairo_surface_create_similar_image (other,
5574 _subsurface (csi_t *ctx)
5577 double x, y, width, height;
5578 cairo_surface_t *target;
5579 csi_status_t status;
5583 status = _csi_ostack_get_number (ctx, 0, &height);
5584 if (_csi_unlikely (status))
5586 status = _csi_ostack_get_number (ctx, 1, &width);
5587 if (_csi_unlikely (status))
5589 status = _csi_ostack_get_number (ctx, 2, &y);
5590 if (_csi_unlikely (status))
5592 status = _csi_ostack_get_number (ctx, 3, &x);
5593 if (_csi_unlikely (status))
5595 status = _csi_ostack_get_surface (ctx, 4, &target);
5596 if (_csi_unlikely (status))
5599 obj.type = CSI_OBJECT_TYPE_SURFACE;
5600 obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height);
5606 _show_text (csi_t *ctx)
5608 csi_status_t status;
5614 status = _csi_ostack_get_string (ctx, 0, &text);
5615 if (_csi_unlikely (status))
5617 status = _csi_ostack_get_context (ctx, 1, &cr);
5618 if (_csi_unlikely (status))
5621 cairo_show_text (cr, text->string);
5623 return CSI_STATUS_SUCCESS;
5627 _show_glyphs (csi_t *ctx)
5630 csi_status_t status;
5632 cairo_glyph_t stack_glyphs[256], *glyphs;
5633 csi_integer_t nglyphs, i;
5637 status = _csi_ostack_get_array (ctx, 0, &array);
5638 if (_csi_unlikely (status))
5640 status = _csi_ostack_get_context (ctx, 1, &cr);
5641 if (_csi_unlikely (status))
5646 for (i = 0; i < array->stack.len; i++) {
5647 csi_object_t *obj = &array->stack.objects[i];
5648 int type = csi_object_get_type (obj);
5650 case CSI_OBJECT_TYPE_ARRAY:
5651 nglyphs += obj->datum.array->stack.len;
5653 case CSI_OBJECT_TYPE_STRING:
5654 nglyphs += obj->datum.string->len;
5660 return CSI_STATUS_SUCCESS;
5663 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5664 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
5665 return _csi_error (CSI_STATUS_NO_MEMORY);
5667 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5668 if (_csi_unlikely (glyphs == NULL))
5669 return _csi_error (CSI_STATUS_NO_MEMORY);
5671 glyphs = stack_glyphs;
5673 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5674 cairo_show_glyphs (cr, glyphs, nglyphs);
5676 if (glyphs != stack_glyphs)
5677 _csi_free (ctx, glyphs);
5680 return CSI_STATUS_SUCCESS;
5684 _show_text_glyphs (csi_t *ctx)
5688 csi_string_t *string;
5689 csi_string_t *utf8_string;
5690 csi_status_t status;
5692 cairo_text_cluster_t stack_clusters[256], *clusters;
5693 cairo_glyph_t stack_glyphs[256], *glyphs;
5694 csi_integer_t nglyphs, nclusters, i;
5700 status = _csi_ostack_get_integer (ctx, 0, &direction);
5701 if (_csi_unlikely (status))
5704 obj = _csi_peek_ostack (ctx, 1);
5705 type = csi_object_get_type (obj);
5707 case CSI_OBJECT_TYPE_ARRAY:
5708 array = obj->datum.array;
5709 nclusters = array->stack.len / 2;
5710 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5711 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5712 return _csi_error (CSI_STATUS_NO_MEMORY);
5713 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5714 if (_csi_unlikely (clusters == NULL))
5715 return _csi_error (CSI_STATUS_NO_MEMORY);
5717 clusters = stack_clusters;
5719 for (i = 0; i < nclusters; i++) {
5720 clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]);
5721 clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]);
5725 case CSI_OBJECT_TYPE_STRING:
5726 string = obj->datum.string;
5727 nclusters = string->len / 2;
5728 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5729 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5730 return _csi_error (CSI_STATUS_NO_MEMORY);
5731 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5732 if (_csi_unlikely (clusters == NULL))
5733 return _csi_error (CSI_STATUS_NO_MEMORY);
5735 clusters = stack_clusters;
5737 for (i = 0; i < nclusters; i++) {
5738 clusters[i].num_bytes = string->string[2*i+0];
5739 clusters[i].num_glyphs = string->string[2*i+1];
5744 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5747 status = _csi_ostack_get_array (ctx, 2, &array);
5748 if (_csi_unlikely (status))
5750 status = _csi_ostack_get_string (ctx, 3, &utf8_string);
5751 if (_csi_unlikely (status))
5753 status = _csi_ostack_get_context (ctx, 4, &cr);
5754 if (_csi_unlikely (status))
5759 for (i = 0; i < array->stack.len; i++) {
5760 obj = &array->stack.objects[i];
5761 type = csi_object_get_type (obj);
5763 case CSI_OBJECT_TYPE_ARRAY:
5764 nglyphs += obj->datum.array->stack.len;
5766 case CSI_OBJECT_TYPE_STRING:
5767 nglyphs += obj->datum.string->len;
5773 return CSI_STATUS_SUCCESS;
5776 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5777 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
5778 return _csi_error (CSI_STATUS_NO_MEMORY);
5780 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5781 if (_csi_unlikely (glyphs == NULL))
5782 return _csi_error (CSI_STATUS_NO_MEMORY);
5784 glyphs = stack_glyphs;
5786 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5787 cairo_show_text_glyphs (cr,
5788 utf8_string->string, utf8_string->len,
5790 clusters, nclusters,
5793 if (clusters != stack_clusters)
5794 _csi_free (ctx, clusters);
5795 if (glyphs != stack_glyphs)
5796 _csi_free (ctx, glyphs);
5799 return CSI_STATUS_SUCCESS;
5803 _stroke (csi_t *ctx)
5805 return _do_cairo_op (ctx, cairo_stroke);
5809 _stroke_preserve (csi_t *ctx)
5811 return _do_cairo_op (ctx, cairo_stroke_preserve);
5819 csi_object_type_t type_a, type_b;
5823 B = _csi_peek_ostack (ctx, 0);
5824 A = _csi_peek_ostack (ctx, 1);
5826 type_a = csi_object_get_type (A);
5827 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
5828 type_a == CSI_OBJECT_TYPE_REAL)))
5830 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5833 type_b = csi_object_get_type (B);
5834 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
5835 type_b == CSI_OBJECT_TYPE_REAL)))
5837 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5842 if (type_a == CSI_OBJECT_TYPE_REAL &&
5843 type_b == CSI_OBJECT_TYPE_REAL)
5845 return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real);
5848 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
5849 type_b == CSI_OBJECT_TYPE_INTEGER)
5851 return _csi_push_ostack_integer (ctx,
5852 A->datum.integer - B->datum.integer);
5858 if (type_a == CSI_OBJECT_TYPE_REAL)
5861 v = A->datum.integer;
5863 if (type_b == CSI_OBJECT_TYPE_REAL)
5866 v -= B->datum.integer;
5868 return _csi_push_ostack_real (ctx, v);
5873 _surface (csi_t *ctx)
5876 csi_dictionary_t *dict;
5879 double width, height;
5880 csi_surface_create_func_t hook;
5882 cairo_surface_t *surface;
5884 csi_status_t status;
5888 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
5889 if (_csi_unlikely (status))
5892 status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width);
5893 if (_csi_unlikely (status))
5895 status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height);
5896 if (_csi_unlikely (status))
5899 content = CAIRO_CONTENT_COLOR_ALPHA;
5900 status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content);
5901 if (_csi_unlikely (status))
5905 status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid);
5906 if (_csi_unlikely (status))
5909 status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid);
5910 if (_csi_unlikely (status))
5914 hook = ctx->hooks.surface_create;
5915 assert (hook != NULL);
5917 surface = hook (ctx->hooks.closure, content, width, height, uid);
5918 if (_csi_unlikely (surface == NULL)) {
5919 return _csi_error (CSI_STATUS_NULL_POINTER);
5922 proxy = _csi_proxy_create (ctx, surface, dict,
5923 ctx->hooks.surface_destroy,
5924 ctx->hooks.closure);
5925 if (_csi_unlikely (proxy == NULL)) {
5926 cairo_surface_destroy (surface);
5927 return _csi_error (CSI_STATUS_NO_MEMORY);
5930 status = cairo_surface_set_user_data (surface,
5932 proxy, _csi_proxy_destroy);
5933 if (_csi_unlikely (status)) {
5934 _csi_proxy_destroy (proxy);
5935 cairo_surface_destroy (surface);
5939 status = csi_name_new_static (ctx, &key, "fallback-resolution");
5940 if (_csi_unlikely (status)) {
5941 cairo_surface_destroy (surface);
5944 if (csi_dictionary_has (dict, key.datum.name)) {
5945 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
5946 if (_csi_unlikely (status)) {
5947 cairo_surface_destroy (surface);
5950 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
5951 csi_array_t *array = obj.datum.array;
5952 if (array->stack.len == 2) {
5953 cairo_surface_set_fallback_resolution (surface,
5954 csi_number_get_value
5955 (&array->stack.objects[0]),
5956 csi_number_get_value
5957 (&array->stack.objects[1]));
5961 /* initialise surface to source */
5962 status = csi_name_new_static (ctx, &key, "source");
5963 if (_csi_unlikely (status)) {
5964 cairo_surface_destroy (surface);
5967 if (csi_dictionary_has (dict, key.datum.name)) {
5968 cairo_surface_t *image;
5971 status = _image_load_from_dictionary (ctx, dict, &image);
5972 if (_csi_unlikely (status)) {
5973 cairo_surface_destroy (surface);
5977 cr = cairo_create (surface);
5978 cairo_set_source_surface (cr, image, 0, 0);
5979 cairo_surface_destroy (image);
5981 status = cairo_status (cr);
5984 if (_csi_unlikely (status))
5988 status = csi_name_new_static (ctx, &key, "device-offset");
5989 if (_csi_unlikely (status)) {
5990 cairo_surface_destroy (surface);
5993 if (csi_dictionary_has (dict, key.datum.name)) {
5994 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
5995 if (_csi_unlikely (status))
5998 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
5999 csi_array_t *array = obj.datum.array;
6001 if (array->stack.len == 2) {
6002 cairo_surface_set_device_offset (surface,
6003 csi_number_get_value
6004 (&array->stack.objects[0]),
6005 csi_number_get_value
6006 (&array->stack.objects[1]));
6011 obj.type = CSI_OBJECT_TYPE_SURFACE;
6012 obj.datum.surface = surface;
6018 _record (csi_t *ctx)
6023 csi_status_t status;
6024 cairo_rectangle_t extents;
6025 cairo_rectangle_t *r;
6029 status = _csi_ostack_get_array (ctx, 0, &array);
6030 if (_csi_unlikely (status))
6033 status = _csi_ostack_get_integer (ctx, 1, &content);
6034 if (_csi_unlikely (status))
6037 switch (array->stack.len) {
6042 extents.x = extents.y = 0;
6043 extents.width = _csi_object_as_real (&array->stack.objects[0]);
6044 extents.height = _csi_object_as_real (&array->stack.objects[1]);
6048 extents.x = _csi_object_as_real (&array->stack.objects[0]);
6049 extents.y = _csi_object_as_real (&array->stack.objects[1]);
6050 extents.width = _csi_object_as_real (&array->stack.objects[2]);
6051 extents.height = _csi_object_as_real (&array->stack.objects[3]);
6055 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6058 obj.type = CSI_OBJECT_TYPE_SURFACE;
6059 obj.datum.surface = cairo_recording_surface_create (content, r);
6065 _text_path (csi_t *ctx)
6067 csi_status_t status;
6073 status = _csi_ostack_get_string (ctx, 0, &text);
6074 if (_csi_unlikely (status))
6076 status = _csi_ostack_get_context (ctx, 1, &cr);
6077 if (_csi_unlikely (status))
6080 cairo_text_path (cr, text->string);
6082 return CSI_STATUS_SUCCESS;
6088 csi_name_t name = 0; /* silence the compiler */
6089 csi_status_t status;
6093 status = _csi_ostack_get_name (ctx, 0, &name);
6094 if (_csi_unlikely (status))
6097 status = _csi_name_undefine (ctx, name);
6098 if (_csi_unlikely (status))
6102 return CSI_STATUS_SUCCESS;
6109 csi_name_t name = 0; /* silence the compiler */
6110 csi_status_t status;
6115 status = _csi_ostack_get_name (ctx, 0, &name);
6116 if (_csi_unlikely (status))
6119 dst = _csi_peek_ostack (ctx, 1);
6120 type = csi_object_get_type (dst);
6122 case CSI_OBJECT_TYPE_DICTIONARY:
6123 csi_dictionary_remove (ctx, dst->datum.dictionary, name);
6125 case CSI_OBJECT_TYPE_STRING:
6126 case CSI_OBJECT_TYPE_ARRAY:
6128 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6132 return CSI_STATUS_SUCCESS;
6136 _write_to_png (csi_t *ctx)
6138 csi_status_t status;
6139 csi_string_t *filename;
6140 cairo_surface_t *surface;
6144 status = _csi_ostack_get_string (ctx, 0, &filename);
6145 if (_csi_unlikely (status))
6147 status = _csi_ostack_get_surface (ctx, 1, &surface);
6148 if (_csi_unlikely (status))
6151 #if CAIRO_HAS_PNG_FUNCTIONS
6152 status = cairo_surface_write_to_png (surface, filename->string);
6153 if (_csi_unlikely (status))
6156 return CAIRO_STATUS_WRITE_ERROR;
6160 return CSI_STATUS_SUCCESS;
6164 _write_to_script (csi_t *ctx)
6166 csi_status_t status;
6167 csi_string_t *filename;
6168 cairo_surface_t *record;
6172 status = _csi_ostack_get_string (ctx, 0, &filename);
6173 if (_csi_unlikely (status))
6175 status = _csi_ostack_get_surface (ctx, 1, &record);
6176 if (_csi_unlikely (status))
6179 if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING)
6180 return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
6182 #if CAIRO_HAS_SCRIPT_SURFACE
6184 cairo_device_t *script;
6186 script = cairo_script_create (filename->string);
6187 status = cairo_script_from_recording_surface (script, record);
6188 cairo_device_destroy (script);
6189 if (_csi_unlikely (status))
6193 return CAIRO_STATUS_WRITE_ERROR;
6197 return CSI_STATUS_SUCCESS;
6203 csi_object_t *a, *b;
6208 a = _csi_peek_ostack (ctx, 0);
6209 b = _csi_peek_ostack (ctx, 1);
6210 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
6211 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6214 type = csi_object_get_type (a);
6216 case CSI_OBJECT_TYPE_INTEGER:
6217 return _csi_push_ostack_integer (ctx,
6218 a->datum.integer ^ b->datum.integer);
6219 case CSI_OBJECT_TYPE_BOOLEAN:
6220 return _csi_push_ostack_boolean (ctx,
6221 a->datum.boolean ^ b->datum.boolean);
6223 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6228 _debug_print (csi_t *ctx)
6233 obj = _csi_peek_ostack (ctx, 0);
6234 switch (csi_object_get_type (obj)) {
6235 case CSI_OBJECT_TYPE_NULL:
6236 fprintf (stderr, "NULL\n");
6240 case CSI_OBJECT_TYPE_BOOLEAN:
6241 fprintf (stderr, "boolean: %s\n",
6242 obj->datum.boolean ? "true" : "false");
6244 case CSI_OBJECT_TYPE_INTEGER:
6245 fprintf (stderr, "integer: %ld\n", obj->datum.integer);
6247 case CSI_OBJECT_TYPE_MARK:
6248 fprintf (stderr, "mark\n");
6250 case CSI_OBJECT_TYPE_NAME:
6251 fprintf (stderr, "name: %s\n", (char *) obj->datum.name);
6253 case CSI_OBJECT_TYPE_OPERATOR:
6254 fprintf (stderr, "operator: %p\n", obj->datum.ptr);
6256 case CSI_OBJECT_TYPE_REAL:
6257 fprintf (stderr, "real: %g\n", obj->datum.real);
6261 case CSI_OBJECT_TYPE_ARRAY:
6262 fprintf (stderr, "array\n");
6264 case CSI_OBJECT_TYPE_DICTIONARY:
6265 fprintf (stderr, "dictionary\n");
6267 case CSI_OBJECT_TYPE_FILE:
6268 fprintf (stderr, "file\n");
6270 case CSI_OBJECT_TYPE_MATRIX:
6271 fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n",
6272 obj->datum.matrix->matrix.xx,
6273 obj->datum.matrix->matrix.yx,
6274 obj->datum.matrix->matrix.xy,
6275 obj->datum.matrix->matrix.yy,
6276 obj->datum.matrix->matrix.x0,
6277 obj->datum.matrix->matrix.y0);
6279 case CSI_OBJECT_TYPE_STRING:
6280 fprintf (stderr, "string: %s\n", obj->datum.string->string);
6284 case CSI_OBJECT_TYPE_CONTEXT:
6285 fprintf (stderr, "context\n");
6287 case CSI_OBJECT_TYPE_FONT:
6288 fprintf (stderr, "font\n");
6290 case CSI_OBJECT_TYPE_PATTERN:
6291 fprintf (stderr, "pattern\n");
6293 case CSI_OBJECT_TYPE_SCALED_FONT:
6294 fprintf (stderr, "scaled-font\n");
6296 case CSI_OBJECT_TYPE_SURFACE:
6297 fprintf (stderr, "surface\n");
6301 return CSI_STATUS_SUCCESS;
6304 static const csi_operator_def_t
6307 { ">>", end_dict_construction },
6309 { "]", end_array_construction },
6313 { "add-color-stop", _add_color_stop },
6316 { "arc-negative", _arc_negative },
6317 { "arc-", _arc_negative },
6319 { "array", _array },
6323 { "bitshift", _bitshift },
6325 { "C", _rel_curve_to },
6326 { "ceiling", NULL },
6328 { "clear-to-mark", NULL },
6330 { "clip-extents", NULL },
6331 { "clip-preserve", _clip_preserve },
6332 { "clip+", _clip_preserve },
6333 { "close-path", _close_path },
6334 { "context", _context },
6336 { "copy-page", _copy_page },
6339 { "count-to-mark", NULL },
6340 { "curve-to", _curve_to },
6344 { "device-to-user", NULL },
6345 { "device-to-user-distance", NULL },
6348 { "dup", _duplicate },
6353 { "false", _false },
6355 { "fill-extents", NULL },
6356 { "fill-preserve", _fill_preserve },
6357 { "fill+", _fill_preserve },
6358 { "filter", _filter },
6366 { "glyph-path", _glyph_path },
6368 { "h", _close_path },
6369 { "identity", _identity },
6371 { "ifelse", _ifelse },
6372 { "image", _image },
6373 { "index", _index },
6374 { "integer", _integer },
6375 { "invert", _invert },
6376 { "in-stroke", NULL },
6377 { "in-fill", NULL },
6380 { "L", _rel_line_to },
6381 { "languagelevel", NULL },
6384 { "linear", _linear },
6385 { "line-to", _line_to },
6392 { "M", _rel_move_to },
6393 { "map-to-image", _map_to_image },
6396 { "matrix", _matrix },
6399 { "begin-patch", _mesh_begin_patch },
6400 { "end-patch", _mesh_end_patch },
6401 { "set-control-point", _mesh_set_control_point },
6402 { "set-corner-color", _mesh_set_corner_color },
6405 { "move-to", _move_to },
6407 { "multiply", NULL },
6409 { "N", _new_sub_path },
6412 { "new-path", _new_path },
6413 { "new-sub-path", _new_sub_path },
6417 { "paint", _paint },
6418 { "paint-with-alpha", _paint_with_alpha },
6419 { "pattern", _pattern },
6421 { "pop-group", _pop_group },
6422 { "push-group", _push_group },
6423 { "radial", _radial },
6425 { "record", _record },
6426 { "rectangle", _rectangle },
6427 { "repeat", _repeat },
6428 { "restore", _restore },
6429 { "rel-curve-to", _rel_curve_to },
6430 { "rel-line-to", _rel_line_to },
6431 { "rel-move-to", _rel_move_to },
6432 { "reset-clip", _reset_clip },
6436 { "rotate", _rotate },
6440 { "scale", _scale },
6441 { "scaled-font", _scaled_font },
6442 { "select-font-face", _select_font_face },
6444 { "set-antialias", _set_antialias },
6445 { "set-dash", _set_dash },
6446 { "set-device-offset", _set_device_offset },
6447 { "set-extend", _set_extend },
6448 { "set-fallback-resolution", _set_fallback_resolution },
6449 { "set-fill-rule", _set_fill_rule },
6450 { "set-filter", _set_filter },
6451 { "set-font-face", _set_font_face },
6452 { "set-font-options", _set_font_options },
6453 { "set-font-matrix", _set_font_matrix },
6454 { "set-font-size", _set_font_size },
6455 { "set-line-cap", _set_line_cap },
6456 { "set-line-join", _set_line_join },
6457 { "set-line-width", _set_line_width },
6458 { "set-matrix", _set_matrix },
6459 { "set-miter-limit", _set_miter_limit },
6460 { "set-mime-data", _set_mime_data },
6461 { "set-operator", _set_operator },
6462 { "set-scaled-font", _set_scaled_font },
6463 { "set-source", _set_source },
6464 { "set-source-image", _set_source_image },
6465 { "set-source-rgb", _set_source_rgb },
6466 { "set-source-rgba", _set_source_rgba },
6467 { "set-tolerance", _set_tolerance },
6468 { "show-glyphs", _show_glyphs },
6469 { "show-text", _show_text },
6470 { "show-text-glyphs", _show_text_glyphs },
6471 { "show-page", _show_page },
6472 { "similar", _similar },
6473 { "similar-image", _similar_image },
6477 { "subsurface", _subsurface },
6478 { "surface", _surface },
6480 { "stroke", _stroke },
6481 { "stroke-extents", NULL },
6482 { "stroke-preserve", _stroke_preserve },
6483 { "stroke+", _stroke_preserve },
6484 { "text-path", _text_path },
6485 { "transform", _transform },
6486 { "transform-distance", NULL },
6487 { "transform-point", NULL },
6488 { "translate", _translate },
6491 { "undef", _undef },
6492 { "unmap-image", _unmap_image },
6493 { "unset", _unset },
6494 { "user-to-device", NULL },
6495 { "user-to-device-distance", NULL },
6497 { "write-to-png", _write_to_png },
6498 { "write-to-script", _write_to_script },
6501 { "=", _debug_print },
6506 const csi_operator_def_t *
6507 _csi_operators (void)
6512 static const csi_integer_constant_def_t
6513 _integer_constants[] = {
6514 { "CLEAR", CAIRO_OPERATOR_CLEAR },
6515 { "SOURCE", CAIRO_OPERATOR_SOURCE },
6516 { "OVER", CAIRO_OPERATOR_OVER },
6517 { "IN", CAIRO_OPERATOR_IN },
6518 { "OUT", CAIRO_OPERATOR_OUT },
6519 { "ATOP", CAIRO_OPERATOR_ATOP },
6520 { "DEST", CAIRO_OPERATOR_DEST },
6521 { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER },
6522 { "DEST_IN", CAIRO_OPERATOR_DEST_IN },
6523 { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT },
6524 { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP },
6525 { "XOR", CAIRO_OPERATOR_XOR },
6526 { "ADD", CAIRO_OPERATOR_ADD },
6527 { "SATURATE", CAIRO_OPERATOR_SATURATE },
6528 { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY },
6529 { "SCREEN", CAIRO_OPERATOR_SCREEN },
6530 { "OVERLAY", CAIRO_OPERATOR_OVERLAY },
6531 { "DARKEN", CAIRO_OPERATOR_DARKEN },
6532 { "LIGHTEN", CAIRO_OPERATOR_LIGHTEN },
6533 { "DODGE", CAIRO_OPERATOR_COLOR_DODGE },
6534 { "BURN", CAIRO_OPERATOR_COLOR_BURN },
6535 { "HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT },
6536 { "SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT },
6537 { "DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE },
6538 { "EXCLUSION", CAIRO_OPERATOR_EXCLUSION },
6539 { "HSL_HUE", CAIRO_OPERATOR_HSL_HUE },
6540 { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION },
6541 { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR },
6542 { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY },
6544 { "WINDING", CAIRO_FILL_RULE_WINDING },
6545 { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD },
6547 { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT },
6548 { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE },
6549 { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY },
6550 { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL },
6551 { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST },
6552 { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD },
6553 { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST },
6555 { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT },
6556 { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND },
6557 { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE },
6559 { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER },
6560 { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND },
6561 { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL },
6563 { "EXTEND_NONE", CAIRO_EXTEND_NONE },
6564 { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT },
6565 { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT },
6566 { "EXTEND_PAD", CAIRO_EXTEND_PAD },
6568 { "FILTER_FAST", CAIRO_FILTER_FAST },
6569 { "FILTER_GOOD", CAIRO_FILTER_GOOD },
6570 { "FILTER_BEST", CAIRO_FILTER_BEST },
6571 { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR },
6572 { "FILTER_NEAREST", CAIRO_FILTER_NEAREST },
6573 { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN },
6575 { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL },
6576 { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC },
6577 { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE },
6579 { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL },
6580 { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD },
6582 { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT },
6583 { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB },
6584 { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR },
6585 { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB },
6586 { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR },
6588 { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT },
6589 { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE },
6590 { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT },
6591 { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM },
6592 { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL },
6594 { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT },
6595 { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF },
6596 { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON },
6601 { "COLOR", CAIRO_CONTENT_COLOR },
6602 { "ALPHA", CAIRO_CONTENT_ALPHA },
6603 { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA },
6605 { "A1", CAIRO_FORMAT_A1 },
6606 { "A8", CAIRO_FORMAT_A8 },
6607 { "RGB16_565", CAIRO_FORMAT_RGB16_565 },
6608 { "RGB24", CAIRO_FORMAT_RGB24 },
6609 { "ARGB32", CAIRO_FORMAT_ARGB32 },
6610 { "INVALID", CAIRO_FORMAT_INVALID },
6616 const csi_integer_constant_def_t *
6617 _csi_integer_constants (void)
6619 return _integer_constants;
6622 static const csi_real_constant_def_t
6623 _real_constants[] = {
6624 { "math.pi", M_PI },
6625 { "math.2pi", 2 * M_PI },
6626 { "math.sqrt2", M_SQRT2 },
6627 { "math.ln2", M_LN2 },
6632 const csi_real_constant_def_t *
6633 _csi_real_constants (void)
6635 return _real_constants;