1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: zgstate.c,v 1.2.6.1.2.1 2003/01/17 00:49:06 giles Exp $ */
20 /* Graphics state operators */
21 #include "math_.h"
22 #include "ghost.h"
23 #include "oper.h"
24 #include "ialloc.h"
25 #include "icremap.h"
26 #include "idict.h"
27 #include "istruct.h"
28 #include "igstate.h"
29 #include "gsmatrix.h"
30 #include "store.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)(P2 (gs_state *,floatp)))39 zset_real(i_ctx_t *i_ctx_p, int (*set_proc)(P2(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)(P2 (gs_state *,bool)))54 zset_bool(i_ctx_t *i_ctx_p, void (*set_proc)(P2(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)(P1 (const gs_state *)))65 zcurrent_bool(i_ctx_t *i_ctx_p, bool (*current_proc)(P1(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 /* ------ Operations on the entire graphics state ------ */
75 
76 /* "Client" procedures */
77 private void *gs_istate_alloc(P1(gs_memory_t * mem));
78 private int gs_istate_copy(P2(void *to, const void *from));
79 private void gs_istate_free(P2(void *old, gs_memory_t * mem));
80 private const gs_state_client_procs istate_procs = {
81     gs_istate_alloc,
82     gs_istate_copy,
83     gs_istate_free
84 };
85 
86 /* Initialize the graphics stack. */
87 gs_state *
int_gstate_alloc(const gs_dual_memory_t * dmem)88 int_gstate_alloc(const gs_dual_memory_t * dmem)
89 {
90     int_gstate *iigs;
91     ref proc0;
92     int_remap_color_info_t *prci;
93     gs_ref_memory_t *lmem = dmem->space_local;
94     gs_ref_memory_t *gmem = dmem->space_global;
95     gs_state *pgs = gs_state_alloc((gs_memory_t *)lmem);
96 
97     iigs = gs_alloc_struct((gs_memory_t *)lmem, int_gstate, &st_int_gstate,
98 			   "int_gstate_alloc(int_gstate)");
99     int_gstate_map_refs(iigs, make_null);
100     make_empty_array(&iigs->dash_pattern, a_all);
101     gs_alloc_ref_array(lmem, &proc0, a_readonly + a_executable, 2,
102 		       "int_gstate_alloc(proc0)");
103     make_oper(proc0.value.refs, 0, zpop);
104     make_real(proc0.value.refs + 1, 0.0);
105     iigs->black_generation = proc0;
106     iigs->undercolor_removal = proc0;
107     /*
108      * Even though the gstate itself is allocated in local VM, the
109      * container for the color remapping procedure must be allocated in
110      * global VM so that the gstate can be copied into global VM.
111      */
112     prci = gs_alloc_struct((gs_memory_t *)gmem, int_remap_color_info_t,
113 			   &st_int_remap_color_info,
114 			   "int_gstate_alloc(remap color info)");
115     make_struct(&iigs->remap_color_info, imemory_space(gmem), prci);
116     clear_pagedevice(iigs);
117     gs_state_set_client(pgs, iigs, &istate_procs);
118     /* PostScript code wants limit clamping enabled. */
119     gs_setlimitclamp(pgs, true);
120     /*
121      * gsave and grestore only work properly
122      * if there are always at least 2 entries on the stack.
123      * We count on the PostScript initialization code to do a gsave.
124      */
125     return pgs;
126 }
127 
128 /* - gsave - */
129 int
zgsave(i_ctx_t * i_ctx_p)130 zgsave(i_ctx_t *i_ctx_p)
131 {
132     return gs_gsave(igs);
133 }
134 
135 /* - grestore - */
136 int
zgrestore(i_ctx_t * i_ctx_p)137 zgrestore(i_ctx_t *i_ctx_p)
138 {
139     return gs_grestore(igs);
140 }
141 
142 /* - grestoreall - */
143 int
zgrestoreall(i_ctx_t * i_ctx_p)144 zgrestoreall(i_ctx_t *i_ctx_p)
145 {
146     return gs_grestoreall(igs);
147 }
148 
149 /* - initgraphics - */
150 private int
zinitgraphics(i_ctx_t * i_ctx_p)151 zinitgraphics(i_ctx_t *i_ctx_p)
152 {
153     /* gs_initgraphics does a setgray; we must clear the interpreter's */
154     /* cached copy of the color space object. */
155     int code = gs_initgraphics(igs);
156 
157     if (code >= 0)
158 	make_null(&istate->colorspace.array);
159     return code;
160 }
161 
162 /* ------ Operations on graphics state elements ------ */
163 
164 /* <num> setlinewidth - */
165 private int
zsetlinewidth(i_ctx_t * i_ctx_p)166 zsetlinewidth(i_ctx_t *i_ctx_p)
167 {
168     os_ptr op = osp;
169 	/*
170 	 * The Red Book doesn't say anything about this, but Adobe
171 	 * interpreters return (or perhaps store) the absolute value
172 	 * of the width.
173 	 */
174     double width;
175     int code = real_param(op, &width);
176 
177     if (code < 0)
178 	return_op_typecheck(op);
179     code = gs_setlinewidth(igs, fabs(width));
180     if (code >= 0)
181 	pop(1);
182     return code;
183 }
184 
185 /* - currentlinewidth <num> */
186 private int
zcurrentlinewidth(i_ctx_t * i_ctx_p)187 zcurrentlinewidth(i_ctx_t *i_ctx_p)
188 {
189     os_ptr op = osp;
190 
191     push(1);
192     make_real(op, gs_currentlinewidth(igs));
193     return 0;
194 }
195 
196 /* <cap_int> .setlinecap - */
197 private int
zsetlinecap(i_ctx_t * i_ctx_p)198 zsetlinecap(i_ctx_t *i_ctx_p)
199 {
200     os_ptr op = osp;
201     int param;
202     int code = int_param(op, max_int, &param);
203 
204     if (code < 0 || (code = gs_setlinecap(igs, (gs_line_cap) param)) < 0)
205 	return code;
206     pop(1);
207     return 0;
208 }
209 
210 /* - currentlinecap <cap_int> */
211 private int
zcurrentlinecap(i_ctx_t * i_ctx_p)212 zcurrentlinecap(i_ctx_t *i_ctx_p)
213 {
214     os_ptr op = osp;
215 
216     push(1);
217     make_int(op, (int)gs_currentlinecap(igs));
218     return 0;
219 }
220 
221 /* <join_int> .setlinejoin - */
222 private int
zsetlinejoin(i_ctx_t * i_ctx_p)223 zsetlinejoin(i_ctx_t *i_ctx_p)
224 {
225     os_ptr op = osp;
226     int param;
227     int code = int_param(op, max_int, &param);
228 
229     if (code < 0 || (code = gs_setlinejoin(igs, (gs_line_join) param)) < 0)
230 	return code;
231     pop(1);
232     return 0;
233 }
234 
235 /* - currentlinejoin <join_int> */
236 private int
zcurrentlinejoin(i_ctx_t * i_ctx_p)237 zcurrentlinejoin(i_ctx_t *i_ctx_p)
238 {
239     os_ptr op = osp;
240 
241     push(1);
242     make_int(op, (int)gs_currentlinejoin(igs));
243     return 0;
244 }
245 
246 /* <num> setmiterlimit - */
247 private int
zsetmiterlimit(i_ctx_t * i_ctx_p)248 zsetmiterlimit(i_ctx_t *i_ctx_p)
249 {
250     return zset_real(i_ctx_p, gs_setmiterlimit);
251 }
252 
253 /* - currentmiterlimit <num> */
254 private int
zcurrentmiterlimit(i_ctx_t * i_ctx_p)255 zcurrentmiterlimit(i_ctx_t *i_ctx_p)
256 {
257     os_ptr op = osp;
258 
259     push(1);
260     make_real(op, gs_currentmiterlimit(igs));
261     return 0;
262 }
263 
264 /* <array> <offset> setdash - */
265 private int
zsetdash(i_ctx_t * i_ctx_p)266 zsetdash(i_ctx_t *i_ctx_p)
267 {
268     os_ptr op = osp;
269     os_ptr op1 = op - 1;
270     double offset;
271     int code = real_param(op, &offset);
272     uint i, n;
273     gs_memory_t *mem = imemory;
274     float *pattern;
275 
276     if (code < 0)
277 	return_op_typecheck(op);
278     if (!r_is_array(op1))
279 	return_op_typecheck(op1);
280     /* Adobe interpreters apparently don't check the array for */
281     /* read access, so we won't either. */
282     /*check_read(*op1); */
283     /* Unpack the dash pattern and check it */
284     n = r_size(op1);
285     pattern =
286 	(float *)gs_alloc_byte_array(mem, n, sizeof(float), "setdash");
287 
288     if (pattern == 0)
289 	return_error(e_VMerror);
290     for (i = 0, code = 0; i < n && code >= 0; ++i) {
291 	ref element;
292 
293 	array_get(op1, (long)i, &element);
294 	code = float_param(&element, &pattern[i]);
295     }
296     if (code >= 0)
297 	code = gs_setdash(igs, pattern, n, offset);
298     gs_free_object(mem, pattern, "setdash");	/* gs_setdash copies this */
299     if (code < 0)
300 	return code;
301     ref_assign(&istate->dash_pattern, op1);
302     pop(2);
303     return code;
304 }
305 
306 /* - currentdash <array> <offset> */
307 private int
zcurrentdash(i_ctx_t * i_ctx_p)308 zcurrentdash(i_ctx_t *i_ctx_p)
309 {
310     os_ptr op = osp;
311 
312     push(2);
313     ref_assign(op - 1, &istate->dash_pattern);
314     make_real(op, gs_currentdash_offset(igs));
315     return 0;
316 }
317 
318 /* <num> setflat - */
319 private int
zsetflat(i_ctx_t * i_ctx_p)320 zsetflat(i_ctx_t *i_ctx_p)
321 {
322     return zset_real(i_ctx_p, gs_setflat);
323 }
324 
325 /* - currentflat <num> */
326 private int
zcurrentflat(i_ctx_t * i_ctx_p)327 zcurrentflat(i_ctx_t *i_ctx_p)
328 {
329     os_ptr op = osp;
330 
331     push(1);
332     make_real(op, gs_currentflat(igs));
333     return 0;
334 }
335 
336 /* ------ Extensions ------ */
337 
338 /* <bool> .setaccuratecurves - */
339 private int
zsetaccuratecurves(i_ctx_t * i_ctx_p)340 zsetaccuratecurves(i_ctx_t *i_ctx_p)
341 {
342     return zset_bool(i_ctx_p, gs_setaccuratecurves);
343 }
344 
345 /* - .currentaccuratecurves <bool> */
346 private int
zcurrentaccuratecurves(i_ctx_t * i_ctx_p)347 zcurrentaccuratecurves(i_ctx_t *i_ctx_p)
348 {
349     return zcurrent_bool(i_ctx_p, gs_currentaccuratecurves);
350 }
351 
352 /* <join_int|-1> .setcurvejoin - */
353 private int
zsetcurvejoin(i_ctx_t * i_ctx_p)354 zsetcurvejoin(i_ctx_t *i_ctx_p)
355 {
356     os_ptr op = osp;
357     int code;
358 
359     check_type(*op, t_integer);
360     if (op->value.intval < -1 || op->value.intval > max_int)
361 	return_error(e_rangecheck);
362     code = gs_setcurvejoin(igs, (int)op->value.intval);
363     if (code < 0)
364 	return code;
365     pop(1);
366     return 0;
367 }
368 
369 /* - .currentcurvejoin <join_int|-1> */
370 private int
zcurrentcurvejoin(i_ctx_t * i_ctx_p)371 zcurrentcurvejoin(i_ctx_t *i_ctx_p)
372 {
373     os_ptr op = osp;
374 
375     push(1);
376     make_int(op, gs_currentcurvejoin(igs));
377     return 0;
378 }
379 
380 /* <adjust.x> <adjust.y> .setfilladjust2 - */
381 private int
zsetfilladjust2(i_ctx_t * i_ctx_p)382 zsetfilladjust2(i_ctx_t *i_ctx_p)
383 {
384     os_ptr op = osp;
385     double adjust[2];
386     int code = num_params(op, 2, adjust);
387 
388     if (code < 0)
389 	return code;
390     code = gs_setfilladjust(igs, adjust[0], adjust[1]);
391     if (code < 0)
392 	return code;
393     pop(2);
394     return 0;
395 }
396 
397 /* - .currentfilladjust2 <adjust.x> <adjust.y> */
398 private int
zcurrentfilladjust2(i_ctx_t * i_ctx_p)399 zcurrentfilladjust2(i_ctx_t *i_ctx_p)
400 {
401     os_ptr op = osp;
402     gs_point adjust;
403 
404     push(2);
405     gs_currentfilladjust(igs, &adjust);
406     make_real(op - 1, adjust.x);
407     make_real(op, adjust.y);
408     return 0;
409 }
410 
411 /* <bool> .setdashadapt - */
412 private int
zsetdashadapt(i_ctx_t * i_ctx_p)413 zsetdashadapt(i_ctx_t *i_ctx_p)
414 {
415     return zset_bool(i_ctx_p, gs_setdashadapt);
416 }
417 
418 /* - .currentdashadapt <bool> */
419 private int
zcurrentdashadapt(i_ctx_t * i_ctx_p)420 zcurrentdashadapt(i_ctx_t *i_ctx_p)
421 {
422     return zcurrent_bool(i_ctx_p, gs_currentdashadapt);
423 }
424 
425 /* <num> <bool> .setdotlength - */
426 private int
zsetdotlength(i_ctx_t * i_ctx_p)427 zsetdotlength(i_ctx_t *i_ctx_p)
428 {
429     os_ptr op = osp;
430     double length;
431     int code = real_param(op - 1, &length);
432 
433     if (code < 0)
434 	return code;
435     check_type(*op, t_boolean);
436     code = gs_setdotlength(igs, length, op->value.boolval);
437     if (code < 0)
438 	return code;
439     pop(2);
440     return 0;
441 }
442 
443 /* - .currentdotlength <num> <bool> */
444 private int
zcurrentdotlength(i_ctx_t * i_ctx_p)445 zcurrentdotlength(i_ctx_t *i_ctx_p)
446 {
447     os_ptr op = osp;
448 
449     push(2);
450     make_real(op - 1, gs_currentdotlength(igs));
451     make_bool(op, gs_currentdotlength_absolute(igs));
452     return 0;
453 }
454 
455 /* - .setdotorientation - */
456 private int
zsetdotorientation(i_ctx_t * i_ctx_p)457 zsetdotorientation(i_ctx_t *i_ctx_p)
458 {
459     return gs_setdotorientation(igs);
460 }
461 
462 /* - .dotorientation - */
463 private int
zdotorientation(i_ctx_t * i_ctx_p)464 zdotorientation(i_ctx_t *i_ctx_p)
465 {
466     return gs_dotorientation(igs);
467 }
468 
469 /* <bool> .setlimitclamp - */
470 private int
zsetlimitclamp(i_ctx_t * i_ctx_p)471 zsetlimitclamp(i_ctx_t *i_ctx_p)
472 {
473     return zset_bool(i_ctx_p, gs_setlimitclamp);
474 }
475 
476 /* - .currentlimitclamp <bool> */
477 private int
zcurrentlimitclamp(i_ctx_t * i_ctx_p)478 zcurrentlimitclamp(i_ctx_t *i_ctx_p)
479 {
480     return zcurrent_bool(i_ctx_p, gs_currentlimitclamp);
481 }
482 
483 /* ------ Initialization procedure ------ */
484 
485 /* We need to split the table because of the 16-element limit. */
486 const op_def zgstate1_op_defs[] = {
487     {"0.currentaccuratecurves", zcurrentaccuratecurves},
488     {"0.currentcurvejoin", zcurrentcurvejoin},
489     {"0currentdash", zcurrentdash},
490     {"0.currentdashadapt", zcurrentdashadapt},
491     {"0.currentdotlength", zcurrentdotlength},
492     {"0.currentfilladjust2", zcurrentfilladjust2},
493     {"0currentflat", zcurrentflat},
494     {"0.currentlimitclamp", zcurrentlimitclamp},
495     {"0currentlinecap", zcurrentlinecap},
496     {"0currentlinejoin", zcurrentlinejoin},
497     {"0currentlinewidth", zcurrentlinewidth},
498     {"0currentmiterlimit", zcurrentmiterlimit},
499     {"0.dotorientation", zdotorientation},
500     {"0grestore", zgrestore},
501     {"0grestoreall", zgrestoreall},
502     op_def_end(0)
503 };
504 const op_def zgstate2_op_defs[] = {
505     {"0gsave", zgsave},
506     {"0initgraphics", zinitgraphics},
507     {"1.setaccuratecurves", zsetaccuratecurves},
508     {"1.setcurvejoin", zsetcurvejoin},
509     {"2setdash", zsetdash},
510     {"1.setdashadapt", zsetdashadapt},
511     {"2.setdotlength", zsetdotlength},
512     {"0.setdotorientation", zsetdotorientation},
513     {"2.setfilladjust2", zsetfilladjust2},
514     {"1.setlimitclamp", zsetlimitclamp},
515     {"1setflat", zsetflat},
516     {"1.setlinecap", zsetlinecap},
517     {"1.setlinejoin", zsetlinejoin},
518     {"1setlinewidth", zsetlinewidth},
519     {"1setmiterlimit", zsetmiterlimit},
520     op_def_end(0)
521 };
522 
523 /* ------ Internal routines ------ */
524 
525 /* Allocate the interpreter's part of a graphics state. */
526 private void *
gs_istate_alloc(gs_memory_t * mem)527 gs_istate_alloc(gs_memory_t * mem)
528 {
529     return gs_alloc_struct(mem, int_gstate, &st_int_gstate, "int_gsave");
530 }
531 
532 /* Copy the interpreter's part of a graphics state. */
533 private int
gs_istate_copy(void * to,const void * from)534 gs_istate_copy(void *to, const void *from)
535 {
536     *(int_gstate *) to = *(const int_gstate *)from;
537     return 0;
538 }
539 
540 /* Free the interpreter's part of a graphics state. */
541 private void
gs_istate_free(void * old,gs_memory_t * mem)542 gs_istate_free(void *old, gs_memory_t * mem)
543 {
544     gs_free_object(mem, old, "int_grestore");
545 }
546