1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: zgstate.c,v 1.10 2004/08/04 19:36:13 stefan Exp $ */
18 /* Graphics state operators */
19 #include "math_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "ialloc.h"
23 #include "icremap.h"
24 #include "idict.h"
25 #include "istruct.h"
26 #include "igstate.h"
27 #include "gsmatrix.h"
28 #include "store.h"
29 #include "gscspace.h"
30 #include "iname.h"
31
32 /* Structure descriptors */
33 private_st_int_gstate();
34 private_st_int_remap_color_info();
35
36 /* ------ Utilities ------ */
37
38 private int
zset_real(i_ctx_t * i_ctx_p,int (* set_proc)(gs_state *,floatp))39 zset_real(i_ctx_t *i_ctx_p, int (*set_proc)(gs_state *, floatp))
40 {
41 os_ptr op = osp;
42 double param;
43 int code = real_param(op, ¶m);
44
45 if (code < 0)
46 return_op_typecheck(op);
47 code = set_proc(igs, param);
48 if (!code)
49 pop(1);
50 return code;
51 }
52
53 private int
zset_bool(i_ctx_t * i_ctx_p,void (* set_proc)(gs_state *,bool))54 zset_bool(i_ctx_t *i_ctx_p, void (*set_proc)(gs_state *, bool))
55 {
56 os_ptr op = osp;
57
58 check_type(*op, t_boolean);
59 set_proc(igs, op->value.boolval);
60 pop(1);
61 return 0;
62 }
63
64 private int
zcurrent_bool(i_ctx_t * i_ctx_p,bool (* current_proc)(const gs_state *))65 zcurrent_bool(i_ctx_t *i_ctx_p, bool (*current_proc)(const gs_state *))
66 {
67 os_ptr op = osp;
68
69 push(1);
70 make_bool(op, current_proc(igs));
71 return 0;
72 }
73
74 private int
zset_uint(i_ctx_t * i_ctx_p,void (* set_proc)(gs_state *,uint))75 zset_uint(i_ctx_t *i_ctx_p, void (*set_proc)(gs_state *, uint))
76 {
77 os_ptr op = osp;
78
79 check_type(*op, t_integer);
80 set_proc(igs, op->value.intval);
81 pop(1);
82 return 0;
83 }
84
85 private int
zcurrent_uint(i_ctx_t * i_ctx_p,uint (* current_proc)(const gs_state *))86 zcurrent_uint(i_ctx_t *i_ctx_p, uint (*current_proc)(const gs_state *))
87 {
88 os_ptr op = osp;
89
90 push(1);
91 make_int(op, current_proc(igs));
92 return 0;
93 }
94
95 /* ------ Operations on the entire graphics state ------ */
96
97 /* "Client" procedures */
98 private void *gs_istate_alloc(gs_memory_t * mem);
99 private int gs_istate_copy(void *to, const void *from);
100 private void gs_istate_free(void *old, gs_memory_t * mem);
101 private const gs_state_client_procs istate_procs = {
102 gs_istate_alloc,
103 gs_istate_copy,
104 gs_istate_free,
105 0, /* copy_for */
106 };
107
108 /* Initialize the graphics stack. */
109 gs_state *
int_gstate_alloc(const gs_dual_memory_t * dmem)110 int_gstate_alloc(const gs_dual_memory_t * dmem)
111 {
112 int_gstate *iigs;
113 ref proc0;
114 int_remap_color_info_t *prci;
115 gs_ref_memory_t *lmem = dmem->space_local;
116 gs_ref_memory_t *gmem = dmem->space_global;
117 gs_state *pgs = gs_state_alloc((gs_memory_t *)lmem);
118
119 iigs = gs_alloc_struct((gs_memory_t *)lmem, int_gstate, &st_int_gstate,
120 "int_gstate_alloc(int_gstate)");
121 int_gstate_map_refs(iigs, make_null);
122 make_empty_array(&iigs->dash_pattern, a_all);
123 gs_alloc_ref_array(lmem, &proc0, a_readonly + a_executable, 2,
124 "int_gstate_alloc(proc0)");
125 make_oper(proc0.value.refs, 0, zpop);
126 make_real(proc0.value.refs + 1, 0.0);
127 iigs->black_generation = proc0;
128 iigs->undercolor_removal = proc0;
129 make_false(&iigs->use_cie_color);
130 /*
131 * Even though the gstate itself is allocated in local VM, the
132 * container for the color remapping procedure must be allocated in
133 * global VM so that the gstate can be copied into global VM.
134 */
135 prci = gs_alloc_struct((gs_memory_t *)gmem, int_remap_color_info_t,
136 &st_int_remap_color_info,
137 "int_gstate_alloc(remap color info)");
138 make_struct(&iigs->remap_color_info, imemory_space(gmem), prci);
139 clear_pagedevice(iigs);
140 gs_state_set_client(pgs, iigs, &istate_procs, true);
141 /* PostScript code wants limit clamping enabled. */
142 gs_setlimitclamp(pgs, true);
143 /*
144 * gsave and grestore only work properly
145 * if there are always at least 2 entries on the stack.
146 * We count on the PostScript initialization code to do a gsave.
147 */
148 return pgs;
149 }
150
151 /* - gsave - */
152 int
zgsave(i_ctx_t * i_ctx_p)153 zgsave(i_ctx_t *i_ctx_p)
154 {
155 return gs_gsave(igs);
156 }
157
158 /* - grestore - */
159 int
zgrestore(i_ctx_t * i_ctx_p)160 zgrestore(i_ctx_t *i_ctx_p)
161 {
162 return gs_grestore(igs);
163 }
164
165 /* - grestoreall - */
166 int
zgrestoreall(i_ctx_t * i_ctx_p)167 zgrestoreall(i_ctx_t *i_ctx_p)
168 {
169 return gs_grestoreall(igs);
170 }
171
172 /* - initgraphics - */
173 private int
zinitgraphics(i_ctx_t * i_ctx_p)174 zinitgraphics(i_ctx_t *i_ctx_p)
175 {
176 /*
177 * gs_initigraphics does not reset the colorspace;
178 * this is now handled in the PostScript code.
179 */
180 return gs_initgraphics(igs);
181 }
182
183 /* ------ Operations on graphics state elements ------ */
184
185 /* <num> setlinewidth - */
186 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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, op1);
323 pop(2);
324 return code;
325 }
326
327 /* - currentdash <array> <offset> */
328 private 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);
335 make_real(op, gs_currentdash_offset(igs));
336 return 0;
337 }
338
339 /* <num> setflat - */
340 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 /* ------ Initialization procedure ------ */
519
520 /* We need to split the table because of the 16-element limit. */
521 const op_def zgstate1_op_defs[] = {
522 {"0.currentaccuratecurves", zcurrentaccuratecurves},
523 {"0.currentcurvejoin", zcurrentcurvejoin},
524 {"0currentdash", zcurrentdash},
525 {"0.currentdashadapt", zcurrentdashadapt},
526 {"0.currentdotlength", zcurrentdotlength},
527 {"0.currentfilladjust2", zcurrentfilladjust2},
528 {"0currentflat", zcurrentflat},
529 {"0.currentlimitclamp", zcurrentlimitclamp},
530 {"0currentlinecap", zcurrentlinecap},
531 {"0currentlinejoin", zcurrentlinejoin},
532 {"0currentlinewidth", zcurrentlinewidth},
533 {"0currentmiterlimit", zcurrentmiterlimit},
534 {"0.dotorientation", zdotorientation},
535 {"0grestore", zgrestore},
536 {"0grestoreall", zgrestoreall},
537 op_def_end(0)
538 };
539 const op_def zgstate2_op_defs[] = {
540 {"0gsave", zgsave},
541 {"0initgraphics", zinitgraphics},
542 {"1.setaccuratecurves", zsetaccuratecurves},
543 {"1.setcurvejoin", zsetcurvejoin},
544 {"2setdash", zsetdash},
545 {"1.setdashadapt", zsetdashadapt},
546 {"2.setdotlength", zsetdotlength},
547 {"0.setdotorientation", zsetdotorientation},
548 {"2.setfilladjust2", zsetfilladjust2},
549 {"1.setlimitclamp", zsetlimitclamp},
550 {"1setflat", zsetflat},
551 {"1.setlinecap", zsetlinecap},
552 {"1.setlinejoin", zsetlinejoin},
553 {"1setlinewidth", zsetlinewidth},
554 {"1setmiterlimit", zsetmiterlimit},
555 op_def_end(0)
556 };
557 const op_def zgstate3_op_defs[] = {
558 {"0.settextrenderingmode", zsettextrenderingmode},
559 {"0.currenttextrenderingmode", zcurrenttextrenderingmode},
560 op_def_end(0)
561 };
562
563 /* ------ Internal routines ------ */
564
565 /* Allocate the interpreter's part of a graphics state. */
566 private void *
gs_istate_alloc(gs_memory_t * mem)567 gs_istate_alloc(gs_memory_t * mem)
568 {
569 return gs_alloc_struct(mem, int_gstate, &st_int_gstate, "int_gsave");
570 }
571
572 /* Copy the interpreter's part of a graphics state. */
573 private int
gs_istate_copy(void * to,const void * from)574 gs_istate_copy(void *to, const void *from)
575 {
576 *(int_gstate *) to = *(const int_gstate *)from;
577 return 0;
578 }
579
580 /* Free the interpreter's part of a graphics state. */
581 private void
gs_istate_free(void * old,gs_memory_t * mem)582 gs_istate_free(void *old, gs_memory_t * mem)
583 {
584 gs_free_object(mem, old, "int_grestore");
585 }
586