1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: zgstate.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* Graphics state operators */
16 #include "math_.h"
17 #include "ghost.h"
18 #include "oper.h"
19 #include "ialloc.h"
20 #include "icremap.h"
21 #include "idict.h"
22 #include "istruct.h"
23 #include "igstate.h"
24 #include "gsmatrix.h"
25 #include "store.h"
26 #include "gscspace.h"
27 #include "iname.h"
28
29 /* Structure descriptors */
30 private_st_int_gstate();
31 private_st_int_remap_color_info();
32
33 /* ------ Utilities ------ */
34
35 static int
zset_real(i_ctx_t * i_ctx_p,int (* set_proc)(gs_state *,floatp))36 zset_real(i_ctx_t *i_ctx_p, int (*set_proc)(gs_state *, floatp))
37 {
38 os_ptr op = osp;
39 double param;
40 int code = real_param(op, ¶m);
41
42 if (code < 0)
43 return_op_typecheck(op);
44 code = set_proc(igs, param);
45 if (!code)
46 pop(1);
47 return code;
48 }
49
50 static int
zset_bool(i_ctx_t * i_ctx_p,void (* set_proc)(gs_state *,bool))51 zset_bool(i_ctx_t *i_ctx_p, void (*set_proc)(gs_state *, bool))
52 {
53 os_ptr op = osp;
54
55 check_type(*op, t_boolean);
56 set_proc(igs, op->value.boolval);
57 pop(1);
58 return 0;
59 }
60
61 static int
zcurrent_bool(i_ctx_t * i_ctx_p,bool (* current_proc)(const gs_state *))62 zcurrent_bool(i_ctx_t *i_ctx_p, bool (*current_proc)(const gs_state *))
63 {
64 os_ptr op = osp;
65
66 push(1);
67 make_bool(op, current_proc(igs));
68 return 0;
69 }
70
71 static int
zset_uint(i_ctx_t * i_ctx_p,void (* set_proc)(gs_state *,uint))72 zset_uint(i_ctx_t *i_ctx_p, void (*set_proc)(gs_state *, uint))
73 {
74 os_ptr op = osp;
75
76 check_type(*op, t_integer);
77 set_proc(igs, op->value.intval);
78 pop(1);
79 return 0;
80 }
81
82 static int
zcurrent_uint(i_ctx_t * i_ctx_p,uint (* current_proc)(const gs_state *))83 zcurrent_uint(i_ctx_t *i_ctx_p, uint (*current_proc)(const gs_state *))
84 {
85 os_ptr op = osp;
86
87 push(1);
88 make_int(op, current_proc(igs));
89 return 0;
90 }
91
92 /* ------ Operations on the entire graphics state ------ */
93
94 /* "Client" procedures */
95 static void *gs_istate_alloc(gs_memory_t * mem);
96 static int gs_istate_copy(void *to, const void *from);
97 static void gs_istate_free(void *old, gs_memory_t * mem);
98 static const gs_state_client_procs istate_procs = {
99 gs_istate_alloc,
100 gs_istate_copy,
101 gs_istate_free,
102 0, /* copy_for */
103 };
104
105 /* Initialize the graphics stack. */
106 gs_state *
int_gstate_alloc(const gs_dual_memory_t * dmem)107 int_gstate_alloc(const gs_dual_memory_t * dmem)
108 {
109 int_gstate *iigs;
110 ref proc0;
111 int_remap_color_info_t *prci;
112 gs_ref_memory_t *lmem = dmem->space_local;
113 gs_ref_memory_t *gmem = dmem->space_global;
114 gs_state *pgs = gs_state_alloc((gs_memory_t *)lmem);
115
116 iigs = gs_alloc_struct((gs_memory_t *)lmem, int_gstate, &st_int_gstate,
117 "int_gstate_alloc(int_gstate)");
118 int_gstate_map_refs(iigs, make_null);
119 make_empty_array(&iigs->dash_pattern_array, a_all);
120 gs_alloc_ref_array(lmem, &proc0, a_readonly + a_executable, 2,
121 "int_gstate_alloc(proc0)");
122 make_oper(proc0.value.refs, 0, zpop);
123 make_real(proc0.value.refs + 1, 0.0);
124 iigs->black_generation = proc0;
125 iigs->undercolor_removal = proc0;
126 make_false(&iigs->use_cie_color);
127 /*
128 * Even though the gstate itself is allocated in local VM, the
129 * container for the color remapping procedure must be allocated in
130 * global VM so that the gstate can be copied into global VM.
131 */
132 prci = gs_alloc_struct((gs_memory_t *)gmem, int_remap_color_info_t,
133 &st_int_remap_color_info,
134 "int_gstate_alloc(remap color info)");
135 make_struct(&iigs->remap_color_info, imemory_space(gmem), prci);
136 clear_pagedevice(iigs);
137 gs_state_set_client(pgs, iigs, &istate_procs, true);
138 /* PostScript code wants limit clamping enabled. */
139 gs_setlimitclamp(pgs, true);
140 /*
141 * gsave and grestore only work properly
142 * if there are always at least 2 entries on the stack.
143 * We count on the PostScript initialization code to do a gsave.
144 */
145 return pgs;
146 }
147
148 /* - gsave - */
149 int
zgsave(i_ctx_t * i_ctx_p)150 zgsave(i_ctx_t *i_ctx_p)
151 {
152 return gs_gsave(igs);
153 }
154
155 /* - grestore - */
156 int
zgrestore(i_ctx_t * i_ctx_p)157 zgrestore(i_ctx_t *i_ctx_p)
158 {
159 return gs_grestore(igs);
160 }
161
162 /* - grestoreall - */
163 int
zgrestoreall(i_ctx_t * i_ctx_p)164 zgrestoreall(i_ctx_t *i_ctx_p)
165 {
166 return gs_grestoreall(igs);
167 }
168
169 /* - initgraphics - */
170 static int
zinitgraphics(i_ctx_t * i_ctx_p)171 zinitgraphics(i_ctx_t *i_ctx_p)
172 {
173 /*
174 * gs_initigraphics does not reset the colorspace;
175 * this is now handled in the PostScript code.
176 */
177 make_empty_array(&istate->dash_pattern_array, a_all);
178 return gs_initgraphics(igs);
179 }
180
181 /* ------ Operations on graphics state elements ------ */
182
183 /* <num> setlinewidth - */
184 static int
zsetlinewidth(i_ctx_t * i_ctx_p)185 zsetlinewidth(i_ctx_t *i_ctx_p)
186 {
187 os_ptr op = osp;
188 /*
189 * The Red Book doesn't say anything about this, but Adobe
190 * interpreters return (or perhaps store) the absolute value
191 * of the width.
192 */
193 double width;
194 int code = real_param(op, &width);
195
196 if (code < 0)
197 return_op_typecheck(op);
198 code = gs_setlinewidth(igs, fabs(width));
199 if (code >= 0)
200 pop(1);
201 return code;
202 }
203
204 /* - currentlinewidth <num> */
205 static int
zcurrentlinewidth(i_ctx_t * i_ctx_p)206 zcurrentlinewidth(i_ctx_t *i_ctx_p)
207 {
208 os_ptr op = osp;
209
210 push(1);
211 make_real(op, gs_currentlinewidth(igs));
212 return 0;
213 }
214
215 /* <cap_int> .setlinecap - */
216 static int
zsetlinecap(i_ctx_t * i_ctx_p)217 zsetlinecap(i_ctx_t *i_ctx_p)
218 {
219 os_ptr op = osp;
220 int param;
221 int code = int_param(op, max_int, ¶m);
222
223 if (code < 0 || (code = gs_setlinecap(igs, (gs_line_cap) param)) < 0)
224 return code;
225 pop(1);
226 return 0;
227 }
228
229 /* - currentlinecap <cap_int> */
230 static int
zcurrentlinecap(i_ctx_t * i_ctx_p)231 zcurrentlinecap(i_ctx_t *i_ctx_p)
232 {
233 os_ptr op = osp;
234
235 push(1);
236 make_int(op, (int)gs_currentlinecap(igs));
237 return 0;
238 }
239
240 /* <join_int> .setlinejoin - */
241 static int
zsetlinejoin(i_ctx_t * i_ctx_p)242 zsetlinejoin(i_ctx_t *i_ctx_p)
243 {
244 os_ptr op = osp;
245 int param;
246 int code = int_param(op, max_int, ¶m);
247
248 if (code < 0 || (code = gs_setlinejoin(igs, (gs_line_join) param)) < 0)
249 return code;
250 pop(1);
251 return 0;
252 }
253
254 /* - currentlinejoin <join_int> */
255 static int
zcurrentlinejoin(i_ctx_t * i_ctx_p)256 zcurrentlinejoin(i_ctx_t *i_ctx_p)
257 {
258 os_ptr op = osp;
259
260 push(1);
261 make_int(op, (int)gs_currentlinejoin(igs));
262 return 0;
263 }
264
265 /* <num> setmiterlimit - */
266 static int
zsetmiterlimit(i_ctx_t * i_ctx_p)267 zsetmiterlimit(i_ctx_t *i_ctx_p)
268 {
269 return zset_real(i_ctx_p, gs_setmiterlimit);
270 }
271
272 /* - currentmiterlimit <num> */
273 static int
zcurrentmiterlimit(i_ctx_t * i_ctx_p)274 zcurrentmiterlimit(i_ctx_t *i_ctx_p)
275 {
276 os_ptr op = osp;
277
278 push(1);
279 make_real(op, gs_currentmiterlimit(igs));
280 return 0;
281 }
282
283 /* <array> <offset> setdash - */
284 static int
zsetdash(i_ctx_t * i_ctx_p)285 zsetdash(i_ctx_t *i_ctx_p)
286 {
287 os_ptr op = osp;
288 os_ptr op1 = op - 1;
289 double offset;
290 int code = real_param(op, &offset);
291 uint i, n;
292 gs_memory_t *mem = imemory;
293 float *pattern;
294
295 if (code < 0)
296 return_op_typecheck(op);
297 if (!r_is_array(op1))
298 return_op_typecheck(op1);
299 /* Adobe interpreters apparently don't check the array for */
300 /* read access, so we won't either. */
301 /*check_read(*op1); */
302 /* Unpack the dash pattern and check it */
303 n = r_size(op1);
304 pattern =
305 (float *)gs_alloc_byte_array(mem, n, sizeof(float), "setdash");
306
307 if (pattern == 0)
308 return_error(e_VMerror);
309 for (i = 0, code = 0; i < n && code >= 0; ++i) {
310 ref element;
311
312 array_get(mem, op1, (long)i, &element);
313 code = float_param(&element, &pattern[i]);
314 }
315 if (code >= 0)
316 code = gs_setdash(igs, pattern, n, offset);
317 gs_free_object(mem, pattern, "setdash"); /* gs_setdash copies this */
318 if (code < 0)
319 return code;
320 ref_assign(&istate->dash_pattern_array, op1);
321 pop(2);
322 return code;
323 }
324
325 /* - currentdash <array> <offset> */
326 static int
zcurrentdash(i_ctx_t * i_ctx_p)327 zcurrentdash(i_ctx_t *i_ctx_p)
328 {
329 os_ptr op = osp;
330
331 push(2);
332 ref_assign(op - 1, &istate->dash_pattern_array);
333 make_real(op, gs_currentdash_offset(igs));
334 return 0;
335 }
336
337 /* <num> setflat - */
338 static int
zsetflat(i_ctx_t * i_ctx_p)339 zsetflat(i_ctx_t *i_ctx_p)
340 {
341 return zset_real(i_ctx_p, gs_setflat);
342 }
343
344 /* - currentflat <num> */
345 static int
zcurrentflat(i_ctx_t * i_ctx_p)346 zcurrentflat(i_ctx_t *i_ctx_p)
347 {
348 os_ptr op = osp;
349
350 push(1);
351 make_real(op, gs_currentflat(igs));
352 return 0;
353 }
354
355 /* ------ Extensions ------ */
356
357 /* <bool> .setaccuratecurves - */
358 static int
zsetaccuratecurves(i_ctx_t * i_ctx_p)359 zsetaccuratecurves(i_ctx_t *i_ctx_p)
360 {
361 return zset_bool(i_ctx_p, gs_setaccuratecurves);
362 }
363
364 /* - .currentaccuratecurves <bool> */
365 static int
zcurrentaccuratecurves(i_ctx_t * i_ctx_p)366 zcurrentaccuratecurves(i_ctx_t *i_ctx_p)
367 {
368 return zcurrent_bool(i_ctx_p, gs_currentaccuratecurves);
369 }
370
371 /* <join_int|-1> .setcurvejoin - */
372 static int
zsetcurvejoin(i_ctx_t * i_ctx_p)373 zsetcurvejoin(i_ctx_t *i_ctx_p)
374 {
375 os_ptr op = osp;
376 int code;
377
378 check_type(*op, t_integer);
379 if (op->value.intval < -1 || op->value.intval > max_int)
380 return_error(e_rangecheck);
381 code = gs_setcurvejoin(igs, (int)op->value.intval);
382 if (code < 0)
383 return code;
384 pop(1);
385 return 0;
386 }
387
388 /* - .currentcurvejoin <join_int|-1> */
389 static int
zcurrentcurvejoin(i_ctx_t * i_ctx_p)390 zcurrentcurvejoin(i_ctx_t *i_ctx_p)
391 {
392 os_ptr op = osp;
393
394 push(1);
395 make_int(op, gs_currentcurvejoin(igs));
396 return 0;
397 }
398
399 /* <adjust.x> <adjust.y> .setfilladjust2 - */
400 static int
zsetfilladjust2(i_ctx_t * i_ctx_p)401 zsetfilladjust2(i_ctx_t *i_ctx_p)
402 {
403 os_ptr op = osp;
404 double adjust[2];
405 int code = num_params(op, 2, adjust);
406
407 if (code < 0)
408 return code;
409 code = gs_setfilladjust(igs, adjust[0], adjust[1]);
410 if (code < 0)
411 return code;
412 pop(2);
413 return 0;
414 }
415
416 /* - .currentfilladjust2 <adjust.x> <adjust.y> */
417 static int
zcurrentfilladjust2(i_ctx_t * i_ctx_p)418 zcurrentfilladjust2(i_ctx_t *i_ctx_p)
419 {
420 os_ptr op = osp;
421 gs_point adjust;
422
423 push(2);
424 gs_currentfilladjust(igs, &adjust);
425 make_real(op - 1, adjust.x);
426 make_real(op, adjust.y);
427 return 0;
428 }
429
430 /* <bool> .setdashadapt - */
431 static int
zsetdashadapt(i_ctx_t * i_ctx_p)432 zsetdashadapt(i_ctx_t *i_ctx_p)
433 {
434 return zset_bool(i_ctx_p, gs_setdashadapt);
435 }
436
437 /* - .currentdashadapt <bool> */
438 static int
zcurrentdashadapt(i_ctx_t * i_ctx_p)439 zcurrentdashadapt(i_ctx_t *i_ctx_p)
440 {
441 return zcurrent_bool(i_ctx_p, gs_currentdashadapt);
442 }
443
444 /* <num> <bool> .setdotlength - */
445 static int
zsetdotlength(i_ctx_t * i_ctx_p)446 zsetdotlength(i_ctx_t *i_ctx_p)
447 {
448 os_ptr op = osp;
449 double length;
450 int code = real_param(op - 1, &length);
451
452 if (code < 0)
453 return code;
454 check_type(*op, t_boolean);
455 code = gs_setdotlength(igs, length, op->value.boolval);
456 if (code < 0)
457 return code;
458 pop(2);
459 return 0;
460 }
461
462 /* - .currentdotlength <num> <bool> */
463 static int
zcurrentdotlength(i_ctx_t * i_ctx_p)464 zcurrentdotlength(i_ctx_t *i_ctx_p)
465 {
466 os_ptr op = osp;
467
468 push(2);
469 make_real(op - 1, gs_currentdotlength(igs));
470 make_bool(op, gs_currentdotlength_absolute(igs));
471 return 0;
472 }
473
474 /* - .setdotorientation - */
475 static int
zsetdotorientation(i_ctx_t * i_ctx_p)476 zsetdotorientation(i_ctx_t *i_ctx_p)
477 {
478 return gs_setdotorientation(igs);
479 }
480
481 /* - .dotorientation - */
482 static int
zdotorientation(i_ctx_t * i_ctx_p)483 zdotorientation(i_ctx_t *i_ctx_p)
484 {
485 return gs_dotorientation(igs);
486 }
487
488 /* <bool> .setlimitclamp - */
489 static int
zsetlimitclamp(i_ctx_t * i_ctx_p)490 zsetlimitclamp(i_ctx_t *i_ctx_p)
491 {
492 return zset_bool(i_ctx_p, gs_setlimitclamp);
493 }
494
495 /* - .currentlimitclamp <bool> */
496 static int
zcurrentlimitclamp(i_ctx_t * i_ctx_p)497 zcurrentlimitclamp(i_ctx_t *i_ctx_p)
498 {
499 return zcurrent_bool(i_ctx_p, gs_currentlimitclamp);
500 }
501
502 /* <int> .settextrenderingmode - */
503 static int
zsettextrenderingmode(i_ctx_t * i_ctx_p)504 zsettextrenderingmode(i_ctx_t *i_ctx_p)
505 {
506 return zset_uint(i_ctx_p, gs_settextrenderingmode);
507 }
508
509 /* - .currenttextrenderingmode <int> */
510 static int
zcurrenttextrenderingmode(i_ctx_t * i_ctx_p)511 zcurrenttextrenderingmode(i_ctx_t *i_ctx_p)
512 {
513 return zcurrent_uint(i_ctx_p, gs_currenttextrenderingmode);
514 }
515
516 /* ------ Initialization procedure ------ */
517
518 /* We need to split the table because of the 16-element limit. */
519 const op_def zgstate1_op_defs[] = {
520 {"0.currentaccuratecurves", zcurrentaccuratecurves},
521 {"0.currentcurvejoin", zcurrentcurvejoin},
522 {"0currentdash", zcurrentdash},
523 {"0.currentdashadapt", zcurrentdashadapt},
524 {"0.currentdotlength", zcurrentdotlength},
525 {"0.currentfilladjust2", zcurrentfilladjust2},
526 {"0currentflat", zcurrentflat},
527 {"0.currentlimitclamp", zcurrentlimitclamp},
528 {"0currentlinecap", zcurrentlinecap},
529 {"0currentlinejoin", zcurrentlinejoin},
530 {"0currentlinewidth", zcurrentlinewidth},
531 {"0currentmiterlimit", zcurrentmiterlimit},
532 {"0.dotorientation", zdotorientation},
533 {"0grestore", zgrestore},
534 {"0grestoreall", zgrestoreall},
535 op_def_end(0)
536 };
537 const op_def zgstate2_op_defs[] = {
538 {"0gsave", zgsave},
539 {"0initgraphics", zinitgraphics},
540 {"1.setaccuratecurves", zsetaccuratecurves},
541 {"1.setcurvejoin", zsetcurvejoin},
542 {"2setdash", zsetdash},
543 {"1.setdashadapt", zsetdashadapt},
544 {"2.setdotlength", zsetdotlength},
545 {"0.setdotorientation", zsetdotorientation},
546 {"2.setfilladjust2", zsetfilladjust2},
547 {"1.setlimitclamp", zsetlimitclamp},
548 {"1setflat", zsetflat},
549 {"1.setlinecap", zsetlinecap},
550 {"1.setlinejoin", zsetlinejoin},
551 {"1setlinewidth", zsetlinewidth},
552 {"1setmiterlimit", zsetmiterlimit},
553 op_def_end(0)
554 };
555 const op_def zgstate3_op_defs[] = {
556 {"0.settextrenderingmode", zsettextrenderingmode},
557 {"0.currenttextrenderingmode", zcurrenttextrenderingmode},
558 op_def_end(0)
559 };
560
561 /* ------ Internal routines ------ */
562
563 /* Allocate the interpreter's part of a graphics state. */
564 static void *
gs_istate_alloc(gs_memory_t * mem)565 gs_istate_alloc(gs_memory_t * mem)
566 {
567 return gs_alloc_struct(mem, int_gstate, &st_int_gstate, "int_gsave");
568 }
569
570 /* Copy the interpreter's part of a graphics state. */
571 static int
gs_istate_copy(void * to,const void * from)572 gs_istate_copy(void *to, const void *from)
573 {
574 *(int_gstate *) to = *(const int_gstate *)from;
575 return 0;
576 }
577
578 /* Free the interpreter's part of a graphics state. */
579 static void
gs_istate_free(void * old,gs_memory_t * mem)580 gs_istate_free(void *old, gs_memory_t * mem)
581 {
582 gs_free_object(mem, old, "int_grestore");
583 }
584