diff options
Diffstat (limited to 'gs/src/zdevice2.c')
-rw-r--r-- | gs/src/zdevice2.c | 330 |
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; +} |