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