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 /* Level 2 / Display PostScript graphics extensions */
18 #include "ghost.h"
19 #include "oper.h"
20 #include "gsmatrix.h"
21 #include "gspath.h"
22 #include "gspath2.h"
23 #include "gsstate.h"
24 #include "ialloc.h"
25 #include "igstate.h"
26 #include "ivmspace.h"
27 #include "store.h"
28 #include "stream.h"
29 #include "ibnum.h"
30
31 /* Forward references */
32 static int gstate_unshare(i_ctx_t *);
33
34 /* Declare exported procedures (for zupath.c) */
35 int zsetbbox(i_ctx_t *);
36
37 /* Structure descriptors */
38 public_st_igstate_obj();
39
40 /* Extend the `copy' operator to deal with gstates. */
41 /* This is done with a hack -- we know that gstates are the only */
42 /* t_astruct subtype that implements copy. */
43 static int
z1copy(i_ctx_t * i_ctx_p)44 z1copy(i_ctx_t *i_ctx_p)
45 {
46 os_ptr op = osp;
47 int code = zcopy(i_ctx_p);
48
49 if (code >= 0)
50 return code;
51 if (!r_has_type(op, t_astruct))
52 return code;
53 return zcopy_gstate(i_ctx_p);
54 }
55
56 /* ------ Graphics state ------ */
57
58 /* <bool> setstrokeadjust - */
59 static int
zsetstrokeadjust(i_ctx_t * i_ctx_p)60 zsetstrokeadjust(i_ctx_t *i_ctx_p)
61 {
62 os_ptr op = osp;
63
64 check_type(*op, t_boolean);
65 gs_setstrokeadjust(igs, op->value.boolval);
66 pop(1);
67 return 0;
68 }
69
70 /* - currentstrokeadjust <bool> */
71 static int
zcurrentstrokeadjust(i_ctx_t * i_ctx_p)72 zcurrentstrokeadjust(i_ctx_t *i_ctx_p)
73 {
74 os_ptr op = osp;
75
76 push(1);
77 make_bool(op, gs_currentstrokeadjust(igs));
78 return 0;
79 }
80
81 /* ------ Graphics state objects ------ */
82
83 /*
84 * Check to make sure that all the elements of a graphics state
85 * can be stored in the given allocation space.
86 */
87 /* ****** DOESN'T CHECK THE NON-REFS. ****** */
88 static int
gstate_check_space(i_ctx_t * i_ctx_p,int_gstate * isp,uint space)89 gstate_check_space(i_ctx_t *i_ctx_p, int_gstate *isp, uint space)
90 {
91 /*
92 * ****** WORKAROUND ALERT ******
93 * This code doesn't check the space of the non-refs, or copy their
94 * contents, so it can create dangling references from global VM to
95 * local VM. Because of this, we simply disallow writing into gstates
96 * in global VM (including creating them in the first place) if the
97 * save level is greater than 0.
98 * ****** WORKAROUND ALERT ******
99 */
100 #if 1 /* ****** WORKAROUND ****** */
101 if (space != avm_local && imemory_save_level(iimemory) > 0)
102 return_error(e_invalidaccess);
103 #endif /* ****** END ****** */
104 #define gsref_check(p) store_check_space(space, p)
105 int_gstate_map_refs(isp, gsref_check);
106 #undef gsref_check
107 return 0;
108 }
109
110 /* - gstate <gstate> */
111 int
zgstate(i_ctx_t * i_ctx_p)112 zgstate(i_ctx_t *i_ctx_p)
113 {
114 os_ptr op = osp;
115
116 int code = gstate_check_space(i_ctx_p, istate, icurrent_space);
117 igstate_obj *pigo;
118 gs_state *pnew;
119 int_gstate *isp;
120
121 if (code < 0)
122 return code;
123 pigo = ialloc_struct(igstate_obj, &st_igstate_obj, "gstate");
124 if (pigo == 0)
125 return_error(e_VMerror);
126 pnew = gs_state_copy(igs, imemory);
127 if (pnew == 0) {
128 ifree_object(pigo, "gstate");
129 return_error(e_VMerror);
130 }
131 isp = gs_int_gstate(pnew);
132 int_gstate_map_refs(isp, ref_mark_new);
133 push(1);
134 /*
135 * Since igstate_obj isn't a ref, but only contains a ref, save won't
136 * clear its l_new bit automatically, and restore won't set it
137 * automatically; we have to make sure this ref is on the changes chain.
138 */
139 make_iastruct(op, a_all, pigo);
140 #if 0 /* Bug 689849 "gstate leaks memory" */
141 make_null(&pigo->gstate);
142 ref_save(op, &pigo->gstate, "gstate");
143 make_istruct_new(&pigo->gstate, 0, pnew);
144 #else
145 make_istruct(&pigo->gstate, 0, pnew);
146 #endif
147 return 0;
148 }
149
150 /* copy for gstates */
151 int
zcopy_gstate(i_ctx_t * i_ctx_p)152 zcopy_gstate(i_ctx_t *i_ctx_p)
153 {
154 os_ptr op = osp;
155 os_ptr op1 = op - 1;
156 gs_state *pgs;
157 gs_state *pgs1;
158 int_gstate *pistate;
159 gs_memory_t *mem;
160 int code;
161
162 check_stype(*op, st_igstate_obj);
163 check_stype(*op1, st_igstate_obj);
164 check_write(*op);
165 code = gstate_unshare(i_ctx_p);
166 if (code < 0)
167 return code;
168 pgs = igstate_ptr(op);
169 pgs1 = igstate_ptr(op1);
170 pistate = gs_int_gstate(pgs);
171 code = gstate_check_space(i_ctx_p, gs_int_gstate(pgs1), r_space(op));
172 if (code < 0)
173 return code;
174 #define gsref_save(p) ref_save(op, p, "copygstate")
175 int_gstate_map_refs(pistate, gsref_save);
176 #undef gsref_save
177 mem = gs_state_swap_memory(pgs, imemory);
178 code = gs_copygstate(pgs, pgs1);
179 gs_state_swap_memory(pgs, mem);
180 if (code < 0)
181 return code;
182 int_gstate_map_refs(pistate, ref_mark_new);
183 *op1 = *op;
184 pop(1);
185 return 0;
186 }
187
188 /* <gstate> currentgstate <gstate> */
189 int
zcurrentgstate(i_ctx_t * i_ctx_p)190 zcurrentgstate(i_ctx_t *i_ctx_p)
191 {
192 os_ptr op = osp;
193 gs_state *pgs;
194 int_gstate *pistate;
195 int code;
196 gs_memory_t *mem;
197
198 check_stype(*op, st_igstate_obj);
199 check_write(*op);
200 code = gstate_unshare(i_ctx_p);
201 if (code < 0)
202 return code;
203 pgs = igstate_ptr(op);
204 pistate = gs_int_gstate(pgs);
205 code = gstate_check_space(i_ctx_p, istate, r_space(op));
206 if (code < 0)
207 return code;
208 #define gsref_save(p) ref_save(op, p, "currentgstate")
209 int_gstate_map_refs(pistate, gsref_save);
210 #undef gsref_save
211 mem = gs_state_swap_memory(pgs, imemory);
212 code = gs_currentgstate(pgs, igs);
213 gs_state_swap_memory(pgs, mem);
214 if (code < 0)
215 return code;
216 int_gstate_map_refs(pistate, ref_mark_new);
217 return 0;
218 }
219
220 /* <gstate> setgstate - */
221 int
zsetgstate(i_ctx_t * i_ctx_p)222 zsetgstate(i_ctx_t *i_ctx_p)
223 {
224 os_ptr op = osp;
225 int code;
226
227 check_stype(*op, st_igstate_obj);
228 check_read(*op);
229 code = gs_setgstate(igs, igstate_ptr(op));
230 if (code < 0)
231 return code;
232 pop(1);
233 return 0;
234 }
235
236 /* ------ Rectangles ------- */
237
238 /*
239 * We preallocate a short list for rectangles, because
240 * the rectangle operators usually will involve very few rectangles.
241 */
242 #define MAX_LOCAL_RECTS 5
243 typedef struct local_rects_s {
244 gs_rect *pr;
245 uint count;
246 gs_rect rl[MAX_LOCAL_RECTS];
247 } local_rects_t;
248
249 /* Forward references */
250 static int rect_get(local_rects_t *, os_ptr, gs_memory_t *);
251 static void rect_release(local_rects_t *, gs_memory_t *);
252
253 /* <x> <y> <width> <height> .rectappend - */
254 /* <numarray|numstring> .rectappend - */
255 static int
zrectappend(i_ctx_t * i_ctx_p)256 zrectappend(i_ctx_t *i_ctx_p)
257 {
258 os_ptr op = osp;
259 local_rects_t lr;
260 int npop = rect_get(&lr, op, imemory);
261 int code;
262
263 if (npop < 0)
264 return npop;
265 code = gs_rectappend(igs, lr.pr, lr.count);
266 rect_release(&lr, imemory);
267 if (code < 0)
268 return code;
269 pop(npop);
270 return 0;
271 }
272
273 /* <x> <y> <width> <height> rectclip - */
274 /* <numarray|numstring> rectclip - */
275 static int
zrectclip(i_ctx_t * i_ctx_p)276 zrectclip(i_ctx_t *i_ctx_p)
277 {
278 os_ptr op = osp;
279 local_rects_t lr;
280 int npop = rect_get(&lr, op, imemory);
281 int code;
282
283 if (npop < 0)
284 return npop;
285 code = gs_rectclip(igs, lr.pr, lr.count);
286 rect_release(&lr, imemory);
287 if (code < 0)
288 return code;
289 pop(npop);
290 return 0;
291 }
292
293 /* <x> <y> <width> <height> rectfill - */
294 /* <numarray|numstring> rectfill - */
295 static int
zrectfill(i_ctx_t * i_ctx_p)296 zrectfill(i_ctx_t *i_ctx_p)
297 {
298 os_ptr op = osp;
299 local_rects_t lr;
300 int npop = rect_get(&lr, op, imemory);
301 int code;
302
303 if (npop < 0)
304 return npop;
305 code = gs_rectfill(igs, lr.pr, lr.count);
306 rect_release(&lr, imemory);
307 if (code < 0)
308 return code;
309 pop(npop);
310 return 0;
311 }
312
313 /* <x> <y> <width> <height> rectstroke - */
314 /* <numarray|numstring> rectstroke - */
315 static int
zrectstroke(i_ctx_t * i_ctx_p)316 zrectstroke(i_ctx_t *i_ctx_p)
317 {
318 os_ptr op = osp;
319 gs_matrix mat;
320 local_rects_t lr;
321 int npop, code;
322
323 if (read_matrix(imemory, op, &mat) >= 0) {
324 /* Concatenate the matrix to the CTM just before stroking the path. */
325 npop = rect_get(&lr, op - 1, imemory);
326 if (npop < 0)
327 return npop;
328 code = gs_rectstroke(igs, lr.pr, lr.count, &mat);
329 npop++;
330 } else {
331 /* No matrix. */
332 npop = rect_get(&lr, op, imemory);
333 if (npop < 0)
334 return npop;
335 code = gs_rectstroke(igs, lr.pr, lr.count, (gs_matrix *) 0);
336 }
337 rect_release(&lr, imemory);
338 if (code < 0)
339 return code;
340 pop(npop);
341 return 0;
342 }
343
344 /* --- Internal routines --- */
345
346 /* Get rectangles from the stack. */
347 /* Return the number of elements to pop (>0) if OK, <0 if error. */
348 static int
rect_get(local_rects_t * plr,os_ptr op,gs_memory_t * mem)349 rect_get(local_rects_t * plr, os_ptr op, gs_memory_t *mem)
350 {
351 int format, code;
352 uint n, count;
353 gs_rect *pr;
354 double rv[4];
355
356 switch (r_type(op)) {
357 case t_array:
358 case t_mixedarray:
359 case t_shortarray:
360 case t_string:
361 code = num_array_format(op);
362 if (code < 0)
363 return code;
364 format = code;
365 count = num_array_size(op, format);
366 if (count % 4)
367 return_error(e_typecheck);
368 count /= 4;
369 break;
370 default: /* better be 4 numbers */
371 code = num_params(op, 4, rv);
372 if (code < 0)
373 return code;
374 plr->pr = plr->rl;
375 plr->count = 1;
376 plr->rl[0].q.x = (plr->rl[0].p.x = rv[0]) + rv[2];
377 plr->rl[0].q.y = (plr->rl[0].p.y = rv[1]) + rv[3];
378 return 4;
379 }
380 plr->count = count;
381 if (count <= MAX_LOCAL_RECTS)
382 pr = plr->rl;
383 else {
384 pr = (gs_rect *)gs_alloc_byte_array(mem, count, sizeof(gs_rect),
385 "rect_get");
386 if (pr == 0)
387 return_error(e_VMerror);
388 }
389 plr->pr = pr;
390 for (n = 0; n < count; n++, pr++) {
391 ref rnum;
392 int i;
393
394 for (i = 0; i < 4; i++) {
395 code = num_array_get(mem, (const ref *)op, format,
396 (n << 2) + i, &rnum);
397 switch (code) {
398 case t_integer:
399 rv[i] = rnum.value.intval;
400 break;
401 case t_real:
402 rv[i] = rnum.value.realval;
403 break;
404 default: /* code < 0 */
405 return code;
406 }
407 }
408 pr->q.x = (pr->p.x = rv[0]) + rv[2];
409 pr->q.y = (pr->p.y = rv[1]) + rv[3];
410 }
411 return 1;
412 }
413
414 /* Release the rectangle list if needed. */
415 static void
rect_release(local_rects_t * plr,gs_memory_t * mem)416 rect_release(local_rects_t * plr, gs_memory_t *mem)
417 {
418 if (plr->pr != plr->rl)
419 gs_free_object(mem, plr->pr, "rect_release");
420 }
421
422 /* ------ Graphics state ------ */
423
424 /* <llx> <lly> <urx> <ury> setbbox - */
425 int
zsetbbox(i_ctx_t * i_ctx_p)426 zsetbbox(i_ctx_t *i_ctx_p)
427 {
428 os_ptr op = osp;
429 double box[4];
430
431 int code = num_params(op, 4, box);
432
433 if (code < 0)
434 return code;
435 if ((code = gs_setbbox(igs, box[0], box[1], box[2], box[3])) < 0)
436 return code;
437 pop(4);
438 return 0;
439 }
440
441 /* ------ Initialization procedure ------ */
442
443 const op_def zdps1_l2_op_defs[] =
444 {
445 op_def_begin_level2(),
446 /* Graphics state */
447 {"0currentstrokeadjust", zcurrentstrokeadjust},
448 {"1setstrokeadjust", zsetstrokeadjust},
449 /* Graphics state objects */
450 {"1copy", z1copy},
451 {"1currentgstate", zcurrentgstate},
452 {"0gstate", zgstate},
453 {"1setgstate", zsetgstate},
454 /* Rectangles */
455 {"1.rectappend", zrectappend},
456 {"1rectclip", zrectclip},
457 {"1rectfill", zrectfill},
458 {"1rectstroke", zrectstroke},
459 /* Graphics state components */
460 {"4setbbox", zsetbbox},
461 op_def_end(0)
462 };
463
464 /* ------ Internal routines ------ */
465
466 /* Ensure that a gstate is not shared with an outer save level. */
467 /* *op is of type t_astruct(igstate_obj). */
468 static int
gstate_unshare(i_ctx_t * i_ctx_p)469 gstate_unshare(i_ctx_t *i_ctx_p)
470 {
471 os_ptr op = osp;
472 ref *pgsref = &r_ptr(op, igstate_obj)->gstate;
473 gs_state *pgs = r_ptr(pgsref, gs_state);
474 gs_state *pnew;
475 int_gstate *isp;
476
477 if (!ref_must_save(pgsref))
478 return 0;
479 /* Copy the gstate. */
480 pnew = gs_gstate(pgs);
481 if (pnew == 0)
482 return_error(e_VMerror);
483 isp = gs_int_gstate(pnew);
484 int_gstate_map_refs(isp, ref_mark_new);
485 ref_do_save(op, pgsref, "gstate_unshare");
486 make_istruct_new(pgsref, 0, pnew);
487 return 0;
488 }
489