home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / ZDEVICE2.C < prev    next >
C/C++ Source or Header  |  1994-07-27  |  15KB  |  545 lines

  1. /* Copyright (C) 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* zdevice2.c */
  20. /* Level 2 device operators */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "ghost.h"
  24. #include "errors.h"
  25. #include "oper.h"
  26. #include "dstack.h"            /* for dict_find_name */
  27. #include "estack.h"
  28. #include "idict.h"
  29. #include "idparam.h"
  30. #include "igstate.h"
  31. #include "iname.h"
  32. #include "store.h"
  33. #include "gxdevice.h"
  34. #include "gsstate.h"
  35.  
  36. extern int zreadonly(P1(os_ptr));
  37.  
  38. /* - currentpagedevice <dict> */
  39. private int
  40. zcurrentpagedevice(register os_ptr op)
  41. {    int code = 0;
  42.     gx_device *dev = gs_currentdevice(igs);
  43.     push(1);
  44.     if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
  45.         *op = istate->pagedevice;
  46.     else
  47.     {    code = dict_create(0, op);
  48.         if ( code < 0 )
  49.             pop(1);
  50.     }
  51.     return code;
  52. }
  53.  
  54. /* <pagedict> <attrdict> <keys> .matchmedia <key> true */
  55. /* <pagedict> <attrdict> <keys> .matchmedia false */
  56. /* <pagedict> null <keys> .matchmedia null true */
  57. private int near attr_eq(P3(const ref *, const ref *, const ref *));
  58. private int
  59. zmatchmedia(register os_ptr op)
  60. {    os_ptr preq = op - 2;
  61.     os_ptr pattr = op - 1;
  62. #define pkeys op
  63.     ref mmkey, nmkey;
  64.     uint matched_priority;
  65.     ref no_priority;
  66.     ref *ppriority;
  67.     int code;
  68.     int ai;
  69.     ref aelt[2];
  70. #define mkey aelt[0]
  71. #define mdict aelt[1]
  72.     if ( r_has_type(op - 1, t_null) )
  73.       {    check_op(3);
  74.         make_null(op - 2);
  75.         make_true(op - 1);
  76.         pop(1);
  77.         return 0;
  78.       }
  79.     check_dict_read(*preq);
  80.     check_dict_read(*pattr);
  81.     check_array(*op);
  82.     check_read(*op);
  83.     if ( dict_find_string(pattr, "Priority", &ppriority) > 0 )
  84.     {    check_array(*ppriority);
  85.         check_read(*ppriority);
  86.     }
  87.     else
  88.     {    make_array(&no_priority, a_readonly, 0, NULL);
  89.         ppriority = &no_priority;
  90.     }
  91.     matched_priority = r_size(ppriority);
  92.     make_null(&mmkey);
  93.     make_null(&nmkey);
  94.     for ( ai = dict_first(pattr); (ai = dict_next(pattr, ai, aelt)) >= 0; )
  95.     {    if ( r_has_type(&mdict, t_dictionary) &&
  96.              r_has_attr(dict_access_ref(&mdict), a_read) &&
  97.              r_has_type(&mkey, t_integer)
  98.            )
  99.         {    bool match_all;
  100.             uint ki, pi;
  101.             code = dict_bool_param(&mdict, "MatchAll", false,
  102.                            &match_all);
  103.             if ( code < 0 )
  104.                 return code;
  105.             for ( ki = 0; ki < r_size(pkeys); ki++ )
  106.             {    ref key;
  107.                 ref *prvalue;
  108.                 ref *pmvalue;
  109.                 array_get(pkeys, ki, &key);
  110.                 if ( dict_find(&mdict, &key, &pmvalue) <= 0 )
  111.                     continue;
  112.                 if ( dict_find(preq, &key, &prvalue) <= 0 ||
  113.                      r_has_type(prvalue, t_null)
  114.                    )
  115.                 {    if ( match_all )
  116.                         goto no;
  117.                     else
  118.                         continue;
  119.                 }
  120.                 if ( !attr_eq(&key, prvalue, pmvalue) )
  121.                     goto no;
  122.             }
  123.             /* We have a match.  See if it has priority. */
  124.             for ( pi = matched_priority; pi > 0; )
  125.             {    ref pri;
  126.                 pi--;
  127.                 array_get(ppriority, pi, &pri);
  128.                 if ( obj_eq(&mkey, &pri) )
  129.                 {    /* Yes, higher priority. */
  130.                     mmkey = mkey;
  131.                     matched_priority = pi;
  132.                     break;
  133.                 }
  134.             }
  135.             /* Save the match in case no match has priority. */
  136.             nmkey = mkey;
  137. no:            ;
  138.         }
  139.     }
  140. #undef mkey
  141. #undef mdict
  142. #undef pkeys
  143.     if ( r_has_type(&nmkey, t_null) )
  144.     {    make_false(op - 2);
  145.         pop(2);
  146.     }
  147.     else
  148.     {    if ( r_has_type(&mmkey, t_null) )
  149.             op[-2] = nmkey;
  150.         else
  151.             op[-2] = mmkey;
  152.         make_true(op - 1);
  153.         pop(1);
  154.     }
  155.     return 0;
  156. }
  157. /* Compare two attribute values for equality. */
  158. /* PageSize is special. */
  159. private int near
  160. attr_eq(const ref *pkey, const ref *pv1, const ref *pv2)
  161. {    ref kstr;
  162.     if ( r_has_type(pkey, t_name) &&
  163.          (name_string_ref(pkey, &kstr),
  164.           r_size(&kstr) == 8 &&
  165.           !memcmp(kstr.value.bytes, "PageSize", 8))
  166.        )
  167.     {    /* Compare PageSize specially. */
  168.         if ( r_is_array(pv1) && r_size(pv1) == 2 &&
  169.              r_is_array(pv2) && r_size(pv2) == 2
  170.            )
  171.         {    ref rv[4];
  172.             float v[4];
  173.             array_get(pv1, 0, &rv[0]);
  174.             array_get(pv1, 1, &rv[1]);
  175.             array_get(pv2, 0, &rv[2]);
  176.             array_get(pv2, 1, &rv[3]);
  177.             if ( num_params(rv + 3, 4, v) >= 0 )
  178.             {    float t;
  179. #define swap(x, y) t = x, x = y, y = t
  180.                 if ( v[0] > v[1] )
  181.                     swap(v[0], v[1]);
  182.                 if ( v[2] > v[3] )
  183.                     swap(v[2], v[3]);
  184.                 return (fabs(v[2] - v[0]) <= 5 &&
  185.                     fabs(v[3] - v[1]) <= 5);
  186. #undef swap
  187.             }
  188.         }
  189.     }
  190.     return obj_eq(pv1, pv2);
  191. }
  192.  
  193. /* <dict> .setpagedevice - */
  194. private int
  195. zsetpagedevice(register os_ptr op)
  196. {    int code;
  197. /******
  198.     if ( igs->in_cachedevice )
  199.         return_error(e_undefined);
  200.  ******/
  201.     check_dict_read(*op);
  202.     /* Make the dictionary read-only. */
  203.     code = zreadonly(op);
  204.     if ( code < 0 )
  205.         return code;
  206.     istate->pagedevice = *op;
  207.     pop(1);
  208.     return 0;
  209. }
  210.  
  211. /* - .beginpage - */
  212. private int
  213. z2beginpage(register os_ptr op)
  214. {    gx_device *dev = gs_currentdevice(igs);
  215.     ref *pproc;
  216.     es_ptr ep = esp;
  217.     if ( !((*dev_proc(dev, get_page_device))(dev) != 0 &&
  218.            dict_find_string(&istate->pagedevice, "BeginPage", &pproc) > 0)
  219.        )
  220.       return 0;
  221.     check_estack(1);
  222.     push(1);
  223.     esp = ++ep;
  224.     make_int(op, dev->showpage_count);
  225.     *ep = *pproc;
  226.     return o_push_estack;
  227. }
  228.  
  229. /* <reason_int> .endpage <flush_bool> */
  230. private int
  231. z2endpage(register os_ptr op)
  232. {    gx_device *dev = gs_currentdevice(igs);
  233.     ref *pproc;
  234.     es_ptr ep = esp;
  235.     check_type(*op, t_integer);
  236.     if ( !((*dev_proc(dev, get_page_device))(dev) != 0 &&
  237.            dict_find_string(&istate->pagedevice, "EndPage", &pproc) > 0)
  238.        )
  239.     {    make_bool(op, op->value.intval != 2);
  240.         return 0;
  241.     }
  242.     check_estack(1);
  243.     push(1);
  244.     esp = ++ep;
  245.     *op = op[-1];
  246.     make_int(op - 1, dev->showpage_count);
  247.     *ep = *pproc;
  248.     return o_push_estack;
  249. }
  250.  
  251. /* Wrap setdevice so we clear the current pagedevice. */
  252. /* (This is not correct, but we aren't sure yet what is.) */
  253. extern int zsetdevice(P1(os_ptr));
  254. private int
  255. z2setdevice(os_ptr op)
  256. {    int code = zsetdevice(op);
  257.     gx_device *dev;
  258.     if ( code < 0 )
  259.         return code;
  260.     dev = gs_currentdevice(igs);
  261.     if ( (*dev_proc(dev, get_page_device))(dev) != 0 )
  262.         code = dict_create(0, &istate->pagedevice);
  263.     return code;
  264. }
  265.  
  266. /* Default Install/BeginPage/EndPage procedures */
  267. /* that just call the procedure in the device. */
  268.  
  269. /* - .callinstall - */
  270. private int
  271. zcallinstall(os_ptr op)
  272. {    gx_device *dev = gs_currentdevice(igs);
  273.     if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
  274.       {    int code = (*dev->page.install)(dev, igs);
  275.         if ( code < 0 )
  276.           return code;
  277.       }
  278.     return 0;
  279. }
  280.  
  281. /* <showpage_count> .callbeginpage - */
  282. private int
  283. zcallbeginpage(os_ptr op)
  284. {    gx_device *dev = gs_currentdevice(igs);
  285.     check_type(*op, t_integer);
  286.     if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
  287.       {    int code = (*dev->page.begin_page)(dev, igs);
  288.         if ( code < 0 )
  289.           return code;
  290.       }
  291.     pop(1);
  292.     return 0;
  293. }
  294.  
  295. /* <showpage_count> <reason_int> .callendpage <flush_bool> */
  296. private int
  297. zcallendpage(os_ptr op)
  298. {    gx_device *dev = gs_currentdevice(igs);
  299.     int code;
  300.     check_type(op[-1], t_integer);
  301.     check_type(*op, t_integer);
  302.     if ( (dev = (*dev_proc(dev, get_page_device))(dev)) != 0 )
  303.       {    int code = (*dev->page.end_page)(dev, (int)op->value.intval, igs);
  304.         if ( code < 0 )
  305.           return code;
  306.         if ( code > 1 )
  307.           return_error(e_rangecheck);
  308.       }
  309.     else
  310.       {    code = (op->value.intval == 2 ? 0 : 1);
  311.       }
  312.     make_bool(op - 1, code);
  313.     pop(1);
  314.     return 0;
  315. }
  316.  
  317. /* ------ Replacements for operators that reset the graphics state. ------ */
  318.  
  319. /* Forward references */
  320. private int push_end_page(P3(const ref *, int, int (*)(P1(os_ptr))));
  321. private int push_begin_page(P2(const ref *, int (*)(P1(os_ptr))));
  322. private int finish_page(P1(os_ptr));
  323.  
  324. #define switch_page_device(dev_old, dev_new, dev_t1, dev_t2)\
  325.   (dev_old != dev_new &&\
  326.    (dev_t1 = (*dev_proc(dev_old, get_page_device))(dev_old)) != 0 &&\
  327.    (dev_t2 = (*dev_proc(dev_new, get_page_device))(dev_new)) != 0 &&\
  328.    dev_t1 != dev_t2)
  329.  
  330. /* - grestore - */
  331. extern int zgrestore(P1(os_ptr));
  332. private int grestore_continue(P1(os_ptr));
  333. private int no_continue(P1(os_ptr));
  334. private int
  335. z2grestore(os_ptr op)
  336. {    gx_device *dev_old = gs_currentdevice(igs);
  337.     gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
  338.     gx_device *dev_t1;
  339.     gx_device *dev_t2;
  340.     if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
  341.         return zgrestore(op);
  342.     return push_end_page(NULL, 2, grestore_continue);
  343. }
  344. private int
  345. grestore_continue(os_ptr op)
  346. {    /* Force the grestore to succeed. */
  347.     int code;
  348.     gx_device_no_output(igs);
  349.     code = gs_grestore(igs);
  350.     if ( code < 0 )
  351.         return code;
  352.     return push_begin_page(NULL, no_continue);
  353. }
  354. private int
  355. no_continue(os_ptr op)
  356. {    return 0;
  357. }
  358.  
  359. /* - grestoreall - */
  360. extern int zgrestoreall(P1(os_ptr));
  361. private int grestoreall_continue(P1(os_ptr));
  362. private int
  363. z2grestoreall(os_ptr op)
  364. {    for ( ; ; )
  365.     {    gx_device *dev_old = gs_currentdevice(igs);
  366.         gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
  367.         gx_device *dev_t1;
  368.         gx_device *dev_t2;
  369.         if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
  370.         {    zgrestore(op);
  371.             if ( !gs_state_saved(gs_state_saved(igs)) )
  372.                 break;
  373.         }
  374.         else
  375.             return push_end_page(NULL, 2, grestoreall_continue);
  376.     }
  377.     return 0;
  378. }
  379. private int
  380. grestoreall_continue(os_ptr op)
  381. {    /* Force the grestore to succeed. */
  382.     int code;
  383.     gx_device_no_output(igs);
  384.     code = gs_grestore(igs);
  385.     if ( code < 0 )
  386.         return code;
  387.     return push_begin_page(NULL, z2grestoreall);
  388. }
  389.  
  390. /* <save> restore - */
  391. extern int zrestore(P1(os_ptr));
  392. private int restore_continue(P1(os_ptr));
  393. private int
  394. z2restore(os_ptr op)
  395. {    for ( ; ; )
  396.     {    gx_device *dev_old = gs_currentdevice(igs);
  397.         gx_device *dev_new = gs_currentdevice(gs_state_saved(igs));
  398.         gx_device *dev_t1;
  399.         gx_device *dev_t2;
  400.         if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
  401.         {    zgrestore(op);
  402.             if ( !gs_state_saved(gs_state_saved(igs)) )
  403.                 break;
  404.         }
  405.         else
  406.         {    pop(1);  op = osp;
  407.             return push_end_page(op + 1, 2, restore_continue);
  408.         }
  409.     }
  410.     return zrestore(op);
  411. }
  412. private int
  413. restore_continue(os_ptr op)
  414. {    ref *param = op;
  415.     /* Force the grestore to succeed. */
  416.     int code;
  417.     gx_device_no_output(igs);
  418.     code = gs_grestore(igs);
  419.     if ( code < 0 )
  420.         return code;
  421.     pop(1);  op = osp;
  422.     return push_begin_page(param, z2restore);
  423. }
  424.  
  425. /* <gstate> setgstate - */
  426. extern int zsetgstate(P1(os_ptr));
  427. private int setgstate_continue(P1(os_ptr));
  428. private int
  429. z2setgstate(os_ptr op)
  430. {    gx_device *dev_old = gs_currentdevice(igs);
  431.     gx_device *dev_new;
  432.     gx_device *dev_t1;
  433.     gx_device *dev_t2;
  434.     check_stype(*op, st_gstate);
  435.     dev_new = gs_currentdevice(r_ptr(op, gs_state));
  436.     if ( !switch_page_device(dev_old, dev_new, dev_t1, dev_t2) )
  437.         return zsetgstate(op);
  438.     pop(1);  op = osp;
  439.     return push_end_page(op + 1, 2, setgstate_continue);
  440. }
  441. private int
  442. setgstate_continue(os_ptr op)
  443. {    /* Force the grestore to succeed. */
  444.     int code;
  445.     gx_device_no_output(igs);
  446.     code = gs_setgstate(igs, r_ptr(op, gs_state));
  447.     if ( code < 0 )
  448.         return code;
  449.     pop(1);  op = osp;
  450.     return push_begin_page(NULL, no_continue);
  451. }
  452.  
  453. /* ------ Initialization procedure ------ */
  454.  
  455. op_def zdevice2_l2_op_defs[] = {
  456.         op_def_begin_level2(),
  457.     {"0currentpagedevice", zcurrentpagedevice},
  458.     {"3.matchmedia", zmatchmedia},
  459.     {"1.setpagedevice", zsetpagedevice},
  460.         /* Note that the following replace prior definitions */
  461.         /* in the indicated files: */
  462.     {"0.beginpage", z2beginpage},        /* gs_init.ps */
  463.     {"1.endpage", z2endpage},        /* gs_init.ps */
  464.     {"0grestore", z2grestore},        /* zgstate.c */
  465.     {"0grestoreall", z2grestoreall},    /* zgstate.c */
  466.     {"1restore", z2restore},        /* zvmem.c */
  467.     {"1.setdevice", z2setdevice},        /* zdevice.c */
  468.     {"1setgstate", z2setgstate},        /* zdps1.c */
  469.         /* Default Install/BeginPage/EndPage procedures */
  470.         /* that just call the procedure in the device. */
  471.     {"0.callinstall", zcallinstall},
  472.     {"1.callbeginpage", zcallbeginpage},
  473.     {"2.callendpage", zcallendpage},
  474.         /* Internal operators */
  475.     {"0%no_continue", no_continue},
  476.     {"0%grestore_continue", grestore_continue},
  477.     {"0%grestoreall_continue", grestoreall_continue},
  478.     {"0%restore_continue", restore_continue},
  479.     {"0%setgstate_continue", setgstate_continue},
  480.     {"1%finish_page", finish_page},
  481.     op_def_end(0)
  482. };
  483.  
  484. /* ------ Internal routines ------ */
  485.  
  486. /* Schedule the call on the EndPage procedure when resetting the gstate. */
  487. private int
  488. push_end_page(const ref *param, int reason, int (*contin)(P1(os_ptr)))
  489. {    int epush = (param ? 5 : 4);
  490.     es_ptr ep = esp;
  491.     check_estack(epush);
  492.     make_op_estack(ep + 1, contin);
  493.     esp = ep += epush;
  494.     if ( param )
  495.         ep[-3] = *param;
  496.     make_op_estack(ep - 2, finish_page);
  497.     make_op_estack(ep - 1, z2endpage);
  498.     make_int(ep, reason);
  499.     return o_push_estack;
  500. }
  501.  
  502. /* Schedule the call on the BeginPage procedure when resetting the gstate. */
  503. private int
  504. push_begin_page(const ref *param, int (*contin)(P1(os_ptr)))
  505. {    int epush = (param ? 3 : 2);
  506.     es_ptr ep = esp;
  507.     check_estack(epush);
  508.     make_op_estack(ep + 1, contin);
  509.     esp = ep += epush;
  510.     if ( param )
  511.         ep[-1] = *param;
  512.     make_op_estack(ep, z2beginpage);
  513.     return o_push_estack;
  514. }
  515.  
  516. /* Finish the page.  The top of the ostack contains the Boolean value */
  517. /* returned by the EndPage procedure. */
  518. private int
  519. finish_page(register os_ptr op)
  520. {    check_type(*op, t_boolean);
  521.     if ( op->value.boolval )
  522.       {    int code;
  523.         ref *pcopies;
  524.         long ncopies;
  525.         const ref *pagedict = &gs_int_gstate(igs)->pagedevice;
  526.         if ( dict_find_string(pagedict, "NumCopies", &pcopies) <= 0 ||
  527.              !r_has_type(pcopies, t_integer) ||
  528.              (ncopies = pcopies->value.intval) < 0
  529.            )
  530.           {    ref name_ncopies;
  531.             if ( name_enter_string("#copies", &name_ncopies) != 0 ||
  532.                  (pcopies = dict_find_name(&name_ncopies)) == 0 ||
  533.                  !r_has_type(pcopies, t_integer) ||
  534.                  (ncopies = pcopies->value.intval) < 0
  535.                )
  536.               ncopies = 1;
  537.           }
  538.         code = gs_output_page(igs, (int)ncopies, false);
  539.         if ( code < 0 )
  540.           return code;
  541.       }
  542.     pop(1);
  543.     return 0;
  544. }
  545.