xref: /plan9/sys/src/cmd/gs/src/zgstate.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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, &param);
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, &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 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, &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 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