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, ¶m);
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, ¶m);
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, ¶m);
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