1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, 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 "isave.h"
30 #include "store.h"
31 #include "gxdevice.h"
32 #include "gsstate.h"
33
34 /* Exported for zfunc4.c */
35 int z2copy(i_ctx_t *);
36
37 /* Forward references */
38 static int z2copy_gstate(i_ctx_t *);
39 static int push_callout(i_ctx_t *, const char *);
40
41 /* Extend the `copy' operator to deal with gstates. */
42 /* This is done with a hack -- we know that gstates are the only */
43 /* t_astruct subtype that implements copy. */
44 /* We export this for recognition in FunctionType 4 functions. */
45 int
z2copy(i_ctx_t * i_ctx_p)46 z2copy(i_ctx_t *i_ctx_p)
47 {
48 os_ptr op = osp;
49 int code = zcopy(i_ctx_p);
50
51 if (code >= 0)
52 return code;
53 if (!r_has_type(op, t_astruct))
54 return code;
55 return z2copy_gstate(i_ctx_p);
56 }
57
58 /* - .currentshowpagecount <count> true */
59 /* - .currentshowpagecount false */
60 static int
zcurrentshowpagecount(i_ctx_t * i_ctx_p)61 zcurrentshowpagecount(i_ctx_t *i_ctx_p)
62 {
63 os_ptr op = osp;
64 gx_device *dev1, *dev = gs_currentdevice(igs);
65
66 if ((*dev_proc(dev, get_page_device))(dev) == 0) {
67 push(1);
68 make_false(op);
69 } else {
70 dev1 = (*dev_proc(dev, get_page_device))(dev);
71 push(2);
72 make_int(op - 1, dev1->ShowpageCount);
73 make_true(op);
74 }
75 return 0;
76 }
77
78 /* - .currentpagedevice <dict> <bool> */
79 static int
zcurrentpagedevice(i_ctx_t * i_ctx_p)80 zcurrentpagedevice(i_ctx_t *i_ctx_p)
81 {
82 os_ptr op = osp;
83 gx_device *dev = gs_currentdevice(igs);
84
85 push(2);
86 if ((*dev_proc(dev, get_page_device))(dev) != 0) {
87 op[-1] = istate->pagedevice;
88 make_true(op);
89 } else {
90 make_null(op - 1);
91 make_false(op);
92 }
93 return 0;
94 }
95
96 /* <local_dict|null> .setpagedevice - */
97 static int
zsetpagedevice(i_ctx_t * i_ctx_p)98 zsetpagedevice(i_ctx_t *i_ctx_p)
99 {
100 os_ptr op = osp;
101 int code;
102
103 /******
104 if ( igs->in_cachedevice )
105 return_error(gs_error_undefined);
106 ******/
107 if (r_has_type(op, t_dictionary)) {
108 check_dict_read(*op);
109 #if 0 /****************/
110 /*
111 * In order to avoid invalidaccess errors on setpagedevice,
112 * the dictionary must be allocated in local VM.
113 */
114 if (!(r_is_local(op)))
115 return_error(gs_error_invalidaccess);
116 #endif /****************/
117 /* Make the dictionary read-only. */
118 code = zreadonly(i_ctx_p);
119 if (code < 0)
120 return code;
121 } else {
122 check_type(*op, t_null);
123 }
124 istate->pagedevice = *op;
125 pop(1);
126 return 0;
127 }
128
129 /* Default Install/BeginPage/EndPage procedures */
130 /* that just call the procedure in the device. */
131
132 /* - .callinstall - */
133 static int
zcallinstall(i_ctx_t * i_ctx_p)134 zcallinstall(i_ctx_t *i_ctx_p)
135 {
136 gx_device *dev = gs_currentdevice(igs);
137
138 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
139 int code = (*dev->page_procs.install) (dev, igs);
140
141 if (code < 0)
142 return code;
143 }
144 return 0;
145 }
146
147 /* <showpage_count> .callbeginpage - */
148 static int
zcallbeginpage(i_ctx_t * i_ctx_p)149 zcallbeginpage(i_ctx_t *i_ctx_p)
150 {
151 os_ptr op = osp;
152 gx_device *dev = gs_currentdevice(igs);
153
154 check_type(*op, t_integer);
155 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
156 int code = (*dev->page_procs.begin_page)(dev, igs);
157
158 if (code < 0)
159 return code;
160 }
161 pop(1);
162 return 0;
163 }
164
165 /* <showpage_count> <reason_int> .callendpage <flush_bool> */
166 static int
zcallendpage(i_ctx_t * i_ctx_p)167 zcallendpage(i_ctx_t *i_ctx_p)
168 {
169 os_ptr op = osp;
170 gx_device *dev = gs_currentdevice(igs);
171 int code;
172
173 check_type(op[-1], t_integer);
174 check_type(*op, t_integer);
175 if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
176 code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
177 if (code < 0)
178 return code;
179 if (code > 1)
180 return_error(gs_error_rangecheck);
181 } else {
182 code = (op->value.intval == 2 ? 0 : 1);
183 }
184 make_bool(op - 1, code);
185 pop(1);
186 return 0;
187 }
188
189 /* ------ Wrappers for operators that save the graphics state. ------ */
190
191 /* When saving the state with the current device a page device, */
192 /* we need to make sure that the page device dictionary exists */
193 /* so that grestore can use it to reset the device parameters. */
194 /* This may have significant performance consequences, but we don't see */
195 /* any way around it. */
196
197 /* Check whether we need to call out to create the page device dictionary. */
198 static bool
save_page_device(gs_gstate * pgs)199 save_page_device(gs_gstate *pgs)
200 {
201 return
202 (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
203 (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
204 }
205
206 /* - gsave - */
207 static int
z2gsave(i_ctx_t * i_ctx_p)208 z2gsave(i_ctx_t *i_ctx_p)
209 {
210 if (!save_page_device(igs))
211 return gs_gsave(igs);
212 return push_callout(i_ctx_p, "%gsavepagedevice");
213 }
214
215 /* - save - */
216 static int
z2save(i_ctx_t * i_ctx_p)217 z2save(i_ctx_t *i_ctx_p)
218 {
219 if (!save_page_device(igs))
220 return zsave(i_ctx_p);
221 return push_callout(i_ctx_p, "%savepagedevice");
222 }
223
224 /* - gstate <gstate> */
225 static int
z2gstate(i_ctx_t * i_ctx_p)226 z2gstate(i_ctx_t *i_ctx_p)
227 {
228 if (!save_page_device(igs))
229 return zgstate(i_ctx_p);
230 return push_callout(i_ctx_p, "%gstatepagedevice");
231 }
232
233 /* <gstate1> <gstate2> copy <gstate2> */
234 static int
z2copy_gstate(i_ctx_t * i_ctx_p)235 z2copy_gstate(i_ctx_t *i_ctx_p)
236 {
237 if (!save_page_device(igs))
238 return zcopy_gstate(i_ctx_p);
239 return push_callout(i_ctx_p, "%copygstatepagedevice");
240 }
241
242 /* <gstate> currentgstate <gstate> */
243 static int
z2currentgstate(i_ctx_t * i_ctx_p)244 z2currentgstate(i_ctx_t *i_ctx_p)
245 {
246 if (!save_page_device(igs))
247 return zcurrentgstate(i_ctx_p);
248 return push_callout(i_ctx_p, "%currentgstatepagedevice");
249 }
250
251 /* ------ Wrappers for operators that reset the graphics state. ------ */
252
253 /* Check whether we need to call out to restore the page device. */
254 static int
restore_page_device(i_ctx_t * i_ctx_p,const gs_gstate * pgs_old,const gs_gstate * pgs_new)255 restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate * pgs_new)
256 {
257 gx_device *dev_old = gs_currentdevice(pgs_old);
258 gx_device *dev_new;
259 gx_device *dev_t1;
260 gx_device *dev_t2;
261 bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
262 &gs_int_gstate(pgs_new)->pagedevice);
263 bool LockSafetyParams = dev_old->LockSafetyParams;
264
265 if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
266 return 0;
267 /* If we are going to putdeviceparams in a callout, we need to */
268 /* unlock temporarily. The device will be re-locked as needed */
269 /* by putdeviceparams from the pgs_old->pagedevice dict state. */
270 if (!samepagedevice)
271 dev_old->LockSafetyParams = false;
272 dev_new = gs_currentdevice(pgs_new);
273 if (dev_old != dev_new) {
274 if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
275 samepagedevice = true;
276 else if (dev_t1 != dev_t2)
277 samepagedevice = false;
278 }
279
280 if (LockSafetyParams) {
281 const int required_ops = 512;
282 const int required_es = 32;
283
284 /* The %grestorepagedevice must complete: the biggest danger
285 is operand stack overflow. As we use get/putdeviceparams
286 that means pushing all the device params onto the stack,
287 pdfwrite having by far the largest number of parameters
288 at (currently) 212 key/value pairs - thus needing (currently)
289 424 entries on the op stack. Allowing for working stack
290 space, and safety margin.....
291 */
292 if (required_ops + ref_stack_count(&o_stack) >= ref_stack_max_count(&o_stack)) {
293 gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
294 return_error(gs_error_stackoverflow);
295 }
296 /* We also want enough exec stack space - 32 is an overestimate of
297 what we need to complete the Postscript call out.
298 */
299 if (required_es + ref_stack_count(&e_stack) >= ref_stack_max_count(&e_stack)) {
300 gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
301 return_error(gs_error_execstackoverflow);
302 }
303 }
304 /*
305 * The current implementation of setpagedevice just sets new
306 * parameters in the same device object, so we have to check
307 * whether the page device dictionaries are the same.
308 */
309 return samepagedevice ? 0 : 1;
310 }
311
312 /* - grestore - */
313 static int
z2grestore(i_ctx_t * i_ctx_p)314 z2grestore(i_ctx_t *i_ctx_p)
315 {
316 int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
317 if (code < 0) return code;
318
319 if (code == 0)
320 return gs_grestore(igs);
321 return push_callout(i_ctx_p, "%grestorepagedevice");
322 }
323
324 /* - grestoreall - */
325 static int
z2grestoreall(i_ctx_t * i_ctx_p)326 z2grestoreall(i_ctx_t *i_ctx_p)
327 {
328 for (;;) {
329 int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
330 if (code < 0) return code;
331 if (code == 0) {
332 bool done = !gs_gstate_saved(gs_gstate_saved(igs));
333
334 gs_grestore(igs);
335 if (done)
336 break;
337 } else
338 return push_callout(i_ctx_p, "%grestoreallpagedevice");
339 }
340 return 0;
341 }
342 /* This is the Level 2+ variant of restore - which adds restoring
343 of the page device to the Level 1 variant in zvmem.c.
344 Previous this restored the device state before calling zrestore.c
345 which validated operands etc, meaning a restore could error out
346 partially complete.
347 The operand checking, and actual VM restore are now in two functions
348 so they can called separately thus, here, we can do as much
349 checking as possible, before embarking on actual changes
350 */
351 /* <save> restore - */
352 static int
z2restore(i_ctx_t * i_ctx_p)353 z2restore(i_ctx_t *i_ctx_p)
354 {
355 alloc_save_t *asave;
356 bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams;
357 int code = restore_check_save(i_ctx_p, &asave);
358
359 if (code < 0) return code;
360
361 while (gs_gstate_saved(gs_gstate_saved(igs))) {
362 code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
363 if (code < 0) return code;
364 if (code > 0)
365 return push_callout(i_ctx_p, "%restore1pagedevice");
366 gs_grestore(igs);
367 }
368 code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
369 if (code < 0) return code;
370 if (code > 0)
371 return push_callout(i_ctx_p, "%restorepagedevice");
372
373 code = dorestore(i_ctx_p, asave);
374
375 if (code < 0) {
376 /* An error here is basically fatal, but....
377 restore_page_device() has to set LockSafetyParams false so it can
378 configure the restored device correctly - in normal operation, that
379 gets reset by that configuration. If we hit an error, though, that
380 may not happen - at least ensure we keep the setting through the
381 error.
382 */
383 gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety;
384 }
385 return code;
386 }
387
388 /* <gstate> setgstate - */
389 static int
z2setgstate(i_ctx_t * i_ctx_p)390 z2setgstate(i_ctx_t *i_ctx_p)
391 {
392 os_ptr op = osp;
393 int code;
394
395 check_stype(*op, st_igstate_obj);
396 code = restore_page_device(i_ctx_p, igs, igstate_ptr(op));
397 if (code < 0) return code;
398 if (code == 0)
399 return zsetgstate(i_ctx_p);
400 return push_callout(i_ctx_p, "%setgstatepagedevice");
401 }
402
403 /* ------ Initialization procedure ------ */
404
405 const op_def zdevice2_l2_op_defs[] =
406 {
407 op_def_begin_level2(),
408 {"0.currentshowpagecount", zcurrentshowpagecount},
409 {"0.currentpagedevice", zcurrentpagedevice},
410 {"1.setpagedevice", zsetpagedevice},
411 /* Note that the following replace prior definitions */
412 /* in the indicated files: */
413 {"1copy", z2copy}, /* zdps1.c */
414 {"0gsave", z2gsave}, /* zgstate.c */
415 {"0save", z2save}, /* zvmem.c */
416 {"0gstate", z2gstate}, /* zdps1.c */
417 {"1currentgstate", z2currentgstate}, /* zdps1.c */
418 {"0grestore", z2grestore}, /* zgstate.c */
419 {"0grestoreall", z2grestoreall}, /* zgstate.c */
420 {"1restore", z2restore}, /* zvmem.c */
421 {"1setgstate", z2setgstate}, /* zdps1.c */
422 /* Default Install/BeginPage/EndPage procedures */
423 /* that just call the procedure in the device. */
424 {"0.callinstall", zcallinstall},
425 {"1.callbeginpage", zcallbeginpage},
426 {"2.callendpage", zcallendpage},
427 op_def_end(0)
428 };
429
430 /* ------ Internal routines ------ */
431
432 /* Call out to a PostScript procedure. */
433 static int
push_callout(i_ctx_t * i_ctx_p,const char * callout_name)434 push_callout(i_ctx_t *i_ctx_p, const char *callout_name)
435 {
436 int code;
437
438 check_estack(1);
439 code = name_enter_string(imemory, callout_name, esp + 1);
440 if (code < 0)
441 return code;
442 ++esp;
443 r_set_attrs(esp, a_executable);
444 return o_push_estack;
445 }
446