summaryrefslogtreecommitdiff
path: root/gs/src/zdevice2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/src/zdevice2.c')
-rw-r--r--gs/src/zdevice2.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/gs/src/zdevice2.c b/gs/src/zdevice2.c
new file mode 100644
index 000000000..55118288f
--- /dev/null
+++ b/gs/src/zdevice2.c
@@ -0,0 +1,330 @@
+/* Copyright (C) 1993, 1995, 1997 Aladdin Enterprises. All rights reserved.
+
+ This file is part of Aladdin Ghostscript.
+
+ Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
+ or distributor accepts any responsibility for the consequences of using it,
+ or for whether it serves any particular purpose or works at all, unless he
+ or she says so in writing. Refer to the Aladdin Ghostscript Free Public
+ License (the "License") for full details.
+
+ Every copy of Aladdin Ghostscript must include a copy of the License,
+ normally in a plain ASCII text file named PUBLIC. The License grants you
+ the right to copy, modify and redistribute Aladdin Ghostscript, but only
+ under certain conditions described in the License. Among other things, the
+ License requires that the copyright notice and this notice be preserved on
+ all copies.
+*/
+
+/* zdevice2.c */
+/* Level 2 device operators */
+#include "math_.h"
+#include "memory_.h"
+#include "ghost.h"
+#include "errors.h"
+#include "oper.h"
+#include "dstack.h" /* for dict_find_name */
+#include "estack.h"
+#include "idict.h"
+#include "idparam.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+#include "gxdevice.h"
+#include "gsstate.h"
+
+/* Imported data */
+extern op_proc_p zcopy_procs[t_next_index];
+
+/* Forward references */
+private int z2copy_gstate(P1(os_ptr));
+private int near push_callout(P1(const char _ds *));
+
+/* Initialize by adding changing the `copy' operator for gstates. */
+/* This is a hack -- we know that gstates are the only */
+/* t_astruct subtype that implements copy. */
+private void
+zdevice2_init(void)
+{ zcopy_procs[t_astruct] = z2copy_gstate;
+}
+
+/* - .currentshowpagecount <count> true */
+/* - .currentshowpagecount false */
+private int
+zcurrentshowpagecount(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ if ( (*dev_proc(dev, get_page_device))(dev) == 0 )
+ { push(1);
+ make_false(op);
+ }
+ else
+ { push(2);
+ make_int(op - 1, dev->ShowpageCount);
+ make_true(op);
+ }
+ return 0;
+}
+
+/* - .currentpagedevice <dict> <bool> */
+private int
+zcurrentpagedevice(register os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ push(2);
+ if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
+ { op[-1] = istate->pagedevice;
+ make_true(op);
+ }
+ else
+ { op[-1] = i_null_pagedevice;
+ make_false(op);
+ }
+ return 0;
+}
+
+/* <dict> .setpagedevice - */
+private int
+zsetpagedevice(register os_ptr op)
+{ int code;
+
+/******
+ if ( igs->in_cachedevice )
+ return_error(e_undefined);
+ ******/
+ check_type(*op, t_dictionary);
+ check_dict_read(*op);
+ /* Make the dictionary read-only. */
+ code = zreadonly(op);
+ if ( code < 0 )
+ return code;
+ istate->pagedevice = *op;
+ pop(1);
+ return 0;
+}
+
+/* Default Install/BeginPage/EndPage procedures */
+/* that just call the procedure in the device. */
+
+/* - .callinstall - */
+private int
+zcallinstall(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { int code = (*dev->page_procs.install)(dev, igs);
+ if ( code < 0 )
+ return code;
+ }
+ return 0;
+}
+
+/* <showpage_count> .callbeginpage - */
+private int
+zcallbeginpage(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+
+ check_type(*op, t_integer);
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { int code = (*dev->page_procs.begin_page)(dev, igs);
+ if ( code < 0 )
+ return code;
+ }
+ pop(1);
+ return 0;
+}
+
+/* <showpage_count> <reason_int> .callendpage <flush_bool> */
+private int
+zcallendpage(os_ptr op)
+{ gx_device *dev = gs_currentdevice(igs);
+ int code;
+
+ check_type(op[-1], t_integer);
+ check_type(*op, t_integer);
+ if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
+ { code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
+ if ( code < 0 )
+ return code;
+ if ( code > 1 )
+ return_error(e_rangecheck);
+ }
+ else
+ { code = (op->value.intval == 2 ? 0 : 1);
+ }
+ make_bool(op - 1, code);
+ pop(1);
+ return 0;
+}
+
+/* ------ Wrappers for operators that save the graphics state. ------ */
+
+/* When saving the state with the current device a page device, */
+/* we need to make sure that the page device dictionary exists */
+/* so that grestore can use it to reset the device parameters. */
+/* This may have significant performance consequences, but we don't see */
+/* any way around it. */
+
+/* Check whether we need to call out to create the page device dictionary. */
+#define save_page_device(pgs)\
+ (gs_int_gstate(pgs)->pagedevice.value.pdict ==\
+ i_null_pagedevice.value.pdict &&\
+ (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs))\
+ != 0)
+
+/* - gsave - */
+private int
+z2gsave(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return gs_gsave(igs);
+ return push_callout("%gsavepagedevice");
+}
+
+/* - save - */
+private int
+z2save(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zsave(op);
+ return push_callout("%savepagedevice");
+}
+
+/* - gstate <gstate> */
+private int
+z2gstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zgstate(op);
+ return push_callout("%gstatepagedevice");
+}
+
+/* <gstate1> <gstate2> copy <gstate2> */
+private int
+z2copy_gstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zcopy_gstate(op);
+ return push_callout("%copygstatepagedevice");
+}
+
+/* <gstate1> <gstate2> currentgstate <gstate2> */
+private int
+z2currentgstate(os_ptr op)
+{ if ( !save_page_device(igs) )
+ return zcurrentgstate(op);
+ return push_callout("%currentgstatepagedevice");
+}
+
+/* ------ Wrappers for operators that reset the graphics state. ------ */
+
+/* Check whether we need to call out to restore the page device. */
+private bool near
+restore_page_device(const gs_state *pgs_old, const gs_state *pgs_new)
+{ gx_device *dev_old = gs_currentdevice(pgs_old);
+ gx_device *dev_new;
+ gx_device *dev_t1;
+ gx_device *dev_t2;
+
+ if ( (dev_t1 = (*dev_proc(dev_old, get_page_device))(dev_old)) == 0 )
+ return false;
+ dev_new = gs_currentdevice(pgs_new);
+ if ( dev_old != dev_new )
+ { if ( (dev_t2 = (*dev_proc(dev_new, get_page_device))(dev_new)) == 0 )
+ return false;
+ if ( dev_t1 != dev_t2 )
+ return true;
+ }
+ /* The current implementation of setpagedevice just sets new */
+ /* parameters in the same device object, so we have to check */
+ /* whether the page device dictionaries are the same. */
+ { const ref *pdict1 = &gs_int_gstate(pgs_old)->pagedevice;
+ const ref *pdict2 = &gs_int_gstate(pgs_new)->pagedevice;
+ return pdict1->value.pdict != pdict2->value.pdict;
+ }
+}
+
+/* - grestore - */
+private int
+z2grestore(os_ptr op)
+{ if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ return gs_grestore(igs);
+ return push_callout("%grestorepagedevice");
+}
+
+/* - grestoreall - */
+private int
+z2grestoreall(os_ptr op)
+{ for ( ; ; )
+ { if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ { bool done = !gs_state_saved(gs_state_saved(igs));
+
+ gs_grestore(igs);
+ if ( done )
+ break;
+ }
+ else
+ return push_callout("%grestoreallpagedevice");
+ }
+ return 0;
+}
+
+/* <save> restore - */
+private int
+z2restore(os_ptr op)
+{ for ( ; ; )
+ { if ( !restore_page_device(igs, gs_state_saved(igs)) )
+ { zgrestore(op);
+ if ( !gs_state_saved(gs_state_saved(igs)) )
+ break;
+ }
+ else
+ return push_callout("%restorepagedevice");
+ }
+ return zrestore(op);
+}
+
+/* <gstate> setgstate - */
+private int
+z2setgstate(os_ptr op)
+{ check_stype(*op, st_igstate_obj);
+ if ( !restore_page_device(igs, igstate_ptr(op)) )
+ return zsetgstate(op);
+ return push_callout("%setgstatepagedevice");
+}
+
+/* ------ Initialization procedure ------ */
+
+BEGIN_OP_DEFS(zdevice2_l2_op_defs) {
+ op_def_begin_level2(),
+ {"0.currentshowpagecount", zcurrentshowpagecount},
+ {"0.currentpagedevice", zcurrentpagedevice},
+ {"1.setpagedevice", zsetpagedevice},
+ /* Note that the following replace prior definitions */
+ /* in the indicated files: */
+ {"0gsave", z2gsave}, /* zgstate.c */
+ {"0save", z2save}, /* zvmem.c */
+ {"0gstate", z2gstate}, /* zdps1.c */
+ {"1currentgstate", z2currentgstate}, /* zdps1.c */
+ {"0grestore", z2grestore}, /* zgstate.c */
+ {"0grestoreall", z2grestoreall}, /* zgstate.c */
+ {"1restore", z2restore}, /* zvmem.c */
+ {"1setgstate", z2setgstate}, /* zdps1.c */
+ /* Default Install/BeginPage/EndPage procedures */
+ /* that just call the procedure in the device. */
+ {"0.callinstall", zcallinstall},
+ {"1.callbeginpage", zcallbeginpage},
+ {"2.callendpage", zcallendpage},
+END_OP_DEFS(zdevice2_init) }
+
+/* ------ Internal routines ------ */
+
+/* Call out to a PostScript procedure. */
+private int near
+push_callout(const char _ds *callout_name)
+{ int code;
+
+ check_estack(1);
+ code = name_enter_string(callout_name, esp + 1);
+ if ( code < 0 )
+ return code;
+ ++esp;
+ r_set_attrs(esp, a_executable);
+ return o_push_estack;
+}