home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gs252src.zip / GS252 / ZUPATH.C < prev    next >
C/C++ Source or Header  |  1992-04-25  |  12KB  |  489 lines

  1. /* Copyright (C) 1990, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* zupath.c */
  21. /* Operators related to user paths */
  22. #include "ghost.h"
  23. #include "errors.h"
  24. #include "oper.h"
  25. #include "dict.h"
  26. #include "dstack.h"
  27. #include "iutil.h"
  28. #include "state.h"
  29. #include "store.h"
  30. #include "stream.h"
  31. #include "bnum.h"
  32. #include "gsmatrix.h"
  33. #include "gspath.h"
  34. #include "gsstate.h"
  35. #include "gscoord.h"
  36. #include "gspaint.h"
  37. #include "gxfixed.h"
  38. #include "gxdevice.h"
  39. #include "gxpath.h"
  40.  
  41. /* Forward references */
  42. private int upath_append(P1(os_ptr));
  43. private int upath_stroke(P1(os_ptr));
  44.  
  45. /* ------ Insideness testing ------ */
  46.  
  47. /* Forward references */
  48. private int in_test(P2(os_ptr, int (*)(P1(gs_state *))));
  49. private int in_path(P1(os_ptr));
  50. private int in_path_result(P3(os_ptr, int, int));
  51. private int in_utest(P2(os_ptr, int (*)(P1(gs_state *))));
  52. private int in_upath(P1(os_ptr));
  53. private int in_upath_result(P3(os_ptr, int, int));
  54.  
  55. /* We use invalidexit, which the painting procedures cannot generate, */
  56. /* as an "error" to indicate that the hit detection device found a hit. */
  57. #define e_hit e_invalidexit
  58.  
  59. /* ineofill */
  60. int
  61. zineofill(os_ptr op)
  62. {    return in_test(op, gs_eofill);
  63. }
  64.  
  65. /* infill */
  66. int
  67. zinfill(os_ptr op)
  68. {    return in_test(op, gs_fill);
  69. }
  70.  
  71. /* instroke */
  72. int
  73. zinstroke(os_ptr op)
  74. {    return in_test(op, gs_stroke);
  75. }
  76.  
  77. /* inueofill */
  78. int
  79. zinueofill(os_ptr op)
  80. {    return in_utest(op, gs_eofill);
  81. }
  82.  
  83. /* inufill */
  84. int
  85. zinufill(os_ptr op)
  86. {    return in_utest(op, gs_fill);
  87. }
  88.  
  89. /* inustroke */
  90. int
  91. zinustroke(os_ptr op)
  92. {    /* This is different because of the optional matrix operand. */
  93.     int code = gs_gsave(igs);
  94.     int spop, npop;
  95.     if ( code < 0 ) return code;
  96.     if ( (spop = upath_stroke(op)) < 0 ||
  97.          (npop = in_path(op - spop)) < 0
  98.        )
  99.        {    gs_grestore(igs);
  100.         return code;
  101.        }
  102.     code = gs_stroke(igs);
  103.     return in_upath_result(op, npop + spop, code);
  104. }
  105.  
  106. /* ------ Internal routines ------ */
  107.  
  108. /* Define a minimal device for insideness testing. */
  109. /* It returns e_hit whenever it is asked to actually paint any pixels. */
  110. private dev_proc_fill_rectangle(hit_fill_rectangle);
  111. private gx_device_procs hit_procs = {
  112.     NULL,                /* open_device */
  113.     NULL,                /* get_initial_matrix */
  114.     NULL,                /* sync_output */
  115.     NULL,                /* output_page */
  116.     NULL,                /* close_device */
  117.     gx_default_map_rgb_color,
  118.     gx_default_map_color_rgb,
  119.     hit_fill_rectangle,
  120.     NULL,                /* tile_rectangle */
  121.     NULL,                /* copy_mono */
  122.     NULL,                /* copy_color */
  123.     gx_default_draw_line
  124. };
  125. private gx_device hit_device =
  126. {    sizeof(gx_device),
  127.     &hit_procs,
  128.     "hit detector",
  129.     0, 0, 1, 1, no_margins, dci_black_and_white, 0    /* generic */
  130. };
  131. /* Test for a hit when filling a rectangle. */
  132. private int
  133. hit_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  134.   gx_color_index color)
  135. {    return (w > 0 && h > 0 ? e_hit : 0);
  136. }
  137.  
  138. /* Do the work of the non-user-path insideness operators. */
  139. private int
  140. in_test(os_ptr op, int (*paintproc)(P1(gs_state *)))
  141. {    int npop = in_path(op);
  142.     int code;
  143.     if ( npop < 0 ) return npop;
  144.     code = (*paintproc)(igs);
  145.     return in_path_result(op, npop, code);
  146. }
  147.  
  148. /* Set up a clipping path and device for insideness testing. */
  149. private int
  150. in_path(os_ptr op)
  151. {    int code = gs_gsave(igs);
  152.     int npop;
  153.     float uxy[2];
  154.     if ( code < 0 ) return code;
  155.     code = num_params(op, 2, uxy);
  156.     if ( code >= 0 )
  157.        {    /* Aperture is a single pixel. */
  158.         gs_point dxy;
  159.         gs_fixed_rect fr;
  160.         gs_transform(igs, uxy[0], uxy[1], &dxy);
  161.         fr.p.x = fixed_truncated(float2fixed(dxy.x));
  162.         fr.p.y = fixed_truncated(float2fixed(dxy.y));
  163.         fr.q.x = fr.p.x + int2fixed(1);
  164.         fr.q.y = fr.p.y + int2fixed(1);
  165.         code = gx_clip_to_rectangle(igs, &fr);
  166.         npop = 2;
  167.        }
  168.     else
  169.        {    /* Aperture is a user path. */
  170.         if ( (code = upath_append(op)) >= 0 )
  171.             code = gx_clip_to_path(igs);
  172.         npop = 1;
  173.        }
  174.     if ( code < 0 )
  175.        {    gs_grestore(igs);
  176.         return code;
  177.        }
  178.     /* Install the hit detection device. */
  179.     gs_setgray(igs, 0.0);
  180.     gx_set_device_only(igs, &hit_device);
  181.     return npop;
  182. }
  183.  
  184. /* Finish an insideness test. */
  185. private int
  186. in_path_result(os_ptr op, int npop, int code)
  187. {    int result;
  188.     gs_grestore(igs);
  189.     switch ( code )
  190.        {
  191.     case e_hit:            /* found a hit */
  192.         result = 1;
  193.         break;
  194.     case 0:                /* completed painting without a hit */
  195.         result = 0;
  196.         break;
  197.     default:            /* error */
  198.         return code;
  199.        }
  200.     npop--;
  201.     pop(npop); op -= npop;
  202.     make_bool(op, result);
  203.     return 0;
  204.         
  205. }
  206.  
  207. /* Do the work of the user-path insideness operators. */
  208. private int
  209. in_utest(os_ptr op, int (*paintproc)(P1(gs_state *)))
  210. {    int npop = in_upath(op);
  211.     int code;
  212.     if ( npop < 0 ) return npop;
  213.     code = (*paintproc)(igs);
  214.     return in_upath_result(op, npop, code);
  215. }
  216.  
  217. /* Set up a clipping path and device for insideness testing */
  218. /* with a user path. */
  219. private int
  220. in_upath(os_ptr op)
  221. {    int code = gs_gsave(igs);
  222.     int npop;
  223.     if ( code < 0 ) return code;
  224.     if ( (code = upath_append(op)) < 0 ||
  225.          (npop = in_path(op - 1)) < 0
  226.        )
  227.        {    gs_grestore(igs);
  228.         return code;
  229.        }
  230.     return npop + 1;
  231. }
  232.  
  233. /* Finish an insideness test with a user path. */
  234. private int
  235. in_upath_result(os_ptr op, int npop, int code)
  236. {    gs_grestore(igs);        /* undo the extra gsave */
  237.     return in_path_result(op, npop, code);
  238. }
  239.  
  240. /* ------ User paths ------ */
  241.  
  242. /* User path operator codes */
  243. typedef enum {
  244.   upath_setbbox = 0,
  245.   upath_moveto = 1,
  246.   upath_rmoveto = 2,
  247.   upath_lineto = 3,
  248.   upath_rlineto = 4,
  249.   upath_curveto = 5,
  250.   upath_rcurveto = 6,
  251.   upath_arc = 7,
  252.   upath_arcn = 8,
  253.   upath_arct = 9,
  254.   upath_closepath = 10,
  255.   upath_ucache = 11
  256. } upath_op;
  257. #define upath_op_max 11
  258. #define upath_repeat 32
  259. static byte up_nargs[upath_op_max + 1] =
  260.    { 4, 2, 2, 2, 2, 6, 6, 5, 5, 5, 0, 0 };
  261. #define zp(proc) extern int proc(P1(os_ptr))
  262.     zp(zsetbbox); zp(zmoveto); zp(zrmoveto);
  263.     zp(zlineto); zp(zrlineto); zp(zcurveto); zp(zrcurveto);
  264.     zp(zarc); zp(zarcn); zp(zarct); zp(zclosepath); zp(zucache);
  265. #undef zp
  266. static op_proc_p up_ops[upath_op_max + 1] =
  267.    {    zsetbbox, zmoveto, zrmoveto, zlineto, zrlineto,
  268.     zcurveto, zrcurveto, zarc, zarcn, zarct,
  269.     zclosepath, zucache
  270.    };
  271.  
  272. /* ucache */
  273. int
  274. zucache(os_ptr op)
  275. {    /* A no-op for now. */
  276.     return 0;
  277. }
  278.  
  279. /* uappend */
  280. int
  281. zuappend(register os_ptr op)
  282. {    int code = gs_gsave(igs);
  283.     if ( code < 0 ) return code;
  284.     if ( (code = upath_append(op)) >= 0 )
  285.         code = gs_upmergepath(igs);
  286.     gs_grestore(igs);
  287.     if ( code < 0 ) return code;
  288.     pop(1);
  289.     return 0;
  290. }
  291.  
  292. /* ueofill */
  293. int
  294. zueofill(register os_ptr op)
  295. {    int code = gs_gsave(igs);
  296.     if ( code < 0 ) return code;
  297.     if ( (code = upath_append(op)) >= 0 )
  298.         code = gs_eofill(igs);
  299.     gs_grestore(igs);
  300.     if ( code < 0 ) return code;
  301.     pop(1);
  302.     return 0;
  303. }
  304.  
  305. /* ufill */
  306. int
  307. zufill(register os_ptr op)
  308. {    int code = gs_gsave(igs);
  309.     if ( code < 0 ) return code;
  310.     if ( (code = upath_append(op)) >= 0 )
  311.         code = gs_fill(igs);
  312.     gs_grestore(igs);
  313.     if ( code < 0 ) return code;
  314.     pop(1);
  315.     return 0;
  316. }
  317.  
  318. /* ustroke */
  319. int
  320. zustroke(register os_ptr op)
  321. {    int code = gs_gsave(igs);
  322.     int npop;
  323.     if ( code < 0 ) return code;
  324.     if ( (code = npop = upath_stroke(op)) >= 0 )
  325.         code = gs_stroke(igs);
  326.     gs_grestore(igs);
  327.     if ( code < 0 ) return code;
  328.     pop(npop);
  329.     return 0;
  330. }
  331.  
  332. /* ustrokepath */
  333. int
  334. zustrokepath(register os_ptr op)
  335. {    int code = gs_gsave(igs);
  336.     int npop;
  337.     if ( code < 0 ) return code;
  338.     if ( (code = npop = upath_stroke(op)) < 0 ||
  339.          (code = gs_strokepath(igs)) < 0 ||
  340.          (code = gs_upmergepath(igs)) < 0
  341.        )
  342.         ;
  343.     gs_grestore(igs);
  344.     if ( code < 0 ) return code;
  345.     pop(npop);
  346.     return 0;
  347. }
  348.  
  349. /* --- Internal routines --- */
  350.  
  351. /* Append a user path to the current path. */
  352. private int
  353. upath_append(os_ptr op)
  354. {    check_read(*op);
  355.     gs_newpath(igs);
  356.     /****** ROUND tx AND ty ******/
  357.     if ( r_has_type(op, t_array) && r_size(op) == 2 &&
  358.          r_has_type(op->value.refs + 1, t_string)
  359.        )
  360.        {    /* 1st element is operators, 2nd is operands */
  361.         stream st;
  362.         int code;
  363.         int repcount = 1;
  364.         const byte *opp;
  365.         uint ocount;
  366.         code = sread_num_array(&st, op->value.refs);
  367.         if ( code < 0 ) return code;
  368.         opp = op->value.refs[1].value.bytes;
  369.         ocount = r_size(&op->value.refs[1]);
  370.         while ( ocount-- )
  371.            {    byte opx = *opp++;
  372.             if ( opx > 32 )
  373.                 repcount = opx - 32;
  374.             else if ( opx > upath_op_max )
  375.                 return e_typecheck;
  376.             else        /* operator */
  377.                {    do
  378.                    {    byte opargs = up_nargs[opx];
  379.                     while ( opargs-- )
  380.                        {    push(1);
  381.                         code = sget_encoded_number(&st, op);
  382.                         switch ( code )
  383.                            {
  384.                         case t_integer:
  385.                             r_set_type_attrs(op, t_integer, 0);
  386.                             break;
  387.                         case t_real:
  388.                             r_set_type_attrs(op, t_real, 0);
  389.                             break;
  390.                         default:
  391.                             return e_typecheck;
  392.                            }
  393.                        }
  394.                     code = (*up_ops[opx])(op);
  395.                     if ( code < 0 ) return code;
  396.                     op = osp;    /* resync */
  397.                    }
  398.                 while ( --repcount );
  399.                 repcount = 1;
  400.                }
  401.            }
  402.        }
  403.     else
  404.        {    /* Ordinary executable array */
  405.         const ref *arp = op;
  406.         ref *defp;
  407.         ref rup;
  408.         uint ocount = r_size(op);
  409.         long index = 0;
  410.         int argcount = 0;
  411.         int (*oproc)(P1(os_ptr));
  412.         int opx, code;
  413.         for ( ; index < ocount; index++ )
  414.          switch ( array_get(arp, index, &rup), r_type(&rup) )
  415.            {
  416.         case t_integer:
  417.         case t_real:
  418.             argcount++;
  419.             push(1);
  420.             *op = rup;
  421.             break;
  422.         case t_name:
  423.             if ( !r_has_attr(&rup, a_executable) )
  424.                 return e_typecheck;
  425.             if ( dict_find(&systemdict, &rup, &defp) <= 0 )
  426.                 return e_undefined;
  427.             if ( r_btype(defp) != t_operator )
  428.                 return e_typecheck;
  429.             goto xop;
  430.         case t_operator:
  431.             defp = &rup;
  432. xop:            if ( !r_has_attr(defp, a_executable) )
  433.                 return e_typecheck;
  434.             oproc = real_opproc(defp);
  435.             for ( opx = 0; opx <= upath_op_max; opx++ )
  436.                 if ( oproc == up_ops[opx] ) break;
  437.             if ( opx > upath_op_max || argcount != up_nargs[opx] )
  438.                 return e_typecheck;
  439.             code = (*oproc)(op);
  440.             if ( code < 0 ) return code;
  441.             op = osp;    /* resync ostack pointer */
  442.             argcount = 0;
  443.             break;
  444.         default:
  445.             return e_typecheck;
  446.            }
  447.         if ( argcount ) return e_typecheck;    /* leftover args */
  448.        }
  449.     return 0;
  450. }
  451.  
  452. /* Append a user path to the current path, and then apply */
  453. /* a transformation if one is supplied. */
  454. private int
  455. upath_stroke(register os_ptr op)
  456. {    int code, npop;
  457.     gs_matrix mat;
  458.     if ( (code = read_matrix(op, &mat)) >= 0 )
  459.        {    if ( (code = upath_append(op - 1)) >= 0 )
  460.             code = gs_concat(igs, &mat);
  461.         npop = 2;
  462.        }
  463.     else
  464.        {    code = upath_append(op);
  465.         npop = 1;
  466.        }
  467.     return (code < 0 ? code : npop);
  468. }
  469.  
  470. /* ------ Initialization procedure ------ */
  471.  
  472. op_def zupath_op_defs[] = {
  473.         /* Insideness testing */
  474.     {"1ineofill", zineofill},
  475.     {"1infill", zinfill},
  476.     {"1instroke", zinstroke},
  477.     {"2inueofill", zinueofill},
  478.     {"2inufill", zinufill},
  479.     {"2inustroke", zinustroke},
  480.         /* User paths */
  481.     {"1uappend", zuappend},
  482.     {"1ueofill", zueofill},
  483.     {"1ufill", zufill},
  484.     {"1ustroke", zustroke},
  485.     {"1ustrokepath", zustrokepath},
  486.     {"0ucache", zucache},
  487.     op_def_end(0)
  488. };
  489.