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 device operators */
18 #include "math_.h"
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "dstack.h" /* for dict_find_name */
23 #include "estack.h"
24 #include "idict.h"
25 #include "idparam.h"
26 #include "igstate.h"
27 #include "iname.h"
28 #include "iutil.h"
29 #include "store.h"
30 #include "gxdevice.h"
31 #include "gsstate.h"
32
33 /* Exported for zfunc4.c */
34 int z2copy(i_ctx_t *);
35
36 /* Forward references */
37 static int z2copy_gstate(i_ctx_t *);
38 static int push_callout(i_ctx_t *, const char *);
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 /* We export this for recognition in FunctionType 4 functions. */
44 int
z2copy(i_ctx_t * i_ctx_p)45 z2copy(i_ctx_t *i_ctx_p)
46 {
47 os_ptr op = osp;
48 int code = zcopy(i_ctx_p);
49
50 if (code >= 0)
51 return code;
52 if (!r_has_type(op, t_astruct))
53 return code;
54 return z2copy_gstate(i_ctx_p);
55 }
56
57 /* - .currentshowpagecount <count> true */
58 /* - .currentshowpagecount false */
59 static int
zcurrentshowpagecount(i_ctx_t * i_ctx_p)60 zcurrentshowpagecount(i_ctx_t *i_ctx_p)
61 {
62 os_ptr op = osp;
63 gx_device *dev = gs_currentdevice(igs);
64
65 if ((*dev_proc(dev, get_page_device))(dev) == 0) {
66 push(1);
67 make_false(op);
68 } else {
69 push(2);
70 make_int(op - 1, dev->ShowpageCount);
71 make_true(op);
72 }
73 return 0;
74 }
75
76 /* - .currentpagedevice <dict> <bool> */
77 static int
zcurrentpagedevice(i_ctx_t * i_ctx_p)78 zcurrentpagedevice(i_ctx_t *i_ctx_p)
79 {
80 os_ptr op = osp;
81 gx_device *dev = gs_currentdevice(igs);
82
83 push(2);
84 if ((*dev_proc(dev, get_page_device))(dev) != 0) {
85 op[-1] = istate->pagedevice;
86 make_true(op);
87 } else {
88 make_null(op - 1);
89 make_false(op);
90 }
91 return 0;
92 }
93
94 /* <local_dict|null> .setpagedevice - */
95 static int
zsetpagedevice(i_ctx_t * i_ctx_p)96 zsetpagedevice(i_ctx_t *i_ctx_p)
97 {
98 os_ptr op = osp;
99 int code;
100
101 /******
102 if ( igs->in_cachedevice )
103 return_error(e_undefined);
104 ******/
105 if (r_has_type(op, t_dictionary)) {
106 check_dict_read(*op);
107 #if 0 /****************/
108 /*
109 * In order to avoid invalidaccess errors on setpagedevice,
110 * the dictionary must be allocated in local VM.
111 */
112 if (!(r_is_local(op)))
113 return_error(e_invalidaccess);
114 #endif /****************/
115 /* Make the dictionary read-only. */
116 code = zreadonly(i_ctx_p);
117 if (code < 0)
118 return code;
119 } else {
120 check_type(*op, t_null);
121 }
122 istate->pagedevice = *op;
123 pop(1);
124 return 0;
125 }
126
127 /* Default Install/BeginPage/EndPage procedures */
128 /* that just call the procedure in the device. */
129
130 /* - .callinstall - */
131 static int
zcallinstall(i_ctx_t * i_ctx_p)132 zcallinstall(i_ctx_t *i_ctx_p)
133 {
134 gx_device *dev = gs_currentdevice(igs);
135
136 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
137 int code = (*dev->page_procs.install) (dev, igs);
138
139 if (code < 0)
140 return code;
141 }
142 return 0;
143 }
144
145 /* <showpage_count> .callbeginpage - */
146 static int
zcallbeginpage(i_ctx_t * i_ctx_p)147 zcallbeginpage(i_ctx_t *i_ctx_p)
148 {
149 os_ptr op = osp;
150 gx_device *dev = gs_currentdevice(igs);
151
152 check_type(*op, t_integer);
153 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
154 int code = (*dev->page_procs.begin_page)(dev, igs);
155
156 if (code < 0)
157 return code;
158 }
159 pop(1);
160 return 0;
161 }
162
163 /* <showpage_count> <reason_int> .callendpage <flush_bool> */
164 static int
zcallendpage(i_ctx_t * i_ctx_p)165 zcallendpage(i_ctx_t *i_ctx_p)
166 {
167 os_ptr op = osp;
168 gx_device *dev = gs_currentdevice(igs);
169 int code;
170
171 check_type(op[-1], t_integer);
172 check_type(*op, t_integer);
173 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
174 code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
175 if (code < 0)
176 return code;
177 if (code > 1)
178 return_error(e_rangecheck);
179 } else {
180 code = (op->value.intval == 2 ? 0 : 1);
181 }
182 make_bool(op - 1, code);
183 pop(1);
184 return 0;
185 }
186
187 /* ------ Wrappers for operators that save the graphics state. ------ */
188
189 /* When saving the state with the current device a page device, */
190 /* we need to make sure that the page device dictionary exists */
191 /* so that grestore can use it to reset the device parameters. */
192 /* This may have significant performance consequences, but we don't see */
193 /* any way around it. */
194
195 /* Check whether we need to call out to create the page device dictionary. */
196 static bool
save_page_device(gs_state * pgs)197 save_page_device(gs_state *pgs)
198 {
199 return
200 (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
201 (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
202 }
203
204 /* - gsave - */
205 static int
z2gsave(i_ctx_t * i_ctx_p)206 z2gsave(i_ctx_t *i_ctx_p)
207 {
208 if (!save_page_device(igs))
209 return gs_gsave(igs);
210 return push_callout(i_ctx_p, "%gsavepagedevice");
211 }
212
213 /* - save - */
214 static int
z2save(i_ctx_t * i_ctx_p)215 z2save(i_ctx_t *i_ctx_p)
216 {
217 if (!save_page_device(igs))
218 return zsave(i_ctx_p);
219 return push_callout(i_ctx_p, "%savepagedevice");
220 }
221
222 /* - gstate <gstate> */
223 static int
z2gstate(i_ctx_t * i_ctx_p)224 z2gstate(i_ctx_t *i_ctx_p)
225 {
226 if (!save_page_device(igs))
227 return zgstate(i_ctx_p);
228 return push_callout(i_ctx_p, "%gstatepagedevice");
229 }
230
231 /* <gstate1> <gstate2> copy <gstate2> */
232 static int
z2copy_gstate(i_ctx_t * i_ctx_p)233 z2copy_gstate(i_ctx_t *i_ctx_p)
234 {
235 if (!save_page_device(igs))
236 return zcopy_gstate(i_ctx_p);
237 return push_callout(i_ctx_p, "%copygstatepagedevice");
238 }
239
240 /* <gstate> currentgstate <gstate> */
241 static int
z2currentgstate(i_ctx_t * i_ctx_p)242 z2currentgstate(i_ctx_t *i_ctx_p)
243 {
244 if (!save_page_device(igs))
245 return zcurrentgstate(i_ctx_p);
246 return push_callout(i_ctx_p, "%currentgstatepagedevice");
247 }
248
249 /* ------ Wrappers for operators that reset the graphics state. ------ */
250
251 /* Check whether we need to call out to restore the page device. */
252 static bool
restore_page_device(const gs_state * pgs_old,const gs_state * pgs_new)253 restore_page_device(const gs_state * pgs_old, const gs_state * pgs_new)
254 {
255 gx_device *dev_old = gs_currentdevice(pgs_old);
256 gx_device *dev_new;
257 gx_device *dev_t1;
258 gx_device *dev_t2;
259 bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
260 &gs_int_gstate(pgs_new)->pagedevice);
261
262 if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
263 return false;
264 /* If we are going to putdeviceparams in a callout, we need to */
265 /* unlock temporarily. The device will be re-locked as needed */
266 /* by putdeviceparams from the pgs_old->pagedevice dict state. */
267 if (!samepagedevice)
268 dev_old->LockSafetyParams = false;
269 dev_new = gs_currentdevice(pgs_new);
270 if (dev_old != dev_new) {
271 if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
272 return false;
273 if (dev_t1 != dev_t2)
274 return true;
275 }
276 /*
277 * The current implementation of setpagedevice just sets new
278 * parameters in the same device object, so we have to check
279 * whether the page device dictionaries are the same.
280 */
281 return !samepagedevice;
282 }
283
284 /* - grestore - */
285 static int
z2grestore(i_ctx_t * i_ctx_p)286 z2grestore(i_ctx_t *i_ctx_p)
287 {
288 if (!restore_page_device(igs, gs_state_saved(igs)))
289 return gs_grestore(igs);
290 return push_callout(i_ctx_p, "%grestorepagedevice");
291 }
292
293 /* - grestoreall - */
294 static int
z2grestoreall(i_ctx_t * i_ctx_p)295 z2grestoreall(i_ctx_t *i_ctx_p)
296 {
297 for (;;) {
298 if (!restore_page_device(igs, gs_state_saved(igs))) {
299 bool done = !gs_state_saved(gs_state_saved(igs));
300
301 gs_grestore(igs);
302 if (done)
303 break;
304 } else
305 return push_callout(i_ctx_p, "%grestoreallpagedevice");
306 }
307 return 0;
308 }
309
310 /* <save> restore - */
311 static int
z2restore(i_ctx_t * i_ctx_p)312 z2restore(i_ctx_t *i_ctx_p)
313 {
314 while (gs_state_saved(gs_state_saved(igs))) {
315 if (restore_page_device(igs, gs_state_saved(igs)))
316 return push_callout(i_ctx_p, "%restore1pagedevice");
317 gs_grestore(igs);
318 }
319 if (restore_page_device(igs, gs_state_saved(igs)))
320 return push_callout(i_ctx_p, "%restorepagedevice");
321 return zrestore(i_ctx_p);
322 }
323
324 /* <gstate> setgstate - */
325 static int
z2setgstate(i_ctx_t * i_ctx_p)326 z2setgstate(i_ctx_t *i_ctx_p)
327 {
328 os_ptr op = osp;
329
330 check_stype(*op, st_igstate_obj);
331 if (!restore_page_device(igs, igstate_ptr(op)))
332 return zsetgstate(i_ctx_p);
333 return push_callout(i_ctx_p, "%setgstatepagedevice");
334 }
335
336 /* ------ Initialization procedure ------ */
337
338 const op_def zdevice2_l2_op_defs[] =
339 {
340 op_def_begin_level2(),
341 {"0.currentshowpagecount", zcurrentshowpagecount},
342 {"0.currentpagedevice", zcurrentpagedevice},
343 {"1.setpagedevice", zsetpagedevice},
344 /* Note that the following replace prior definitions */
345 /* in the indicated files: */
346 {"1copy", z2copy}, /* zdps1.c */
347 {"0gsave", z2gsave}, /* zgstate.c */
348 {"0save", z2save}, /* zvmem.c */
349 {"0gstate", z2gstate}, /* zdps1.c */
350 {"1currentgstate", z2currentgstate}, /* zdps1.c */
351 {"0grestore", z2grestore}, /* zgstate.c */
352 {"0grestoreall", z2grestoreall}, /* zgstate.c */
353 {"1restore", z2restore}, /* zvmem.c */
354 {"1setgstate", z2setgstate}, /* zdps1.c */
355 /* Default Install/BeginPage/EndPage procedures */
356 /* that just call the procedure in the device. */
357 {"0.callinstall", zcallinstall},
358 {"1.callbeginpage", zcallbeginpage},
359 {"2.callendpage", zcallendpage},
360 op_def_end(0)
361 };
362
363 /* ------ Internal routines ------ */
364
365 /* Call out to a PostScript procedure. */
366 static int
push_callout(i_ctx_t * i_ctx_p,const char * callout_name)367 push_callout(i_ctx_t *i_ctx_p, const char *callout_name)
368 {
369 int code;
370
371 check_estack(1);
372 code = name_enter_string(imemory, callout_name, esp + 1);
373 if (code < 0)
374 return code;
375 ++esp;
376 r_set_attrs(esp, a_executable);
377 return o_push_estack;
378 }
379