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