home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1993, 1994 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"
-
- extern int zreadonly(P1(os_ptr));
-
- /* - currentpagedevice <dict> */
- private int
- zcurrentpagedevice(register os_ptr op)
- { int code = 0;
- gx_device *dev = gs_currentdevice(igs);
- push(1);
- if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
- *op = istate->pagedevice;
- else
- { code = dict_create(0, op);
- if ( code < 0 )
- pop(1);
- }
- return code;
- }
-
- /* <pagedict> <attrdict> <keys> .matchmedia <key> true */
- /* <pagedict> <attrdict> <keys> .matchmedia false */
- /* <pagedict> null <keys> .matchmedia null true */
- private int near attr_eq(P3(const ref *, const ref *, const ref *));
- private int
- zmatchmedia(register os_ptr op)
- { os_ptr preq = op - 2;
- os_ptr pattr = op - 1;
- #define pkeys op
- ref mmkey, nmkey;
- uint matched_priority;
- ref no_priority;
- ref *ppriority;
- int code;
- int ai;
- ref aelt[2];
- #define mkey aelt[0]
- #define mdict aelt[1]
- if ( r_has_type(op - 1, t_null) )
- { check_op(3);
- make_null(op - 2);
- make_true(op - 1);
- pop(1);
- return 0;
- }
- check_dict_read(*preq);
- check_dict_read(*pattr);
- check_array(*op);
- check_read(*op);
- if ( dict_find_string(pattr, "Priority", &ppriority) > 0 )
- { check_array(*ppriority);
- check_read(*ppriority);
- }
- else
- { make_array(&no_priority, a_readonly, 0, NULL);
- ppriority = &no_priority;
- }
- matched_priority = r_size(ppriority);
- make_null(&mmkey);
- make_null(&nmkey);
- for ( ai = dict_first(pattr); (ai = dict_next(pattr, ai, aelt)) >= 0; )
- { if ( r_has_type(&mdict, t_dictionary) &&
- r_has_attr(dict_access_ref(&mdict), a_read) &&
- r_has_type(&mkey, t_integer)
- )
- { bool match_all;
- uint ki, pi;
- code = dict_bool_param(&mdict, "MatchAll", false,
- &match_all);
- if ( code < 0 )
- return code;
- for ( ki = 0; ki < r_size(pkeys); ki++ )
- { ref key;
- ref *prvalue;
- ref *pmvalue;
- array_get(pkeys, ki, &key);
- if ( dict_find(&mdict, &key, &pmvalue) <= 0 )
- continue;
- if ( dict_find(preq, &key, &prvalue) <= 0 ||
- r_has_type(prvalue, t_null)
- )
- { if ( match_all )
- goto no;
- else
- continue;
- }
- if ( !attr_eq(&key, prvalue, pmvalue) )
- goto no;
- }
- /* We have a match. See if it has priority. */
- for ( pi = matched_priority; pi > 0; )
- { ref pri;
- pi--;
- array_get(ppriority, pi, &pri);
- if ( obj_eq(&mkey, &pri) )
- { /* Yes, higher priority. */
- mmkey = mkey;
- matched_priority = pi;
- break;
- }
- }
- /* Save the match in case no match has priority. */
- nmkey = mkey;
- no: ;
- }
- }
- #undef mkey
- #undef mdict
- #undef pkeys
- if ( r_has_type(&nmkey, t_null) )
- { make_false(op - 2);
- pop(2);
- }
- else
- { if ( r_has_type(&mmkey, t_null) )
- op[-2] = nmkey;
- else
- op[-2] = mmkey;
- make_true(op - 1);
- pop(1);
- }
- return 0;
- }
- /* Compare two attribute values for equality. */
- /* PageSize is special. */
- private int near
- attr_eq(const ref *pkey, const ref *pv1, const ref *pv2)
- { ref kstr;
- if ( r_has_type(pkey, t_name) &&
- (name_string_ref(pkey, &kstr),
- r_size(&kstr) == 8 &&
- !memcmp(kstr.value.bytes, "PageSize", 8))
- )
- { /* Compare PageSize specially. */
- if ( r_is_array(pv1) && r_size(pv1) == 2 &&
- r_is_array(pv2) && r_size(pv2) == 2
- )
- { ref rv[4];
- float v[4];
- array_get(pv1, 0, &rv[0]);
- array_get(pv1, 1, &rv[1]);
- array_get(pv2, 0, &rv[2]);
- array_get(pv2, 1, &rv[3]);
- if ( num_params(rv + 3, 4, v) >= 0 )
- { float t;
- #define swap(x, y) t = x, x = y, y = t
- if ( v[0] > v[1] )
- swap(v[0], v[1]);
- if ( v[2] > v[3] )
- swap(v[2], v[3]);
- return (fabs(v[2] - v[0]) <= 5 &&
- fabs(v[3] - v[1]) <= 5);
- #undef swap
- }
- }
- }
- return obj_eq(pv1, pv2);
- }
-
- /* <dict> .setpagedevice - */
- private int
- zsetpagedevice(register os_ptr op)
- { int code;
- /******
- if ( igs->in_cachedevice )
- return_error(e_undefined);
- ******/
- check_dict_read(*op);
- /* Make the dictionary read-only. */
- code = zreadonly(op);
- if ( code < 0 )
- return code;
- istate->pagedevice = *op;
- pop(1);
- return 0;
- }
-
- /* - .beginpage - */
- private int
- z2beginpage(register os_ptr op)
- { gx_device *dev = gs_currentdevice(igs);
- ref *pproc;
- es_ptr ep = esp;
- if ( !((*dev_proc(dev, get_page_device))(dev) != 0 &&
- dict_find_string(&istate->pagedevice, "BeginPage", &pproc) > 0)
- )
- return 0;
- check_estack(1);
- push(1);
- esp = ++ep;
- make_int(op, dev->showpage_count);
- *ep = *pproc;
- return o_push_estack;
- }
-
- /* <reason_int> .endpage <flush_bool> */
- private int
- z2endpage(register os_ptr op)
- { gx_device *dev = gs_currentdevice(igs);
- ref *pproc;
- es_ptr ep = esp;
- check_type(*op, t_integer);
- if ( !((*dev_proc(dev, get_page_device))(dev) != 0 &&
- dict_find_string(&istate->pagedevice, "EndPage", &pproc) > 0)
- )
- { make_bool(op, op->value.intval != 2);
- return 0;
- }
- check_estack(1);
- push(1);
- esp = ++ep;
- *op = op[-1];
- make_int(op - 1, dev->showpage_count);
- *ep = *pproc;
- return o_push_estack;
- }
-
- /* Wrap setdevice so we clear the current pagedevice. */
- /* (This is not correct, but we aren't sure yet what is.) */
- extern int zsetdevice(P1(os_ptr));
- private int
- z2setdevice(os_ptr op)
- { int code = zsetdevice(op);
- gx_device *dev;
- if ( code < 0 )
- return code;
- dev = gs_currentdevice(igs);
- if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
- code = dict_create(0, &istate->pagedevice);
- return code;
- }
-
- /* 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.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.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 )
- { int code = (*dev->page.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;
- }
-
- /* ------ Replacements for operators that reset the graphics state. ------ */
-
- /* Forward references */
- private int push_end_page(P3(const ref *, int, int (*)(P1(os_ptr))));
- private int push_begin_page(P2(const ref *, int (*)(P1(os_ptr))));
- private int finish_page(P1(os_ptr));
-
- #define switch_page_device(dev_old, dev_new, dev_t1, dev_t2)\
- (dev_old != dev_new &&\
- (dev_t1 = (*dev_proc(dev_old, get_page_device))(dev_old)) != 0 &&\
- (dev_t2 = (*dev_proc(dev_new, get_page_device))(dev_new)) != 0 &&\
- dev_t1 != dev_t2)
-
- /* - grestore - */
- extern int zgrestore(P1(os_ptr));
- private int grestore_continue(P1(os_ptr));
- private int no_continue(P1(os_ptr));
- private int
- z2grestore(os_ptr op)
- { gx_device *dev_old = gs_currentdevice(igs);
- gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
- gx_device *dev_t1;
- gx_device *dev_t2;
- if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
- return zgrestore(op);
- return push_end_page(NULL, 2, grestore_continue);
- }
- private int
- grestore_continue(os_ptr op)
- { /* Force the grestore to succeed. */
- int code;
- gx_device_no_output(igs);
- code = gs_grestore(igs);
- if ( code < 0 )
- return code;
- return push_begin_page(NULL, no_continue);
- }
- private int
- no_continue(os_ptr op)
- { return 0;
- }
-
- /* - grestoreall - */
- extern int zgrestoreall(P1(os_ptr));
- private int grestoreall_continue(P1(os_ptr));
- private int
- z2grestoreall(os_ptr op)
- { for ( ; ; )
- { gx_device *dev_old = gs_currentdevice(igs);
- gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
- gx_device *dev_t1;
- gx_device *dev_t2;
- if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
- { zgrestore(op);
- if ( !gs_state_saved(gs_state_saved(igs)) )
- break;
- }
- else
- return push_end_page(NULL, 2, grestoreall_continue);
- }
- return 0;
- }
- private int
- grestoreall_continue(os_ptr op)
- { /* Force the grestore to succeed. */
- int code;
- gx_device_no_output(igs);
- code = gs_grestore(igs);
- if ( code < 0 )
- return code;
- return push_begin_page(NULL, z2grestoreall);
- }
-
- /* <save> restore - */
- extern int zrestore(P1(os_ptr));
- private int restore_continue(P1(os_ptr));
- private int
- z2restore(os_ptr op)
- { for ( ; ; )
- { gx_device *dev_old = gs_currentdevice(igs);
- gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
- gx_device *dev_t1;
- gx_device *dev_t2;
- if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
- { zgrestore(op);
- if ( !gs_state_saved(gs_state_saved(igs)) )
- break;
- }
- else
- { pop(1); op = osp;
- return push_end_page(op + 1, 2, restore_continue);
- }
- }
- return zrestore(op);
- }
- private int
- restore_continue(os_ptr op)
- { ref *param = op;
- /* Force the grestore to succeed. */
- int code;
- gx_device_no_output(igs);
- code = gs_grestore(igs);
- if ( code < 0 )
- return code;
- pop(1); op = osp;
- return push_begin_page(param, z2restore);
- }
-
- /* <gstate> setgstate - */
- extern int zsetgstate(P1(os_ptr));
- private int setgstate_continue(P1(os_ptr));
- private int
- z2setgstate(os_ptr op)
- { gx_device *dev_old = gs_currentdevice(igs);
- gx_device *dev_new;
- gx_device *dev_t1;
- gx_device *dev_t2;
- check_stype(*op, st_gstate);
- dev_new = gs_currentdevice(r_ptr(op, gs_state));
- if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
- return zsetgstate(op);
- pop(1); op = osp;
- return push_end_page(op + 1, 2, setgstate_continue);
- }
- private int
- setgstate_continue(os_ptr op)
- { /* Force the grestore to succeed. */
- int code;
- gx_device_no_output(igs);
- code = gs_setgstate(igs, r_ptr(op, gs_state));
- if ( code < 0 )
- return code;
- pop(1); op = osp;
- return push_begin_page(NULL, no_continue);
- }
-
- /* ------ Initialization procedure ------ */
-
- op_def zdevice2_l2_op_defs[] = {
- op_def_begin_level2(),
- {"0currentpagedevice", zcurrentpagedevice},
- {"3.matchmedia", zmatchmedia},
- {"1.setpagedevice", zsetpagedevice},
- /* Note that the following replace prior definitions */
- /* in the indicated files: */
- {"0.beginpage", z2beginpage}, /* gs_init.ps */
- {"1.endpage", z2endpage}, /* gs_init.ps */
- {"0grestore", z2grestore}, /* zgstate.c */
- {"0grestoreall", z2grestoreall}, /* zgstate.c */
- {"1restore", z2restore}, /* zvmem.c */
- {"1.setdevice", z2setdevice}, /* zdevice.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},
- /* Internal operators */
- {"0%no_continue", no_continue},
- {"0%grestore_continue", grestore_continue},
- {"0%grestoreall_continue", grestoreall_continue},
- {"0%restore_continue", restore_continue},
- {"0%setgstate_continue", setgstate_continue},
- {"1%finish_page", finish_page},
- op_def_end(0)
- };
-
- /* ------ Internal routines ------ */
-
- /* Schedule the call on the EndPage procedure when resetting the gstate. */
- private int
- push_end_page(const ref *param, int reason, int (*contin)(P1(os_ptr)))
- { int epush = (param ? 5 : 4);
- es_ptr ep = esp;
- check_estack(epush);
- make_op_estack(ep + 1, contin);
- esp = ep += epush;
- if ( param )
- ep[-3] = *param;
- make_op_estack(ep - 2, finish_page);
- make_op_estack(ep - 1, z2endpage);
- make_int(ep, reason);
- return o_push_estack;
- }
-
- /* Schedule the call on the BeginPage procedure when resetting the gstate. */
- private int
- push_begin_page(const ref *param, int (*contin)(P1(os_ptr)))
- { int epush = (param ? 3 : 2);
- es_ptr ep = esp;
- check_estack(epush);
- make_op_estack(ep + 1, contin);
- esp = ep += epush;
- if ( param )
- ep[-1] = *param;
- make_op_estack(ep, z2beginpage);
- return o_push_estack;
- }
-
- /* Finish the page. The top of the ostack contains the Boolean value */
- /* returned by the EndPage procedure. */
- private int
- finish_page(register os_ptr op)
- { check_type(*op, t_boolean);
- if ( op->value.boolval )
- { int code;
- ref *pcopies;
- long ncopies;
- const ref *pagedict = &gs_int_gstate(igs)->pagedevice;
- if ( dict_find_string(pagedict, "NumCopies", &pcopies) <= 0 ||
- !r_has_type(pcopies, t_integer) ||
- (ncopies = pcopies->value.intval) < 0
- )
- { ref name_ncopies;
- if ( name_enter_string("#copies", &name_ncopies) != 0 ||
- (pcopies = dict_find_name(&name_ncopies)) == 0 ||
- !r_has_type(pcopies, t_integer) ||
- (ncopies = pcopies->value.intval) < 0
- )
- ncopies = 1;
- }
- code = gs_output_page(igs, (int)ncopies, false);
- if ( code < 0 )
- return code;
- }
- pop(1);
- return 0;
- }
-