home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / post17s.lha / postdraw.c < prev    next >
C/C++ Source or Header  |  1992-03-10  |  57KB  |  1,717 lines

  1. /* PostScript interpreter file "postdraw.c" - path fill and images
  2.  * (C) Adrian Aylward 1989, 1992
  3.  * V1.6 First source release
  4.  * V1.7 Fix stroking lines of zero length
  5.  * V1.7 Fix image and kshow procs not observing stack discipline
  6.  */
  7.  
  8. # include "post.h"
  9.  
  10. /* Routines */
  11.  
  12. extern void fillslow(int yy, int y2, int rule);
  13. extern void fillfast(int yy, int y2, int rule);
  14. extern void fillxyxy(double *xy1, double *xy2, int cdir, int fdir);
  15. extern void imageslow(int xpos1, int ypos1, int xpos2, int ypos2);
  16. extern void imagefast(int xpos1, int ypos1, int blen);
  17.  
  18. /* Set up the halftone screens before filling a path */
  19.  
  20. void setupfill(void)
  21. {   if (istate.flags & intgraph) error(errundefined);
  22.  
  23.     if (halfok > gnest) setuphalf();
  24.  
  25.     if (gstate.shadeok == 0) setupshade();
  26.  
  27.     if (screenok == 0)
  28.     {   setupscreen(gstate.shade);
  29.         screenok = 1;
  30.     }
  31. }
  32.  
  33. /* Fill a path */
  34.  
  35. void fill(int beg, int end, int rule)
  36. {   int y2, y1;
  37.  
  38.     /* Set up the fill and clip lines.  Clipping in the x direction merely
  39.      * prevents integer overflow.  Clipping in the y direction minimises the
  40.      * number of scan lines we need to process.  We clip the fill path first,
  41.      * using the fixed limits.  Then we clip the clipping path, using the
  42.      * minimum and maximum y values from the fill path.  This optimises the
  43.      * common case where the fill path fits entirely within the clip path.
  44.      * We can't clip to the exact page width in the x direction, as we always
  45.      * draw the line widths, so we could get spurious lines along the left
  46.      * or right edges.  In the y direction we clip to the exact page size;
  47.      * we assume that integers are represented exactly in floating point */
  48.  
  49.     ymax = ylwb = gstate.dev.ybase * 256.0;
  50.     ymin = yupb = (gstate.dev.ybase + gstate.dev.ysize) * 256.0;
  51.     lineend = 0;
  52.     filllines(&patharray[beg], end - beg, 0, 1);
  53.     if (lineend == 0) return;
  54.  
  55.     /* Determine the vertical limits of the fill */
  56.  
  57.     y1 = ((int) ymin) >> 8;
  58.     y2 = (((int) ymax) >> 8) + 1;
  59.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  60.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  61.  
  62.     /* Only process the clip lines if we have a non-standard clip path */
  63.  
  64.     if (gstate.clipflag)
  65.     {   ylwb = y1 * 256.0;
  66.         yupb = y2 * 256.0;
  67.         filllines(&patharray[gstate.clipbeg],
  68.                   gstate.pathbeg - gstate.clipbeg, 1, 0);
  69.     }
  70.  
  71.     /* Set up the y buckets, and do the fill */
  72.  
  73.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  74.     if (gstate.clipflag)
  75.         fillslow(y1, y2, rule);
  76.     else
  77.         fillfast(y1, y2, rule);
  78.     ybflag = 0;
  79.  
  80.     flushlpage(y1, y2);
  81. }
  82.  
  83. /* Slow fill, has to handle clip lines too */
  84.  
  85. void fillslow(int yy, int y2, int rule)
  86. {   struct line *pline, **ppline;
  87.     struct lineseg lineseg, *plineseg;
  88.     struct halfscreen *hscreen;
  89.     struct halftone *htone;
  90.     char *dptr1, *dptr2;        /* device buffer pointers */
  91.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  92.     int flag, count, segments;  /* in-out flag, counter, segments */
  93.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  94.     int x1, x2, xp, xx;         /* current, previous x position range */
  95.     int cdir, fdir, sdir;       /* clip, fill direction counters */
  96.     int poff;                   /* offset of line from page */
  97.     int xmod, hxsize;           /* position modulo halftone screen */
  98.     int mask1, mask2;           /* bit masks for first and last bytes */
  99.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  100.     int plane;
  101.  
  102.     /* Fill the area.  Start at the lowest scan line in the path and loop
  103.      * until we reach the highest */
  104.  
  105.     active = discard = sort = 0;
  106.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  107.  
  108.     while (yy < y2)
  109.     {
  110.         /* Add all the new lines */
  111.  
  112.         pline = ybucket[yy - gstate.dev.ybase];
  113.         ybucket[yy - gstate.dev.ybase] = NULL;
  114.         while (pline)
  115.         {   lineptr[active++] = pline;
  116.             pline = pline->chain;
  117.             sort++;
  118.         }
  119.  
  120.         /* If we have any lines out of order or (new, being discarded) then
  121.          * we Shell sort the lines according to their current x coordinates.
  122.          * Any previously finished lines have large x coordinates so will be
  123.          * moved to the end of the array where they are discarded */
  124.  
  125.         sort += discard;
  126.         if (sort != 0)
  127.         {   count = active;
  128.             for (;;)
  129.             {   count = count / 3 + 1;
  130.                 for (x1 = count; x1 < active; x1++)
  131.                     for (x2 = x1 - count;
  132.                          x2 >= 0 &&
  133.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  134.                          x2 -= count)
  135.                     {   pline = lineptr[x2];
  136.                         lineptr[x2] = lineptr[x2 + count];
  137.                         lineptr[x2 + count] = pline;
  138.                     }
  139.                 if (count == 1) break;
  140.             }
  141.             active -= discard;
  142.             discard = sort = 0;
  143.         }
  144.  
  145.         /* Scan convert the scan line */
  146.  
  147.         count = active;
  148.         cdir = fdir = 0;
  149.         ppline = &lineptr[0];
  150.         plineseg = linesegarray;
  151.         segments = 0;
  152.         xp = -32767;
  153.  
  154.         while (count--)
  155.         {   pline = *ppline++;
  156.             x1 = pline->xx >> 16;
  157.  
  158.             /* At the end of the line (or if it is horizontal), use the
  159.              * special value of the x increment.  Flag it to be discarded.
  160.              * Draw only its width. We build a list of line segments to be
  161.              * drawn, creating entries for both the line width itself and
  162.              * (when we are not at the end) the area enclosed.  (Score
  163.              * 1 for the beginning of segment and -1 for the end */
  164.  
  165.             if (yy == pline->y2)
  166.             {   pline->xx += pline->d2;
  167.                 x2 = pline->xx >> 16;
  168.                 pline->xx = 0x7fffffff;
  169.                 discard++;
  170.                 if (x2 < x1)
  171.                 {   xx = x1;
  172.                     x1 = x2;
  173.                     x2 = xx;
  174.                 }
  175.                 x2++;
  176.  
  177.                 if (pline->cdir != 0)
  178.                 {   lineseg.fdir = 0;
  179.                     lineseg.cdir =  1;
  180.                     lineseg.x = x1;
  181.                     *plineseg++ = lineseg;
  182.                     lineseg.cdir = -1;
  183.                     lineseg.x = x2;
  184.                     *plineseg++ = lineseg;
  185.                     segments += 2;
  186.                 }
  187.                 else
  188.                 {   lineseg.cdir = 0;
  189.                     lineseg.fdir =  1;
  190.                     lineseg.x = x1;
  191.                     *plineseg++ = lineseg;
  192.                     lineseg.fdir = -1;
  193.                     lineseg.x = x2;
  194.                     *plineseg++ = lineseg;
  195.                     segments += 2;
  196.                 }
  197.             }
  198.  
  199.             /* At the beginning of the line, use the special values of the
  200.              * x increment; otherwise add the gradient to its current x
  201.              * coordinate.  We have to draw both the lines widths and the
  202.              * area enclosed.  Build the segment list; if two endpoints are
  203.              * coincident add the scores.  For left edges we start drawing
  204.              * at the left of the line and draw the width too; for right
  205.              * edges we stop drawing at the right of the line. For interior
  206.              * lines we draw the line width (as it may not be interior
  207.              * higher up in the pixel */
  208.  
  209.             else
  210.             {   if      (yy == pline->y1)
  211.                     pline->xx += pline->d1;  /* Beginning */
  212.                 else
  213.                     pline->xx += pline->dx;  /* Middle */
  214.                 x2 = pline->xx >> 16;
  215.                 if (x2 < xp) sort++;
  216.                 xp = x2;
  217.                 if (x2 < x1)
  218.                 {   xx = x1;
  219.                     x1 = x2;
  220.                     x2 = xx;
  221.                 }
  222.                 x2++;
  223.  
  224.                 if (pline->cdir != 0)
  225.                 {   lineseg.fdir = 0;
  226.                     sdir = cdir;
  227.                     cdir += pline->cdir;
  228.                     if      ((sdir & rule) == 0) /* Left edge */
  229.                     {   lineseg.cdir =  2;
  230.                         lineseg.x = x1;
  231.                         *plineseg++ = lineseg;
  232.                         lineseg.cdir = -1;
  233.                         lineseg.x = x2;
  234.                         *plineseg++ = lineseg;
  235.                         segments += 2;
  236.                     }
  237.                     else if ((cdir & rule) == 0) /* Right edge */
  238.                     {   lineseg.cdir = -1;
  239.                         lineseg.x = x2;
  240.                         *plineseg++ = lineseg;
  241.                         segments += 1;
  242.                     }
  243.                     else if (x1 != x2)           /* Interior, draw width */
  244.                     {   lineseg.cdir =  1;
  245.                         lineseg.x = x1;
  246.                         *plineseg++ = lineseg;
  247.                         lineseg.cdir = -1;
  248.                         lineseg.x = x2;
  249.                         *plineseg++ = lineseg;
  250.                         segments += 2;
  251.                     }
  252.                 }
  253.                 else
  254.                 {   lineseg.cdir = 0;
  255.                     sdir = fdir;
  256.                     fdir += pline->fdir;
  257.                     if      ((sdir & rule) == 0) /* Left edge */
  258.                     {   lineseg.fdir =  2;
  259.                         lineseg.x = x1;
  260.                         *plineseg++ = lineseg;
  261.                         lineseg.fdir = -1;
  262.                         lineseg.x = x2;
  263.                         *plineseg++ = lineseg;
  264.                         segments += 2;
  265.                     }
  266.                     else if ((fdir & rule) == 0) /* Right edge */
  267.                     {   lineseg.fdir = -1;
  268.                         lineseg.x = x2;
  269.                         *plineseg++ = lineseg;
  270.                         segments += 1;
  271.                     }
  272.                     else if (x1 != x2)           /* Interior, draw width */
  273.                     {   lineseg.fdir =  1;
  274.                         lineseg.x = x1;
  275.                         *plineseg++ = lineseg;
  276.                         lineseg.fdir = -1;
  277.                         lineseg.x = x2;
  278.                         *plineseg++ = lineseg;
  279.                         segments += 2;
  280.                     }
  281.                 }
  282.             }
  283.         }
  284.  
  285.         /* Sort the line segment list.  It should be almost in order, so
  286.          * a simple sort is probably optimal */
  287.  
  288.         xx = 0;
  289.         while (xx < segments - 1)
  290.         {   flag = 0;
  291.             count = segments - 1 - xx;
  292.             plineseg = linesegarray;
  293.             while (count--)
  294.             {   if (plineseg->x > (plineseg + 1)->x)
  295.                 {   flag = 1;
  296.                     lineseg = *plineseg;
  297.                     *plineseg = *(plineseg + 1);
  298.                     *(plineseg + 1) = lineseg;
  299.                 }
  300.                 plineseg++;
  301.             }
  302.             if (flag == 0) break;
  303.             xx++;
  304.         }
  305.  
  306.         /* Scan the list, drawing line segments as we find them */
  307.  
  308.         flag = 0;
  309.         cdir = fdir = 0;
  310.         for (plineseg = linesegarray; segments--; plineseg++)
  311.         {   cdir += plineseg->cdir;
  312.             fdir += plineseg->fdir;
  313.             if (flag == 0)
  314.             {   if (cdir && fdir)
  315.                 {   flag = 1;
  316.                     x1 = plineseg->x;
  317.                 }
  318.                 continue;
  319.             }
  320.             else
  321.             {   if (cdir && fdir)
  322.                     continue;
  323.                 else
  324.                 {   flag = 0;
  325.                     x2 = plineseg->x;
  326.                 }
  327.             }
  328.             if (x1 < 0) x1 = 0;
  329.             if (x2 > gstate.dev.xsize) x2 = gstate.dev.xsize;
  330.             if (x1 >= x2) continue;
  331.  
  332.             /* Draw from x1 to x2 */
  333.  
  334.             xbyt1 = x1 >> 3;
  335.             xbyt2 = (x2 - 1) >> 3;
  336.             mask1 =  0xff >> (x1 & 7);
  337.             mask2 = ~0xff >> (((x2 - 1) & 7) + 1);
  338.  
  339.             /* Loop through the bit planes */
  340.  
  341.             hscreen = &halfscreen[0];
  342.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  343.             {   htone = hscreen->halftone;
  344.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  345.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  346.  
  347.                 /* Optimise black or white */
  348.  
  349.                 if      (hscreen->num == 0)
  350.                 {   if (dptr1 == dptr2)
  351.                         *dptr1 |= (mask1 & mask2);
  352.                     else
  353.                     {   *dptr1++ |= mask1;
  354.                         while (dptr1 != dptr2) *dptr1++ = 0xff;
  355.                         *dptr1 |= mask2;
  356.                     }
  357.                 }
  358.                 else if (hscreen->num == htone->area)
  359.                 {   if (dptr1 == dptr2)
  360.                         *dptr1 &= ~(mask1 & mask2);
  361.                     else
  362.                     {   *dptr1++ &= ~mask1;
  363.                         while (dptr1 != dptr2) *dptr1++ = 0x00;
  364.                         *dptr1 &= ~mask2;
  365.                     }
  366.                 }
  367.  
  368.                 /* The general case needs a halftone screen */
  369.  
  370.                 else
  371.                 {   xmod = xbyt1 % htone->xsize;
  372.                     hbeg = hscreen->ptr +
  373.                         (yy % htone->ysize) * htone->xsize;
  374.                     hptr = hbeg + xmod;
  375.                     hxsize = htone->xsize;
  376.                     if (dptr1 == dptr2)
  377.                     {   mask1 &= mask2;
  378.                         *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  379.                     }
  380.                     else
  381.                     {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  382.                         dptr1++;
  383.                         hptr++;
  384.                         for (;;)
  385.                         {   xmod++;
  386.                             if (xmod == hxsize)
  387.                             {   xmod = 0;
  388.                                 hptr = hbeg;
  389.                             }
  390.                             if (dptr1 == dptr2) break;
  391.                             *dptr1++ = *hptr++;
  392.                         }
  393.                         *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  394.                     }
  395.                 }
  396.             }
  397.         }
  398.  
  399.         /* Continue with the next scan line */
  400.  
  401.         poff += gstate.dev.xbytes;
  402.         yy++;
  403.     }
  404. }
  405.  
  406. /* Fast fill a path, no clipping needed */
  407.  
  408. void fillfast(int yy, int y2, int rule)
  409. {   struct line *pline, **ppline;
  410.     struct halfscreen *hscreen;
  411.     struct halftone *htone;
  412.     char *dptr1, *dptr2;        /* device buffer pointers */
  413.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  414.     int count;                  /* counter */
  415.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  416.     int x1, x2, xp, xx;         /* current, previous x position range */
  417.     int fdir;                   /* fill direction counter */
  418.     int poff;                   /* offset of line from page */
  419.     int xmod, hxsize;           /* position modulo halftone screen */
  420.     int mask1, mask2;           /* bit masks for first and last bytes */
  421.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  422.     int s1, s2;                 /* segment to draw */
  423.     int plane;
  424.  
  425.     /* Fill the area.  Start at the lowest scan line in the path and loop
  426.      * until we reach the highest */
  427.  
  428.     active = discard = sort = 0;
  429.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  430.  
  431.     while (yy < y2)
  432.     {
  433.         /* Add all the new lines */
  434.  
  435.         pline = ybucket[yy - gstate.dev.ybase];
  436.         ybucket[yy - gstate.dev.ybase] = NULL;
  437.         while (pline)
  438.         {   lineptr[active++] = pline;
  439.             pline = pline->chain;
  440.             sort++;
  441.         }
  442.  
  443.         /* If we have any lines out of order or (new, being discarded) then
  444.          * we Shell sort the lines according to their current x coordinates.
  445.          * Any previously finished lines have large x coordinates so will be
  446.          * moved to the end of the array where they are discarded */
  447.  
  448.         sort += discard;
  449.         if (sort != 0)
  450.         {   count = active;
  451.             for (;;)
  452.             {   count = count / 3 + 1;
  453.                 for (x1 = count; x1 < active; x1++)
  454.                     for (x2 = x1 - count;
  455.                          x2 >= 0 &&
  456.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  457.                          x2 -= count)
  458.                     {   pline = lineptr[x2];
  459.                         lineptr[x2] = lineptr[x2 + count];
  460.                         lineptr[x2 + count] = pline;
  461.                     }
  462.                 if (count == 1) break;
  463.             }
  464.             active -= discard;
  465.             discard = sort = 0;
  466.         }
  467.  
  468.         /* Scan convert the scan line */
  469.  
  470.         count = active;
  471.         fdir = 0;
  472.         ppline = &lineptr[0];
  473.         xp = -32767;
  474.  
  475.         while (count--)
  476.         {   pline = *ppline++;
  477.             x1 = pline->xx >> 16;
  478.  
  479.             /* At the end of the line (or if it is horizontal), use the
  480.              * special value of the x increment.  Flag it to be discarded.
  481.              * Draw only its width */
  482.  
  483.             if (yy == pline->y2)
  484.             {   pline->xx += pline->d2;
  485.                 x2 = pline->xx >> 16;
  486.                 pline->xx = 0x7fffffff;
  487.                 discard++;
  488.                 if (x2 < x1)
  489.                 {   xx = x1;
  490.                     x1 = x2;
  491.                     x2 = xx;
  492.                 }
  493.                 if ((fdir & rule) == 0)
  494.                 {   s1 = x1;
  495.                     s2 = x2;
  496.                 }
  497.                 else
  498.                 {   if (x1 < s1) s1 = x1;
  499.                     if (x2 > s2) s2 = x2;
  500.                     continue;
  501.                 }
  502.             }
  503.  
  504.             /* At the beginning of the line, use the special value of the
  505.              * x increment; otherwise add the gradient to its current x
  506.              * coordinate.  We have to draw both the lines widths and the
  507.              * area enclosed.  For left edges we start drawing at the left
  508.              * of the line and draw the width too; for right edges we stop
  509.              * drawing at the right of the line. For interior lines we draw
  510.              * the line width (as it may not be interior higher up in the
  511.              * pixel */
  512.  
  513.             else
  514.             {   if      (yy == pline->y1)
  515.                     pline->xx += pline->d1;  /* Beginning */
  516.                 else
  517.                     pline->xx += pline->dx;  /* Middle */
  518.                 x2 = pline->xx >> 16;
  519.                 if (x2 < xp) sort++;
  520.                 xp = x2;
  521.                 if (x2 < x1)
  522.                 {   xx = x1;
  523.                     x1 = x2;
  524.                     x2 = xx;
  525.                 }
  526.                 if      ((fdir & rule) == 0) /* Left edge */
  527.                 {   fdir += pline->fdir;
  528.                     s1 = x1;
  529.                     s2 = x2;
  530.                     continue;
  531.                 }
  532.                 if (x1 < s1) s1 = x1;        /* Right edge, or ... */
  533.                 if (x2 > s2) s2 = x2;
  534.                 fdir += pline->fdir;
  535.                 if      ((fdir & rule) != 0) /* Interior */
  536.                     continue;
  537.             }
  538.  
  539.             /* Draw from s1 to s2 */
  540.  
  541.             s2++;
  542.             if (s1 < 0) s1 = 0;
  543.             if (s2 > gstate.dev.xsize) s2 = gstate.dev.xsize;
  544.             if (s1 >= s2) continue;
  545.             xbyt1 = s1 >> 3;
  546.             xbyt2 = (s2 - 1) >> 3;
  547.             mask1 =  0xff >> (s1 & 7);
  548.             mask2 = ~0xff >> (((s2 - 1) & 7) + 1);
  549.  
  550.             /* Loop through the bit planes */
  551.  
  552.             hscreen = &halfscreen[0];
  553.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  554.             {   htone = hscreen->halftone;
  555.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  556.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  557.  
  558.                 /* Optimise black or white */
  559.  
  560.                 if      (hscreen->num == 0)
  561.                 {   if (dptr1 == dptr2)
  562.                         *dptr1 |= (mask1 & mask2);
  563.                     else
  564.                     {   *dptr1++ |= mask1;
  565.                         while (dptr1 != dptr2) *dptr1++ = 0xff;
  566.                         *dptr1 |= mask2;
  567.                     }
  568.                 }
  569.                 else if (hscreen->num == htone->area)
  570.                 {   if (dptr1 == dptr2)
  571.                         *dptr1 &= ~(mask1 & mask2);
  572.                     else
  573.                     {   *dptr1++ &= ~mask1;
  574.                         while (dptr1 != dptr2) *dptr1++ = 0x00;
  575.                         *dptr1 &= ~mask2;
  576.                     }
  577.                 }
  578.  
  579.                 /* The general case needs a halftone screen */
  580.  
  581.                 else
  582.                 {   xmod = xbyt1 % htone->xsize;
  583.                     hbeg = hscreen->ptr +
  584.                         (yy % htone->ysize) * htone->xsize;
  585.                     hptr = hbeg + xmod;
  586.                     hxsize = htone->xsize;
  587.                     if (dptr1 == dptr2)
  588.                     {   mask1 &= mask2;
  589.                         *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  590.                     }
  591.                     else
  592.                     {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  593.                         dptr1++;
  594.                         hptr++;
  595.                         for (;;)
  596.                         {   xmod++;
  597.                             if (xmod == hxsize)
  598.                             {   xmod = 0;
  599.                                 hptr = hbeg;
  600.                             }
  601.                             if (dptr1 == dptr2) break;
  602.                             *dptr1++ = *hptr++;
  603.                         }
  604.                         *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  605.                     }
  606.                 }
  607.             }
  608.         }
  609.  
  610.         /* Continue with the next scan line */
  611.  
  612.         poff += gstate.dev.xbytes;
  613.         yy++;
  614.     }
  615. }
  616.  
  617. /* Clip lines and scale them ready for filling */
  618.  
  619. void filllines(struct point *ppoint, int count, int cdir, int fdir)
  620. {   double xy1[2], xy2[2];
  621.  
  622.     xy2[0] = xy2[1] = 0.0;
  623.  
  624.     while (count--)
  625.     {
  626.         /* We convert the coordinates to fixed point, with a scale factor
  627.          * of 256.  Then when it comes to calculating the gradients it
  628.          * will all fit into 32 bits without overflow */
  629.  
  630.         xy1[0] = xy2[0];
  631.         xy1[1] = xy2[1];
  632.         xy2[0] = floor(ppoint->x * 256.0 + 0.5);
  633.         xy2[1] = floor(ppoint->y * 256.0 + 0.5);
  634.  
  635.         /* Only draw lines, not moves.  Make y1 <= y2 */
  636.  
  637.         if (ppoint->type != ptmove)
  638.             if (xy1[1] < xy2[1])
  639.                 fillxyxy(xy1, xy2,  cdir,  fdir);
  640.             else
  641.                 fillxyxy(xy2, xy1, -cdir, -fdir);
  642.  
  643.         ppoint++;
  644.     }
  645. }
  646.  
  647.  
  648. /* Clip a line and insert it into its y bucket list ready for filling */
  649.  
  650. void fillxyxy(double *xy1, double *xy2, int cdir, int fdir)
  651. {   struct line line;
  652.     double x1, y1, x2, y2, yy;
  653.  
  654.     x1 = xy1[0];
  655.     y1 = xy1[1];
  656.     x2 = xy2[0];
  657.     y2 = xy2[1];
  658.  
  659.     /* Clip to the bottom and top.  Parts off the bottom or top are discarded
  660.      */
  661.  
  662.     if (y1 < ylwb)
  663.     {   if (y2 < ylwb) return;
  664.         x1 = floor(x1 - (y1 - ylwb) * (x2 - x1) / (y2 - y1) + 0.5);
  665.         y1 = ylwb;
  666.     }
  667.     if (y2 > yupb)
  668.     {   if (y1 > yupb) return;
  669.         x2 = floor(x2 - (y2 - yupb) * (x2 - x1) / (y2 - y1) + 0.5);
  670.         y2 = yupb;
  671.     }
  672.     if (y1 < ymin) ymin = y1;
  673.     if (y2 > ymax) ymax = y2;
  674.  
  675.     /* Clip to the left and right.  Parts off the edges are converted to
  676.      * vertical lines along the edges */
  677.  
  678.     if (x1 < xlwb)
  679.         if (x2 < xlwb)
  680.             x1 = x2 = xlwb;
  681.         else
  682.         {   yy = floor(y1 - (x1 - xlwb) * (y2 - y1) / (x2 - x1) + 0.5);
  683.             if (yy > y1 && yy < y2)
  684.             {   xy1[0] = xlwb;
  685.                 xy1[1] = y1;
  686.                 xy2[0] = xlwb;
  687.                 xy2[1] = yy;
  688.                 fillxyxy(xy1, xy2, cdir, fdir);
  689.                 y1 = yy;
  690.             }
  691.             x1 = xlwb;
  692.         }
  693.     else
  694.         if (x2 < xlwb)
  695.         {   yy = floor(y2 - (x2 - xlwb) * (y1 - y2) / (x1 - x2) + 0.5);
  696.             if (yy > y1 && yy < y2)
  697.             {   xy1[0] = xlwb;
  698.                 xy1[1] = yy;
  699.                 xy2[0] = xlwb;
  700.                 xy2[1] = y2;
  701.                 fillxyxy(xy1, xy2, cdir, fdir);
  702.                 y2 = yy;
  703.             }
  704.             x2 = xlwb;
  705.         }
  706.     if (x1 > xupb)
  707.         if (x2 > xupb)
  708.             x1 = x2 = xupb;
  709.         else
  710.         {   yy = floor(y1 - (x1 - xupb) * (y1 - y2) / (x1 - x2) + 0.5);
  711.             if (yy > y1 && yy < y2)
  712.             {   xy1[0] = xupb;
  713.                 xy1[1] = y1;
  714.                 xy2[0] = xupb;
  715.                 xy2[1] = yy;
  716.                 fillxyxy(xy1, xy2, cdir, fdir);
  717.                 y1 = yy;
  718.             }
  719.             x1 = xupb;
  720.         }
  721.     else
  722.         if (x2 > xupb)
  723.         {   yy = floor(y2 - (x2 - xupb) * (y2 - y1) / (x2 - x1) + 0.5);
  724.             if (yy > y1 && yy < y2)
  725.             {   xy1[0] = xupb;
  726.                 xy1[1] = yy;
  727.                 xy2[0] = xupb;
  728.                 xy2[1] = y2;
  729.                 fillxyxy(xy1, xy2, cdir, fdir);
  730.                 y2 = yy;
  731.             }
  732.             x2 = xupb;
  733.         }
  734.  
  735.     /* The top edge is just outside the page */
  736.  
  737.     if (y1 >= yupb) return;
  738.  
  739.     /* Construct the line.  If it is not horizontal calculate the gradient
  740.      * and the special values of the x displacement for the first and last
  741.      * lines.  The x coordinates are on a scale of 65536  */
  742.  
  743.     line.cdir = cdir;
  744.     line.fdir = fdir;
  745.     line.xx = x1 * 256.0;
  746.     line.y1 = ((int) y1) / 256;
  747.     line.y2 = ((int) y2) / 256;
  748.     if (line.y2 == line.y1)
  749.     {   line.dx = 0;
  750.         line.d1 = 0;
  751.         line.d2 = (x2 - x1) * 256.0;
  752.     }
  753.     else
  754.     {   yy = (x2 - x1) / (y2 - y1) * 256.0;
  755.         line.dx = yy * 256.0;
  756.         line.d1 = ((line.y1 + 1) * 256.0 - y1) * yy;
  757.         line.d2 = (y2 - line.y2 * 256.0) * yy;
  758.     }
  759.  
  760.     /* Store the line in the line array */
  761.  
  762.     checklinesize(lineend + 1);
  763.     linearray[lineend++] = line;
  764.  
  765. }
  766.  
  767. /* Set up the y bucket list */
  768.  
  769. void setybucket(int base, int size)
  770. {   struct line *pline;
  771.     int len, i;
  772.  
  773.     len = size * sizeof (struct line *);
  774.     if (len > memylen)
  775.     {   memfree(memybeg, memylen);
  776.         memylen = 0;
  777.         memybeg = memalloc(len);
  778.         if (memybeg == NULL) error(errmemoryallocation);
  779.         memylen = len;
  780.         ybucket = memybeg;
  781.     }
  782.     else
  783.         if (ybflag) memset((char *) memybeg, 0, memylen);
  784.     ybflag = 1;
  785.  
  786.     pline = &linearray[0];
  787.     i = lineend;
  788.  
  789.     while (i--)
  790.     {   pline->chain = ybucket[pline->y1 - base];
  791.         ybucket[pline->y1 - base] = pline;
  792.         pline++;
  793.     }
  794. }
  795.  
  796. /* Static variables for imaging */
  797.  
  798. static int imode, incol, inproc, imulti, ifast;
  799. static int iwidth, iheight, ibps, ibpsn, ibwdth, ibshf, ismax;
  800. static int ibpos, ix1, iy1, idx, idy;
  801. static float ictm[6], icti[6];
  802.  
  803. static char *ibstring[4], ibodd[3];
  804.  
  805. static int *isample;
  806.  
  807. static struct
  808. {   float shade[4];
  809. } *ishade;
  810.  
  811. static union
  812. {   int i;
  813.     unsigned char b[4];
  814. } is;
  815.  
  816. /* Render an image */
  817.  
  818. void image(int width, int height, int bps, float *matrix, int mode,
  819.            int ncol, int multi, struct object *procs)
  820. {   struct object *token1;
  821.     struct point point;
  822.     float newctm[6], *shade;
  823.     int t0, t1, t2, t3;
  824.     int bmin, bmax, bpos, blen;
  825.     int xpos1, ypos1, xpos2, ypos2, odds;
  826.     int i, lev;
  827.  
  828.     if (istate.flags & intchar)
  829.         if      (istate.type < 2)
  830.             return;
  831.         else if (istate.type == 2 && !gstate.cacheflag)
  832.             return;
  833.     if (istate.flags & intgraph)
  834.         error(errundefined);
  835.  
  836.     lev = flushlevel(-1);
  837.  
  838.     /* Set up the static variables */
  839.  
  840.     imode = mode;
  841.     incol = ncol;
  842.     inproc = multi ? ncol : 1;
  843.     imulti = multi;
  844.     iwidth = width;
  845.     iheight = height;
  846.     ibps = bps;
  847.     ibpsn = multi ? bps : bps * ncol;
  848.     ibwdth = (width * ibpsn + 7) / 8;
  849.     ibshf = (ibps == 1) ? 0 : (ibps == 2) ? 1 : (ibps == 4) ? 2 : 3;
  850.     ismax = ~(~0 << ibps);
  851.  
  852.     /* Find some memory for the sample and shade buffers */
  853.  
  854.     blen = bmax = gstate.dev.xsize * sizeof(int);
  855.     if (incol == 1) bmax += (ismax + 1) * sizeof (float [4]);
  856.     checkimagesize(bmax);
  857.     isample = memibeg;
  858.     ishade = (void *) ((char *) memibeg + blen);
  859.  
  860.     /* Set up the halftone patterns */
  861.  
  862.     if (halfok > gnest) setuphalf();
  863.  
  864.     /* For imagemask set up the halftone screens now */
  865.  
  866.     if (mode >= 0)
  867.         setupfill();
  868.  
  869.     /* Otherwise, if there is only one colour set up the shade table */
  870.  
  871.     else if (incol == 1)
  872.         for (i = 0; i <= ismax; i++)
  873.         {   shade = &ishade[i].shade[0];
  874.             shade[0] = (float) i / ismax;
  875.             mapcolour(1, shade, gstate.dev.depth, shade);
  876.             calltransfer(shade, shade);
  877.         }
  878.  
  879.     /* The transformation matrix from the image to the page is the inverse
  880.      * of the image matrix multiplied by the ctm.  Test if we can do a fast
  881.      * image (no clipping, 1 sample bit per pixel, horizontal).  Calculate
  882.      * the locations of the corners (slow image if we need to clip in the x
  883.      * direction).  For a slow image we also calculate the inverse of the
  884.      * transformation matrix; then we inverse delta transform a unit x pixel
  885.      * step to find the corresponding displacement in image space */
  886.  
  887.     invertmatrix(newctm, matrix);
  888.     multiplymatrix(ictm, newctm, gstate.ctm);
  889.     ifast = 0;
  890.     if (!gstate.clipflag && incol == 1 && ibps == 1)
  891.     {   t0 = floor(iwidth * ictm[0] + 0.5);
  892.         t1 = floor(iwidth * ictm[1] + 0.5);
  893.         t2 = floor(iheight * ictm[2] + 0.5);
  894.         t3 = floor(iheight * ictm[3] + 0.5);
  895.         if (t0 == iwidth && t1 == 0 && t2 == 0)
  896.         {   if      (t3 ==  height)
  897.                 ifast =  1;
  898.             else if (t3 == -height)
  899.                 ifast = -1;
  900.             ix1 = floor(ictm[4] + 0.5);
  901.             iy1 = floor(ictm[5] + 0.5);
  902.             if (ix1 < 0 || (ix1 + iwidth) > gstate.dev.xsize)
  903.                 ifast = 0;
  904.         }
  905.     }
  906.     if (ifast == 0)
  907.     {   invertmatrix(icti, ictm);
  908.         point.x = 1.0;
  909.         point.y = 0.0;
  910.         dtransform(&point, icti);
  911.         idx = (double) point.x * 65536.0;
  912.         idy = (double) point.y * 65536.0;
  913.     }
  914.  
  915.     /* Calculate the number of bytes we need.  Loop until we have rendered
  916.      * them all */
  917.  
  918.     bpos = bmin = 0;
  919.     blen = ibwdth * height;
  920.  
  921.     while (blen)
  922.     {
  923.         /* Call the procs whenever we run out of bytes */
  924.  
  925.         if (bmin == 0)
  926.         {   ibpos = bpos;
  927.             for (i = 0; i < inproc; i++)
  928.             {   pushint();
  929.                 istate.flags = intgraph;
  930.                 interpret(procs + i);
  931.                 popint();
  932.                 token1 = &operstack[opernest - 1];
  933.                 if (token1->type != typestring) error(errtypecheck);
  934.                 if (token1->flags & flagrprot) error(errinvalidaccess);
  935.                 ibstring[i] = vmsptr(token1->value.vref);
  936.                 if (i == 0)
  937.                     bmin = token1->length;
  938.                 else
  939.                     if (token1->length != bmin) error(errrangecheck);
  940.                 opernest--;
  941.             }
  942.             if (bmin == 0) break;
  943.             if (bmin > blen) bmin = blen;
  944.         }
  945.  
  946.         /* Render the bytes we have found */
  947.  
  948.         bmax = bmin;
  949.         xpos1 = bpos % ibwdth;
  950.         ypos1 = bpos / ibwdth;
  951.  
  952.         /* Fast image */
  953.  
  954.         if (ifast != 0)
  955.             imagefast(xpos1, ypos1, bmax);
  956.  
  957.         /* Slow image.  The slow rendering routine can only handle
  958.          * rectangles, so we split into segments as necessary */
  959.  
  960.         else
  961.         {   if (xpos1 != 0)
  962.             {   if ((xpos1 + bmax) >= ibwdth)
  963.                 {   bmax = ibwdth - xpos1;
  964.                     xpos2 = ibwdth;
  965.                 }
  966.                 else
  967.                     xpos2 = xpos1 + bmax;
  968.                 ypos2 = ypos1 + 1;
  969.             }
  970.             else
  971.             {   xpos2 = (bpos + bmax) % ibwdth;
  972.                 ypos2 = (bpos + bmax) / ibwdth;
  973.                 if (ypos2 != ypos1)
  974.                 {   bmax = bmax - xpos2;
  975.                     xpos2 = ibwdth;
  976.                 }
  977.                 else
  978.                     ypos2 = ypos1 + 1;
  979.             }
  980.  
  981.             /* If we mave multiple colous and a single proc, we may have
  982.              * a partial sample left over, which we save in a buffer for
  983.              * next time.  (But ignore the extra bits at the end of a
  984.              * row.)  Adjust the x position according */
  985.  
  986.             xpos1 = (xpos1 << 3) >> ibshf;
  987.             xpos2 = (xpos2 << 3) >> ibshf;
  988.             if (ibpsn != ibps)
  989.             {   odds = xpos2 % incol;
  990.                 xpos1 /= incol;
  991.                 xpos2 /= incol;
  992.                 if (xpos2 >= iwidth)
  993.                     xpos2 = iwidth;
  994.                 else
  995.                     if (odds != 0)
  996.                     {   i = (odds * ibpsn + 7) >> 3;
  997.                         memcpy(&ibodd[3 - i], &ibstring[0][bmax - i], i);
  998.                     }
  999.             }
  1000.             else
  1001.                 if (xpos2 > iwidth)
  1002.                     xpos2 = iwidth;
  1003.  
  1004.             imageslow(xpos1, ypos1, xpos2, ypos2);
  1005.         }
  1006.         bpos += bmax;
  1007.         blen -= bmax;
  1008.         bmin -= bmax;
  1009.     }
  1010.  
  1011.     flushlevel(lev);
  1012. }
  1013.  
  1014. /* Image slow, like path filling but copies image data */
  1015.  
  1016. void imageslow(int xpos1, int ypos1, int xpos2, int ypos2)
  1017. {   struct point point[5];
  1018.     struct line *pline, **ppline;
  1019.     struct lineseg lineseg, *plineseg;
  1020.     struct halfscreen *hscreen;
  1021.     struct halftone *htone;
  1022.     char *dptr1, *dptr2;        /* device buffer pointers */
  1023.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1024.     float shade[4];
  1025.     int flag, count, segments;  /* in-out flag, counter, segments */
  1026.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  1027.     int x1, x2, xp, xx;         /* current, previous x position range */
  1028.     int y1, y2, yy;             /* min, max, current y position */
  1029.     int cdir, fdir, sdir;       /* clip, fill direction counters */
  1030.     int poff;                   /* offset of line from page */
  1031.     int xmod, hxsize;           /* position modulo halftone screen */
  1032.     int mask1, mask2;           /* bit masks for first and last bytes */
  1033.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  1034.     int plane;
  1035.     int ix, iy, jx, jy, bx, by, ib, ii;
  1036.  
  1037.     /* Construct the outline of the area to be imaged */
  1038.  
  1039.     lineend = 0;
  1040.     ymax = ylwb = gstate.dev.ybase * 256.0;
  1041.     ymin = yupb = (gstate.dev.ybase + gstate.dev.ysize) * 256.0;
  1042.  
  1043.     point[0].type = ptmove;
  1044.     point[1].type = ptline;
  1045.     point[2].type = ptline;
  1046.     point[3].type = ptline;
  1047.     point[0].x = point[3].x = xpos1;
  1048.     point[1].x = point[2].x = xpos2;
  1049.     point[0].y = point[1].y = ypos1;
  1050.     point[2].y = point[3].y = ypos2;
  1051.     transform(&point[0], ictm);
  1052.     transform(&point[1], ictm);
  1053.     transform(&point[2], ictm);
  1054.     transform(&point[3], ictm);
  1055.     point[4] = point[0];
  1056.     point[4].type = ptclosei;
  1057.     filllines(&point[0], 5, 0, 1);
  1058.  
  1059.     /* Add the clip lines */
  1060.  
  1061.     y1 =  ((int) ymin) >> 8;
  1062.     y2 = (((int) ymax) >> 8) + 1;
  1063.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  1064.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  1065.     ylwb = ymin;
  1066.     yupb = ymax;
  1067.     filllines(&patharray[gstate.clipbeg],
  1068.               gstate.pathbeg - gstate.clipbeg, 1, 0);
  1069.  
  1070.     /* Set up the y buckets */
  1071.  
  1072.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  1073.  
  1074.     /* Render the area.  Start at the lowest scan line in the path and loop
  1075.      * until we reach the highest */
  1076.  
  1077.     active = discard = sort = 0;
  1078.     poff = (y1 - gstate.dev.ybase) * gstate.dev.xbytes;
  1079.     yy = y1;
  1080.     while (yy < y2)
  1081.     {
  1082.         /* Add all the new lines */
  1083.  
  1084.         pline = ybucket[yy - gstate.dev.ybase];
  1085.         ybucket[yy - gstate.dev.ybase] = 0;
  1086.         while (pline)
  1087.         {   lineptr[active++] = pline;
  1088.             pline = pline->chain;
  1089.             sort++;
  1090.         }
  1091.  
  1092.         /* If we have any lines out of order or (new, being discarded) then
  1093.          * we Shell sort the lines according to their current x coordinates.
  1094.          * Any previously finished lines have large x coordinates so will be
  1095.          * moved to the end of the array where they are discarded */
  1096.  
  1097.         sort += discard;
  1098.         if (sort != 0)
  1099.         {   count = active;
  1100.             for (;;)
  1101.             {   count = count / 3 + 1;
  1102.                 for (x1 = count; x1 < active; x1++)
  1103.                     for (x2 = x1 - count;
  1104.                          x2 >= 0 &&
  1105.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  1106.                          x2 -= count)
  1107.                     {   pline = lineptr[x2];
  1108.                         lineptr[x2] = lineptr[x2 + count];
  1109.                         lineptr[x2 + count] = pline;
  1110.                     }
  1111.                 if (count == 1) break;
  1112.             }
  1113.             active -= discard;
  1114.             discard = sort = 0;
  1115.         }
  1116.  
  1117.         /* Scan convert the scan line.  Only the clip lines have width */
  1118.  
  1119.         count = active;
  1120.         cdir = fdir = 0;
  1121.         ppline = &lineptr[0];
  1122.         plineseg = linesegarray;
  1123.         segments = 0;
  1124.         xp = -32767;
  1125.  
  1126.         while (count--)
  1127.         {   pline = *ppline++;
  1128.             x1 = pline->xx >> 16;
  1129.  
  1130.             /* At the end of the line (or if it is horizontal), use the
  1131.              * special value of the x increment.  Flag it to be discarded */
  1132.  
  1133.             if (yy == pline->y2)
  1134.             {   pline->xx += pline->d2;
  1135.                 x2 = pline->xx >> 16;
  1136.                 pline->xx = 0x7fffffff;
  1137.                 discard++;
  1138.  
  1139.                 if (pline->cdir != 0)
  1140.                 {   if (x2 < x1)
  1141.                     {   xx = x1;
  1142.                         x1 = x2;
  1143.                         x2 = xx;
  1144.                     }
  1145.                     x2++;
  1146.                     lineseg.fdir = 0;
  1147.                     lineseg.cdir =  1;
  1148.                     lineseg.x = x1;
  1149.                     *plineseg++ = lineseg;
  1150.                     lineseg.cdir = -1;
  1151.                     lineseg.x = x2;
  1152.                     *plineseg++ = lineseg;
  1153.                     segments += 2;
  1154.                 }
  1155.             }
  1156.  
  1157.             /* At the beginning of the line, use the special values of the
  1158.              * x increment; otherwise add the gradient to its current x
  1159.              * coordinate */
  1160.  
  1161.             else
  1162.             {   if      (yy == pline->y1)
  1163.                     pline->xx += pline->d1;  /* Beginning */
  1164.                 else
  1165.                     pline->xx += pline->dx;  /* Middle */
  1166.                 x2 = pline->xx >> 16;
  1167.                 if (x2 < xp) sort++;
  1168.                 xp = x2;
  1169.  
  1170.                 if (pline->cdir != 0)
  1171.                 {   if (x2 < x1)
  1172.                     {   xx = x1;
  1173.                         x1 = x2;
  1174.                         x2 = xx;
  1175.                     }
  1176.                     x2++;
  1177.                     lineseg.fdir = 0;
  1178.                     sdir = cdir;
  1179.                     cdir += pline->cdir;
  1180.                     if      (sdir == 0)      /* Left edge */
  1181.                     {   lineseg.cdir =  2;
  1182.                         lineseg.x = x1;
  1183.                         *plineseg++ = lineseg;
  1184.                         lineseg.cdir = -1;
  1185.                         lineseg.x = x2;
  1186.                         *plineseg++ = lineseg;
  1187.                         segments += 2;
  1188.                     }
  1189.                     else if (cdir == 0)      /* Right edge */
  1190.                     {   lineseg.cdir = -1;
  1191.                         lineseg.x = x2;
  1192.                         *plineseg++ = lineseg;
  1193.                         segments += 1;
  1194.                     }
  1195.                     else if (x1 != x2)       /* Interior, draw width */
  1196.                     {   lineseg.cdir =  1;
  1197.                         lineseg.x = x1;
  1198.                         *plineseg++ = lineseg;
  1199.                         lineseg.cdir = -1;
  1200.                         lineseg.x = x2;
  1201.                         *plineseg++ = lineseg;
  1202.                         segments += 2;
  1203.                     }
  1204.                 }
  1205.                 else
  1206.                 {   lineseg.cdir = 0;
  1207.                     if (fdir == 0)           /* Left edge */
  1208.                     {   lineseg.fdir =  1;
  1209.                         lineseg.x = x1;
  1210.                         *plineseg++ = lineseg;
  1211.                         segments += 1;
  1212.                     }
  1213.                     else                     /* Right edge */
  1214.                     {   lineseg.fdir = -1;
  1215.                         lineseg.x = x1;
  1216.                         *plineseg++ = lineseg;
  1217.                         segments += 1;
  1218.                     }
  1219.                     fdir += pline->fdir;
  1220.                 }
  1221.             }
  1222.         }
  1223.  
  1224.         /* Sort the line segment list.  It should be almost in order, so
  1225.          * a simple sort is probably optimal */
  1226.  
  1227.         xx = 0;
  1228.         while (xx < segments - 1)
  1229.         {   flag = 0;
  1230.             count = segments - 1 - xx;
  1231.             plineseg = linesegarray;
  1232.             while (count--)
  1233.             {   if (plineseg->x > (plineseg + 1)->x)
  1234.                 {   flag = 1;
  1235.                     lineseg = *plineseg;
  1236.                     *plineseg = *(plineseg + 1);
  1237.                     *(plineseg + 1) = lineseg;
  1238.                 }
  1239.                 plineseg++;
  1240.             }
  1241.             if (flag == 0) break;
  1242.             xx++;
  1243.         }
  1244.  
  1245.         /* Scan the list, rendering line segments as we find them */
  1246.  
  1247.         flag = 0;
  1248.         cdir = fdir = 0;
  1249.         if (!gstate.clipflag) cdir = 1;
  1250.         for (plineseg = linesegarray; segments--; plineseg++)
  1251.         {   cdir += plineseg->cdir;
  1252.             fdir += plineseg->fdir;
  1253.             if (flag == 0)
  1254.             {   if (cdir && fdir)
  1255.                 {   flag = 1;
  1256.                     x1 = plineseg->x;
  1257.                 }
  1258.                 continue;
  1259.             }
  1260.             else
  1261.             {   if (cdir && fdir)
  1262.                     continue;
  1263.                 else
  1264.                 {   flag = 0;
  1265.                     x2 = plineseg->x;
  1266.                 }
  1267.             }
  1268.             if (x1 < 0) x1 = 0;
  1269.             if (x2 > gstate.dev.xsize) x2 = gstate.dev.xsize;
  1270.             if (x1 >= x2) continue;
  1271.  
  1272.             /* Render from x1 to x2.  Inverse transform the beginning of
  1273.              * the segment to find its location in the image string; to
  1274.              * find the remaining locations we will add the x pixel step
  1275.              * values */
  1276.  
  1277.             point[0].x = x1 + 0.5;
  1278.             point[0].y = yy + 0.5;
  1279.             transform(&point[0], icti);
  1280.             ix = point[0].x * 65536.0;
  1281.             iy = point[0].y * 65536.0;
  1282.  
  1283.             /* Unpack all the sample values for the segment.  Make sure the
  1284.              * locations are within the rectangle.  For multiple procs we
  1285.              * extract all the sample bits in parallel */
  1286.  
  1287.             for (xx = x1; xx < x2; xx++)
  1288.             {   jx = ix >> 16;
  1289.                 jy = iy >> 16;
  1290.                 if (jx < xpos1) jx = xpos1;
  1291.                 if (jx >= xpos2) jx = xpos2 - 1;
  1292.                 if (jy < ypos1) jy = ypos1;
  1293.                 if (jy >= ypos2) jy = ypos2 - 1;
  1294.                 by = jy * ibwdth - ibpos;
  1295.                 if      (incol == 1)
  1296.                 {   bx = jx << ibshf;
  1297.                     ib = by + (bx >> 3);
  1298.                     is.i = ((unsigned char *) ibstring[0])[ib];
  1299.                     if      (ibps == 1)
  1300.                         is.i = (is.i >> (~bx & 7)) & 0x01;
  1301.                     else if (ibps == 2)
  1302.                         is.i = (is.i >> (~bx & 6)) & 0x03;
  1303.                     else if (ibps == 4)
  1304.                         is.i = (bx & 4) ? is.i & 0x0f : is.i >> 4;
  1305.                 }
  1306.                 else if (incol == inproc)
  1307.                 {   bx = jx << ibshf;
  1308.                     ib = by + (bx >> 3);
  1309.                     is.b[0] = ibstring[0][ib];
  1310.                     is.b[1] = ibstring[1][ib];
  1311.                     is.b[2] = ibstring[2][ib];
  1312.                     is.b[3] = (inproc == 4) ? ibstring[3][ib]: 0;
  1313.                     if      (ibps == 1)
  1314.                         is.i = (is.i >> (~bx & 7)) & 0x01010101;
  1315.                     else if (ibps == 2)
  1316.                         is.i = (is.i >> (~bx & 6)) & 0x03030303;
  1317.                     else if (ibps == 4)
  1318.                     {   if (!(bx & 4)) is.i >>= 4;
  1319.                         is.i &= 0x0f0f0f0f;
  1320.                     }
  1321.                 }
  1322.                 else
  1323.                 {   bx = jx * ibpsn;
  1324.                     is.b[3] = 0;
  1325.                     for (plane = 0; plane < incol; plane++)
  1326.                     {   ib = by + (bx >> 3);
  1327.                         ii = (ib < 0) ?
  1328.                             ((unsigned char *) ibodd) [3 + ib] :
  1329.                             ((unsigned char *) (ibstring[0])) [ib];
  1330.                         if      (ibps == 1)
  1331.                             is.b[plane] = (ii >> (~bx & 7)) & 0x01;
  1332.                         else if (ibps == 2)
  1333.                             is.b[plane] = (ii >> (~bx & 6)) & 0x03;
  1334.                         else if (ibps == 4)
  1335.                             is.b[plane] = (bx & 4) ? ii & 0x0f : ii >> 4;
  1336.                         else
  1337.                             is.b[plane] = ii;
  1338.                         bx += ibps;
  1339.                     }
  1340.                 }
  1341.  
  1342.                 isample[xx] = is.i;
  1343.                 ix += idx;
  1344.                 iy += idy;
  1345.             }
  1346.  
  1347.             /* Render runs of pixels with the same sample value together */
  1348.  
  1349.             while (x1 < x2)
  1350.             {   is.i = isample[x1];
  1351.                 xx = x1;
  1352.                 while (xx < x2)
  1353.                 {   xx++;
  1354.                     if (isample[xx] != is.i) break;
  1355.                 }
  1356.                 xbyt1 = x1 >> 3;
  1357.                 xbyt2 = (xx - 1) >> 3;
  1358.                 mask1 =  0xff >> (x1 & 7);
  1359.                 mask2 = ~0xff >> (((xx - 1) & 7) + 1);
  1360.                 x1 = xx;
  1361.  
  1362.                 /* Imagemask, halftone screens already set up */
  1363.  
  1364.                 if      (imode >= 0)
  1365.                 {   if (is.i != imode) continue;
  1366.                 }
  1367.  
  1368.                 /* Image, only one colour, use shade table */
  1369.  
  1370.                 else if (incol == 1)
  1371.                     setupscreen(ishade[is.i].shade);
  1372.  
  1373.                 /* Image, multiple colours, no shade table */
  1374.  
  1375.                 else
  1376.                 {   shade[0] = (float) is.b[0] / ismax;
  1377.                     shade[1] = (float) is.b[1] / ismax;
  1378.                     shade[2] = (float) is.b[2] / ismax;
  1379.                     shade[3] = (float) is.b[3] / ismax;
  1380.                     mapcolour(incol, shade, gstate.dev.depth, shade);
  1381.                     calltransfer(shade, shade);
  1382.                     setupscreen(shade);
  1383.                 }
  1384.  
  1385.                 /* Loop through the bit planes */
  1386.  
  1387.                 hscreen = &halfscreen[0];
  1388.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1389.                 {   htone = hscreen->halftone;
  1390.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1391.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  1392.  
  1393.                     /* Optimise black or white */
  1394.  
  1395.                     if      (hscreen->num == 0)
  1396.                     {   if (dptr1 == dptr2)
  1397.                             *dptr1 |= (mask1 & mask2);
  1398.                         else
  1399.                         {   *dptr1++ |= mask1;
  1400.                             while (dptr1 != dptr2) *dptr1++ = 0xffff;
  1401.                             *dptr1 |= mask2;
  1402.                         }
  1403.                     }
  1404.                     else if (hscreen->num == htone->area)
  1405.                     {   if (dptr1 == dptr2)
  1406.                             *dptr1 &= ~(mask1 & mask2);
  1407.                         else
  1408.                         {   *dptr1++ &= ~mask1;
  1409.                             while (dptr1 != dptr2) *dptr1++ = 0x0000;
  1410.                             *dptr1 &= ~mask2;
  1411.                         }
  1412.                     }
  1413.  
  1414.                     /* The general case needs a halftone screen */
  1415.  
  1416.                     else
  1417.                     {   xmod = xbyt1 % htone->xsize;
  1418.                         hbeg = hscreen->ptr +
  1419.                             (yy % htone->ysize) * htone->xsize;
  1420.                         hptr = hbeg + xmod;
  1421.                         hxsize = htone->xsize;
  1422.                         if (dptr1 == dptr2)
  1423.                         {   mask1 &= mask2;
  1424.                             *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  1425.                         }
  1426.                         else
  1427.                         {   *dptr1 = (*dptr1 & ~mask1) | (*hptr & mask1);
  1428.                             dptr1++;
  1429.                             hptr++;
  1430.                             for (;;)
  1431.                             {   xmod++;
  1432.                                 if (xmod == hxsize)
  1433.                                 {   xmod = 0;
  1434.                                     hptr = hbeg;
  1435.                                 }
  1436.                                 if (dptr1 == dptr2) break;
  1437.                                 *dptr1++ = *hptr++;
  1438.                             }
  1439.                             *dptr1 = (*dptr1 & ~mask2) | (*hptr & mask2);
  1440.                         }
  1441.                     }
  1442.                 }
  1443.             }
  1444.         }
  1445.  
  1446.         /* Continue with the next scan line */
  1447.  
  1448.         poff += gstate.dev.xbytes;
  1449.         yy++;
  1450.     }
  1451.  
  1452.     ybflag = 0;
  1453.     flushlpage(y1, y2);
  1454. }
  1455.  
  1456. /* Image fast */
  1457.  
  1458. void imagefast(int xpos1, int ypos1, int blen)
  1459. {   struct halfscreen *hscreen;
  1460.     struct halftone *htone;
  1461.     char *dptr1, *dptr2;        /* device buffer pointers */
  1462.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1463.     unsigned char *bsample, *bstr;
  1464.     char *bstring;
  1465.     int bmax, x1, x2, y1, y2, yy, i;
  1466.     int xshf1, xshf2, ibyte;
  1467.     int poff;                   /* offset of line from page */
  1468.     int xmod, hxsize;           /* position modulo halftone screen */
  1469.     int mask1, mask2;           /* bit masks for first and last bytes */
  1470.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  1471.     int plane;
  1472.  
  1473.     bstring = ibstring[0];
  1474.     if (ifast > 0)
  1475.         yy = iy1 + ypos1;
  1476.     else
  1477.         yy = iy1 - ypos1 - 1;
  1478.     y1 = yy;
  1479.  
  1480.     /* Loop rendering rows */
  1481.  
  1482.     while (blen)
  1483.     {   x1 = ix1 + (xpos1 << 3);
  1484.         x2 = ix1 + iwidth;
  1485.         bmax = ibwdth - xpos1;
  1486.         if (blen < bmax)
  1487.         {   x2 = x1 + (blen << 3);
  1488.             bmax = blen;
  1489.         }
  1490.  
  1491.         /* Clip in the y direction */
  1492.  
  1493.         if (yy >= gstate.dev.ybase &&
  1494.             yy < gstate.dev.ybase + gstate.dev.ysize)
  1495.         {   poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  1496.  
  1497.             /* Bit shift the row */
  1498.  
  1499.             xshf1 = x1 & 7;
  1500.             xshf2 = ((x2 - 1) & 7) + 1;
  1501.             if (xshf1 == 0)
  1502.                 memcpy((char *) isample, bstring, bmax);
  1503.             else
  1504.             {   bstr = (unsigned char *) bstring;
  1505.                 bsample = (char *) isample;
  1506.                 i = bmax;
  1507.                 *bsample++ = *bstr++ >> xshf1;
  1508.                 while (--i)
  1509.                 {   *bsample++ = ((*(bstr - 1) << 8) | *bstr) >> xshf1;
  1510.                     bstr++;
  1511.                 }
  1512.                 *bsample = (*(bstr - 1) << 8) >> xshf1;
  1513.             }
  1514.             bsample = (char *) isample;
  1515.  
  1516.             xbyt1 = x1 >> 3;
  1517.             xbyt2 = (x2 - 1) >> 3;
  1518.             mask1 =  0xff >> xshf1;
  1519.             mask2 = ~0xff >> xshf2;
  1520.  
  1521.             /* Image all the samples that are 0 */
  1522.  
  1523.             if (imode < 0)
  1524.                 setupscreen(ishade[0].shade);
  1525.             if (imode != 1)
  1526.             {   bsample[0] |= ~mask1;
  1527.                 bsample[xbyt2 - xbyt1] |= ~mask2;
  1528.                 hscreen = &halfscreen[0];
  1529.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1530.                 {   htone = hscreen->halftone;
  1531.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1532.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2 + 1;
  1533.                     bstr = bsample;
  1534.  
  1535.                     /* Optimise black or white */
  1536.  
  1537.                     if      (hscreen->num == 0)
  1538.                         for (;;)
  1539.                         {   *dptr1++ |= ~*bstr++;
  1540.                             if (dptr1 == dptr2) break;
  1541.                         }
  1542.                     else if (hscreen->num == htone->area)
  1543.                         for (;;)
  1544.                         {   *dptr1++ &=  *bstr++;
  1545.                             if (dptr1 == dptr2) break;
  1546.                         }
  1547.  
  1548.                     /* The general case needs a halftone screen */
  1549.  
  1550.                     else
  1551.                     {   xmod = xbyt1 % htone->xsize;
  1552.                         hbeg = hscreen->ptr +
  1553.                             (yy % htone->ysize) * htone->xsize;
  1554.                         hptr = hbeg + xmod;
  1555.                         hxsize = htone->xsize;
  1556.                         for (;;)
  1557.                         {   ibyte = *bstr++;
  1558.                             *dptr1 = (*dptr1 &  ibyte) | (*hptr++ & ~ibyte);
  1559.                             dptr1++;
  1560.                             if (dptr1 == dptr2) break;
  1561.                             xmod++;
  1562.                             if (xmod == hxsize)
  1563.                             {   xmod = 0;
  1564.                                 hptr = hbeg;
  1565.                             }
  1566.                         }
  1567.                     }
  1568.                 }
  1569.             }
  1570.  
  1571.             /* Image all the samples that are 1 */
  1572.  
  1573.             if (imode < 0)
  1574.                 setupscreen(ishade[1].shade);
  1575.             if (imode != 0)
  1576.             {   bsample[0] &= mask1;
  1577.                 bsample[xbyt2 - xbyt1] &= mask2;
  1578.                 hscreen = &halfscreen[0];
  1579.                 for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1580.                 {   htone = hscreen->halftone;
  1581.                     dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  1582.                     dptr2 = gstate.dev.buf[plane] + poff + xbyt2 + 1;
  1583.                     bstr = bsample;
  1584.  
  1585.                     /* Optimise black or white */
  1586.  
  1587.                     if      (hscreen->num == 0)
  1588.                         for (;;)
  1589.                         {   *dptr1++ |=  *bstr++;
  1590.                             if (dptr1 == dptr2) break;
  1591.                         }
  1592.                     else if (hscreen->num == htone->area)
  1593.                         for (;;)
  1594.                         {   *dptr1++ &= ~*bstr++;
  1595.                             if (dptr1 == dptr2) break;
  1596.                         }
  1597.  
  1598.                     /* The general case needs a halftone screen */
  1599.  
  1600.                     else
  1601.                     {   xmod = xbyt1 % htone->xsize;
  1602.                         hbeg = hscreen->ptr +
  1603.                             (yy % htone->ysize) * htone->xsize;
  1604.                         hptr = hbeg + xmod;
  1605.                         hxsize = htone->xsize;
  1606.                         for (;;)
  1607.                         {   ibyte = *bstr++;
  1608.                             *dptr1 = (*dptr1 & ~ibyte) | (*hptr++ &  ibyte);
  1609.                             dptr1++;
  1610.                             if (dptr1 == dptr2) break;
  1611.                             xmod++;
  1612.                             if (xmod == hxsize)
  1613.                             {   xmod = 0;
  1614.                                 hptr = hbeg;
  1615.                             }
  1616.                         }
  1617.                     }
  1618.                 }
  1619.             }
  1620.         }
  1621.         xpos1 = 0;
  1622.         yy += ifast;
  1623.         bstring += bmax;
  1624.         blen -= bmax;
  1625.     }
  1626.  
  1627.     if (ifast < 0)
  1628.     {   y2 = y1;
  1629.         y1 = yy;
  1630.     }
  1631.     else
  1632.         y2 = yy;
  1633.     if (y1 < gstate.dev.ybase)
  1634.         y1 = gstate.dev.ybase;
  1635.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  1636.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  1637.     flushlpage(y1, y2);
  1638. }
  1639.  
  1640. /* Erase the page */
  1641.  
  1642. void erasepage(void)
  1643. {   struct halfscreen *hscreen;
  1644.     struct halftone *htone;
  1645.     char *hbeg, *hptr, *pbuf;
  1646.     float shade[4];
  1647.     int xlen, xpos, ypos, ymod;
  1648.     int hxsize, hysize;
  1649.     int plane;
  1650.  
  1651.     if (istate.flags & intgraph) error(errundefined);
  1652.  
  1653.     /* Set up the halftone pattern if necessary */
  1654.  
  1655.     if (halfok > gnest) setuphalf();
  1656.  
  1657.     /* Set up the halftine screens for a gray level of 1.0 */
  1658.  
  1659.     shade[0] = shade[1] = shade[2] = shade[3] = 1.0;
  1660.     calltransfer(shade, shade);
  1661.     setupscreen(shade);
  1662.  
  1663.     /* Loop through the bit planes */
  1664.  
  1665.     hscreen = &halfscreen[0];
  1666.     for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1667.     {   pbuf = gstate.dev.buf[plane];
  1668.         htone = hscreen->halftone;
  1669.  
  1670.         /* Optimse erase to black or white (the commonest cases) */
  1671.  
  1672.         if      (hscreen->num == 0)
  1673.             memset(pbuf, 0xff, gstate.dev.len);
  1674.         else if (hscreen->num == htone->area)
  1675.             memset(pbuf, 0x00, gstate.dev.len);
  1676.  
  1677.         /* Otherwise we replicate the halftone screen */
  1678.  
  1679.         else
  1680.         {   hxsize = htone->xsize;
  1681.             hysize = htone->ysize;
  1682.             hbeg = hscreen->ptr;
  1683.             ymod = gstate.dev.ybase % hysize;
  1684.             hptr = hbeg + ymod * hxsize;
  1685.  
  1686.             /* Loop for all the rows */
  1687.  
  1688.             for (ypos = 0; ypos < gstate.dev.ysize; ypos++)
  1689.             {   xpos = 0;
  1690.  
  1691.                 /* Replicate the screen through the row. */
  1692.  
  1693.                 for (;;)
  1694.                 {   xlen = gstate.dev.xbytes - xpos;
  1695.                     if (xlen == 0) break;
  1696.                     if (xlen > hxsize) xlen = hxsize;
  1697.                     memcpy(pbuf, hptr, xlen);
  1698.                     pbuf += xlen;
  1699.                     xpos += xlen;
  1700.                 }
  1701.  
  1702.                 /* Step on to next row.  Restart the screen as necessary */
  1703.  
  1704.                 hptr += hxsize;
  1705.                 ymod++;
  1706.                 if (ymod == hysize)
  1707.                 {   ymod = 0;
  1708.                     hptr = hbeg;
  1709.                 }
  1710.             }
  1711.         }
  1712.     }
  1713.     flushlpage(gstate.dev.ybase, gstate.dev.ybase + gstate.dev.ysize);
  1714. }
  1715.  
  1716. /* End of file "postdraw.c" */
  1717.