cairo-script-objects.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. /*
  2. * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
  3. *
  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.
  11. *
  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
  17. *
  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/
  22. *
  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.
  26. *
  27. * The Original Code is the cairo graphics library.
  28. *
  29. * The Initial Developer of the Original Code is Chris Wilson.
  30. *
  31. * Contributor(s):
  32. * Chris Wilson <chris@chris-wilson.co.uk>
  33. */
  34. #include "config.h"
  35. #include "cairo-script-private.h"
  36. #include <limits.h> /* INT_MAX */
  37. #include <string.h>
  38. csi_status_t
  39. csi_array_new (csi_t *ctx,
  40. csi_integer_t initial_size,
  41. csi_object_t *obj)
  42. {
  43. csi_array_t *array;
  44. if (ctx->free_array == NULL ||
  45. ctx->free_array->stack.size <= initial_size)
  46. {
  47. csi_status_t status;
  48. array = _csi_slab_alloc (ctx, sizeof (csi_array_t));
  49. if (_csi_unlikely (array == NULL))
  50. return _csi_error (CSI_STATUS_NO_MEMORY);
  51. status = _csi_stack_init (ctx, &array->stack,
  52. initial_size ? initial_size : 32);
  53. if (_csi_unlikely (status)) {
  54. _csi_slab_free (ctx, array, sizeof (csi_array_t));
  55. return status;
  56. }
  57. } else {
  58. array = ctx->free_array;
  59. ctx->free_array = NULL;
  60. }
  61. array->base.type = CSI_OBJECT_TYPE_ARRAY;
  62. array->base.ref = 1;
  63. obj->type = CSI_OBJECT_TYPE_ARRAY;
  64. obj->datum.array = array;
  65. return CSI_STATUS_SUCCESS;
  66. }
  67. csi_status_t
  68. csi_array_put (csi_t *ctx,
  69. csi_array_t *array,
  70. csi_integer_t elem,
  71. csi_object_t *value)
  72. {
  73. if (_csi_unlikely (elem < 0))
  74. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  75. if (_csi_unlikely (elem >= array->stack.len)) {
  76. csi_status_t status;
  77. status = _csi_stack_grow (ctx, &array->stack, elem + 1);
  78. if (_csi_unlikely (status))
  79. return status;
  80. memset (array->stack.objects + array->stack.len,
  81. 0, (elem - array->stack.len + 1) * sizeof (csi_object_t));
  82. array->stack.len = elem + 1;
  83. }
  84. csi_object_free (ctx, &array->stack.objects[elem]);
  85. array->stack.objects[elem] = *csi_object_reference (value);
  86. return CSI_STATUS_SUCCESS;
  87. }
  88. csi_status_t
  89. csi_array_get (csi_t *ctx,
  90. csi_array_t *array,
  91. csi_integer_t elem,
  92. csi_object_t *value)
  93. {
  94. if (_csi_unlikely (elem < 0))
  95. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  96. if (_csi_unlikely (elem > array->stack.len))
  97. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  98. *value = array->stack.objects[elem];
  99. return CSI_STATUS_SUCCESS;
  100. }
  101. csi_status_t
  102. csi_array_append (csi_t *ctx,
  103. csi_array_t *array,
  104. csi_object_t *obj)
  105. {
  106. return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj));
  107. }
  108. inline csi_status_t
  109. _csi_array_execute (csi_t *ctx, csi_array_t *array)
  110. {
  111. csi_integer_t i;
  112. csi_status_t status;
  113. if (_csi_unlikely (array->stack.len == 0))
  114. return CSI_STATUS_SUCCESS;
  115. for (i = 0; i < array->stack.len; i++) {
  116. csi_object_t *obj = &array->stack.objects[i];
  117. if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) {
  118. if (obj->type == (CSI_OBJECT_TYPE_ARRAY |
  119. CSI_OBJECT_ATTR_EXECUTABLE))
  120. {
  121. status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
  122. }
  123. else
  124. status = csi_object_execute (ctx, &array->stack.objects[i]);
  125. } else
  126. status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
  127. if (_csi_unlikely (status))
  128. return status;
  129. }
  130. return CSI_STATUS_SUCCESS;
  131. }
  132. void
  133. csi_array_free (csi_t *ctx, csi_array_t *array)
  134. {
  135. #if CSI_DEBUG_MALLOC
  136. _csi_stack_fini (ctx, &array->stack);
  137. _csi_slab_free (ctx, array, sizeof (csi_array_t));
  138. #else
  139. csi_integer_t n;
  140. for (n = 0; n < array->stack.len; n++)
  141. csi_object_free (ctx, &array->stack.objects[n]);
  142. array->stack.len = 0;
  143. if (ctx->free_array != NULL) {
  144. if (array->stack.size > ctx->free_array->stack.size) {
  145. csi_array_t *tmp = ctx->free_array;
  146. ctx->free_array = array;
  147. array = tmp;
  148. }
  149. _csi_stack_fini (ctx, &array->stack);
  150. _csi_slab_free (ctx, array, sizeof (csi_array_t));
  151. } else
  152. ctx->free_array = array;
  153. #endif
  154. }
  155. static cairo_bool_t
  156. _dictionary_name_equal (const void *_a, const void *_b)
  157. {
  158. return TRUE;
  159. }
  160. csi_status_t
  161. csi_dictionary_new (csi_t *ctx,
  162. csi_object_t *obj)
  163. {
  164. csi_dictionary_t *dict;
  165. if (ctx->free_dictionary != NULL) {
  166. dict = ctx->free_dictionary;
  167. ctx->free_dictionary = NULL;
  168. } else {
  169. csi_status_t status;
  170. dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t));
  171. if (_csi_unlikely (dict == NULL))
  172. return _csi_error (CSI_STATUS_NO_MEMORY);
  173. status = _csi_hash_table_init (&dict->hash_table,
  174. _dictionary_name_equal);
  175. if (_csi_unlikely (status)) {
  176. _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
  177. return status;
  178. }
  179. }
  180. dict->base.type = CSI_OBJECT_TYPE_DICTIONARY;
  181. dict->base.ref = 1;
  182. obj->type = CSI_OBJECT_TYPE_DICTIONARY;
  183. obj->datum.dictionary = dict;
  184. return CSI_STATUS_SUCCESS;
  185. }
  186. struct _dictionary_entry_pluck {
  187. csi_t *ctx;
  188. csi_hash_table_t *hash_table;
  189. };
  190. static void
  191. _dictionary_entry_pluck (void *entry, void *data)
  192. {
  193. csi_dictionary_entry_t *dict_entry;
  194. struct _dictionary_entry_pluck *pluck_data;
  195. dict_entry = entry;
  196. pluck_data = data;
  197. _csi_hash_table_remove (pluck_data->hash_table, entry);
  198. csi_object_free (pluck_data->ctx, &dict_entry->value);
  199. _csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t));
  200. }
  201. void
  202. csi_dictionary_free (csi_t *ctx,
  203. csi_dictionary_t *dict)
  204. {
  205. struct _dictionary_entry_pluck data;
  206. data.ctx = ctx;
  207. data.hash_table = &dict->hash_table;
  208. _csi_hash_table_foreach (&dict->hash_table,
  209. _dictionary_entry_pluck,
  210. &data);
  211. #if CSI_DEBUG_MALLOC
  212. _csi_hash_table_fini (&dict->hash_table);
  213. _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
  214. #else
  215. if (ctx->free_dictionary != NULL) {
  216. _csi_hash_table_fini (&dict->hash_table);
  217. _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
  218. } else
  219. ctx->free_dictionary = dict;
  220. #endif
  221. }
  222. csi_status_t
  223. csi_dictionary_put (csi_t *ctx,
  224. csi_dictionary_t *dict,
  225. csi_name_t name,
  226. csi_object_t *value)
  227. {
  228. csi_dictionary_entry_t *entry;
  229. csi_status_t status;
  230. entry = _csi_hash_table_lookup (&dict->hash_table,
  231. (csi_hash_entry_t *) &name);
  232. if (entry != NULL) {
  233. /* replace the existing entry */
  234. csi_object_free (ctx, &entry->value);
  235. entry->value = *csi_object_reference (value);
  236. return CSI_STATUS_SUCCESS;
  237. }
  238. entry = _csi_slab_alloc (ctx, sizeof (*entry));
  239. if (_csi_unlikely (entry == NULL))
  240. return _csi_error (CSI_STATUS_NO_MEMORY);
  241. entry->hash_entry.hash = name;
  242. status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry);
  243. if (_csi_unlikely (status)) {
  244. _csi_slab_free (ctx, entry, sizeof (*entry));
  245. return status;
  246. }
  247. entry->value = *csi_object_reference (value);
  248. return CSI_STATUS_SUCCESS;
  249. }
  250. csi_status_t
  251. csi_dictionary_get (csi_t *ctx,
  252. csi_dictionary_t *dict,
  253. csi_name_t name,
  254. csi_object_t *value)
  255. {
  256. csi_dictionary_entry_t *entry;
  257. entry = _csi_hash_table_lookup (&dict->hash_table,
  258. (csi_hash_entry_t *) &name);
  259. if (_csi_unlikely (entry == NULL))
  260. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  261. *value = entry->value;
  262. return CSI_STATUS_SUCCESS;
  263. }
  264. csi_boolean_t
  265. csi_dictionary_has (csi_dictionary_t *dict,
  266. csi_name_t name)
  267. {
  268. return _csi_hash_table_lookup (&dict->hash_table,
  269. (csi_hash_entry_t *) &name) != NULL;
  270. }
  271. void
  272. csi_dictionary_remove (csi_t *ctx,
  273. csi_dictionary_t *dict,
  274. csi_name_t name)
  275. {
  276. csi_dictionary_entry_t *entry;
  277. entry = _csi_hash_table_lookup (&dict->hash_table,
  278. (csi_hash_entry_t *) &name);
  279. if (entry != NULL) {
  280. _csi_hash_table_remove (&dict->hash_table, &entry->hash_entry);
  281. csi_object_free (ctx, &entry->value);
  282. _csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t));
  283. }
  284. }
  285. csi_status_t
  286. csi_matrix_new (csi_t *ctx,
  287. csi_object_t *obj)
  288. {
  289. csi_matrix_t *matrix;
  290. matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
  291. if (_csi_unlikely (matrix == NULL))
  292. return _csi_error (CSI_STATUS_NO_MEMORY);
  293. matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
  294. matrix->base.ref = 1;
  295. cairo_matrix_init_identity (&matrix->matrix);
  296. obj->type = CSI_OBJECT_TYPE_MATRIX;
  297. obj->datum.matrix = matrix;
  298. return CSI_STATUS_SUCCESS;
  299. }
  300. csi_status_t
  301. csi_matrix_new_from_array (csi_t *ctx,
  302. csi_object_t *obj,
  303. csi_array_t *array)
  304. {
  305. csi_matrix_t *matrix;
  306. if (_csi_unlikely (array->stack.len != 6))
  307. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  308. matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
  309. if (_csi_unlikely (matrix == NULL))
  310. return _csi_error (CSI_STATUS_NO_MEMORY);
  311. matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
  312. matrix->base.ref = 1;
  313. cairo_matrix_init (&matrix->matrix,
  314. csi_number_get_value (&array->stack.objects[0]),
  315. csi_number_get_value (&array->stack.objects[1]),
  316. csi_number_get_value (&array->stack.objects[2]),
  317. csi_number_get_value (&array->stack.objects[3]),
  318. csi_number_get_value (&array->stack.objects[4]),
  319. csi_number_get_value (&array->stack.objects[5]));
  320. obj->type = CSI_OBJECT_TYPE_MATRIX;
  321. obj->datum.matrix = matrix;
  322. return CSI_STATUS_SUCCESS;
  323. }
  324. csi_status_t
  325. csi_matrix_new_from_matrix (csi_t *ctx,
  326. csi_object_t *obj,
  327. const cairo_matrix_t *m)
  328. {
  329. csi_matrix_t *matrix;
  330. matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
  331. if (_csi_unlikely (matrix == NULL))
  332. return _csi_error (CSI_STATUS_NO_MEMORY);
  333. matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
  334. matrix->base.ref = 1;
  335. matrix->matrix = *m;
  336. obj->type = CSI_OBJECT_TYPE_MATRIX;
  337. obj->datum.matrix = matrix;
  338. return CSI_STATUS_SUCCESS;
  339. }
  340. csi_status_t
  341. csi_matrix_new_from_values (csi_t *ctx,
  342. csi_object_t *obj,
  343. double v[6])
  344. {
  345. csi_matrix_t *matrix;
  346. matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
  347. if (_csi_unlikely (matrix == NULL))
  348. return _csi_error (CSI_STATUS_NO_MEMORY);
  349. matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
  350. matrix->base.ref = 1;
  351. cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]);
  352. obj->type = CSI_OBJECT_TYPE_MATRIX;
  353. obj->datum.matrix = matrix;
  354. return CSI_STATUS_SUCCESS;
  355. }
  356. void
  357. csi_matrix_free (csi_t *ctx,
  358. csi_matrix_t *obj)
  359. {
  360. _csi_slab_free (ctx, obj, sizeof (csi_matrix_t));
  361. }
  362. csi_status_t
  363. csi_name_new (csi_t *ctx,
  364. csi_object_t *obj,
  365. const char *str,
  366. int len)
  367. {
  368. csi_status_t status;
  369. status = _csi_intern_string (ctx, &str, len);
  370. if (_csi_unlikely (status))
  371. return status;
  372. obj->type = CSI_OBJECT_TYPE_NAME;
  373. obj->datum.name = (csi_name_t) str;
  374. return CSI_STATUS_SUCCESS;
  375. }
  376. csi_status_t
  377. csi_name_new_static (csi_t *ctx,
  378. csi_object_t *obj,
  379. const char *str)
  380. {
  381. csi_status_t status;
  382. status = _csi_intern_string (ctx, &str, strlen (str));
  383. if (_csi_unlikely (status))
  384. return status;
  385. obj->type = CSI_OBJECT_TYPE_NAME;
  386. obj->datum.name = (csi_name_t) str;
  387. return CSI_STATUS_SUCCESS;
  388. }
  389. csi_status_t
  390. csi_string_new (csi_t *ctx,
  391. csi_object_t *obj,
  392. const char *str,
  393. int len)
  394. {
  395. csi_string_t *string;
  396. if (len < 0)
  397. len = strlen (str);
  398. if (_csi_unlikely (len >= INT_MAX))
  399. return _csi_error (CSI_STATUS_NO_MEMORY);
  400. if (ctx->free_string == NULL || ctx->free_string->len <= len) {
  401. string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
  402. if (_csi_unlikely (string == NULL))
  403. return _csi_error (CSI_STATUS_NO_MEMORY);
  404. string->string = _csi_alloc (ctx, len + 1);
  405. if (_csi_unlikely (string->string == NULL)) {
  406. _csi_slab_free (ctx, string, sizeof (csi_string_t));
  407. return _csi_error (CSI_STATUS_NO_MEMORY);
  408. }
  409. } else {
  410. string = ctx->free_string;
  411. ctx->free_string = NULL;
  412. }
  413. if (str != NULL) {
  414. memcpy (string->string, str, len);
  415. string->string[len] = '\0';
  416. }
  417. string->len = len;
  418. string->deflate = 0;
  419. string->method = NONE;
  420. string->base.type = CSI_OBJECT_TYPE_STRING;
  421. string->base.ref = 1;
  422. obj->type = CSI_OBJECT_TYPE_STRING;
  423. obj->datum.string = string;
  424. return CSI_STATUS_SUCCESS;
  425. }
  426. csi_status_t
  427. csi_string_deflate_new (csi_t *ctx,
  428. csi_object_t *obj,
  429. void *bytes,
  430. int in_len,
  431. int out_len)
  432. {
  433. csi_status_t status;
  434. csi_string_t *string;
  435. status = csi_string_new (ctx, obj, bytes, in_len);
  436. if (_csi_unlikely (status))
  437. return status;
  438. string = obj->datum.string;
  439. string->deflate = out_len;
  440. string->method = ZLIB;
  441. return CSI_STATUS_SUCCESS;
  442. }
  443. csi_status_t
  444. csi_string_new_from_bytes (csi_t *ctx,
  445. csi_object_t *obj,
  446. char *bytes,
  447. unsigned int len)
  448. {
  449. csi_string_t *string;
  450. if (_csi_unlikely (len >= INT_MAX))
  451. return _csi_error (CSI_STATUS_NO_MEMORY);
  452. string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
  453. if (_csi_unlikely (string == NULL))
  454. return _csi_error (CSI_STATUS_NO_MEMORY);
  455. string->string = bytes;
  456. string->len = len;
  457. string->deflate = 0;
  458. string->method = NONE;
  459. string->base.type = CSI_OBJECT_TYPE_STRING;
  460. string->base.ref = 1;
  461. obj->type = CSI_OBJECT_TYPE_STRING;
  462. obj->datum.string = string;
  463. return CSI_STATUS_SUCCESS;
  464. }
  465. static inline csi_status_t
  466. _csi_string_execute (csi_t *ctx, csi_string_t *string)
  467. {
  468. csi_status_t status;
  469. csi_object_t obj;
  470. if (_csi_unlikely (string->len == 0))
  471. return CSI_STATUS_SUCCESS;
  472. status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len);
  473. if (_csi_unlikely (status))
  474. return status;
  475. status = _csi_scan_file (ctx, obj.datum.file);
  476. csi_object_free (ctx, &obj);
  477. return status;
  478. }
  479. void
  480. csi_string_free (csi_t *ctx, csi_string_t *string)
  481. {
  482. #if CSI_DEBUG_MALLOC
  483. _csi_free (ctx, string->string);
  484. _csi_slab_free (ctx, string, sizeof (csi_string_t));
  485. #else
  486. if (ctx->free_string != NULL) {
  487. if (string->len > ctx->free_string->len) {
  488. csi_string_t *tmp = ctx->free_string;
  489. ctx->free_string = string;
  490. string = tmp;
  491. }
  492. _csi_free (ctx, string->string);
  493. _csi_slab_free (ctx, string, sizeof (csi_string_t));
  494. } else
  495. ctx->free_string = string;
  496. #endif
  497. }
  498. csi_status_t
  499. csi_object_execute (csi_t *ctx, csi_object_t *obj)
  500. {
  501. csi_status_t status;
  502. csi_object_t indirect;
  503. INDIRECT:
  504. switch (obj->type & CSI_OBJECT_TYPE_MASK) {
  505. case CSI_OBJECT_TYPE_NAME:
  506. status = _csi_name_lookup (ctx, obj->datum.name, &indirect);
  507. if (_csi_unlikely (status))
  508. return status;
  509. if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) {
  510. obj = &indirect;
  511. goto INDIRECT;
  512. } else
  513. return _csi_push_ostack_copy (ctx, &indirect);
  514. case CSI_OBJECT_TYPE_OPERATOR:
  515. return obj->datum.op (ctx);
  516. case CSI_OBJECT_TYPE_ARRAY:
  517. return _csi_array_execute (ctx, obj->datum.array);
  518. case CSI_OBJECT_TYPE_FILE:
  519. return _csi_file_execute (ctx, obj->datum.file);
  520. case CSI_OBJECT_TYPE_STRING:
  521. return _csi_string_execute (ctx, obj->datum.string);
  522. default:
  523. return _csi_push_ostack_copy (ctx, obj);
  524. }
  525. }
  526. csi_object_t *
  527. csi_object_reference (csi_object_t *obj)
  528. {
  529. if (CSI_OBJECT_IS_CAIRO (obj)) {
  530. switch (obj->type & CSI_OBJECT_TYPE_MASK) {
  531. case CSI_OBJECT_TYPE_CONTEXT:
  532. cairo_reference (obj->datum.cr);
  533. break;
  534. case CSI_OBJECT_TYPE_FONT:
  535. cairo_font_face_reference (obj->datum.font_face);
  536. break;
  537. case CSI_OBJECT_TYPE_PATTERN:
  538. cairo_pattern_reference (obj->datum.pattern);
  539. break;
  540. case CSI_OBJECT_TYPE_SCALED_FONT:
  541. cairo_scaled_font_reference (obj->datum.scaled_font);
  542. break;
  543. case CSI_OBJECT_TYPE_SURFACE:
  544. cairo_surface_reference (obj->datum.surface);
  545. break;
  546. }
  547. } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
  548. obj->datum.object->ref++;
  549. }
  550. return obj;
  551. }
  552. void
  553. csi_object_free (csi_t *ctx,
  554. csi_object_t *obj)
  555. {
  556. if (CSI_OBJECT_IS_CAIRO (obj)) {
  557. switch (obj->type & CSI_OBJECT_TYPE_MASK) {
  558. case CSI_OBJECT_TYPE_CONTEXT:
  559. cairo_destroy (obj->datum.cr);
  560. break;
  561. case CSI_OBJECT_TYPE_FONT:
  562. cairo_font_face_destroy (obj->datum.font_face);
  563. break;
  564. case CSI_OBJECT_TYPE_PATTERN:
  565. cairo_pattern_destroy (obj->datum.pattern);
  566. break;
  567. case CSI_OBJECT_TYPE_SCALED_FONT:
  568. cairo_scaled_font_destroy (obj->datum.scaled_font);
  569. break;
  570. case CSI_OBJECT_TYPE_SURFACE:
  571. cairo_surface_destroy (obj->datum.surface);
  572. break;
  573. }
  574. } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
  575. if (--obj->datum.object->ref)
  576. return;
  577. switch (obj->type & CSI_OBJECT_TYPE_MASK) {
  578. case CSI_OBJECT_TYPE_ARRAY:
  579. csi_array_free (ctx, obj->datum.array);
  580. break;
  581. case CSI_OBJECT_TYPE_DICTIONARY:
  582. csi_dictionary_free (ctx, obj->datum.dictionary);
  583. break;
  584. case CSI_OBJECT_TYPE_FILE:
  585. _csi_file_free (ctx, obj->datum.file);
  586. break;
  587. case CSI_OBJECT_TYPE_MATRIX:
  588. csi_matrix_free (ctx, obj->datum.matrix);
  589. break;
  590. case CSI_OBJECT_TYPE_STRING:
  591. csi_string_free (ctx, obj->datum.string);
  592. break;
  593. default:
  594. break;
  595. }
  596. }
  597. }
  598. csi_status_t
  599. csi_object_as_file (csi_t *ctx,
  600. csi_object_t *src,
  601. csi_object_t *file)
  602. {
  603. int type = csi_object_get_type (src);
  604. switch (type) {
  605. case CSI_OBJECT_TYPE_FILE:
  606. *file = *csi_object_reference (src);
  607. return CSI_STATUS_SUCCESS;
  608. case CSI_OBJECT_TYPE_STRING:
  609. return csi_file_new_from_string (ctx, file, src->datum.string);
  610. case CSI_OBJECT_TYPE_ARRAY:
  611. #if 0
  612. if (src->type & CSI_OBJECT_ATTR_EXECUTABLE)
  613. return _csi_file_new_from_procedure (cs, src);
  614. #endif
  615. default:
  616. return _csi_error (CSI_STATUS_INVALID_SCRIPT);
  617. }
  618. }
  619. static int
  620. lexcmp (void const *a, size_t alen,
  621. void const *b, size_t blen)
  622. {
  623. size_t len = alen < blen ? alen : blen;
  624. int cmp = memcmp (a, b, len);
  625. if (cmp)
  626. return cmp;
  627. if (alen == blen)
  628. return 0;
  629. return alen < blen ? -1 : +1;
  630. }
  631. csi_boolean_t
  632. csi_object_eq (csi_object_t *a,
  633. csi_object_t *b)
  634. {
  635. csi_object_type_t atype = csi_object_get_type (a);
  636. csi_object_type_t btype = csi_object_get_type (b);
  637. if (atype == btype) {
  638. switch (atype) {
  639. case CSI_OBJECT_TYPE_BOOLEAN:
  640. return a->datum.boolean == b->datum.boolean;
  641. case CSI_OBJECT_TYPE_INTEGER:
  642. return a->datum.integer == b->datum.integer;
  643. case CSI_OBJECT_TYPE_REAL:
  644. return a->datum.real == b->datum.real;
  645. case CSI_OBJECT_TYPE_NAME:
  646. return a->datum.name == b->datum.name;
  647. case CSI_OBJECT_TYPE_STRING:
  648. return 0 == lexcmp (a->datum.string->string,
  649. a->datum.string->len,
  650. b->datum.string->string,
  651. b->datum.string->len);
  652. case CSI_OBJECT_TYPE_NULL:
  653. case CSI_OBJECT_TYPE_MARK:
  654. return TRUE;
  655. case CSI_OBJECT_TYPE_OPERATOR:
  656. return a->datum.op == b->datum.op;
  657. case CSI_OBJECT_TYPE_ARRAY:
  658. case CSI_OBJECT_TYPE_DICTIONARY:
  659. case CSI_OBJECT_TYPE_FILE:
  660. case CSI_OBJECT_TYPE_MATRIX:
  661. case CSI_OBJECT_TYPE_CONTEXT:
  662. case CSI_OBJECT_TYPE_FONT:
  663. case CSI_OBJECT_TYPE_PATTERN:
  664. case CSI_OBJECT_TYPE_SCALED_FONT:
  665. case CSI_OBJECT_TYPE_SURFACE:
  666. return a->datum.ptr == b->datum.ptr;
  667. }
  668. }
  669. if (atype < btype) {
  670. csi_object_t *c;
  671. csi_object_type_t ctype;
  672. c = a; a = b; b = c;
  673. ctype = atype; atype = btype; btype = ctype;
  674. }
  675. switch ((int) atype) {
  676. case CSI_OBJECT_TYPE_INTEGER:
  677. if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
  678. return a->datum.integer == b->datum.boolean;
  679. }
  680. break;
  681. case CSI_OBJECT_TYPE_REAL:
  682. if (btype == CSI_OBJECT_TYPE_INTEGER) {
  683. return a->datum.real == b->datum.integer;
  684. }
  685. else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
  686. return a->datum.real == b->datum.boolean;
  687. }
  688. break;
  689. case CSI_OBJECT_TYPE_STRING:
  690. if (btype == CSI_OBJECT_TYPE_NAME) {
  691. const char *bstr = (const char *) b->datum.name;
  692. return 0 == lexcmp (a->datum.string->string,
  693. a->datum.string->len,
  694. bstr,
  695. strlen (bstr));
  696. }
  697. break;
  698. default:
  699. break;
  700. }
  701. return FALSE;
  702. }
  703. csi_status_t
  704. csi_object_compare (csi_object_t *a,
  705. csi_object_t *b,
  706. int *out)
  707. {
  708. csi_object_type_t atype = csi_object_get_type (a);
  709. csi_object_type_t btype = csi_object_get_type (b);
  710. int sign;
  711. if (csi_object_eq (a, b)){
  712. *out = 0;
  713. return CSI_STATUS_SUCCESS;
  714. }
  715. #define CMP(x,y) ((x) < (y) ? -1 : +1)
  716. if (atype == btype) {
  717. switch (atype) {
  718. case CSI_OBJECT_TYPE_BOOLEAN:
  719. *out = CMP (a->datum.boolean, b->datum.boolean);
  720. return CSI_STATUS_SUCCESS;
  721. case CSI_OBJECT_TYPE_INTEGER:
  722. *out = CMP (a->datum.integer, b->datum.integer);
  723. return CSI_STATUS_SUCCESS;
  724. case CSI_OBJECT_TYPE_REAL:
  725. *out = CMP (a->datum.real, b->datum.real);
  726. return CSI_STATUS_SUCCESS;
  727. case CSI_OBJECT_TYPE_NAME: {
  728. const char *x = (char const *) a->datum.name;
  729. const char *y = (char const *) b->datum.name;
  730. *out = lexcmp (x, strlen(x), y, strlen (y));
  731. return CSI_STATUS_SUCCESS;
  732. }
  733. case CSI_OBJECT_TYPE_STRING:
  734. *out = lexcmp (a->datum.string->string,
  735. a->datum.string->len,
  736. b->datum.string->string,
  737. b->datum.string->len);
  738. return CSI_STATUS_SUCCESS;
  739. case CSI_OBJECT_TYPE_NULL:
  740. case CSI_OBJECT_TYPE_MARK:
  741. case CSI_OBJECT_TYPE_OPERATOR:
  742. case CSI_OBJECT_TYPE_ARRAY:
  743. case CSI_OBJECT_TYPE_DICTIONARY:
  744. case CSI_OBJECT_TYPE_FILE:
  745. case CSI_OBJECT_TYPE_MATRIX:
  746. case CSI_OBJECT_TYPE_CONTEXT:
  747. case CSI_OBJECT_TYPE_FONT:
  748. case CSI_OBJECT_TYPE_PATTERN:
  749. case CSI_OBJECT_TYPE_SCALED_FONT:
  750. case CSI_OBJECT_TYPE_SURFACE:
  751. goto TYPE_CHECK_ERROR;
  752. }
  753. }
  754. sign = +1;
  755. if (atype < btype) {
  756. csi_object_t *c;
  757. csi_object_type_t ctype;
  758. c = a; a = b; b = c;
  759. ctype = atype; atype = btype; btype = ctype;
  760. sign = -1;
  761. }
  762. switch ((int) atype) {
  763. case CSI_OBJECT_TYPE_INTEGER:
  764. if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
  765. *out = sign * CMP (a->datum.integer, !!b->datum.boolean);
  766. return CSI_STATUS_SUCCESS;
  767. }
  768. break;
  769. case CSI_OBJECT_TYPE_REAL:
  770. if (btype == CSI_OBJECT_TYPE_INTEGER) {
  771. *out = sign * CMP (a->datum.real, b->datum.integer);
  772. return CSI_STATUS_SUCCESS;
  773. }
  774. else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
  775. *out = sign * CMP (a->datum.real, !!b->datum.boolean);
  776. return CSI_STATUS_SUCCESS;
  777. }
  778. break;
  779. case CSI_OBJECT_TYPE_STRING:
  780. if (btype == CSI_OBJECT_TYPE_NAME) {
  781. const char *bstr = (const char *) b->datum.name;
  782. *out = sign * lexcmp (a->datum.string->string,
  783. a->datum.string->len,
  784. bstr,
  785. strlen (bstr));
  786. return CSI_STATUS_SUCCESS;
  787. }
  788. break;
  789. default:
  790. break;
  791. }
  792. #undef CMP
  793. TYPE_CHECK_ERROR:
  794. return _csi_error (CSI_STATUS_SCRIPT_INVALID_TYPE);
  795. }