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, &param);
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, &param);
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, &param);
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