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