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);
1926 if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) {
1927 /* prior to 1.9, you needed to pass a resolved pattern */
1928 resolved = FcFontMatch (NULL, pattern, NULL);
1929 if (_csi_unlikely (resolved == NULL)) {
1930 FcPatternDestroy (pattern);
1931 return _csi_error (CSI_STATUS_NO_MEMORY);
1935 font_face = cairo_ft_font_face_create_for_pattern (resolved);
1936 FcPatternDestroy (resolved);
1937 if (resolved != pattern)
1938 FcPatternDestroy (pattern);
1940 data = _csi_slab_alloc (ctx, sizeof (*data));
1941 ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
1942 data->ctx = cairo_script_interpreter_reference (ctx);
1943 data->blob.hash = tmpl.hash;
1944 data->blob.len = tmpl.len;
1948 vec.bytes = tmpl.bytes;
1949 vec.num_bytes = tmpl.len;
1950 data->blob.bytes = _mmap_bytes (&vec, 1);
1951 if (data->blob.bytes != MAP_FAILED) {
1952 data->source = NULL;
1953 if (--string->base.ref == 0)
1954 csi_string_free (ctx, string);
1956 data->blob.bytes = tmpl.bytes;
1957 data->source = string;
1960 data->blob.bytes = tmpl.bytes;
1961 data->source = string;
1964 status = cairo_font_face_set_user_data (font_face,
1966 data, _ft_done_face);
1967 if (_csi_unlikely (status)) {
1968 _ft_done_face (data);
1969 cairo_font_face_destroy (font_face);
1973 data->font_face = font_face;
1974 *font_face_out = font_face;
1975 return CSI_STATUS_SUCCESS;
1977 if (--string->base.ref == 0)
1978 csi_string_free (ctx, string);
1979 return CSI_INT_STATUS_UNSUPPORTED;
1984 _ft_type42_create (csi_t *ctx,
1985 csi_dictionary_t *font,
1986 cairo_font_face_t **font_face_out)
1989 csi_status_t status;
1991 /* two basic sub-types, either an FcPattern or embedded font */
1992 status = csi_name_new_static (ctx, &key, "pattern");
1993 if (_csi_unlikely (status))
1996 if (csi_dictionary_has (font, key.datum.name)) {
2000 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2001 if (_csi_unlikely (status))
2004 type = csi_object_get_type (&obj);
2006 case CSI_OBJECT_TYPE_FILE:
2007 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2008 if (_csi_unlikely (status))
2011 case CSI_OBJECT_TYPE_STRING:
2012 obj.datum.object->ref++;
2015 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2018 return _ft_create_for_pattern (ctx,
2023 status = csi_name_new_static (ctx, &key, "source");
2024 if (_csi_unlikely (status))
2027 if (csi_dictionary_has (font, key.datum.name)) {
2033 status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index);
2034 if (_csi_unlikely (status))
2038 status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags);
2039 if (_csi_unlikely (status))
2042 status = csi_name_new_static (ctx, &key, "source");
2043 if (_csi_unlikely (status))
2045 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2046 if (_csi_unlikely (status))
2048 type = csi_object_get_type (&obj);
2050 case CSI_OBJECT_TYPE_FILE:
2051 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2052 if (_csi_unlikely (status))
2055 case CSI_OBJECT_TYPE_STRING:
2056 obj.datum.object->ref++;
2059 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2062 return _ft_create_for_source (ctx, obj.datum.string,
2067 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2070 #define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED
2074 _fc_strcpy (csi_t *ctx, const char *str)
2079 ret = strchr (str, ':');
2085 ret = _csi_alloc (ctx, len+1);
2086 if (_csi_unlikely (ret == NULL))
2089 memcpy (ret, str, len);
2095 static cairo_font_face_t *
2096 _select_font (const char *name)
2098 cairo_surface_t *surface;
2099 cairo_font_face_t *face;
2102 /* create a dummy context to choose a font */
2103 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
2104 cr = cairo_create (surface);
2105 cairo_surface_destroy (surface);
2107 cairo_select_font_face (cr, name,
2108 CAIRO_FONT_SLANT_NORMAL,
2109 CAIRO_FONT_WEIGHT_NORMAL);
2110 face = cairo_font_face_reference (cairo_get_font_face (cr));
2117 _ft_fallback_create_for_pattern (csi_t *ctx,
2118 csi_string_t *string,
2119 cairo_font_face_t **font_face_out)
2123 str = string->string;
2125 name = strstr (str, "fullname=");
2130 name = _fc_strcpy (ctx, str);
2131 if (_csi_unlikely (name == NULL))
2132 return _csi_error (CSI_STATUS_NO_MEMORY);
2134 *font_face_out = _select_font (name);
2135 _csi_free (ctx, name);
2137 return CSI_STATUS_SUCCESS;
2141 _ft_type42_fallback_create (csi_t *ctx,
2142 csi_dictionary_t *font,
2143 cairo_font_face_t **font_face_out)
2146 csi_status_t status;
2148 /* attempt to select a similar font */
2150 /* two basic sub-types, either an FcPattern or embedded font */
2151 status = csi_name_new_static (ctx, &key, "pattern");
2152 if (_csi_unlikely (status))
2155 if (csi_dictionary_has (font, key.datum.name)) {
2159 status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
2160 if (_csi_unlikely (status))
2163 type = csi_object_get_type (&obj);
2165 case CSI_OBJECT_TYPE_FILE:
2166 status = _csi_file_as_string (ctx, obj.datum.file, &obj);
2167 if (_csi_unlikely (status))
2170 case CSI_OBJECT_TYPE_STRING:
2171 obj.datum.object->ref++;
2174 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2177 return _ft_fallback_create_for_pattern (ctx,
2182 /* XXX: enable the trace to run */
2183 *font_face_out = _select_font ("Sans");
2184 return CSI_STATUS_SUCCESS;
2188 _font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face)
2190 csi_status_t status;
2192 status = _ft_type42_create (ctx, font, font_face);
2193 if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED))
2196 return _ft_type42_fallback_create (ctx, font, font_face);
2202 csi_dictionary_t *font;
2203 csi_status_t status;
2204 cairo_font_face_t *font_face = NULL; /* silence the compiler */
2211 status = _csi_ostack_get_dictionary (ctx, 0, &font);
2212 if (_csi_unlikely (status))
2215 status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type);
2216 if (_csi_unlikely (status))
2221 status = _font_type3 (ctx, font, &font_face);
2224 status = _font_type42 (ctx, font, &font_face);
2227 status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
2231 if (_csi_unlikely (status))
2234 /* transfer ownership of dictionary to cairo_font_face_t */
2235 proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL);
2236 if (_csi_unlikely (proxy == NULL)) {
2237 cairo_font_face_destroy (font_face);
2238 return _csi_error (CSI_STATUS_NO_MEMORY);
2241 status = cairo_font_face_set_user_data (font_face,
2243 proxy, _csi_proxy_destroy);
2244 if (_csi_unlikely (status)) {
2245 _csi_proxy_destroy (proxy);
2246 cairo_font_face_destroy (font_face);
2250 obj.type = CSI_OBJECT_TYPE_FONT;
2251 obj.datum.font_face = font_face;
2254 status = push (&obj);
2255 if (_csi_unlikely (status)) {
2256 cairo_font_face_destroy (font_face);
2260 return CSI_STATUS_SUCCESS;
2267 csi_status_t status;
2272 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2273 if (_csi_unlikely (status))
2275 status = _csi_ostack_get_integer (ctx, 1, &limit);
2276 if (_csi_unlikely (status))
2278 status = _csi_ostack_get_integer (ctx, 2, &inc);
2279 if (_csi_unlikely (status))
2281 status = _csi_ostack_get_integer (ctx, 3, &i);
2282 if (_csi_unlikely (status))
2288 for (; i <= limit; i += inc) {
2289 status = _csi_push_ostack_integer (ctx, i);
2290 if (_csi_unlikely (status))
2293 status = _csi_array_execute (ctx, proc);
2294 if (_csi_unlikely (status))
2298 if (--proc->base.ref == 0)
2299 csi_array_free (ctx, proc);
2306 csi_status_t status;
2307 csi_object_t *a, *b;
2312 b = _csi_peek_ostack (ctx, 0);
2313 a = _csi_peek_ostack (ctx, 1);
2315 status = csi_object_compare (a, b, &cmp);
2316 if (_csi_unlikely (status))
2320 return _csi_push_ostack_boolean (ctx, cmp >= 0);
2324 _proxy_get (csi_proxy_t *proxy,
2328 csi_status_t status;
2330 if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL))
2331 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2333 status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj);
2334 if (_csi_unlikely (status))
2337 return _csi_push_ostack_copy (proxy->ctx, &obj);
2341 _context_get (csi_t *ctx,
2345 csi_status_t status;
2348 if (strcmp ((char *) key, "current-point") == 0) {
2351 cairo_get_current_point (cr, &x, &y);
2353 status = _csi_push_ostack_real (ctx, x);
2354 if (_csi_unlikely (status))
2356 status = _csi_push_ostack_real (ctx, y);
2357 if (_csi_unlikely (status))
2360 return CSI_STATUS_SUCCESS;
2361 } else if (strcmp ((char *) key, "source") == 0) {
2362 obj.type = CSI_OBJECT_TYPE_PATTERN;
2363 obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr));
2364 } else if (strcmp ((char *) key, "target") == 0) {
2365 obj.type = CSI_OBJECT_TYPE_SURFACE;
2366 obj.datum.surface = cairo_surface_reference (cairo_get_target (cr));
2367 } else if (strcmp ((char *) key, "group-target") == 0) {
2368 obj.type = CSI_OBJECT_TYPE_SURFACE;
2369 obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr));
2370 } else if (strcmp ((char *) key, "scaled-font") == 0) {
2371 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
2372 obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr));
2373 } else if (strcmp ((char *) key, "font-face") == 0) {
2374 obj.type = CSI_OBJECT_TYPE_FONT;
2375 obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr));
2377 return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key);
2383 _font_get (csi_t *ctx,
2384 cairo_font_face_t *font_face,
2387 return _proxy_get (cairo_font_face_get_user_data (font_face,
2393 _pattern_get (csi_t *ctx,
2394 cairo_pattern_t *pattern,
2397 csi_status_t status;
2399 if (strcmp ((char *) key, "type") == 0)
2400 return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern));
2402 if (strcmp ((char *) key, "filter") == 0)
2403 return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern));
2405 if (strcmp ((char *) key, "extend") == 0)
2406 return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern));
2408 if (strcmp ((char *) key, "matrix") == 0) {
2412 cairo_pattern_get_matrix (pattern, &m);
2413 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
2414 if (_csi_unlikely (status))
2420 return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key),
2425 _scaled_font_get (csi_t *ctx,
2426 cairo_scaled_font_t *font,
2429 return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key),
2434 _surface_get (csi_t *ctx,
2435 cairo_surface_t *surface,
2438 if (strcmp ((char *) key, "type") == 0) {
2439 return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface));
2442 if (strcmp ((char *) key, "content") == 0) {
2443 return _csi_push_ostack_integer (ctx,
2444 cairo_surface_get_content (surface));
2447 return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key),
2454 csi_object_t *key, *src, obj;
2455 csi_status_t status;
2460 key = _csi_peek_ostack (ctx, 0);
2461 src = _csi_peek_ostack (ctx, 1);
2463 type = csi_object_get_type (src);
2465 case CSI_OBJECT_TYPE_DICTIONARY:
2466 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2467 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2469 status = csi_dictionary_get (ctx,
2470 src->datum.dictionary,
2474 case CSI_OBJECT_TYPE_ARRAY:
2475 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER))
2476 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2478 status = csi_array_get (ctx,
2484 case CSI_OBJECT_TYPE_STRING:
2485 status = csi_string_get (src, key, &obj);
2489 case CSI_OBJECT_TYPE_CONTEXT:
2490 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2491 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2492 return _context_get (ctx, src->datum.cr, key->datum.name);
2494 case CSI_OBJECT_TYPE_FONT:
2495 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2496 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2497 return _font_get (ctx, src->datum.font_face, key->datum.name);
2499 case CSI_OBJECT_TYPE_PATTERN:
2500 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2501 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2502 return _pattern_get (ctx, src->datum.pattern, key->datum.name);
2504 case CSI_OBJECT_TYPE_SCALED_FONT:
2505 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2506 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2507 return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name);
2509 case CSI_OBJECT_TYPE_SURFACE:
2510 if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME))
2511 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2512 return _surface_get (ctx, src->datum.surface, key->datum.name);
2515 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2518 if (_csi_unlikely (status))
2521 return _csi_push_ostack_copy (ctx, &obj);
2524 struct glyph_advance_cache {
2526 double glyph_advance[256][2];
2527 unsigned long have_glyph_advance[256];
2531 glyph_advance_cache_destroy (void *closure)
2533 struct glyph_advance_cache *cache = closure;
2534 _csi_free (cache->ctx, cache);
2538 _glyph_string (csi_t *ctx,
2540 cairo_scaled_font_t *scaled_font,
2541 cairo_glyph_t *glyphs)
2543 struct glyph_advance_cache uncached;
2544 struct glyph_advance_cache *cache;
2545 csi_integer_t nglyphs, i, j;
2547 cairo_status_t status;
2549 if (cairo_scaled_font_status (scaled_font))
2552 cache = cairo_scaled_font_get_user_data (scaled_font,
2553 (cairo_user_data_key_t *) ctx);
2554 if (cache == NULL) {
2555 cache = _csi_alloc (ctx, sizeof (*cache));
2556 if (_csi_likely (cache != NULL)) {
2558 memset (cache->have_glyph_advance, 0xff,
2559 sizeof (cache->have_glyph_advance));
2561 status = cairo_scaled_font_set_user_data (scaled_font,
2562 (cairo_user_data_key_t *) ctx,
2564 glyph_advance_cache_destroy);
2565 if (_csi_unlikely (status)) {
2566 _csi_free (ctx, cache);
2572 if (_csi_unlikely (cache == NULL)) {
2576 memset (cache->have_glyph_advance, 0xff,
2577 sizeof (cache->have_glyph_advance));
2582 for (i = 0; i < array->stack.len; i++) {
2583 const csi_object_t *obj = &array->stack.objects[i];
2584 int type = csi_object_get_type (obj);
2587 case CSI_OBJECT_TYPE_ARRAY: {
2588 const csi_array_t *glyph_array = obj->datum.array;
2589 for (j = 0; j < glyph_array->stack.len; j++) {
2593 obj = &glyph_array->stack.objects[j];
2594 if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
2596 g = obj->datum.integer;
2598 glyphs[nglyphs].index = g;
2599 glyphs[nglyphs].x = x;
2600 glyphs[nglyphs].y = y;
2602 gi = g % ARRAY_LENGTH (cache->have_glyph_advance);
2603 if (cache->have_glyph_advance[gi] != g) {
2604 cairo_text_extents_t extents;
2606 cairo_scaled_font_glyph_extents (scaled_font,
2607 &glyphs[nglyphs], 1,
2610 cache->glyph_advance[gi][0] = extents.x_advance;
2611 cache->glyph_advance[gi][1] = extents.y_advance;
2612 cache->have_glyph_advance[gi] = g;
2615 x += cache->glyph_advance[gi][0];
2616 y += cache->glyph_advance[gi][1];
2622 case CSI_OBJECT_TYPE_STRING: {
2623 const csi_string_t *glyph_string = obj->datum.string;
2624 for (j = 0; j < glyph_string->len; j++) {
2627 g = glyph_string->string[j];
2628 glyphs[nglyphs].index = g;
2629 glyphs[nglyphs].x = x;
2630 glyphs[nglyphs].y = y;
2632 if (cache->have_glyph_advance[g] != g) {
2633 cairo_text_extents_t extents;
2635 cairo_scaled_font_glyph_extents (scaled_font,
2636 &glyphs[nglyphs], 1,
2639 cache->glyph_advance[g][0] = extents.x_advance;
2640 cache->glyph_advance[g][1] = extents.y_advance;
2641 cache->have_glyph_advance[g] = g;
2644 x += cache->glyph_advance[g][0];
2645 y += cache->glyph_advance[g][1];
2651 case CSI_OBJECT_TYPE_INTEGER:
2652 case CSI_OBJECT_TYPE_REAL: /* dx or x*/
2653 dx = csi_number_get_value (obj);
2654 if (i+1 == array->stack.len)
2657 type = csi_object_get_type (&array->stack.objects[i+1]);
2659 case CSI_OBJECT_TYPE_INTEGER:
2660 case CSI_OBJECT_TYPE_REAL: /* y */
2661 y = csi_number_get_value (&array->stack.objects[i+1]);
2676 _glyph_path (csi_t *ctx)
2679 csi_status_t status;
2681 cairo_glyph_t stack_glyphs[256], *glyphs;
2682 csi_integer_t nglyphs, i;
2686 status = _csi_ostack_get_array (ctx, 0, &array);
2687 if (_csi_unlikely (status))
2689 status = _csi_ostack_get_context (ctx, 1, &cr);
2690 if (_csi_unlikely (status))
2695 for (i = 0; i < array->stack.len; i++) {
2696 csi_object_t *obj = &array->stack.objects[i];
2697 int type = csi_object_get_type (obj);
2699 case CSI_OBJECT_TYPE_ARRAY:
2700 nglyphs += obj->datum.array->stack.len;
2702 case CSI_OBJECT_TYPE_STRING:
2703 nglyphs += obj->datum.string->len;
2709 return CSI_STATUS_SUCCESS;
2712 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
2713 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
2714 return _csi_error (CSI_STATUS_NO_MEMORY);
2716 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
2717 if (_csi_unlikely (glyphs == NULL))
2718 return _csi_error (CSI_STATUS_NO_MEMORY);
2720 glyphs = stack_glyphs;
2722 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
2723 cairo_glyph_path (cr, glyphs, nglyphs);
2725 if (glyphs != stack_glyphs)
2726 _csi_free (ctx, glyphs);
2729 return CSI_STATUS_SUCCESS;
2736 csi_status_t status;
2741 status = _csi_ostack_get_number (ctx, 0, &g);
2742 if (_csi_unlikely (status))
2747 obj.type = CSI_OBJECT_TYPE_PATTERN;
2748 obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1);
2755 csi_status_t status;
2756 csi_object_t *a, *b;
2761 b = _csi_peek_ostack (ctx, 0);
2762 a = _csi_peek_ostack (ctx, 1);
2764 status = csi_object_compare (a, b, &cmp);
2765 if (_csi_unlikely (status))
2769 return _csi_push_ostack_boolean (ctx, cmp > 0);
2773 _identity (csi_t *ctx)
2776 csi_status_t status;
2778 status = csi_matrix_new (ctx, &obj);
2779 if (_csi_unlikely (status))
2789 csi_boolean_t predicate = FALSE; /* silence the compiler */
2790 csi_status_t status;
2794 status = _csi_ostack_get_procedure (ctx, 0, &proc);
2795 if (_csi_unlikely (status))
2798 status = _csi_ostack_get_boolean (ctx, 1, &predicate);
2799 if (_csi_unlikely (status))
2806 status = _csi_array_execute (ctx, proc);
2808 if (--proc->base.ref == 0)
2809 csi_array_free (ctx, proc);
2815 _ifelse (csi_t *ctx)
2817 csi_array_t *true_proc, *false_proc;
2818 csi_boolean_t predicate = FALSE; /* silence the compiler */
2819 csi_status_t status;
2823 status = _csi_ostack_get_procedure (ctx, 0, &false_proc);
2824 if (_csi_unlikely (status))
2825 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2827 status = _csi_ostack_get_procedure (ctx, 1, &true_proc);
2828 if (_csi_unlikely (status))
2829 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
2831 status = _csi_ostack_get_boolean (ctx, 2, &predicate);
2832 if (_csi_unlikely (status))
2835 true_proc->base.ref++;
2836 false_proc->base.ref++;
2840 status = _csi_array_execute (ctx, true_proc);
2842 status = _csi_array_execute (ctx, false_proc);
2844 if (--true_proc->base.ref == 0)
2845 csi_array_free (ctx, true_proc);
2846 if (--false_proc->base.ref == 0)
2847 csi_array_free (ctx, false_proc);
2853 _image_read_raw (csi_file_t *src,
2854 cairo_format_t format,
2855 int width, int height,
2856 cairo_surface_t **image_out)
2858 cairo_surface_t *image;
2860 int rem, len, ret, x, rowlen, instride, stride;
2861 cairo_status_t status;
2863 stride = cairo_format_stride_for_width (format, width);
2864 data = malloc (stride * height);
2866 return CAIRO_STATUS_NO_MEMORY;
2868 image = cairo_image_surface_create_for_data (data, format,
2869 width, height, stride);
2870 status = cairo_surface_set_user_data (image,
2871 (const cairo_user_data_key_t *) image,
2874 cairo_surface_destroy (image);
2880 case CAIRO_FORMAT_A1:
2881 instride = rowlen = (width+7)/8;
2883 case CAIRO_FORMAT_A8:
2884 instride = rowlen = width;
2886 case CAIRO_FORMAT_RGB16_565:
2887 instride = rowlen = 2 * width;
2889 case CAIRO_FORMAT_RGB24:
2891 instride = 4 *width;
2894 case CAIRO_FORMAT_RGB30:
2895 case CAIRO_FORMAT_INVALID:
2896 case CAIRO_FORMAT_ARGB32:
2897 instride = rowlen = 4 * width;
2900 len = rowlen * height;
2905 ret = csi_file_read (src, bp, rem);
2906 if (_csi_unlikely (ret == 0)) {
2907 cairo_surface_destroy (image);
2908 return _csi_error (CSI_STATUS_READ_ERROR);
2914 if (len != height * stride) {
2916 uint8_t *row = data + height * stride;
2918 /* XXX pixel conversion */
2920 case CAIRO_FORMAT_A1:
2921 for (x = rowlen; x--; ) {
2922 uint8_t byte = *--bp;
2923 row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2926 case CAIRO_FORMAT_A8:
2927 for (x = width; x--; )
2930 case CAIRO_FORMAT_RGB16_565:
2931 for (x = width; x--; ) {
2932 #ifdef WORDS_BIGENDIAN
2933 row[2*x + 1] = *--bp;
2934 row[2*x + 0] = *--bp;
2936 row[2*x + 0] = *--bp;
2937 row[2*x + 1] = *--bp;
2941 case CAIRO_FORMAT_RGB24:
2942 for (x = width; x--; ) {
2943 #ifdef WORDS_BIGENDIAN
2944 row[4*x + 3] = *--bp;
2945 row[4*x + 2] = *--bp;
2946 row[4*x + 1] = *--bp;
2947 row[4*x + 0] = 0xff;
2949 row[4*x + 0] = *--bp;
2950 row[4*x + 1] = *--bp;
2951 row[4*x + 2] = *--bp;
2952 row[4*x + 3] = 0xff;
2956 case CAIRO_FORMAT_RGB30:
2957 case CAIRO_FORMAT_INVALID:
2958 case CAIRO_FORMAT_ARGB32:
2959 /* stride == width */
2963 memset (row + instride, 0, stride - instride);
2966 /* need to treat last row carefully */
2968 case CAIRO_FORMAT_A1:
2969 for (x = rowlen; x--; ) {
2970 uint8_t byte = *--bp;
2971 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2974 case CAIRO_FORMAT_A8:
2975 for (x = width; x--; )
2978 case CAIRO_FORMAT_RGB16_565:
2979 for (x = width; x--; ) {
2980 #ifdef WORDS_BIGENDIAN
2981 data[2*x + 1] = *--bp;
2982 data[2*x + 0] = *--bp;
2984 data[2*x + 0] = *--bp;
2985 data[2*x + 1] = *--bp;
2989 case CAIRO_FORMAT_RGB24:
2990 for (x = width; --x>1; ) {
2991 #ifdef WORDS_BIGENDIAN
2992 data[4*x + 3] = *--bp;
2993 data[4*x + 2] = *--bp;
2994 data[4*x + 1] = *--bp;
2995 data[4*x + 0] = 0xff;
2997 data[4*x + 0] = *--bp;
2998 data[4*x + 1] = *--bp;
2999 data[4*x + 2] = *--bp;
3000 data[4*x + 3] = 0xff;
3005 /* shuffle the last couple of overlapping pixels */
3006 rgb[1][0] = data[5];
3007 rgb[1][1] = data[4];
3008 rgb[1][2] = data[3];
3009 rgb[0][0] = data[2];
3010 rgb[0][1] = data[1];
3011 rgb[0][2] = data[0];
3012 #ifdef WORDS_BIGENDIAN
3014 data[5] = rgb[1][2];
3015 data[6] = rgb[1][1];
3016 data[7] = rgb[1][0];
3018 data[1] = rgb[0][2];
3019 data[2] = rgb[0][1];
3020 data[3] = rgb[0][0];
3023 data[6] = rgb[1][2];
3024 data[5] = rgb[1][1];
3025 data[4] = rgb[1][0];
3027 data[2] = rgb[0][2];
3028 data[1] = rgb[0][1];
3029 data[0] = rgb[0][0];
3032 #ifdef WORDS_BIGENDIAN
3045 case CAIRO_FORMAT_RGB30:
3046 case CAIRO_FORMAT_INVALID:
3047 case CAIRO_FORMAT_ARGB32:
3048 /* stride == width */
3051 memset (data + instride, 0, stride - instride);
3053 #ifndef WORDS_BIGENDIAN
3055 case CAIRO_FORMAT_A1:
3056 for (x = 0; x < len; x++) {
3057 uint8_t byte = data[x];
3058 data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
3061 case CAIRO_FORMAT_RGB16_565:
3063 uint32_t *rgba = (uint32_t *) data;
3064 for (x = len/2; x--; rgba++) {
3065 *rgba = bswap_16 (*rgba);
3069 case CAIRO_FORMAT_ARGB32:
3071 uint32_t *rgba = (uint32_t *) data;
3072 for (x = len/4; x--; rgba++) {
3073 *rgba = bswap_32 (*rgba);
3078 case CAIRO_FORMAT_A8:
3081 case CAIRO_FORMAT_RGB30:
3082 case CAIRO_FORMAT_RGB24:
3083 case CAIRO_FORMAT_INVALID:
3090 cairo_surface_mark_dirty (image);
3092 return CSI_STATUS_SUCCESS;
3095 static cairo_status_t
3096 png_read_func (void *closure, uint8_t *data, unsigned int len)
3100 ret = csi_file_read (closure, data, len);
3101 if ((unsigned int) ret != len)
3102 return CAIRO_STATUS_READ_ERROR;
3104 return CAIRO_STATUS_SUCCESS;
3108 _image_read_png (csi_file_t *src, cairo_surface_t **out)
3110 #if CAIRO_HAS_PNG_FUNCTIONS
3111 *out = cairo_image_surface_create_from_png_stream (png_read_func, src);
3112 return cairo_surface_status (*out);
3114 return CAIRO_STATUS_READ_ERROR;
3121 cairo_surface_t *surface;
3125 _image_tag_done (void *closure)
3127 struct _image_tag *tag = closure;
3128 csi_t *ctx = tag->ctx;
3130 ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list);
3131 _csi_slab_free (ctx, tag, sizeof (*tag));
3132 cairo_script_interpreter_destroy (ctx);
3136 _image_hash (csi_blob_t *blob,
3137 cairo_surface_t *surface)
3141 value = cairo_image_surface_get_width (surface);
3142 _csi_blob_hash (blob, &value, 1);
3144 value = cairo_image_surface_get_height (surface);
3145 _csi_blob_hash (blob, &value, 1);
3147 value = cairo_image_surface_get_format (surface);
3148 _csi_blob_hash (blob, &value, 1);
3151 static cairo_surface_t *
3152 _image_cached (csi_t *ctx, cairo_surface_t *surface)
3158 struct _image_tag *tag;
3160 /* check for an existing image */
3162 data = cairo_image_surface_get_data (surface);
3163 stride = cairo_image_surface_get_stride (surface);
3164 height = cairo_image_surface_get_height (surface);
3165 _csi_blob_init (&tmpl, data, stride * height);
3166 _image_hash (&tmpl, surface);
3167 link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
3169 cairo_surface_destroy (surface);
3170 tag = csi_container_of (link, struct _image_tag, blob.list);
3171 return cairo_surface_reference (tag->surface);
3174 /* none found, insert a tag for this one */
3176 tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag));
3180 ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list);
3181 tag->ctx = cairo_script_interpreter_reference (ctx);
3182 tag->blob.hash = tmpl.hash;
3183 tag->blob.bytes = tmpl.bytes;
3184 tag->blob.len = tmpl.len;
3185 tag->surface = surface;
3187 if (cairo_surface_set_user_data (surface, &_csi_blob_key,
3188 tag, _image_tag_done))
3190 _image_tag_done (tag);
3197 _image_load_from_dictionary (csi_t *ctx,
3198 csi_dictionary_t *dict,
3199 cairo_surface_t **image_out)
3201 csi_object_t obj, key;
3205 cairo_surface_t *image = NULL; /* silence the compiler */
3206 csi_status_t status;
3208 /* check for "status? */
3210 status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width);
3211 if (_csi_unlikely (status))
3213 status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height);
3214 if (_csi_unlikely (status))
3217 format = CAIRO_FORMAT_ARGB32;
3218 status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format);
3219 if (_csi_unlikely (status))
3222 status = csi_name_new_static (ctx, &key, "source");
3223 if (_csi_unlikely (status))
3226 if (csi_dictionary_has (dict, key.datum.name)) {
3227 enum mime_type mime_type;
3230 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
3231 if (_csi_unlikely (status))
3234 status = csi_name_new_static (ctx, &key, "mime-type");
3235 if (_csi_unlikely (status))
3238 mime_type = MIME_TYPE_NONE;
3239 if (csi_dictionary_has (dict, key.datum.name)) {
3240 csi_object_t type_obj;
3241 const char *type_str;
3244 status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj);
3245 if (_csi_unlikely (status))
3248 type = csi_object_get_type (&type_obj);
3250 case CSI_OBJECT_TYPE_STRING:
3251 type_str = type_obj.datum.string->string;
3253 case CSI_OBJECT_TYPE_NAME:
3254 type_str = (char *) type_obj.datum.name;
3257 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3260 if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0)
3261 mime_type = MIME_TYPE_PNG;
3264 status = csi_object_as_file (ctx, &obj, &file);
3265 if (_csi_unlikely (status))
3268 /* XXX hook for general mime-type decoder */
3270 switch (mime_type) {
3271 case MIME_TYPE_NONE:
3272 status = _image_read_raw (file.datum.file,
3273 format, width, height, &image);
3276 status = _image_read_png (file.datum.file, &image);
3279 csi_object_free (ctx, &file);
3280 if (_csi_unlikely (status))
3283 image = _image_cached (ctx, image);
3285 image = cairo_image_surface_create (format, width, height);
3288 return CSI_STATUS_SUCCESS;
3294 csi_dictionary_t *dict;
3295 cairo_surface_t *image;
3296 csi_status_t status;
3301 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
3302 if (_csi_unlikely (status))
3305 status = _image_load_from_dictionary (ctx, dict, &image);
3306 if (_csi_unlikely (status))
3310 obj.type = CSI_OBJECT_TYPE_SURFACE;
3311 obj.datum.surface = image;
3318 csi_status_t status;
3323 status = _csi_ostack_get_integer (ctx, 0, &n);
3324 if (_csi_unlikely (status))
3330 return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n));
3334 _integer (csi_t *ctx)
3341 obj = _csi_peek_ostack (ctx, 0);
3342 type = csi_object_get_type (obj);
3344 case CSI_OBJECT_TYPE_INTEGER:
3346 case CSI_OBJECT_TYPE_REAL:
3347 obj->datum.integer = obj->datum.real;
3350 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3352 obj->type = CSI_OBJECT_TYPE_INTEGER;
3354 return CSI_STATUS_SUCCESS;
3358 _invert (csi_t *ctx)
3361 csi_status_t status;
3366 status = _csi_ostack_get_matrix (ctx, 0, &m);
3367 if (_csi_unlikely (status))
3370 cairo_matrix_invert (&m);
3372 status = csi_matrix_new_from_matrix (ctx, &obj, &m);
3373 if (_csi_unlikely (status))
3384 csi_status_t status;
3385 csi_object_t *a, *b;
3390 b = _csi_peek_ostack (ctx, 0);
3391 a = _csi_peek_ostack (ctx, 1);
3393 status = csi_object_compare (a, b, &cmp);
3394 if (_csi_unlikely (status))
3398 return _csi_push_ostack_boolean (ctx, cmp <= 0);
3402 _linear (csi_t *ctx)
3405 csi_status_t status;
3406 double x1, y1, x2, y2;
3410 status = _csi_ostack_get_number (ctx, 0, &y2);
3411 if (_csi_unlikely (status))
3413 status = _csi_ostack_get_number (ctx, 1, &x2);
3414 if (_csi_unlikely (status))
3416 status = _csi_ostack_get_number (ctx, 2, &y1);
3417 if (_csi_unlikely (status))
3419 status = _csi_ostack_get_number (ctx, 3, &x1);
3420 if (_csi_unlikely (status))
3425 obj.type = CSI_OBJECT_TYPE_PATTERN;
3426 obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
3431 _line_to (csi_t *ctx)
3433 csi_status_t status;
3440 status = _csi_ostack_get_number (ctx, 0, &y);
3441 if (_csi_unlikely (status))
3443 status = _csi_ostack_get_number (ctx, 1, &x);
3444 if (_csi_unlikely (status))
3447 /* XXX path object */
3449 obj = _csi_peek_ostack (ctx, 2);
3450 type = csi_object_get_type (obj);
3452 case CSI_OBJECT_TYPE_CONTEXT:
3453 cairo_line_to (obj->datum.cr, x, y);
3455 case CSI_OBJECT_TYPE_PATTERN:
3456 cairo_mesh_pattern_line_to (obj->datum.pattern, x, y);
3461 return CSI_STATUS_SUCCESS;
3467 csi_status_t status;
3468 csi_object_t *a, *b;
3473 b = _csi_peek_ostack (ctx, 0);
3474 a = _csi_peek_ostack (ctx, 1);
3476 status = csi_object_compare (a, b, &cmp);
3477 if (_csi_unlikely (status))
3481 return _csi_push_ostack_boolean (ctx, cmp < 0);
3487 return _csi_push_ostack_mark (ctx);
3493 csi_object_t *a, *b;
3498 b = _csi_peek_ostack (ctx, 0);
3499 a = _csi_peek_ostack (ctx, 1);
3501 v = ! csi_object_eq (a, b);
3504 return _csi_push_ostack_boolean (ctx, v);
3515 obj = _csi_peek_ostack (ctx, 0);
3516 type = csi_object_get_type (obj);
3518 case CSI_OBJECT_TYPE_INTEGER:
3519 obj->datum.integer = -obj->datum.integer;
3521 case CSI_OBJECT_TYPE_REAL:
3522 obj->datum.real = -obj->datum.real;
3525 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3528 return CSI_STATUS_SUCCESS;
3539 obj = _csi_peek_ostack (ctx, 0);
3540 type = csi_object_get_type (obj);
3542 case CSI_OBJECT_TYPE_BOOLEAN:
3543 obj->datum.boolean = ! obj->datum.boolean;
3545 case CSI_OBJECT_TYPE_INTEGER:
3546 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3547 obj->datum.boolean = ! obj->datum.integer;
3549 case CSI_OBJECT_TYPE_REAL:
3550 obj->type = CSI_OBJECT_TYPE_BOOLEAN;
3551 obj->datum.boolean = obj->datum.real == 0.0;
3554 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3557 return CSI_STATUS_SUCCESS;
3561 _new_path (csi_t *ctx)
3563 /* XXX handle path object */
3564 return _do_cairo_op (ctx, cairo_new_path);
3568 _new_sub_path (csi_t *ctx)
3570 /* XXX handle path object */
3571 return _do_cairo_op (ctx, cairo_new_sub_path);
3577 return _csi_push_ostack_null (ctx);
3584 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3585 csi_status_t status;
3589 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3590 if (_csi_unlikely (status))
3592 status = _csi_ostack_get_context (ctx, 1, &cr);
3593 if (_csi_unlikely (status))
3596 cairo_mask (cr, pattern);
3599 return CSI_STATUS_SUCCESS;
3603 _matrix (csi_t *ctx)
3605 csi_object_t *obj, matrix;
3607 csi_status_t status;
3612 obj = _csi_peek_ostack (ctx, 0);
3613 if (csi_object_is_number (obj)) {
3616 for (n = 6; n--; ) {
3617 status = _csi_ostack_get_number (ctx, 5-n, &v[n]);
3618 if (_csi_unlikely (status))
3621 status = csi_matrix_new_from_values (ctx, &matrix, v);
3622 if (_csi_unlikely (status))
3629 status = _csi_ostack_get_array (ctx, 0, &array);
3630 if (_csi_unlikely (status))
3633 status = csi_matrix_new_from_array (ctx, &matrix, array);
3634 if (_csi_unlikely (status))
3640 return push (&matrix);
3644 _map_to_image (csi_t *ctx)
3648 csi_status_t status;
3649 cairo_rectangle_int_t extents, *r;
3650 cairo_surface_t *surface;
3654 status = _csi_ostack_get_array (ctx, 0, &array);
3655 if (_csi_unlikely (status))
3658 status = _csi_ostack_get_surface (ctx, 1, &surface);
3659 if (_csi_unlikely (status))
3662 switch (array->stack.len) {
3667 extents.x = floor (_csi_object_as_real (&array->stack.objects[0]));
3668 extents.y = floor (_csi_object_as_real (&array->stack.objects[1]));
3669 extents.width = ceil (_csi_object_as_real (&array->stack.objects[2]));
3670 extents.height = ceil (_csi_object_as_real (&array->stack.objects[3]));
3674 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3677 obj.type = CSI_OBJECT_TYPE_SURFACE;
3678 obj.datum.surface = cairo_surface_map_to_image (surface, r);
3684 _unmap_image (csi_t *ctx)
3686 cairo_surface_t *surface, *image;
3687 csi_status_t status;
3691 status = _csi_ostack_get_surface (ctx, 0, &image);
3692 if (_csi_unlikely (status))
3694 status = _csi_ostack_get_surface (ctx, 1, &surface);
3695 if (_csi_unlikely (status))
3698 cairo_surface_unmap_image (surface, image);
3701 return CSI_STATUS_SUCCESS;
3709 obj.type = CSI_OBJECT_TYPE_PATTERN;
3710 obj.datum.pattern = cairo_pattern_create_mesh ();
3715 _mesh_begin_patch (csi_t *ctx)
3717 csi_status_t status;
3718 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3722 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3723 if (_csi_unlikely (status))
3726 cairo_mesh_pattern_begin_patch (pattern);
3727 return CSI_STATUS_SUCCESS;
3731 _mesh_end_patch (csi_t *ctx)
3733 csi_status_t status;
3734 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3738 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
3739 if (_csi_unlikely (status))
3742 cairo_mesh_pattern_end_patch (pattern);
3743 return CSI_STATUS_SUCCESS;
3747 _mesh_set_control_point (csi_t *ctx)
3749 csi_status_t status;
3751 csi_integer_t point;
3752 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3756 status = _csi_ostack_get_number (ctx, 0, &y);
3757 if (_csi_unlikely (status))
3759 status = _csi_ostack_get_number (ctx, 1, &x);
3760 if (_csi_unlikely (status))
3762 status = _csi_ostack_get_integer (ctx, 2, &point);
3763 if (_csi_unlikely (status))
3765 status = _csi_ostack_get_pattern (ctx, 3, &pattern);
3766 if (_csi_unlikely (status))
3769 cairo_mesh_pattern_set_control_point (pattern, point, x, y);
3772 return CSI_STATUS_SUCCESS;
3776 _mesh_set_corner_color (csi_t *ctx)
3778 csi_status_t status;
3780 csi_integer_t corner;
3781 cairo_pattern_t *pattern = NULL; /* silence the compiler */
3785 status = _csi_ostack_get_number (ctx, 0, &a);
3786 if (_csi_unlikely (status))
3788 status = _csi_ostack_get_number (ctx, 1, &b);
3789 if (_csi_unlikely (status))
3791 status = _csi_ostack_get_number (ctx, 2, &g);
3792 if (_csi_unlikely (status))
3794 status = _csi_ostack_get_number (ctx, 3, &r);
3795 if (_csi_unlikely (status))
3797 status = _csi_ostack_get_integer (ctx, 4, &corner);
3798 if (_csi_unlikely (status))
3800 status = _csi_ostack_get_pattern (ctx, 5, &pattern);
3801 if (_csi_unlikely (status))
3804 cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a);
3807 return CSI_STATUS_SUCCESS;
3814 csi_status_t status;
3818 status = _csi_ostack_get_integer (ctx, 0, &y);
3819 if (_csi_unlikely (status))
3821 status = _csi_ostack_get_integer (ctx, 1, &x);
3822 if (_csi_unlikely (status))
3826 return _csi_push_ostack_integer (ctx, x % y);
3830 _move_to (csi_t *ctx)
3832 csi_status_t status;
3839 status = _csi_ostack_get_number (ctx, 0, &y);
3840 if (_csi_unlikely (status))
3842 status = _csi_ostack_get_number (ctx, 1, &x);
3843 if (_csi_unlikely (status))
3846 obj = _csi_peek_ostack (ctx, 2);
3847 type = csi_object_get_type (obj);
3849 case CSI_OBJECT_TYPE_CONTEXT:
3850 cairo_move_to (obj->datum.cr, x, y);
3852 case CSI_OBJECT_TYPE_PATTERN:
3853 cairo_mesh_pattern_move_to (obj->datum.pattern, x, y);
3856 /* XXX path object */
3860 return CSI_STATUS_SUCCESS;
3868 csi_object_type_t type_a, type_b;
3872 B = _csi_peek_ostack (ctx, 0);
3873 A = _csi_peek_ostack (ctx, 1);
3875 type_a = csi_object_get_type (A);
3876 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
3877 type_a == CSI_OBJECT_TYPE_REAL)))
3879 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3881 type_b = csi_object_get_type (B);
3882 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
3883 type_b == CSI_OBJECT_TYPE_REAL)))
3885 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3890 if (type_a == CSI_OBJECT_TYPE_REAL &&
3891 type_b == CSI_OBJECT_TYPE_REAL)
3893 return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real);
3896 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
3897 type_b == CSI_OBJECT_TYPE_INTEGER)
3899 return _csi_push_ostack_integer (ctx,
3900 A->datum.integer * B->datum.integer);
3906 if (type_a == CSI_OBJECT_TYPE_REAL)
3909 v = A->datum.integer;
3911 if (type_b == CSI_OBJECT_TYPE_REAL)
3914 v *= B->datum.integer;
3916 return _csi_push_ostack_real (ctx, v);
3923 csi_object_t *a, *b;
3928 a = _csi_peek_ostack (ctx, 0);
3929 b = _csi_peek_ostack (ctx, 1);
3930 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
3931 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3934 type = csi_object_get_type (a);
3936 case CSI_OBJECT_TYPE_INTEGER:
3937 return _csi_push_ostack_integer (ctx,
3938 a->datum.integer | b->datum.integer);
3939 case CSI_OBJECT_TYPE_BOOLEAN:
3940 return _csi_push_ostack_boolean (ctx,
3941 a->datum.boolean | b->datum.boolean);
3943 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
3950 return _do_cairo_op (ctx, cairo_paint);
3954 _paint_with_alpha (csi_t *ctx)
3957 csi_status_t status;
3962 status = _csi_ostack_get_number (ctx, 0, &alpha);
3963 if (_csi_unlikely (status))
3966 status = _csi_ostack_get_context (ctx, 1, &cr);
3967 if (_csi_unlikely (status))
3970 cairo_paint_with_alpha (cr, alpha);
3972 return CSI_STATUS_SUCCESS;
3976 _pattern (csi_t *ctx)
3979 csi_status_t status;
3980 cairo_surface_t *surface;
3984 status = _csi_ostack_get_surface (ctx, 0, &surface);
3985 if (_csi_unlikely (status))
3988 obj.type = CSI_OBJECT_TYPE_PATTERN;
3989 obj.datum.pattern = cairo_pattern_create_for_surface (surface);
4001 return CSI_STATUS_SUCCESS;
4005 _pop_group (csi_t *ctx)
4008 csi_status_t status;
4013 status = _csi_ostack_get_context (ctx, 0, &cr);
4014 if (_csi_unlikely (status))
4017 obj.type = CSI_OBJECT_TYPE_PATTERN;
4018 obj.datum.pattern = cairo_pop_group (cr);
4024 _push_group (csi_t *ctx)
4026 csi_status_t status;
4032 status = _csi_ostack_get_integer (ctx, 0, &content);
4033 if (_csi_unlikely (status))
4036 status = _csi_ostack_get_context (ctx, 1, &cr);
4037 if (_csi_unlikely (status))
4040 cairo_push_group_with_content (cr, content);
4042 return CSI_STATUS_SUCCESS;
4046 _radial (csi_t *ctx)
4049 csi_status_t status;
4050 double x1, y1, r1, x2, y2, r2;
4054 status = _csi_ostack_get_number (ctx, 0, &r2);
4055 if (_csi_unlikely (status))
4057 status = _csi_ostack_get_number (ctx, 1, &y2);
4058 if (_csi_unlikely (status))
4060 status = _csi_ostack_get_number (ctx, 2, &x2);
4061 if (_csi_unlikely (status))
4063 status = _csi_ostack_get_number (ctx, 3, &r1);
4064 if (_csi_unlikely (status))
4066 status = _csi_ostack_get_number (ctx, 4, &y1);
4067 if (_csi_unlikely (status))
4069 status = _csi_ostack_get_number (ctx, 5, &x1);
4070 if (_csi_unlikely (status))
4073 obj.type = CSI_OBJECT_TYPE_PATTERN;
4074 obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2);
4080 _rectangle (csi_t *ctx)
4082 csi_status_t status;
4089 status = _csi_ostack_get_number (ctx, 0, &h);
4090 if (_csi_unlikely (status))
4092 status = _csi_ostack_get_number (ctx, 1, &w);
4093 if (_csi_unlikely (status))
4095 status = _csi_ostack_get_number (ctx, 2, &y);
4096 if (_csi_unlikely (status))
4098 status = _csi_ostack_get_number (ctx, 3, &x);
4099 if (_csi_unlikely (status))
4101 status = _csi_ostack_get_context (ctx, 4, &cr);
4102 if (_csi_unlikely (status))
4105 /* XXX path object */
4107 cairo_rectangle (cr, x, y, w, h);
4109 return CSI_STATUS_SUCCESS;
4113 _rel_curve_to (csi_t *ctx)
4115 csi_status_t status;
4123 status = _csi_ostack_get_number (ctx, 0, &y3);
4124 if (_csi_unlikely (status))
4126 status = _csi_ostack_get_number (ctx, 1, &x3);
4127 if (_csi_unlikely (status))
4129 status = _csi_ostack_get_number (ctx, 2, &y2);
4130 if (_csi_unlikely (status))
4132 status = _csi_ostack_get_number (ctx, 3, &x2);
4133 if (_csi_unlikely (status))
4135 status = _csi_ostack_get_number (ctx, 4, &y1);
4136 if (_csi_unlikely (status))
4138 status = _csi_ostack_get_number (ctx, 5, &x1);
4139 if (_csi_unlikely (status))
4141 status = _csi_ostack_get_context (ctx, 6, &cr);
4142 if (_csi_unlikely (status))
4145 /* XXX path object */
4147 cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3);
4149 return CSI_STATUS_SUCCESS;
4153 _rel_line_to (csi_t *ctx)
4155 csi_status_t status;
4161 status = _csi_ostack_get_number (ctx, 0, &y);
4162 if (_csi_unlikely (status))
4164 status = _csi_ostack_get_number (ctx, 1, &x);
4165 if (_csi_unlikely (status))
4167 status = _csi_ostack_get_context (ctx, 2, &cr);
4168 if (_csi_unlikely (status))
4171 /* XXX path object */
4173 cairo_rel_line_to (cr, x, y);
4175 return CSI_STATUS_SUCCESS;
4179 _rel_move_to (csi_t *ctx)
4181 csi_status_t status;
4187 status = _csi_ostack_get_number (ctx, 0, &y);
4188 if (_csi_unlikely (status))
4190 status = _csi_ostack_get_number (ctx, 1, &x);
4191 if (_csi_unlikely (status))
4193 status = _csi_ostack_get_context (ctx, 2, &cr);
4194 if (_csi_unlikely (status))
4197 /* XXX path object */
4198 cairo_rel_move_to (cr, x, y);
4200 return CSI_STATUS_SUCCESS;
4204 _repeat (csi_t *ctx)
4207 csi_integer_t count;
4208 csi_status_t status;
4212 status = _csi_ostack_get_procedure (ctx, 0, &proc);
4213 if (_csi_unlikely (status))
4216 status = _csi_ostack_get_integer (ctx, 1, &count);
4217 if (_csi_unlikely (status))
4220 if (_csi_unlikely (count < 0))
4221 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4227 status = _csi_array_execute (ctx, proc);
4228 if (_csi_unlikely (status))
4232 if (--proc->base.ref == 0)
4233 csi_array_free (ctx, proc);
4239 _reset_clip (csi_t *ctx)
4241 return _do_cairo_op (ctx, cairo_reset_clip);
4245 _restore (csi_t *ctx)
4247 return _do_cairo_op (ctx, cairo_restore);
4254 csi_status_t status;
4259 status = _csi_ostack_get_number (ctx, 0, &b);
4260 if (_csi_unlikely (status))
4262 status = _csi_ostack_get_number (ctx, 1, &g);
4263 if (_csi_unlikely (status))
4265 status = _csi_ostack_get_number (ctx, 2, &r);
4266 if (_csi_unlikely (status))
4269 obj.type = CSI_OBJECT_TYPE_PATTERN;
4270 obj.datum.pattern = cairo_pattern_create_rgb (r, g, b);
4279 csi_status_t status;
4284 status = _csi_ostack_get_number (ctx, 0, &a);
4285 if (_csi_unlikely (status))
4287 status = _csi_ostack_get_number (ctx, 1, &b);
4288 if (_csi_unlikely (status))
4290 status = _csi_ostack_get_number (ctx, 2, &g);
4291 if (_csi_unlikely (status))
4293 status = _csi_ostack_get_number (ctx, 3, &r);
4294 if (_csi_unlikely (status))
4297 obj.type = CSI_OBJECT_TYPE_PATTERN;
4298 obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a);
4306 csi_status_t status;
4311 status = _csi_ostack_get_integer (ctx, 0, &j);
4312 if (_csi_unlikely (status))
4314 status = _csi_ostack_get_integer (ctx, 1, &n);
4315 if (_csi_unlikely (status))
4320 return _csi_stack_roll (ctx, &ctx->ostack, j, n);
4324 _rotate (csi_t *ctx)
4327 csi_status_t status;
4333 status = _csi_ostack_get_number (ctx, 0, &theta);
4334 if (_csi_unlikely (status))
4337 obj = _csi_peek_ostack (ctx, 1);
4338 type = csi_object_get_type (obj);
4340 case CSI_OBJECT_TYPE_CONTEXT:
4341 cairo_rotate (obj->datum.cr, theta);
4344 case CSI_OBJECT_TYPE_PATTERN:
4347 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4348 cairo_matrix_rotate (&ctm, theta);
4349 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4354 case CSI_OBJECT_TYPE_MATRIX:
4355 cairo_matrix_rotate (&obj->datum.matrix->matrix, theta);
4359 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4363 return CSI_STATUS_SUCCESS;
4369 return _do_cairo_op (ctx, cairo_save);
4376 csi_status_t status;
4382 status = _csi_ostack_get_number (ctx, 0, &y);
4383 if (_csi_unlikely (status))
4385 status = _csi_ostack_get_number (ctx, 1, &x);
4386 if (_csi_unlikely (status))
4389 obj = _csi_peek_ostack (ctx, 2);
4390 type = csi_object_get_type (obj);
4392 case CSI_OBJECT_TYPE_CONTEXT:
4393 cairo_scale (obj->datum.cr, x, y);
4396 case CSI_OBJECT_TYPE_PATTERN:
4399 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
4400 cairo_matrix_scale (&ctm, x, y);
4401 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
4406 case CSI_OBJECT_TYPE_MATRIX:
4407 cairo_matrix_scale (&obj->datum.matrix->matrix, x, y);
4411 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4415 return CSI_STATUS_SUCCESS;
4419 _font_options_load_from_dictionary (csi_t *ctx,
4420 csi_dictionary_t *dict,
4421 cairo_font_options_t *options)
4425 void (*setter) (cairo_font_options_t *, int val);
4428 (void (*)(cairo_font_options_t *, int val))
4429 cairo_font_options_set_antialias },
4431 (void (*)(cairo_font_options_t *, int val))
4432 cairo_font_options_set_subpixel_order },
4434 (void (*)(cairo_font_options_t *, int val))
4435 cairo_font_options_set_hint_style },
4437 (void (*)(cairo_font_options_t *, int val))
4438 cairo_font_options_set_hint_metrics },
4440 }, *prop = properties;
4442 while (prop->key != NULL) {
4443 csi_object_t key, value;
4444 csi_status_t status;
4446 status = csi_name_new_static (ctx, &key, prop->key);
4447 if (_csi_unlikely (status))
4450 if (csi_dictionary_has (dict, key.datum.name)) {
4451 status = csi_dictionary_get (ctx, dict, key.datum.name, &value);
4452 if (_csi_unlikely (status))
4455 if (_csi_unlikely (csi_object_get_type (&value) !=
4456 CSI_OBJECT_TYPE_INTEGER))
4458 csi_object_free (ctx, &value);
4459 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4462 prop->setter (options, value.datum.integer);
4468 return CSI_STATUS_SUCCESS;
4472 _scaled_font (csi_t *ctx)
4475 csi_dictionary_t *dict;
4476 cairo_font_face_t *font_face = NULL; /* silence the compiler */
4477 cairo_matrix_t font_matrix, ctm;
4478 cairo_font_options_t *options;
4479 csi_status_t status;
4483 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
4484 if (_csi_unlikely (status))
4486 options = cairo_font_options_create ();
4487 status = _font_options_load_from_dictionary (ctx, dict, options);
4488 if (_csi_unlikely (status)) {
4489 cairo_font_options_destroy (options);
4493 status = _csi_ostack_get_matrix (ctx, 1, &ctm);
4494 if (_csi_unlikely (status)) {
4495 cairo_font_options_destroy (options);
4499 status = _csi_ostack_get_matrix (ctx, 2, &font_matrix);
4500 if (_csi_unlikely (status)) {
4501 cairo_font_options_destroy (options);
4505 status = _csi_ostack_get_font_face (ctx, 3, &font_face);
4506 if (_csi_unlikely (status)) {
4507 cairo_font_options_destroy (options);
4511 obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
4512 obj.datum.scaled_font = cairo_scaled_font_create (font_face,
4516 cairo_font_options_destroy (options);
4522 _select_font_face (csi_t *ctx)
4527 csi_string_t *family;
4528 csi_status_t status;
4532 status = _csi_ostack_get_integer (ctx, 0, &weight);
4533 if (_csi_unlikely (status))
4535 status = _csi_ostack_get_integer (ctx, 1, &slant);
4536 if (_csi_unlikely (status))
4538 status = _csi_ostack_get_string (ctx, 2, &family);
4539 if (_csi_unlikely (status))
4541 status = _csi_ostack_get_context (ctx, 3, &cr);
4542 if (_csi_unlikely (status))
4545 cairo_select_font_face (cr, family->string, slant, weight);
4547 return CSI_STATUS_SUCCESS;
4551 _context_set (csi_t *ctx,
4556 if (strcmp ((char *) key, "source") == 0) {
4557 if (_csi_unlikely (csi_object_get_type (obj) !=
4558 CSI_OBJECT_TYPE_PATTERN))
4559 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4561 cairo_set_source (cr, obj->datum.pattern);
4562 return CSI_STATUS_SUCCESS;
4565 if (strcmp ((char *) key, "scaled-font") == 0) {
4566 if (_csi_unlikely (csi_object_get_type (obj) !=
4567 CSI_OBJECT_TYPE_SCALED_FONT))
4568 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4570 cairo_set_scaled_font (cr, obj->datum.scaled_font);
4571 return CSI_STATUS_SUCCESS;
4574 if (strcmp ((char *) key, "font-face") == 0) {
4575 if (_csi_unlikely (csi_object_get_type (obj) !=
4576 CSI_OBJECT_TYPE_FONT))
4577 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4579 cairo_set_font_face (cr, obj->datum.font_face);
4580 return CSI_STATUS_SUCCESS;
4583 /* return _proxy_set()? */
4584 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4590 csi_object_t *key, *value, *dst;
4591 csi_status_t status;
4596 value = _csi_peek_ostack (ctx, 0);
4597 key = _csi_peek_ostack (ctx, 1);
4598 dst = _csi_peek_ostack (ctx, 2);
4600 type = csi_object_get_type (dst);
4602 case CSI_OBJECT_TYPE_DICTIONARY:
4603 if (_csi_unlikely (csi_object_get_type (key) !=
4604 CSI_OBJECT_TYPE_NAME))
4605 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4607 status = csi_dictionary_put (ctx,
4608 dst->datum.dictionary,
4612 case CSI_OBJECT_TYPE_ARRAY:
4613 if (_csi_unlikely (csi_object_get_type (key) !=
4614 CSI_OBJECT_TYPE_INTEGER))
4615 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4617 status = csi_array_put (ctx,
4623 case CSI_OBJECT_TYPE_CONTEXT:
4624 if (_csi_unlikely (csi_object_get_type (key) !=
4625 CSI_OBJECT_TYPE_NAME))
4626 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4628 status = _context_set (ctx,
4634 case CSI_OBJECT_TYPE_STRING:
4636 status = csi_string_put (dst, key, value);
4640 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4648 _set_antialias (csi_t *ctx)
4650 csi_status_t status;
4656 status = _csi_ostack_get_integer (ctx, 0, &antialias);
4657 if (_csi_unlikely (status))
4659 status = _csi_ostack_get_context (ctx, 1, &cr);
4660 if (_csi_unlikely (status))
4663 cairo_set_antialias (cr, antialias);
4665 return CSI_STATUS_SUCCESS;
4669 _set_dash (csi_t *ctx)
4672 csi_status_t status;
4678 status = _csi_ostack_get_number (ctx, 0, &offset);
4679 if (_csi_unlikely (status))
4681 status = _csi_ostack_get_array (ctx, 1, &array);
4682 if (_csi_unlikely (status))
4684 status = _csi_ostack_get_context (ctx, 2, &cr);
4685 if (_csi_unlikely (status))
4688 if (array->stack.len == 0) {
4689 cairo_set_dash (cr, NULL, 0., 0.);
4691 double stack_dashes[8];
4695 if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) {
4696 dashes = stack_dashes;
4698 if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double)))
4699 return _csi_error (CSI_STATUS_NO_MEMORY);
4700 dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len);
4701 if (_csi_unlikely (dashes == NULL))
4702 return _csi_error (CSI_STATUS_NO_MEMORY);
4705 for (n = 0; n < array->stack.len; n++) {
4706 if (_csi_unlikely (! csi_object_is_number
4707 (&array->stack.objects[n])))
4709 if (dashes != stack_dashes)
4710 _csi_free (ctx, dashes);
4711 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4714 dashes[n] = csi_number_get_value (&array->stack.objects[n]);
4717 cairo_set_dash (cr, dashes, n, offset);
4719 if (dashes != stack_dashes)
4720 _csi_free (ctx, dashes);
4724 return CSI_STATUS_SUCCESS;
4728 _set_device_offset (csi_t *ctx)
4730 csi_status_t status;
4731 cairo_surface_t *surface;
4736 status = _csi_ostack_get_number (ctx, 0, &y);
4737 if (_csi_unlikely (status))
4739 status = _csi_ostack_get_number (ctx, 1, &x);
4740 if (_csi_unlikely (status))
4742 status = _csi_ostack_get_surface (ctx, 2, &surface);
4743 if (_csi_unlikely (status))
4746 cairo_surface_set_device_offset (surface, x, y);
4748 return CSI_STATUS_SUCCESS;
4752 _set_extend (csi_t *ctx)
4754 csi_status_t status;
4761 status = _csi_ostack_get_integer (ctx, 0, &extend);
4762 if (_csi_unlikely (status))
4765 obj = _csi_peek_ostack (ctx, 1);
4766 type = csi_object_get_type (obj);
4768 case CSI_OBJECT_TYPE_CONTEXT:
4769 cairo_pattern_set_extend (cairo_get_source (obj->datum.cr),
4772 case CSI_OBJECT_TYPE_PATTERN:
4773 cairo_pattern_set_extend (obj->datum.pattern, extend);
4776 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4780 return CSI_STATUS_SUCCESS;
4784 _set_fallback_resolution (csi_t *ctx)
4786 csi_status_t status;
4787 cairo_surface_t *surface;
4788 double dpi_x, dpi_y;
4792 status = _csi_ostack_get_number (ctx, 0, &dpi_y);
4793 if (_csi_unlikely (status))
4795 status = _csi_ostack_get_number (ctx, 1, &dpi_x);
4796 if (_csi_unlikely (status))
4798 status = _csi_ostack_get_surface (ctx, 2, &surface);
4799 if (_csi_unlikely (status))
4802 cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y);
4804 return CSI_STATUS_SUCCESS;
4808 _set_fill_rule (csi_t *ctx)
4810 csi_status_t status;
4816 status = _csi_ostack_get_integer (ctx, 0, &fill_rule);
4817 if (_csi_unlikely (status))
4819 status = _csi_ostack_get_context (ctx, 1, &cr);
4820 if (_csi_unlikely (status))
4823 cairo_set_fill_rule (cr, fill_rule);
4825 return CSI_STATUS_SUCCESS;
4829 _set_filter (csi_t *ctx)
4831 csi_status_t status;
4838 status = _csi_ostack_get_integer (ctx, 0, &filter);
4839 if (_csi_unlikely (status))
4842 obj = _csi_peek_ostack (ctx, 1);
4843 type = csi_object_get_type (obj);
4845 case CSI_OBJECT_TYPE_CONTEXT:
4846 cairo_pattern_set_filter (cairo_get_source (obj->datum.cr),
4849 case CSI_OBJECT_TYPE_PATTERN:
4850 cairo_pattern_set_filter (obj->datum.pattern, filter);
4853 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
4857 return CSI_STATUS_SUCCESS;
4861 _set_font_face (csi_t *ctx)
4864 cairo_font_face_t *font = NULL; /* silence the compiler */
4865 csi_status_t status;
4869 status = _csi_ostack_get_font_face (ctx, 0, &font);
4870 if (_csi_unlikely (status))
4872 status = _csi_ostack_get_context (ctx, 1, &cr);
4873 if (_csi_unlikely (status))
4876 cairo_set_font_face (cr, font);
4878 return CSI_STATUS_SUCCESS;
4882 _set_font_options (csi_t *ctx)
4884 csi_status_t status;
4886 csi_dictionary_t *dict;
4887 cairo_font_options_t *options;
4891 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
4892 if (_csi_unlikely (status))
4894 status = _csi_ostack_get_context (ctx, 1, &cr);
4895 if (_csi_unlikely (status))
4898 options = cairo_font_options_create ();
4899 status = _font_options_load_from_dictionary (ctx, dict, options);
4900 if (_csi_unlikely (status))
4903 cairo_set_font_options (cr, options);
4904 cairo_font_options_destroy (options);
4906 return CSI_STATUS_SUCCESS;
4910 _set_font_matrix (csi_t *ctx)
4912 csi_status_t status;
4918 status = _csi_ostack_get_matrix (ctx, 0, &m);
4919 if (_csi_unlikely (status))
4921 status = _csi_ostack_get_context (ctx, 1, &cr);
4922 if (_csi_unlikely (status))
4925 cairo_set_font_matrix (cr, &m);
4927 return CSI_STATUS_SUCCESS;
4931 _set_font_size (csi_t *ctx)
4933 csi_status_t status;
4939 status = _csi_ostack_get_number (ctx, 0, &size);
4940 if (_csi_unlikely (status))
4942 status = _csi_ostack_get_context (ctx, 1, &cr);
4943 if (_csi_unlikely (status))
4946 cairo_set_font_size (cr, size);
4948 return CSI_STATUS_SUCCESS;
4952 _set_line_cap (csi_t *ctx)
4954 csi_status_t status;
4960 status = _csi_ostack_get_integer (ctx, 0, &line_cap);
4961 if (_csi_unlikely (status))
4963 status = _csi_ostack_get_context (ctx, 1, &cr);
4964 if (_csi_unlikely (status))
4967 cairo_set_line_cap (cr, line_cap);
4969 return CSI_STATUS_SUCCESS;
4973 _set_line_join (csi_t *ctx)
4975 csi_status_t status;
4979 status = _csi_ostack_get_integer (ctx, 0, &line_join);
4980 if (_csi_unlikely (status))
4982 status = _csi_ostack_get_context (ctx, 1, &cr);
4983 if (_csi_unlikely (status))
4986 cairo_set_line_join (cr, line_join);
4988 return CSI_STATUS_SUCCESS;
4992 _set_line_width (csi_t *ctx)
4994 csi_status_t status;
5000 status = _csi_ostack_get_number (ctx, 0, &line_width);
5001 if (_csi_unlikely (status))
5003 status = _csi_ostack_get_context (ctx, 1, &cr);
5004 if (_csi_unlikely (status))
5007 cairo_set_line_width (cr, line_width);
5009 return CSI_STATUS_SUCCESS;
5013 _set_matrix (csi_t *ctx)
5016 csi_status_t status;
5022 status = _csi_ostack_get_matrix (ctx, 0, &m);
5023 if (_csi_unlikely (status))
5026 obj = _csi_peek_ostack (ctx, 1);
5027 type = csi_object_get_type (obj);
5029 case CSI_OBJECT_TYPE_CONTEXT:
5030 cairo_set_matrix (obj->datum.cr, &m);
5032 case CSI_OBJECT_TYPE_PATTERN:
5033 cairo_pattern_set_matrix (obj->datum.pattern, &m);
5035 case CSI_OBJECT_TYPE_MATRIX:
5036 obj->datum.matrix->matrix = m;
5039 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5043 return CSI_STATUS_SUCCESS;
5048 csi_string_t *source;
5051 _mime_tag_destroy (void *closure)
5053 struct _mime_tag *tag = closure;
5055 if (--tag->source->base.ref)
5056 csi_string_free (tag->ctx, tag->source);
5058 _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag));
5062 _set_mime_data (csi_t *ctx)
5064 csi_status_t status;
5066 const char *mime = NULL; /* silence the compiler */
5067 csi_object_t source;
5068 cairo_surface_t *surface;
5069 struct _mime_tag *tag;
5074 obj = _csi_peek_ostack (ctx, 0);
5075 type = csi_object_get_type (obj);
5077 case CSI_OBJECT_TYPE_FILE:
5078 status = _csi_file_as_string (ctx, obj->datum.file, &source);
5079 if (_csi_unlikely (status))
5084 case CSI_OBJECT_TYPE_STRING:
5085 source = *csi_object_reference (obj);
5089 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5092 status = _csi_ostack_get_string_constant (ctx, 1, &mime);
5093 if (_csi_unlikely (status))
5096 status = _csi_ostack_get_surface (ctx, 2, &surface);
5097 if (_csi_unlikely (status))
5101 /* XXX free source */
5102 tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag));
5103 if (_csi_unlikely (tag == NULL))
5104 return _csi_error (CSI_STATUS_NO_MEMORY);
5105 tag->ctx = cairo_script_interpreter_reference (ctx);
5106 tag->source = source.datum.string;
5107 tag->source->base.ref++;
5109 status = cairo_surface_set_mime_data (surface,
5112 source.datum.string->string,
5113 source.datum.string->len,
5114 _mime_tag_destroy, tag);
5115 if (_csi_unlikely (status)) {
5116 _mime_tag_destroy (tag);
5121 return CSI_STATUS_SUCCESS;
5125 _set_miter_limit (csi_t *ctx)
5127 csi_status_t status;
5133 status = _csi_ostack_get_number (ctx, 0, &miter_limit);
5134 if (_csi_unlikely (status))
5136 status = _csi_ostack_get_context (ctx, 1, &cr);
5137 if (_csi_unlikely (status))
5140 cairo_set_miter_limit (cr, miter_limit);
5142 return CSI_STATUS_SUCCESS;
5146 _set_operator (csi_t *ctx)
5150 csi_status_t status;
5154 status = _csi_ostack_get_integer (ctx, 0, &val);
5155 if (_csi_unlikely (status))
5157 status = _csi_ostack_get_context (ctx, 1, &cr);
5158 if (_csi_unlikely (status))
5161 cairo_set_operator (cr, val);
5163 return CSI_STATUS_SUCCESS;
5167 _set_scaled_font (csi_t *ctx)
5170 cairo_scaled_font_t *font = NULL; /* silence the compiler */
5171 csi_status_t status;
5175 status = _csi_ostack_get_scaled_font (ctx, 0, &font);
5176 if (_csi_unlikely (status))
5178 status = _csi_ostack_get_context (ctx, 1, &cr);
5179 if (_csi_unlikely (status))
5182 cairo_set_scaled_font (cr, font);
5184 return CSI_STATUS_SUCCESS;
5188 _set_source (csi_t *ctx)
5191 cairo_pattern_t *pattern = NULL; /* silence the compiler */
5192 csi_status_t status;
5196 status = _csi_ostack_get_pattern (ctx, 0, &pattern);
5197 if (_csi_unlikely (status))
5199 status = _csi_ostack_get_context (ctx, 1, &cr);
5200 if (_csi_unlikely (status))
5203 cairo_set_source (cr, pattern);
5205 return CSI_STATUS_SUCCESS;
5208 static csi_boolean_t
5209 _matching_images (cairo_surface_t *a, cairo_surface_t *b)
5211 cairo_format_t format_a, format_b;
5213 if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE)
5215 if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE)
5218 if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b))
5221 if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b))
5224 format_a = cairo_image_surface_get_format (a);
5225 if (format_a == CAIRO_FORMAT_RGB24)
5226 format_a = CAIRO_FORMAT_ARGB32;
5228 format_b = cairo_image_surface_get_format (b);
5229 if (format_b == CAIRO_FORMAT_RGB24)
5230 format_b = CAIRO_FORMAT_ARGB32;
5232 if (format_a != format_b)
5239 _set_source_image (csi_t *ctx)
5241 csi_status_t status;
5242 cairo_surface_t *surface;
5243 cairo_surface_t *source;
5247 status = _csi_ostack_get_surface (ctx, 0, &source);
5248 if (_csi_unlikely (status))
5250 status = _csi_ostack_get_surface (ctx, 1, &surface);
5251 if (_csi_unlikely (status))
5254 /* Catch the most frequent use of simply uploading pixel data,
5255 * principally to remove the pixman ops from the profiles.
5257 if (_csi_likely (_matching_images (surface, source))) {
5258 cairo_surface_flush (surface);
5259 memcpy (cairo_image_surface_get_data (surface),
5260 cairo_image_surface_get_data (source),
5261 cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
5262 cairo_surface_mark_dirty (surface);
5266 cr = cairo_create (surface);
5267 cairo_set_source_surface (cr, source, 0, 0);
5273 return CSI_STATUS_SUCCESS;
5277 _set_source_rgb (csi_t *ctx)
5279 csi_status_t status;
5285 status = _csi_ostack_get_number (ctx, 0, &b);
5286 if (_csi_unlikely (status))
5288 status = _csi_ostack_get_number (ctx, 1, &g);
5289 if (_csi_unlikely (status))
5291 status = _csi_ostack_get_number (ctx, 2, &r);
5292 if (_csi_unlikely (status))
5294 status = _csi_ostack_get_context (ctx, 3, &cr);
5295 if (_csi_unlikely (status))
5298 cairo_set_source_rgb (cr, r, g, b);
5300 return CSI_STATUS_SUCCESS;
5304 _set_source_rgba (csi_t *ctx)
5306 csi_status_t status;
5312 status = _csi_ostack_get_number (ctx, 0, &a);
5313 if (_csi_unlikely (status))
5315 status = _csi_ostack_get_number (ctx, 1, &b);
5316 if (_csi_unlikely (status))
5318 status = _csi_ostack_get_number (ctx, 2, &g);
5319 if (_csi_unlikely (status))
5321 status = _csi_ostack_get_number (ctx, 3, &r);
5322 if (_csi_unlikely (status))
5324 status = _csi_ostack_get_context (ctx, 4, &cr);
5325 if (_csi_unlikely (status))
5328 cairo_set_source_rgba (cr, r, g, b, a);
5330 return CSI_STATUS_SUCCESS;
5334 _set_tolerance (csi_t *ctx)
5336 csi_status_t status;
5342 status = _csi_ostack_get_number (ctx, 0, &tolerance);
5343 if (_csi_unlikely (status))
5345 status = _csi_ostack_get_context (ctx, 1, &cr);
5346 if (_csi_unlikely (status))
5349 cairo_set_tolerance (cr, tolerance);
5351 return CSI_STATUS_SUCCESS;
5355 _transform (csi_t *ctx)
5358 csi_status_t status;
5364 status = _csi_ostack_get_matrix (ctx, 0, &m);
5365 if (_csi_unlikely (status))
5368 obj = _csi_peek_ostack (ctx, 1);
5369 type = csi_object_get_type (obj);
5371 case CSI_OBJECT_TYPE_CONTEXT:
5372 cairo_transform (obj->datum.cr, &m);
5374 case CSI_OBJECT_TYPE_PATTERN:
5377 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5378 cairo_matrix_multiply (&ctm, &m, &ctm);
5379 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5382 case CSI_OBJECT_TYPE_MATRIX:
5383 cairo_matrix_multiply (&obj->datum.matrix->matrix,
5385 &obj->datum.matrix->matrix);
5388 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5392 return CSI_STATUS_SUCCESS;
5396 _translate (csi_t *ctx)
5399 csi_status_t status;
5405 status = _csi_ostack_get_number (ctx, 0, &y);
5406 if (_csi_unlikely (status))
5408 status = _csi_ostack_get_number (ctx, 1, &x);
5409 if (_csi_unlikely (status))
5412 obj = _csi_peek_ostack (ctx, 2);
5413 type = csi_object_get_type (obj);
5415 case CSI_OBJECT_TYPE_CONTEXT:
5416 cairo_translate (obj->datum.cr, x, y);
5419 case CSI_OBJECT_TYPE_PATTERN:
5422 cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
5423 cairo_matrix_translate (&ctm, x, y);
5424 cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
5429 case CSI_OBJECT_TYPE_MATRIX:
5430 cairo_matrix_translate (&obj->datum.matrix->matrix, x, y);
5434 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5438 return CSI_STATUS_SUCCESS;
5444 return _csi_push_ostack_boolean (ctx, TRUE);
5448 _show_page (csi_t *ctx)
5455 obj = _csi_peek_ostack (ctx, 0);
5456 type = csi_object_get_type (obj);
5458 case CSI_OBJECT_TYPE_CONTEXT:
5459 cairo_show_page (obj->datum.cr);
5460 if (ctx->hooks.copy_page != NULL)
5461 ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
5463 case CSI_OBJECT_TYPE_SURFACE:
5464 cairo_surface_show_page (obj->datum.surface);
5468 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5471 return CSI_STATUS_SUCCESS;
5475 _similar (csi_t *ctx)
5479 double width, height;
5480 cairo_surface_t *other;
5481 csi_status_t status;
5485 status = _csi_ostack_get_integer (ctx, 0, &content);
5486 if (_csi_unlikely (status))
5488 status = _csi_ostack_get_number (ctx, 1, &height);
5489 if (_csi_unlikely (status))
5491 status = _csi_ostack_get_number (ctx, 2, &width);
5492 if (_csi_unlikely (status))
5494 status = _csi_ostack_get_surface (ctx, 3, &other);
5495 if (_csi_unlikely (status))
5498 /* silently fix-up a common bug when writing CS */
5499 if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) {
5500 if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA))
5501 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5503 switch ((int) content) {
5505 case CAIRO_FORMAT_ARGB32:
5506 content = CAIRO_CONTENT_COLOR_ALPHA;
5508 case CAIRO_FORMAT_RGB16_565:
5509 case CAIRO_FORMAT_RGB24:
5510 content = CAIRO_CONTENT_COLOR;
5512 case CAIRO_FORMAT_A8:
5513 case CAIRO_FORMAT_A1:
5514 content = CAIRO_CONTENT_ALPHA;
5519 obj.type = CSI_OBJECT_TYPE_SURFACE;
5520 obj.datum.surface = cairo_surface_create_similar (other,
5521 content, width, height);
5527 _similar_image (csi_t *ctx)
5531 double width, height;
5532 cairo_surface_t *other;
5533 csi_status_t status;
5537 status = _csi_ostack_get_number (ctx, 0, &height);
5538 if (_csi_unlikely (status))
5540 status = _csi_ostack_get_number (ctx, 1, &width);
5541 if (_csi_unlikely (status))
5543 status = _csi_ostack_get_integer (ctx, 2, &format);
5544 if (_csi_unlikely (status))
5546 status = _csi_ostack_get_surface (ctx, 3, &other);
5547 if (_csi_unlikely (status))
5550 obj.type = CSI_OBJECT_TYPE_SURFACE;
5551 obj.datum.surface = cairo_surface_create_similar_image (other,
5559 _subsurface (csi_t *ctx)
5562 double x, y, width, height;
5563 cairo_surface_t *target;
5564 csi_status_t status;
5568 status = _csi_ostack_get_number (ctx, 0, &height);
5569 if (_csi_unlikely (status))
5571 status = _csi_ostack_get_number (ctx, 1, &width);
5572 if (_csi_unlikely (status))
5574 status = _csi_ostack_get_number (ctx, 2, &y);
5575 if (_csi_unlikely (status))
5577 status = _csi_ostack_get_number (ctx, 3, &x);
5578 if (_csi_unlikely (status))
5580 status = _csi_ostack_get_surface (ctx, 4, &target);
5581 if (_csi_unlikely (status))
5584 obj.type = CSI_OBJECT_TYPE_SURFACE;
5585 obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height);
5591 _show_text (csi_t *ctx)
5593 csi_status_t status;
5599 status = _csi_ostack_get_string (ctx, 0, &text);
5600 if (_csi_unlikely (status))
5602 status = _csi_ostack_get_context (ctx, 1, &cr);
5603 if (_csi_unlikely (status))
5606 cairo_show_text (cr, text->string);
5608 return CSI_STATUS_SUCCESS;
5612 _show_glyphs (csi_t *ctx)
5615 csi_status_t status;
5617 cairo_glyph_t stack_glyphs[256], *glyphs;
5618 csi_integer_t nglyphs, i;
5622 status = _csi_ostack_get_array (ctx, 0, &array);
5623 if (_csi_unlikely (status))
5625 status = _csi_ostack_get_context (ctx, 1, &cr);
5626 if (_csi_unlikely (status))
5631 for (i = 0; i < array->stack.len; i++) {
5632 csi_object_t *obj = &array->stack.objects[i];
5633 int type = csi_object_get_type (obj);
5635 case CSI_OBJECT_TYPE_ARRAY:
5636 nglyphs += obj->datum.array->stack.len;
5638 case CSI_OBJECT_TYPE_STRING:
5639 nglyphs += obj->datum.string->len;
5645 return CSI_STATUS_SUCCESS;
5648 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5649 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
5650 return _csi_error (CSI_STATUS_NO_MEMORY);
5652 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5653 if (_csi_unlikely (glyphs == NULL))
5654 return _csi_error (CSI_STATUS_NO_MEMORY);
5656 glyphs = stack_glyphs;
5658 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5659 cairo_show_glyphs (cr, glyphs, nglyphs);
5661 if (glyphs != stack_glyphs)
5662 _csi_free (ctx, glyphs);
5665 return CSI_STATUS_SUCCESS;
5669 _show_text_glyphs (csi_t *ctx)
5673 csi_string_t *string;
5674 csi_string_t *utf8_string;
5675 csi_status_t status;
5677 cairo_text_cluster_t stack_clusters[256], *clusters;
5678 cairo_glyph_t stack_glyphs[256], *glyphs;
5679 csi_integer_t nglyphs, nclusters, i;
5685 status = _csi_ostack_get_integer (ctx, 0, &direction);
5686 if (_csi_unlikely (status))
5689 obj = _csi_peek_ostack (ctx, 1);
5690 type = csi_object_get_type (obj);
5692 case CSI_OBJECT_TYPE_ARRAY:
5693 array = obj->datum.array;
5694 nclusters = array->stack.len / 2;
5695 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5696 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5697 return _csi_error (CSI_STATUS_NO_MEMORY);
5698 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5699 if (_csi_unlikely (clusters == NULL))
5700 return _csi_error (CSI_STATUS_NO_MEMORY);
5702 clusters = stack_clusters;
5704 for (i = 0; i < nclusters; i++) {
5705 clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]);
5706 clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]);
5710 case CSI_OBJECT_TYPE_STRING:
5711 string = obj->datum.string;
5712 nclusters = string->len / 2;
5713 if (nclusters > ARRAY_LENGTH (stack_clusters)) {
5714 if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t)))
5715 return _csi_error (CSI_STATUS_NO_MEMORY);
5716 clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
5717 if (_csi_unlikely (clusters == NULL))
5718 return _csi_error (CSI_STATUS_NO_MEMORY);
5720 clusters = stack_clusters;
5722 for (i = 0; i < nclusters; i++) {
5723 clusters[i].num_bytes = string->string[2*i+0];
5724 clusters[i].num_glyphs = string->string[2*i+1];
5729 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5732 status = _csi_ostack_get_array (ctx, 2, &array);
5733 if (_csi_unlikely (status))
5735 status = _csi_ostack_get_string (ctx, 3, &utf8_string);
5736 if (_csi_unlikely (status))
5738 status = _csi_ostack_get_context (ctx, 4, &cr);
5739 if (_csi_unlikely (status))
5744 for (i = 0; i < array->stack.len; i++) {
5745 obj = &array->stack.objects[i];
5746 type = csi_object_get_type (obj);
5748 case CSI_OBJECT_TYPE_ARRAY:
5749 nglyphs += obj->datum.array->stack.len;
5751 case CSI_OBJECT_TYPE_STRING:
5752 nglyphs += obj->datum.string->len;
5758 return CSI_STATUS_SUCCESS;
5761 if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
5762 if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
5763 return _csi_error (CSI_STATUS_NO_MEMORY);
5765 glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
5766 if (_csi_unlikely (glyphs == NULL))
5767 return _csi_error (CSI_STATUS_NO_MEMORY);
5769 glyphs = stack_glyphs;
5771 nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
5772 cairo_show_text_glyphs (cr,
5773 utf8_string->string, utf8_string->len,
5775 clusters, nclusters,
5778 if (clusters != stack_clusters)
5779 _csi_free (ctx, clusters);
5780 if (glyphs != stack_glyphs)
5781 _csi_free (ctx, glyphs);
5784 return CSI_STATUS_SUCCESS;
5788 _stroke (csi_t *ctx)
5790 return _do_cairo_op (ctx, cairo_stroke);
5794 _stroke_preserve (csi_t *ctx)
5796 return _do_cairo_op (ctx, cairo_stroke_preserve);
5804 csi_object_type_t type_a, type_b;
5808 B = _csi_peek_ostack (ctx, 0);
5809 A = _csi_peek_ostack (ctx, 1);
5811 type_a = csi_object_get_type (A);
5812 if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
5813 type_a == CSI_OBJECT_TYPE_REAL)))
5815 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5818 type_b = csi_object_get_type (B);
5819 if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
5820 type_b == CSI_OBJECT_TYPE_REAL)))
5822 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
5827 if (type_a == CSI_OBJECT_TYPE_REAL &&
5828 type_b == CSI_OBJECT_TYPE_REAL)
5830 return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real);
5833 else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
5834 type_b == CSI_OBJECT_TYPE_INTEGER)
5836 return _csi_push_ostack_integer (ctx,
5837 A->datum.integer - B->datum.integer);
5843 if (type_a == CSI_OBJECT_TYPE_REAL)
5846 v = A->datum.integer;
5848 if (type_b == CSI_OBJECT_TYPE_REAL)
5851 v -= B->datum.integer;
5853 return _csi_push_ostack_real (ctx, v);
5858 _surface (csi_t *ctx)
5861 csi_dictionary_t *dict;
5864 double width, height;
5865 csi_surface_create_func_t hook;
5867 cairo_surface_t *surface;
5869 csi_status_t status;
5873 status = _csi_ostack_get_dictionary (ctx, 0, &dict);
5874 if (_csi_unlikely (status))
5877 status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width);
5878 if (_csi_unlikely (status))
5880 status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height);
5881 if (_csi_unlikely (status))
5884 content = CAIRO_CONTENT_COLOR_ALPHA;
5885 status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content);
5886 if (_csi_unlikely (status))
5890 status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid);
5891 if (_csi_unlikely (status))
5894 status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid);
5895 if (_csi_unlikely (status))
5899 hook = ctx->hooks.surface_create;
5900 assert (hook != NULL);
5902 surface = hook (ctx->hooks.closure, content, width, height, uid);
5903 if (_csi_unlikely (surface == NULL)) {
5904 return _csi_error (CSI_STATUS_NULL_POINTER);
5907 proxy = _csi_proxy_create (ctx, surface, dict,
5908 ctx->hooks.surface_destroy,
5909 ctx->hooks.closure);
5910 if (_csi_unlikely (proxy == NULL)) {
5911 cairo_surface_destroy (surface);
5912 return _csi_error (CSI_STATUS_NO_MEMORY);
5915 status = cairo_surface_set_user_data (surface,
5917 proxy, _csi_proxy_destroy);
5918 if (_csi_unlikely (status)) {
5919 _csi_proxy_destroy (proxy);
5920 cairo_surface_destroy (surface);
5924 status = csi_name_new_static (ctx, &key, "fallback-resolution");
5925 if (_csi_unlikely (status)) {
5926 cairo_surface_destroy (surface);
5929 if (csi_dictionary_has (dict, key.datum.name)) {
5930 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
5931 if (_csi_unlikely (status)) {
5932 cairo_surface_destroy (surface);
5935 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
5936 csi_array_t *array = obj.datum.array;
5937 if (array->stack.len == 2) {
5938 cairo_surface_set_fallback_resolution (surface,
5939 csi_number_get_value
5940 (&array->stack.objects[0]),
5941 csi_number_get_value
5942 (&array->stack.objects[1]));
5946 /* initialise surface to source */
5947 status = csi_name_new_static (ctx, &key, "source");
5948 if (_csi_unlikely (status)) {
5949 cairo_surface_destroy (surface);
5952 if (csi_dictionary_has (dict, key.datum.name)) {
5953 cairo_surface_t *image;
5956 status = _image_load_from_dictionary (ctx, dict, &image);
5957 if (_csi_unlikely (status)) {
5958 cairo_surface_destroy (surface);
5962 cr = cairo_create (surface);
5963 cairo_set_source_surface (cr, image, 0, 0);
5964 cairo_surface_destroy (image);
5966 status = cairo_status (cr);
5969 if (_csi_unlikely (status))
5973 status = csi_name_new_static (ctx, &key, "device-offset");
5974 if (_csi_unlikely (status)) {
5975 cairo_surface_destroy (surface);
5978 if (csi_dictionary_has (dict, key.datum.name)) {
5979 status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
5980 if (_csi_unlikely (status))
5983 if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
5984 csi_array_t *array = obj.datum.array;
5986 if (array->stack.len == 2) {
5987 cairo_surface_set_device_offset (surface,
5988 csi_number_get_value
5989 (&array->stack.objects[0]),
5990 csi_number_get_value
5991 (&array->stack.objects[1]));
5996 obj.type = CSI_OBJECT_TYPE_SURFACE;
5997 obj.datum.surface = surface;
6003 _record (csi_t *ctx)
6008 csi_status_t status;
6009 cairo_rectangle_t extents;
6010 cairo_rectangle_t *r;
6014 status = _csi_ostack_get_array (ctx, 0, &array);
6015 if (_csi_unlikely (status))
6018 status = _csi_ostack_get_integer (ctx, 1, &content);
6019 if (_csi_unlikely (status))
6022 switch (array->stack.len) {
6027 extents.x = extents.y = 0;
6028 extents.width = _csi_object_as_real (&array->stack.objects[0]);
6029 extents.height = _csi_object_as_real (&array->stack.objects[1]);
6033 extents.x = _csi_object_as_real (&array->stack.objects[0]);
6034 extents.y = _csi_object_as_real (&array->stack.objects[1]);
6035 extents.width = _csi_object_as_real (&array->stack.objects[2]);
6036 extents.height = _csi_object_as_real (&array->stack.objects[3]);
6040 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6043 obj.type = CSI_OBJECT_TYPE_SURFACE;
6044 obj.datum.surface = cairo_recording_surface_create (content, r);
6050 _text_path (csi_t *ctx)
6052 csi_status_t status;
6058 status = _csi_ostack_get_string (ctx, 0, &text);
6059 if (_csi_unlikely (status))
6061 status = _csi_ostack_get_context (ctx, 1, &cr);
6062 if (_csi_unlikely (status))
6065 cairo_text_path (cr, text->string);
6067 return CSI_STATUS_SUCCESS;
6073 csi_name_t name = 0; /* silence the compiler */
6074 csi_status_t status;
6078 status = _csi_ostack_get_name (ctx, 0, &name);
6079 if (_csi_unlikely (status))
6082 status = _csi_name_undefine (ctx, name);
6083 if (_csi_unlikely (status))
6087 return CSI_STATUS_SUCCESS;
6094 csi_name_t name = 0; /* silence the compiler */
6095 csi_status_t status;
6100 status = _csi_ostack_get_name (ctx, 0, &name);
6101 if (_csi_unlikely (status))
6104 dst = _csi_peek_ostack (ctx, 1);
6105 type = csi_object_get_type (dst);
6107 case CSI_OBJECT_TYPE_DICTIONARY:
6108 csi_dictionary_remove (ctx, dst->datum.dictionary, name);
6110 case CSI_OBJECT_TYPE_STRING:
6111 case CSI_OBJECT_TYPE_ARRAY:
6113 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6117 return CSI_STATUS_SUCCESS;
6121 _write_to_png (csi_t *ctx)
6123 csi_status_t status;
6124 csi_string_t *filename;
6125 cairo_surface_t *surface;
6129 status = _csi_ostack_get_string (ctx, 0, &filename);
6130 if (_csi_unlikely (status))
6132 status = _csi_ostack_get_surface (ctx, 1, &surface);
6133 if (_csi_unlikely (status))
6136 #if CAIRO_HAS_PNG_FUNCTIONS
6137 status = cairo_surface_write_to_png (surface, filename->string);
6138 if (_csi_unlikely (status))
6141 return CAIRO_STATUS_WRITE_ERROR;
6145 return CSI_STATUS_SUCCESS;
6149 _write_to_script (csi_t *ctx)
6151 csi_status_t status;
6152 csi_string_t *filename;
6153 cairo_surface_t *record;
6157 status = _csi_ostack_get_string (ctx, 0, &filename);
6158 if (_csi_unlikely (status))
6160 status = _csi_ostack_get_surface (ctx, 1, &record);
6161 if (_csi_unlikely (status))
6164 if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING)
6165 return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
6167 #if CAIRO_HAS_SCRIPT_SURFACE
6169 cairo_device_t *script;
6171 script = cairo_script_create (filename->string);
6172 status = cairo_script_from_recording_surface (script, record);
6173 cairo_device_destroy (script);
6174 if (_csi_unlikely (status))
6178 return CAIRO_STATUS_WRITE_ERROR;
6182 return CSI_STATUS_SUCCESS;
6188 csi_object_t *a, *b;
6193 a = _csi_peek_ostack (ctx, 0);
6194 b = _csi_peek_ostack (ctx, 1);
6195 if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
6196 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6199 type = csi_object_get_type (a);
6201 case CSI_OBJECT_TYPE_INTEGER:
6202 return _csi_push_ostack_integer (ctx,
6203 a->datum.integer ^ b->datum.integer);
6204 case CSI_OBJECT_TYPE_BOOLEAN:
6205 return _csi_push_ostack_boolean (ctx,
6206 a->datum.boolean ^ b->datum.boolean);
6208 return _csi_error (CSI_STATUS_INVALID_SCRIPT);
6213 _debug_print (csi_t *ctx)
6218 obj = _csi_peek_ostack (ctx, 0);
6219 switch (csi_object_get_type (obj)) {
6220 case CSI_OBJECT_TYPE_NULL:
6221 fprintf (stderr, "NULL\n");
6225 case CSI_OBJECT_TYPE_BOOLEAN:
6226 fprintf (stderr, "boolean: %s\n",
6227 obj->datum.boolean ? "true" : "false");
6229 case CSI_OBJECT_TYPE_INTEGER:
6230 fprintf (stderr, "integer: %ld\n", obj->datum.integer);
6232 case CSI_OBJECT_TYPE_MARK:
6233 fprintf (stderr, "mark\n");
6235 case CSI_OBJECT_TYPE_NAME:
6236 fprintf (stderr, "name: %s\n", (char *) obj->datum.name);
6238 case CSI_OBJECT_TYPE_OPERATOR:
6239 fprintf (stderr, "operator: %p\n", obj->datum.ptr);
6241 case CSI_OBJECT_TYPE_REAL:
6242 fprintf (stderr, "real: %g\n", obj->datum.real);
6246 case CSI_OBJECT_TYPE_ARRAY:
6247 fprintf (stderr, "array\n");
6249 case CSI_OBJECT_TYPE_DICTIONARY:
6250 fprintf (stderr, "dictionary\n");
6252 case CSI_OBJECT_TYPE_FILE:
6253 fprintf (stderr, "file\n");
6255 case CSI_OBJECT_TYPE_MATRIX:
6256 fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n",
6257 obj->datum.matrix->matrix.xx,
6258 obj->datum.matrix->matrix.yx,
6259 obj->datum.matrix->matrix.xy,
6260 obj->datum.matrix->matrix.yy,
6261 obj->datum.matrix->matrix.x0,
6262 obj->datum.matrix->matrix.y0);
6264 case CSI_OBJECT_TYPE_STRING:
6265 fprintf (stderr, "string: %s\n", obj->datum.string->string);
6269 case CSI_OBJECT_TYPE_CONTEXT:
6270 fprintf (stderr, "context\n");
6272 case CSI_OBJECT_TYPE_FONT:
6273 fprintf (stderr, "font\n");
6275 case CSI_OBJECT_TYPE_PATTERN:
6276 fprintf (stderr, "pattern\n");
6278 case CSI_OBJECT_TYPE_SCALED_FONT:
6279 fprintf (stderr, "scaled-font\n");
6281 case CSI_OBJECT_TYPE_SURFACE:
6282 fprintf (stderr, "surface\n");
6286 return CSI_STATUS_SUCCESS;
6289 static const csi_operator_def_t
6292 { ">>", end_dict_construction },
6294 { "]", end_array_construction },
6298 { "add-color-stop", _add_color_stop },
6301 { "arc-negative", _arc_negative },
6302 { "arc-", _arc_negative },
6304 { "array", _array },
6308 { "bitshift", _bitshift },
6310 { "C", _rel_curve_to },
6311 { "ceiling", NULL },
6313 { "clear-to-mark", NULL },
6315 { "clip-extents", NULL },
6316 { "clip-preserve", _clip_preserve },
6317 { "clip+", _clip_preserve },
6318 { "close-path", _close_path },
6319 { "context", _context },
6321 { "copy-page", _copy_page },
6324 { "count-to-mark", NULL },
6325 { "curve-to", _curve_to },
6329 { "device-to-user", NULL },
6330 { "device-to-user-distance", NULL },
6333 { "dup", _duplicate },
6338 { "false", _false },
6340 { "fill-extents", NULL },
6341 { "fill-preserve", _fill_preserve },
6342 { "fill+", _fill_preserve },
6343 { "filter", _filter },
6351 { "glyph-path", _glyph_path },
6353 { "h", _close_path },
6354 { "identity", _identity },
6356 { "ifelse", _ifelse },
6357 { "image", _image },
6358 { "index", _index },
6359 { "integer", _integer },
6360 { "invert", _invert },
6361 { "in-stroke", NULL },
6362 { "in-fill", NULL },
6365 { "L", _rel_line_to },
6366 { "languagelevel", NULL },
6369 { "linear", _linear },
6370 { "line-to", _line_to },
6377 { "M", _rel_move_to },
6378 { "map-to-image", _map_to_image },
6381 { "matrix", _matrix },
6384 { "begin-patch", _mesh_begin_patch },
6385 { "end-patch", _mesh_end_patch },
6386 { "set-control-point", _mesh_set_control_point },
6387 { "set-corner-color", _mesh_set_corner_color },
6390 { "move-to", _move_to },
6392 { "multiply", NULL },
6394 { "N", _new_sub_path },
6397 { "new-path", _new_path },
6398 { "new-sub-path", _new_sub_path },
6402 { "paint", _paint },
6403 { "paint-with-alpha", _paint_with_alpha },
6404 { "pattern", _pattern },
6406 { "pop-group", _pop_group },
6407 { "push-group", _push_group },
6408 { "radial", _radial },
6410 { "record", _record },
6411 { "rectangle", _rectangle },
6412 { "repeat", _repeat },
6413 { "restore", _restore },
6414 { "rel-curve-to", _rel_curve_to },
6415 { "rel-line-to", _rel_line_to },
6416 { "rel-move-to", _rel_move_to },
6417 { "reset-clip", _reset_clip },
6421 { "rotate", _rotate },
6425 { "scale", _scale },
6426 { "scaled-font", _scaled_font },
6427 { "select-font-face", _select_font_face },
6429 { "set-antialias", _set_antialias },
6430 { "set-dash", _set_dash },
6431 { "set-device-offset", _set_device_offset },
6432 { "set-extend", _set_extend },
6433 { "set-fallback-resolution", _set_fallback_resolution },
6434 { "set-fill-rule", _set_fill_rule },
6435 { "set-filter", _set_filter },
6436 { "set-font-face", _set_font_face },
6437 { "set-font-options", _set_font_options },
6438 { "set-font-matrix", _set_font_matrix },
6439 { "set-font-size", _set_font_size },
6440 { "set-line-cap", _set_line_cap },
6441 { "set-line-join", _set_line_join },
6442 { "set-line-width", _set_line_width },
6443 { "set-matrix", _set_matrix },
6444 { "set-miter-limit", _set_miter_limit },
6445 { "set-mime-data", _set_mime_data },
6446 { "set-operator", _set_operator },
6447 { "set-scaled-font", _set_scaled_font },
6448 { "set-source", _set_source },
6449 { "set-source-image", _set_source_image },
6450 { "set-source-rgb", _set_source_rgb },
6451 { "set-source-rgba", _set_source_rgba },
6452 { "set-tolerance", _set_tolerance },
6453 { "show-glyphs", _show_glyphs },
6454 { "show-text", _show_text },
6455 { "show-text-glyphs", _show_text_glyphs },
6456 { "show-page", _show_page },
6457 { "similar", _similar },
6458 { "similar-image", _similar_image },
6462 { "subsurface", _subsurface },
6463 { "surface", _surface },
6465 { "stroke", _stroke },
6466 { "stroke-extents", NULL },
6467 { "stroke-preserve", _stroke_preserve },
6468 { "stroke+", _stroke_preserve },
6469 { "text-path", _text_path },
6470 { "transform", _transform },
6471 { "transform-distance", NULL },
6472 { "transform-point", NULL },
6473 { "translate", _translate },
6476 { "undef", _undef },
6477 { "unmap-image", _unmap_image },
6478 { "unset", _unset },
6479 { "user-to-device", NULL },
6480 { "user-to-device-distance", NULL },
6482 { "write-to-png", _write_to_png },
6483 { "write-to-script", _write_to_script },
6486 { "=", _debug_print },
6491 const csi_operator_def_t *
6492 _csi_operators (void)
6497 static const csi_integer_constant_def_t
6498 _integer_constants[] = {
6499 { "CLEAR", CAIRO_OPERATOR_CLEAR },
6500 { "SOURCE", CAIRO_OPERATOR_SOURCE },
6501 { "OVER", CAIRO_OPERATOR_OVER },
6502 { "IN", CAIRO_OPERATOR_IN },
6503 { "OUT", CAIRO_OPERATOR_OUT },
6504 { "ATOP", CAIRO_OPERATOR_ATOP },
6505 { "DEST", CAIRO_OPERATOR_DEST },
6506 { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER },
6507 { "DEST_IN", CAIRO_OPERATOR_DEST_IN },
6508 { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT },
6509 { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP },
6510 { "XOR", CAIRO_OPERATOR_XOR },
6511 { "ADD", CAIRO_OPERATOR_ADD },
6512 { "SATURATE", CAIRO_OPERATOR_SATURATE },
6513 { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY },
6514 { "SCREEN", CAIRO_OPERATOR_SCREEN },
6515 { "OVERLAY", CAIRO_OPERATOR_OVERLAY },
6516 { "DARKEN", CAIRO_OPERATOR_DARKEN },
6517 { "LIGHTEN", CAIRO_OPERATOR_LIGHTEN },
6518 { "DODGE", CAIRO_OPERATOR_COLOR_DODGE },
6519 { "BURN", CAIRO_OPERATOR_COLOR_BURN },
6520 { "HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT },
6521 { "SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT },
6522 { "DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE },
6523 { "EXCLUSION", CAIRO_OPERATOR_EXCLUSION },
6524 { "HSL_HUE", CAIRO_OPERATOR_HSL_HUE },
6525 { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION },
6526 { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR },
6527 { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY },
6529 { "WINDING", CAIRO_FILL_RULE_WINDING },
6530 { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD },
6532 { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT },
6533 { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE },
6534 { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY },
6535 { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL },
6536 { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST },
6537 { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD },
6538 { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST },
6540 { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT },
6541 { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND },
6542 { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE },
6544 { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER },
6545 { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND },
6546 { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL },
6548 { "EXTEND_NONE", CAIRO_EXTEND_NONE },
6549 { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT },
6550 { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT },
6551 { "EXTEND_PAD", CAIRO_EXTEND_PAD },
6553 { "FILTER_FAST", CAIRO_FILTER_FAST },
6554 { "FILTER_GOOD", CAIRO_FILTER_GOOD },
6555 { "FILTER_BEST", CAIRO_FILTER_BEST },
6556 { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR },
6557 { "FILTER_NEAREST", CAIRO_FILTER_NEAREST },
6558 { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN },
6560 { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL },
6561 { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC },
6562 { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE },
6564 { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL },
6565 { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD },
6567 { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT },
6568 { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB },
6569 { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR },
6570 { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB },
6571 { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR },
6573 { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT },
6574 { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE },
6575 { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT },
6576 { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM },
6577 { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL },
6579 { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT },
6580 { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF },
6581 { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON },
6586 { "COLOR", CAIRO_CONTENT_COLOR },
6587 { "ALPHA", CAIRO_CONTENT_ALPHA },
6588 { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA },
6590 { "A1", CAIRO_FORMAT_A1 },
6591 { "A8", CAIRO_FORMAT_A8 },
6592 { "RGB16_565", CAIRO_FORMAT_RGB16_565 },
6593 { "RGB24", CAIRO_FORMAT_RGB24 },
6594 { "ARGB32", CAIRO_FORMAT_ARGB32 },
6595 { "INVALID", CAIRO_FORMAT_INVALID },
6601 const csi_integer_constant_def_t *
6602 _csi_integer_constants (void)
6604 return _integer_constants;
6607 static const csi_real_constant_def_t
6608 _real_constants[] = {
6609 { "math.pi", M_PI },
6610 { "math.2pi", 2 * M_PI },
6611 { "math.sqrt2", M_SQRT2 },
6612 { "math.ln2", M_LN2 },
6617 const csi_real_constant_def_t *
6618 _csi_real_constants (void)
6620 return _real_constants;