home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / ddx / mi / miwideline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  47.1 KB  |  2,163 lines

  1. /*
  2.  * $XConsortium: miwideline.c,v 1.45 91/11/20 15:33:19 keith Exp $
  3.  *
  4.  * Copyright 1988 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted, provided
  8.  * that the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * Author:  Keith Packard, MIT X Consortium
  17.  */
  18.  
  19. /*
  20.  * Mostly integer wideline code.  Uses a technique similar to
  21.  * bresenham zero-width lines, except walks an X edge
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <math.h>
  26. #include "X.h"
  27. #include "windowstr.h"
  28. #include "gcstruct.h"
  29. #include "miscstruct.h"
  30. #include "miwideline.h"
  31.  
  32. #if (defined(SVR4) || defined(SYSV) && defined(SYSV386)) && __STDC__
  33. extern double hypot(double, double);
  34. #endif
  35.  
  36. #ifdef ICEILTEMPDECL
  37. ICEILTEMPDECL
  38. #endif
  39.  
  40. static void miLineArc();
  41.  
  42. /*
  43.  * spans-based polygon filler
  44.  */
  45.  
  46. void
  47. miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, overall_height,
  48.           left, right, left_count, right_count)
  49.     DrawablePtr    pDrawable;
  50.     GCPtr    pGC;
  51.     unsigned long   pixel;
  52.     SpanDataPtr    spanData;
  53.     int        y;            /* start y coordinate */
  54.     int        overall_height;        /* height of entire segment */
  55.     PolyEdgePtr    left, right;
  56.     int        left_count, right_count;
  57. {
  58.     register int left_x, left_e;
  59.     int    left_stepx;
  60.     int    left_signdx;
  61.     int    left_dy, left_dx;
  62.  
  63.     register int right_x, right_e;
  64.     int    right_stepx;
  65.     int    right_signdx;
  66.     int    right_dy, right_dx;
  67.  
  68.     int    height;
  69.     int    left_height, right_height;
  70.  
  71.     register DDXPointPtr ppt;
  72.     DDXPointPtr pptInit;
  73.     register int *pwidth;
  74.     int *pwidthInit;
  75.     unsigned long oldPixel;
  76.     int        xorg;
  77.     Spans    spanRec;
  78.  
  79.     left_height = 0;
  80.     right_height = 0;
  81.     
  82.     if (!spanData)
  83.     {
  84.         pptInit = (DDXPointPtr) ALLOCATE_LOCAL (overall_height * sizeof(*ppt));
  85.         if (!pptInit)
  86.         return;
  87.         pwidthInit = (int *) ALLOCATE_LOCAL (overall_height * sizeof(*pwidth));
  88.         if (!pwidthInit)
  89.         {
  90.         DEALLOCATE_LOCAL (pptInit);
  91.         return;
  92.         }
  93.     ppt = pptInit;
  94.     pwidth = pwidthInit;
  95.         oldPixel = pGC->fgPixel;
  96.         if (pixel != oldPixel)
  97.         {
  98.             DoChangeGC (pGC, GCForeground, (XID *)&pixel, FALSE);
  99.             ValidateGC (pDrawable, pGC);
  100.         }
  101.     }
  102.     else
  103.     {
  104.     spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt));
  105.     if (!spanRec.points)
  106.         return;
  107.     spanRec.widths = (int *) xalloc (overall_height * sizeof (int));
  108.     if (!spanRec.widths)
  109.     {
  110.         xfree (spanRec.points);
  111.         return;
  112.     }
  113.     ppt = spanRec.points;
  114.     pwidth = spanRec.widths;
  115.     }
  116.  
  117.     xorg = 0;
  118.     if (pGC->miTranslate)
  119.     {
  120.     y += pDrawable->y;
  121.     xorg = pDrawable->x;
  122.     }
  123.     while ((left_count || left_height) &&
  124.        (right_count || right_height))
  125.     {
  126.     MIPOLYRELOADLEFT
  127.     MIPOLYRELOADRIGHT
  128.  
  129.     height = left_height;
  130.     if (height > right_height)
  131.         height = right_height;
  132.  
  133.     left_height -= height;
  134.     right_height -= height;
  135.  
  136.     while (--height >= 0)
  137.     {
  138.         if (right_x >= left_x)
  139.         {
  140.         ppt->y = y;
  141.         ppt->x = left_x + xorg;
  142.         ppt++;
  143.         *pwidth++ = right_x - left_x + 1;
  144.         }
  145.             y++;
  146.         
  147.         MIPOLYSTEPLEFT
  148.  
  149.         MIPOLYSTEPRIGHT
  150.     }
  151.     }
  152.     if (!spanData)
  153.     {
  154.         (*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE);
  155.         DEALLOCATE_LOCAL (pwidthInit);
  156.         DEALLOCATE_LOCAL (pptInit);
  157.         if (pixel != oldPixel)
  158.         {
  159.         DoChangeGC (pGC, GCForeground, (XID *)&oldPixel, FALSE);
  160.         ValidateGC (pDrawable, pGC);
  161.         }
  162.     }
  163.     else
  164.     {
  165.     SpanGroup   *group;
  166.  
  167.     spanRec.count = ppt - spanRec.points;
  168.     if (pixel == pGC->fgPixel)
  169.         group = &spanData->fgGroup;
  170.     else
  171.         group = &spanData->bgGroup;
  172.     miAppendSpans (group, &spanRec);
  173.     }
  174. }
  175.  
  176. static void
  177. miFillRectPolyHelper (pDrawable, pGC, pixel, spanData, x, y, w, h)
  178.     DrawablePtr    pDrawable;
  179.     GCPtr    pGC;
  180.     unsigned long   pixel;
  181.     SpanDataPtr    spanData;
  182.     int        x, y, w, h;
  183. {
  184.     register DDXPointPtr ppt;
  185.     DDXPointPtr pptInit;
  186.     register int *pwidth;
  187.     int *pwidthInit;
  188.     unsigned long oldPixel;
  189.     Spans    spanRec;
  190.     xRectangle  rect;
  191.     int        xorg;
  192.  
  193.     if (!spanData)
  194.     {
  195.     rect.x = x;
  196.     rect.y = y;
  197.     rect.width = w;
  198.     rect.height = h;
  199.         oldPixel = pGC->fgPixel;
  200.         if (pixel != oldPixel)
  201.         {
  202.             DoChangeGC (pGC, GCForeground, (XID *)&pixel, FALSE);
  203.             ValidateGC (pDrawable, pGC);
  204.         }
  205.     (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
  206.         if (pixel != oldPixel)
  207.         {
  208.         DoChangeGC (pGC, GCForeground, (XID *)&oldPixel, FALSE);
  209.         ValidateGC (pDrawable, pGC);
  210.         }
  211.     }
  212.     else
  213.     {
  214.     SpanGroup   *group;
  215.     spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt));
  216.     if (!spanRec.points)
  217.         return;
  218.     spanRec.widths = (int *) xalloc (h * sizeof (int));
  219.     if (!spanRec.widths)
  220.     {
  221.         xfree (spanRec.points);
  222.         return;
  223.     }
  224.     ppt = spanRec.points;
  225.     pwidth = spanRec.widths;
  226.  
  227.         if (pGC->miTranslate)
  228.         {
  229.         y += pDrawable->y;
  230.         x += pDrawable->x;
  231.         }
  232.     while (h--)
  233.     {
  234.         ppt->x = x;
  235.         ppt->y = y;
  236.         ppt++;
  237.         *pwidth++ = w;
  238.         y++;
  239.     }
  240.     spanRec.count = ppt - spanRec.points;
  241.     if (pixel == pGC->fgPixel)
  242.         group = &spanData->fgGroup;
  243.     else
  244.         group = &spanData->bgGroup;
  245.     miAppendSpans (group, &spanRec);
  246.     }
  247. }
  248.  
  249. static int
  250. miPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge)
  251.     double    x0, y0;
  252.     double    k;  /* x0 * dy - y0 * dx */
  253.     register int dx, dy;
  254.     int        xi, yi;
  255.     int        left;
  256.     register PolyEdgePtr edge;
  257. {
  258.     int        x, y, e;
  259.     int        xady;
  260.  
  261.     if (dy < 0)
  262.     {
  263.     dy = -dy;
  264.     dx = -dx;
  265.     k = -k;
  266.     }
  267.  
  268. #ifdef NOTDEF
  269.     {
  270.     double    realk, kerror;
  271.         realk = x0 * dy - y0 * dx;
  272.         kerror = fabs (realk - k);
  273.         if (kerror > .1)
  274.         printf ("realk: %g k: %g\n", realk, k);
  275.     }
  276. #endif
  277.     y = ICEIL (y0);
  278.     xady = ICEIL (k) + y * dx;
  279.  
  280.     if (xady <= 0)
  281.     x = - (-xady / dy) - 1;
  282.     else
  283.     x = (xady - 1) / dy;
  284.  
  285.     e = xady - x * dy;
  286.  
  287.     if (dx >= 0)
  288.     {
  289.     edge->signdx = 1;
  290.     edge->stepx = dx / dy;
  291.     edge->dx = dx % dy;
  292.     }
  293.     else
  294.     {
  295.     edge->signdx = -1;
  296.     edge->stepx = - (-dx / dy);
  297.     edge->dx = -dx % dy;
  298.     e = dy - e + 1;
  299.     }
  300.     edge->dy = dy;
  301.     edge->x = x + left + xi;
  302.     edge->e = e - dy;    /* bias to compare against 0 instead of dy */
  303.     return y + yi;
  304. }
  305.  
  306. #define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
  307.  
  308. static int
  309. miPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h)
  310.     register PolyVertexPtr vertices;
  311.     register PolySlopePtr  slopes;
  312.     int            count;
  313.     int            xi, yi;
  314.     PolyEdgePtr        left, right;
  315.     int            *pnleft, *pnright;
  316.     int            *h;
  317. {
  318.     int        top, bottom;
  319.     double  miny, maxy;
  320.     register int i;
  321.     int        j;
  322.     int        clockwise;
  323.     int        slopeoff;
  324.     register int s;
  325.     register int nright, nleft;
  326.     int        y, lasty, bottomy, topy;
  327.  
  328.     /* find the top of the polygon */
  329.     maxy = miny = vertices[0].y;
  330.     bottom = top = 0;
  331.     for (i = 1; i < count; i++)
  332.     {
  333.     if (vertices[i].y < miny)
  334.     {
  335.         top = i;
  336.         miny = vertices[i].y;
  337.     }
  338.     if (vertices[i].y >= maxy)
  339.     {
  340.         bottom = i;
  341.         maxy = vertices[i].y;
  342.     }
  343.     }
  344.     clockwise = 1;
  345.     slopeoff = 0;
  346.  
  347.     i = top;
  348.     j = StepAround (top, -1, count);
  349.  
  350.     if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
  351.     {
  352.     clockwise = -1;
  353.     slopeoff = -1;
  354.     }
  355.  
  356.     bottomy = ICEIL (maxy) + yi;
  357.  
  358.     nright = 0;
  359.  
  360.     s = StepAround (top, slopeoff, count);
  361.     i = top;
  362.     while (i != bottom)
  363.     {
  364.     if (slopes[s].dy != 0)
  365.     {
  366.         y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
  367.             slopes[s].k,
  368.             slopes[s].dx, slopes[s].dy,
  369.             xi, yi, 0,
  370.             &right[nright]);
  371.         if (nright != 0)
  372.             right[nright-1].height = y - lasty;
  373.         else
  374.             topy = y;
  375.         nright++;
  376.         lasty = y;
  377.     }
  378.  
  379.     i = StepAround (i, clockwise, count);
  380.     s = StepAround (s, clockwise, count);
  381.     }
  382.     if (nright != 0)
  383.     right[nright-1].height = bottomy - lasty;
  384.  
  385.     if (slopeoff == 0)
  386.     slopeoff = -1;
  387.     else
  388.     slopeoff = 0;
  389.  
  390.     nleft = 0;
  391.     s = StepAround (top, slopeoff, count);
  392.     i = top;
  393.     while (i != bottom)
  394.     {
  395.     if (slopes[s].dy != 0)
  396.     {
  397.         y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
  398.                slopes[s].k,
  399.                       slopes[s].dx,  slopes[s].dy, xi, yi, 1,
  400.                       &left[nleft]);
  401.     
  402.         if (nleft != 0)
  403.             left[nleft-1].height = y - lasty;
  404.         nleft++;
  405.         lasty = y;
  406.     }
  407.     i = StepAround (i, -clockwise, count);
  408.     s = StepAround (s, -clockwise, count);
  409.     }
  410.     if (nleft != 0)
  411.     left[nleft-1].height = bottomy - lasty;
  412.     *pnleft = nleft;
  413.     *pnright = nright;
  414.     *h = bottomy - topy;
  415.     return topy;
  416. }
  417.  
  418. static void
  419. miLineJoin (pDrawable, pGC, pixel, spanData, pLeft, pRight)
  420.     DrawablePtr        pDrawable;
  421.     GCPtr        pGC;
  422.     unsigned long   pixel;
  423.     SpanDataPtr        spanData;
  424.     register LineFacePtr pLeft, pRight;
  425. {
  426.     double        mx, my;
  427.     int            denom;
  428.     PolyVertexRec   vertices[4];
  429.     PolySlopeRec    slopes[4];
  430.     int            edgecount;
  431.     PolyEdgeRec        left[4], right[4];
  432.     int            nleft, nright;
  433.     int            y, height;
  434.     int            swapslopes;
  435.     int            joinStyle = pGC->joinStyle;
  436.     int            lw = pGC->lineWidth;
  437.  
  438.     if (joinStyle == JoinRound)
  439.     {
  440.     miLineArc(pDrawable, pGC, pixel, spanData,
  441.           pLeft, pRight,
  442.           (double)0.0, (double)0.0, TRUE);
  443.     return;
  444.     }
  445.     denom = - pLeft->dx * pRight->dy + pRight->dx * pLeft->dy;
  446.     if (denom == 0)
  447.     return;    /* no join to draw */
  448.  
  449.     swapslopes = 0;
  450.     if (denom > 0)
  451.     {
  452.     pLeft->xa = -pLeft->xa;
  453.     pLeft->ya = -pLeft->ya;
  454.     pLeft->dx = -pLeft->dx;
  455.     pLeft->dy = -pLeft->dy;
  456.     }
  457.     else
  458.     {
  459.     swapslopes = 1;
  460.     pRight->xa = -pRight->xa;
  461.     pRight->ya = -pRight->ya;
  462.     pRight->dx = -pRight->dx;
  463.     pRight->dy = -pRight->dy;
  464.     }
  465.  
  466.     vertices[0].x = pRight->xa;
  467.     vertices[0].y = pRight->ya;
  468.     slopes[0].dx = -pRight->dy;
  469.     slopes[0].dy =  pRight->dx;
  470.     slopes[0].k = 0;
  471.  
  472.     vertices[1].x = 0;
  473.     vertices[1].y = 0;
  474.     slopes[1].dx =  pLeft->dy;
  475.     slopes[1].dy = -pLeft->dx;
  476.     slopes[1].k = 0;
  477.  
  478.     vertices[2].x = pLeft->xa;
  479.     vertices[2].y = pLeft->ya;
  480.  
  481.     if (joinStyle == JoinMiter)
  482.     {
  483.         my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
  484.               pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
  485.           (double) denom;
  486.         if (pLeft->dy != 0)
  487.         {
  488.         mx = pLeft->xa + (my - pLeft->ya) *
  489.                 (double) pLeft->dx / (double) pLeft->dy;
  490.         }
  491.         else
  492.         {
  493.         mx = pRight->xa + (my - pRight->ya) *
  494.                 (double) pRight->dx / (double) pRight->dy;
  495.         }
  496.     /* check miter limit */
  497.     if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
  498.         joinStyle = JoinBevel;
  499.     }
  500.  
  501.     if (joinStyle == JoinMiter)
  502.     {
  503.     slopes[2].dx = pLeft->dx;
  504.     slopes[2].dy = pLeft->dy;
  505.     slopes[2].k =  pLeft->k;
  506.     if (swapslopes)
  507.     {
  508.         slopes[2].dx = -slopes[2].dx;
  509.         slopes[2].dy = -slopes[2].dy;
  510.         slopes[2].k  = -slopes[2].k;
  511.     }
  512.     vertices[3].x = mx;
  513.     vertices[3].y = my;
  514.     slopes[3].dx = pRight->dx;
  515.     slopes[3].dy = pRight->dy;
  516.     slopes[3].k  = pRight->k;
  517.     if (swapslopes)
  518.     {
  519.         slopes[3].dx = -slopes[3].dx;
  520.         slopes[3].dy = -slopes[3].dy;
  521.         slopes[3].k  = -slopes[3].k;
  522.     }
  523.     edgecount = 4;
  524.     }
  525.     else
  526.     {
  527.     double    scale, dx, dy, adx, ady;
  528.  
  529.     adx = dx = pRight->xa - pLeft->xa;
  530.     ady = dy = pRight->ya - pLeft->ya;
  531.     if (adx < 0)
  532.         adx = -adx;
  533.     if (ady < 0)
  534.         ady = -ady;
  535.     scale = ady;
  536.     if (adx > ady)
  537.         scale = adx;
  538.     slopes[2].dx = (dx * 65536) / scale;
  539.     slopes[2].dy = (dy * 65536) / scale;
  540.     slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
  541.                (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
  542.     edgecount = 3;
  543.     }
  544.  
  545.     y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
  546.            left, right, &nleft, &nright, &height);
  547.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
  548. }
  549.  
  550. static int
  551. miLineArcI (pDraw, pGC, xorg, yorg, points, widths)
  552.     DrawablePtr        pDraw;
  553.     GCPtr        pGC;
  554.     int            xorg, yorg;
  555.     DDXPointPtr        points;
  556.     int            *widths;
  557. {
  558.     register DDXPointPtr tpts, bpts;
  559.     register int *twids, *bwids;
  560.     register int x, y, e, ex, slw;
  561.  
  562.     tpts = points;
  563.     twids = widths;
  564.     if (pGC->miTranslate)
  565.     {
  566.     xorg += pDraw->x;
  567.     yorg += pDraw->y;
  568.     }
  569.     slw = pGC->lineWidth;
  570.     if (slw == 1)
  571.     {
  572.     tpts->x = xorg;
  573.     tpts->y = yorg;
  574.     *twids = 1;
  575.     return 1;
  576.     }
  577.     bpts = tpts + slw;
  578.     bwids = twids + slw;
  579.     y = (slw >> 1) + 1;
  580.     if (slw & 1)
  581.     e = - ((y << 2) + 3);
  582.     else
  583.     e = - (y << 3);
  584.     ex = -4;
  585.     x = 0;
  586.     while (y)
  587.     {
  588.     e += (y << 3) - 4;
  589.     while (e >= 0)
  590.     {
  591.         x++;
  592.         e += (ex = -((x << 3) + 4));
  593.     }
  594.     y--;
  595.     slw = (x << 1) + 1;
  596.     if ((e == ex) && (slw > 1))
  597.         slw--;
  598.     tpts->x = xorg - x;
  599.     tpts->y = yorg - y;
  600.     tpts++;
  601.     *twids++ = slw;
  602.     if ((y != 0) && ((slw > 1) || (e != ex)))
  603.     {
  604.         bpts--;
  605.         bpts->x = xorg - x;
  606.         bpts->y = yorg + y;
  607.         *--bwids = slw;
  608.     }
  609.     }
  610.     return (pGC->lineWidth);
  611. }
  612.  
  613. #define CLIPSTEPEDGE(edgey,edge,edgeleft) \
  614.     if (ybase == edgey) \
  615.     { \
  616.     if (edgeleft) \
  617.     { \
  618.         if (edge->x > xcl) \
  619.         xcl = edge->x; \
  620.     } \
  621.     else \
  622.     { \
  623.         if (edge->x < xcr) \
  624.         xcr = edge->x; \
  625.     } \
  626.     edgey++; \
  627.     edge->x += edge->stepx; \
  628.     edge->e += edge->dx; \
  629.     if (edge->e > 0) \
  630.     { \
  631.         edge->x += edge->signdx; \
  632.         edge->e -= edge->dy; \
  633.     } \
  634.     }
  635.  
  636. static int
  637. miLineArcD (pDraw, pGC, xorg, yorg, points, widths,
  638.         edge1, edgey1, edgeleft1, edge2, edgey2, edgeleft2)
  639.     DrawablePtr        pDraw;
  640.     GCPtr        pGC;
  641.     double        xorg, yorg;
  642.     DDXPointPtr        points;
  643.     int            *widths;
  644.     PolyEdgePtr        edge1, edge2;
  645.     int            edgey1, edgey2;
  646.     Bool        edgeleft1, edgeleft2;
  647. {
  648.     register DDXPointPtr pts;
  649.     register int *wids;
  650.     double radius, x0, y0, el, er, yk, xlk, xrk, k;
  651.     int xbase, ybase, y, boty, xl, xr, xcl, xcr;
  652.     int ymin, ymax;
  653.     Bool edge1IsMin, edge2IsMin;
  654.     int ymin1, ymin2;
  655.  
  656.     pts = points;
  657.     wids = widths;
  658.     xbase = floor(xorg);
  659.     x0 = xorg - xbase;
  660.     ybase = ICEIL (yorg);
  661.     y0 = yorg - ybase;
  662.     if (pGC->miTranslate)
  663.     {
  664.     xbase += pDraw->x;
  665.     ybase += pDraw->y;
  666.     edge1->x += pDraw->x;
  667.     edge2->x += pDraw->x;
  668.     edgey1 += pDraw->y;
  669.     edgey2 += pDraw->y;
  670.     }
  671.     xlk = x0 + x0 + 1.0;
  672.     xrk = x0 + x0 - 1.0;
  673.     yk = y0 + y0 - 1.0;
  674.     radius = ((double)pGC->lineWidth) / 2.0;
  675.     y = floor(radius - y0 + 1.0);
  676.     ybase -= y;
  677.     ymin = ybase;
  678.     ymax = 65536;
  679.     edge1IsMin = FALSE;
  680.     ymin1 = edgey1;
  681.     if (edge1->dy >= 0)
  682.     {
  683.         if (!edge1->dy)
  684.         {
  685.         if (edgeleft1)
  686.             edge1IsMin = TRUE;
  687.         else
  688.             ymax = edgey1;
  689.         edgey1 = 65536;
  690.         }
  691.         else
  692.         {
  693.         if ((edge1->signdx < 0) == edgeleft1)
  694.             edge1IsMin = TRUE;
  695.         }
  696.     }
  697.     edge2IsMin = FALSE;
  698.     ymin2 = edgey2;
  699.     if (edge2->dy >= 0)
  700.     {
  701.         if (!edge2->dy)
  702.         {
  703.         if (edgeleft2)
  704.             edge2IsMin = TRUE;
  705.         else
  706.             ymax = edgey2;
  707.         edgey2 = 65536;
  708.         }
  709.         else
  710.         {
  711.         if ((edge2->signdx < 0) == edgeleft2)
  712.             edge2IsMin = TRUE;
  713.         }
  714.     }
  715.     if (edge1IsMin)
  716.     {
  717.     ymin = ymin1;
  718.     if (edge2IsMin && ymin1 > ymin2)
  719.         ymin = ymin2;
  720.     } else if (edge2IsMin)
  721.     ymin = ymin2;
  722.     el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
  723.     er = el + xrk;
  724.     xl = 1;
  725.     xr = 0;
  726.     if (x0 < 0.5)
  727.     {
  728.     xl = 0;
  729.     el -= xlk;
  730.     }
  731.     boty = (y0 < -0.5) ? 1 : 0;
  732.     if (ybase + y - boty > ymax)
  733.     boty = ymax - ybase - y;
  734.     while (y > boty)
  735.     {
  736.     k = (y << 1) + yk;
  737.     er += k;
  738.     while (er > 0.0)
  739.     {
  740.         xr++;
  741.         er += xrk - (xr << 1);
  742.     }
  743.     el += k;
  744.     while (el >= 0.0)
  745.     {
  746.         xl--;
  747.         el += (xl << 1) - xlk;
  748.     }
  749.     y--;
  750.     ybase++;
  751.     if (ybase < ymin)
  752.         continue;
  753.     xcl = xl + xbase;
  754.     xcr = xr + xbase;
  755.     CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
  756.     CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
  757.     if (xcr >= xcl)
  758.     {
  759.         pts->x = xcl;
  760.         pts->y = ybase;
  761.         pts++;
  762.         *wids++ = xcr - xcl + 1;
  763.     }
  764.     }
  765.     er = xrk - (xr << 1) - er;
  766.     el = (xl << 1) - xlk - el;
  767.     boty = floor(-y0 - radius + 1.0);
  768.     if (ybase + y - boty > ymax)
  769.     boty = ymax - ybase - y;
  770.     while (y > boty)
  771.     {
  772.     k = (y << 1) + yk;
  773.     er -= k;
  774.     while ((er >= 0.0) && (xr >= 0))
  775.     {
  776.         xr--;
  777.         er += xrk - (xr << 1);
  778.     }
  779.     el -= k;
  780.     while ((el > 0.0) && (xl <= 0))
  781.     {
  782.         xl++;
  783.         el += (xl << 1) - xlk;
  784.     }
  785.     y--;
  786.     ybase++;
  787.     if (ybase < ymin)
  788.         continue;
  789.     xcl = xl + xbase;
  790.     xcr = xr + xbase;
  791.     CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
  792.     CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
  793.     if (xcr >= xcl)
  794.     {
  795.         pts->x = xcl;
  796.         pts->y = ybase;
  797.         pts++;
  798.         *wids++ = xcr - xcl + 1;
  799.     }
  800.     }
  801.     return (pts - points);
  802. }
  803.  
  804. miRoundJoinFace (face, edge, leftEdge)
  805.     register LineFacePtr face;
  806.     register PolyEdgePtr edge;
  807.     Bool    *leftEdge;
  808. {
  809.     int        y;
  810.     int        dx, dy;
  811.     double  xa, ya;
  812.     Bool    left;
  813.  
  814.     dx = -face->dy;
  815.     dy = face->dx;
  816.     xa = face->xa;
  817.     ya = face->ya;
  818.     left = 1;
  819.     if (ya > 0)
  820.     {
  821.     ya = 0.0;
  822.     xa = 0.0;
  823.     }
  824.     if (dy < 0 || dy == 0 && dx > 0)
  825.     {
  826.     dx = -dx;
  827.     dy = -dy;
  828.     left = !left;
  829.     }
  830.     if (dx == 0 && dy == 0)
  831.     dy = 1;
  832.     if (dy == 0)
  833.     {
  834.     y = ICEIL (face->ya) + face->y;
  835.     edge->x = -32767;
  836.     edge->stepx = 0;
  837.     edge->signdx = 0;
  838.     edge->e = -1;
  839.     edge->dy = 0;
  840.     edge->dx = 0;
  841.     edge->height = 0;
  842.     }
  843.     else
  844.     {
  845.     y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
  846.     edge->height = 32767;
  847.     }
  848.     *leftEdge = !left;
  849.     return y;
  850. }
  851.  
  852. miRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2)
  853.     register LineFacePtr pLeft, pRight;
  854.     PolyEdgePtr    edge1, edge2;
  855.     int        *y1, *y2;
  856.     Bool    *left1, *left2;
  857. {
  858.     int    denom;
  859.  
  860.     denom = - pLeft->dx * pRight->dy + pRight->dx * pLeft->dy;
  861.  
  862.     if (denom >= 0)
  863.     {
  864.     pLeft->xa = -pLeft->xa;
  865.     pLeft->ya = -pLeft->ya;
  866.     }
  867.     else
  868.     {
  869.     pRight->xa = -pRight->xa;
  870.     pRight->ya = -pRight->ya;
  871.     }
  872.     *y1 = miRoundJoinFace (pLeft, edge1, left1);
  873.     *y2 = miRoundJoinFace (pRight, edge2, left2);
  874. }
  875.  
  876. miRoundCapClip (face, isInt, edge, leftEdge)
  877.     register LineFacePtr face;
  878.     Bool    isInt;
  879.     register PolyEdgePtr edge;
  880.     Bool    *leftEdge;
  881. {
  882.     int        y;
  883.     register int dx, dy;
  884.     double  xa, ya, k;
  885.     Bool    left;
  886.  
  887.     dx = -face->dy;
  888.     dy = face->dx;
  889.     xa = face->xa;
  890.     ya = face->ya;
  891.     k = 0.0;
  892.     if (!isInt)
  893.     k = face->k;
  894.     left = 1;
  895.     if (dy < 0 || dy == 0 && dx > 0)
  896.     {
  897.     dx = -dx;
  898.     dy = -dy;
  899.     xa = -xa;
  900.     ya = -ya;
  901.     left = !left;
  902.     }
  903.     if (dx == 0 && dy == 0)
  904.     dy = 1;
  905.     if (dy == 0)
  906.     {
  907.     y = ICEIL (face->ya) + face->y;
  908.     edge->x = -32767;
  909.     edge->stepx = 0;
  910.     edge->signdx = 0;
  911.     edge->e = -1;
  912.     edge->dy = 0;
  913.     edge->dx = 0;
  914.     edge->height = 0;
  915.     }
  916.     else
  917.     {
  918.     y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
  919.     edge->height = 32767;
  920.     }
  921.     *leftEdge = !left;
  922.     return y;
  923. }
  924.  
  925. static void
  926. miLineArc (pDraw, pGC, pixel, spanData, leftFace, rightFace, xorg, yorg, isInt)
  927.     DrawablePtr        pDraw;
  928.     register GCPtr  pGC;
  929.     unsigned long   pixel;
  930.     SpanDataPtr        spanData;
  931.     register LineFacePtr leftFace, rightFace;
  932.     double        xorg, yorg;
  933.     Bool        isInt;
  934. {
  935.     DDXPointPtr points;
  936.     int *widths;
  937.     int xorgi, yorgi;
  938.     unsigned long oldPixel;
  939.     Spans spanRec;
  940.     int n;
  941.     PolyEdgeRec    edge1, edge2;
  942.     int        edgey1, edgey2;
  943.     Bool    edgeleft1, edgeleft2;
  944.  
  945.     if (isInt)
  946.     {
  947.     xorgi = leftFace ? leftFace->x : rightFace->x;
  948.     yorgi = leftFace ? leftFace->y : rightFace->y;
  949.     }
  950.     edgey1 = 65536;
  951.     edgey2 = 65536;
  952.     edge1.dy = -1;
  953.     edge2.dy = -1;
  954.     edgeleft1 = FALSE;
  955.     edgeleft2 = FALSE;
  956.     if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
  957.     (pGC->capStyle == CapRound && pGC->joinStyle != JoinRound ||
  958.      pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))
  959.     {
  960.     if (isInt)
  961.     {
  962.         xorg = (double) xorgi;
  963.         yorg = (double) yorgi;
  964.     }
  965.     if (leftFace && rightFace)
  966.     {
  967.         miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
  968.                  &edgey1, &edgey2, &edgeleft1, &edgeleft2);
  969.     }
  970.     else if (leftFace)
  971.     {
  972.         edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
  973.     }
  974.     else if (rightFace)
  975.     {
  976.         edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
  977.     }
  978.     isInt = FALSE;
  979.     }
  980.     if (!spanData)
  981.     {
  982.         points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * pGC->lineWidth);
  983.         if (!points)
  984.         return;
  985.         widths = (int *)ALLOCATE_LOCAL(sizeof(int) * pGC->lineWidth);
  986.         if (!widths)
  987.         {
  988.         DEALLOCATE_LOCAL(points);
  989.         return;
  990.         }
  991.         oldPixel = pGC->fgPixel;
  992.         if (pixel != oldPixel)
  993.         {
  994.         DoChangeGC(pGC, GCForeground, (XID *)&pixel, FALSE);
  995.         ValidateGC (pDraw, pGC);
  996.         }
  997.     }
  998.     else
  999.     {
  1000.     points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec));
  1001.     if (!points)
  1002.         return;
  1003.     widths = (int *) xalloc (pGC->lineWidth * sizeof (int));
  1004.     if (!widths)
  1005.     {
  1006.         xfree (points);
  1007.         return;
  1008.     }
  1009.     spanRec.points = points;
  1010.     spanRec.widths = widths;
  1011.     }
  1012.     if (isInt)
  1013.     n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths);
  1014.     else
  1015.     n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths,
  1016.                &edge1, edgey1, edgeleft1,
  1017.                &edge2, edgey2, edgeleft2);
  1018.  
  1019.     if (!spanData)
  1020.     {
  1021.         (*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE);
  1022.         DEALLOCATE_LOCAL(widths);
  1023.         DEALLOCATE_LOCAL(points);
  1024.         if (pixel != oldPixel)
  1025.         {
  1026.         DoChangeGC(pGC, GCForeground, (XID *)&oldPixel, FALSE);
  1027.         ValidateGC (pDraw, pGC);
  1028.         }
  1029.     }
  1030.     else
  1031.     {
  1032.     SpanGroup   *group;
  1033.  
  1034.     spanRec.count = n;
  1035.     if (pixel == pGC->fgPixel)
  1036.         group = &spanData->fgGroup;
  1037.     else
  1038.         group = &spanData->bgGroup;
  1039.     miAppendSpans (group, &spanRec);
  1040.     }
  1041. }
  1042.  
  1043. miLineProjectingCap (pDrawable, pGC, pixel, spanData, face, isLeft, xorg, yorg, isInt)
  1044.     DrawablePtr        pDrawable;
  1045.     register GCPtr  pGC;
  1046.     unsigned long   pixel;
  1047.     SpanDataPtr        spanData;
  1048.     register LineFacePtr face;
  1049.     Bool        isLeft;
  1050.     double        xorg, yorg;
  1051.     Bool        isInt;
  1052. {
  1053.     int    xorgi, yorgi;
  1054.     int    lw;
  1055.     PolyEdgeRec    lefts[2], rights[2];
  1056.     int        lefty, righty, topy, bottomy;
  1057.     PolyEdgePtr left, right;
  1058.     PolyEdgePtr    top, bottom;
  1059.     double    xa,ya;
  1060.     double    k;
  1061.     double    xap, yap;
  1062.     int        dx, dy;
  1063.     double    projectXoff, projectYoff;
  1064.     int        maxy;
  1065.     int        finaly;
  1066.     
  1067.     if (isInt)
  1068.     {
  1069.     xorgi = face->x;
  1070.     yorgi = face->y;
  1071.     }
  1072.     lw = pGC->lineWidth;
  1073.     dx = face->dx;
  1074.     dy = face->dy;
  1075.     if (dy == 0)
  1076.     {
  1077.     lefts[0].height = lw;
  1078.     lefts[0].x = xorgi;
  1079.     if (isLeft)
  1080.         lefts[0].x -= (lw >> 1);
  1081.     lefts[0].stepx = 0;
  1082.     lefts[0].signdx = 1;
  1083.     lefts[0].e = -lw;
  1084.     lefts[0].dx = 0;
  1085.     lefts[0].dy = lw;
  1086.     rights[0].height = lw;
  1087.     rights[0].x = xorgi;
  1088.     if (!isLeft)
  1089.         rights[0].x += (lw + 1 >> 1);
  1090.     rights[0].stepx = 0;
  1091.     rights[0].signdx = 1;
  1092.     rights[0].e = -lw;
  1093.     rights[0].dx = 0;
  1094.     rights[0].dy = lw;
  1095.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
  1096.              lefts, rights, 1, 1);
  1097.     }
  1098.     else if (dx == 0)
  1099.     {
  1100.     topy = yorgi;
  1101.     bottomy = yorgi + dy;
  1102.     if (isLeft)
  1103.         topy -= (lw >> 1);
  1104.     else
  1105.         bottomy += (lw >> 1);
  1106.     lefts[0].height = bottomy - topy;
  1107.     lefts[0].x = xorgi - (lw >> 1);
  1108.     lefts[0].stepx = 0;
  1109.     lefts[0].signdx = 1;
  1110.     lefts[0].e = -dy;
  1111.     lefts[0].dx = dx;
  1112.     lefts[0].dy = dy;
  1113.  
  1114.     rights[0].height = bottomy - topy;
  1115.     rights[0].x = lefts[0].x + (lw-1);
  1116.     rights[0].stepx = 0;
  1117.     rights[0].signdx = 1;
  1118.     rights[0].e = -dy;
  1119.     rights[0].dx = dx;
  1120.     rights[0].dy = dy;
  1121.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
  1122.     }
  1123.     else
  1124.     {
  1125.     xa = face->xa;
  1126.     ya = face->ya;
  1127.     projectXoff = -ya;
  1128.     projectYoff = xa;
  1129.     if (dx < 0)
  1130.     {
  1131.         right = &rights[1];
  1132.         left = &lefts[0];
  1133.         top = &rights[0];
  1134.         bottom = &lefts[1];
  1135.     }
  1136.     else
  1137.     {
  1138.         right = &rights[0];
  1139.         left = &lefts[1];
  1140.         top = &lefts[0];
  1141.         bottom = &rights[1];
  1142.     }
  1143.     if (isLeft)
  1144.     {
  1145.         righty = miPolyBuildEdge (xa, ya,
  1146.              k, dx, dy, xorgi, yorgi, 0, right);
  1147.         
  1148.         xa = -xa;
  1149.         ya = -ya;
  1150.         k = -k;
  1151.         lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1152.                      k, dx, dy, xorgi, yorgi, 1, left);
  1153.         if (dx > 0)
  1154.         {
  1155.         ya = -ya;
  1156.         xa = -xa;
  1157.         }
  1158.         xap = xa - projectXoff;
  1159.         yap = ya - projectYoff;
  1160.         topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
  1161.                     -dy, dx, xorgi, yorgi, dx > 0, top);
  1162.         bottomy = miPolyBuildEdge (xa, ya,
  1163.                        0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
  1164.         maxy = -ya;
  1165.     }
  1166.     else
  1167.     {
  1168.         righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1169.              k, dx, dy, xorgi, yorgi, 0, right);
  1170.         
  1171.         xa = -xa;
  1172.         ya = -ya;
  1173.         k = -k;
  1174.         lefty = miPolyBuildEdge (xa, ya,
  1175.             k, dx, dy, xorgi, yorgi, 1, left);
  1176.         if (dx > 0)
  1177.         {
  1178.         ya = -ya;
  1179.         xa = -xa;
  1180.         }
  1181.         xap = xa - projectXoff;
  1182.         yap = ya - projectYoff;
  1183.         topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
  1184.         bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
  1185.                        -dy, dx, xorgi, xorgi, dx < 0, bottom);
  1186.         maxy = -ya + projectYoff;
  1187.     }
  1188.     finaly = ICEIL (maxy) + yorgi;
  1189.     if (dx < 0)
  1190.     {
  1191.         left->height = bottomy - lefty;
  1192.         right->height = finaly - righty;
  1193.         top->height = righty - topy;
  1194.     }
  1195.     else
  1196.     {
  1197.         right->height =  bottomy - righty;
  1198.         left->height = finaly - lefty;
  1199.         top->height = lefty - topy;
  1200.     }
  1201.     bottom->height = finaly - bottomy;
  1202.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
  1203.              bottom->height + bottomy - topy, lefts, rights, 2, 2);
  1204.     }
  1205. }
  1206.  
  1207. static void
  1208. miWideSegment (pDrawable, pGC, pixel, spanData,
  1209.            x1, y1, x2, y2, projectLeft, projectRight, leftFace, rightFace)
  1210.     DrawablePtr        pDrawable;
  1211.     GCPtr        pGC;
  1212.     unsigned long   pixel;
  1213.     SpanDataPtr        spanData;
  1214.     register int    x1, y1, x2, y2;
  1215.     Bool        projectLeft, projectRight;
  1216.     register LineFacePtr leftFace, rightFace;
  1217. {
  1218.     double    l, L, r;
  1219.     double    xa, ya;
  1220.     double    projectXoff, projectYoff;
  1221.     double    k;
  1222.     double    maxy;
  1223.     int        x, y;
  1224.     int        dx, dy;
  1225.     int        finaly;
  1226.     PolyEdgePtr left, right;
  1227.     PolyEdgePtr    top, bottom;
  1228.     int        lefty, righty, topy, bottomy;
  1229.     int        signdx;
  1230.     PolyEdgeRec    lefts[2], rights[2];
  1231.     LineFacePtr    tface;
  1232.     int        lw = pGC->lineWidth;
  1233.  
  1234.     /* draw top-to-bottom always */
  1235.     if (y2 < y1 || y2 == y1 && x2 < x1)
  1236.     {
  1237.     x = x1;
  1238.     x1 = x2;
  1239.     x2 = x;
  1240.  
  1241.     y = y1;
  1242.     y1 = y2;
  1243.     y2 = y;
  1244.  
  1245.     x = projectLeft;
  1246.     projectLeft = projectRight;
  1247.     projectRight = x;
  1248.  
  1249.     tface = leftFace;
  1250.     leftFace = rightFace;
  1251.     rightFace = tface;
  1252.     }
  1253.  
  1254.     dy = y2 - y1;
  1255.     signdx = 1;
  1256.     dx = x2 - x1;
  1257.     if (dx < 0)
  1258.     signdx = -1;
  1259.  
  1260.     leftFace->x = x1;
  1261.     leftFace->y = y1;
  1262.     leftFace->dx = dx;
  1263.     leftFace->dy = dy;
  1264.  
  1265.     rightFace->x = x2;
  1266.     rightFace->y = y2;
  1267.     rightFace->dx = -dx;
  1268.     rightFace->dy = -dy;
  1269.  
  1270.     if (dy == 0)
  1271.     {
  1272.     rightFace->xa = 0;
  1273.     rightFace->ya = (double) lw / 2.0;
  1274.     rightFace->k = -(double) (lw * dx) / 2.0;
  1275.     leftFace->xa = 0;
  1276.     leftFace->ya = -rightFace->ya;
  1277.     leftFace->k = rightFace->k;
  1278.     x = x1;
  1279.     if (projectLeft)
  1280.         x -= (lw >> 1);
  1281.     y = y1 - (lw >> 1);
  1282.     dx = x2 - x;
  1283.     if (projectRight)
  1284.         dx += (lw + 1 >> 1);
  1285.     dy = lw;
  1286.     miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
  1287.                   x, y, dx, dy);
  1288.     }
  1289.     else if (dx == 0)
  1290.     {
  1291.     leftFace->xa =  (double) lw / 2.0;
  1292.     leftFace->ya = 0;
  1293.     leftFace->k = (double) (lw * dy) / 2.0;
  1294.     rightFace->xa = -leftFace->xa;
  1295.     rightFace->ya = 0;
  1296.     rightFace->k = leftFace->k;
  1297.     y = y1;
  1298.     if (projectLeft)
  1299.         y -= lw >> 1;
  1300.     x = x1 - (lw >> 1);
  1301.     dy = y2 - y;
  1302.     if (projectRight)
  1303.         dy += (lw + 1 >> 1);
  1304.     dx = lw;
  1305.     miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
  1306.                   x, y, dx, dy);
  1307.     }
  1308.     else
  1309.     {
  1310.         l = ((double) lw) / 2.0;
  1311.         L = hypot ((double) dx, (double) dy);
  1312.  
  1313.     if (dx < 0)
  1314.     {
  1315.         right = &rights[1];
  1316.         left = &lefts[0];
  1317.         top = &rights[0];
  1318.         bottom = &lefts[1];
  1319.     }
  1320.     else
  1321.     {
  1322.         right = &rights[0];
  1323.         left = &lefts[1];
  1324.         top = &lefts[0];
  1325.         bottom = &rights[1];
  1326.     }
  1327.     r = l / L;
  1328.  
  1329.     /* coord of upper bound at integral y */
  1330.     ya = -r * dx;
  1331.     xa = r * dy;
  1332.  
  1333.     if (projectLeft | projectRight)
  1334.     {
  1335.         projectXoff = -ya;
  1336.         projectYoff = xa;
  1337.     }
  1338.  
  1339.         /* xa * dy - ya * dx */
  1340.     k = l * L;
  1341.  
  1342.     leftFace->xa = xa;
  1343.     leftFace->ya = ya;
  1344.     leftFace->k = k;
  1345.     rightFace->xa = -xa;
  1346.     rightFace->ya = -ya;
  1347.     rightFace->k = k;
  1348.  
  1349.     if (projectLeft)
  1350.         righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1351.                       k, dx, dy, x1, y1, 0, right);
  1352.     else
  1353.         righty = miPolyBuildEdge (xa, ya,
  1354.                       k, dx, dy, x1, y1, 0, right);
  1355.  
  1356.     /* coord of lower bound at integral y */
  1357.     ya = -ya;
  1358.     xa = -xa;
  1359.  
  1360.     /* xa * dy - ya * dx */
  1361.     k = - k;
  1362.  
  1363.     if (projectLeft)
  1364.         lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
  1365.                      k, dx, dy, x1, y1, 1, left);
  1366.     else
  1367.         lefty = miPolyBuildEdge (xa, ya,
  1368.                      k, dx, dy, x1, y1, 1, left);
  1369.  
  1370.     /* coord of top face at integral y */
  1371.  
  1372.     if (signdx > 0)
  1373.     {
  1374.         ya = -ya;
  1375.         xa = -xa;
  1376.     }
  1377.  
  1378.     if (projectLeft)
  1379.     {
  1380.         double xap = xa - projectXoff;
  1381.         double yap = ya - projectYoff;
  1382.         topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
  1383.                     -dy, dx, x1, y1, dx > 0, top);
  1384.     }
  1385.     else
  1386.         topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
  1387.  
  1388.     /* coord of bottom face at integral y */
  1389.  
  1390.     if (projectRight)
  1391.     {
  1392.         double xap = xa + projectXoff;
  1393.         double yap = ya + projectYoff;
  1394.         bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
  1395.                        -dy, dx, x2, y2, dx < 0, bottom);
  1396.         maxy = -ya + projectYoff;
  1397.     }
  1398.     else
  1399.     {
  1400.         bottomy = miPolyBuildEdge (xa, ya,
  1401.                        0.0, -dy, dx, x2, y2, dx < 0, bottom);
  1402.         maxy = -ya;
  1403.     }
  1404.  
  1405.     finaly = ICEIL (maxy) + y2;
  1406.  
  1407.     if (dx < 0)
  1408.     {
  1409.         left->height = bottomy - lefty;
  1410.         right->height = finaly - righty;
  1411.         top->height = righty - topy;
  1412.     }
  1413.     else
  1414.     {
  1415.         right->height =  bottomy - righty;
  1416.         left->height = finaly - lefty;
  1417.         top->height = lefty - topy;
  1418.     }
  1419.     bottom->height = finaly - bottomy;
  1420.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
  1421.              bottom->height + bottomy - topy, lefts, rights, 2, 2);
  1422.     }
  1423. }
  1424.  
  1425. SpanDataPtr
  1426. miSetupSpanData (pGC, spanData, npt)
  1427.     register GCPtr pGC;
  1428.     SpanDataPtr    spanData;
  1429.     int        npt;
  1430. {
  1431.     if (npt < 3 && pGC->capStyle != CapRound)
  1432.     return (SpanDataPtr) NULL;
  1433.     switch(pGC->alu)
  1434.     {
  1435.     case GXclear:    /* 0 */
  1436.     case GXand:        /* src AND dst */
  1437.     case GXcopy:    /* src */
  1438.     case GXandInverted:    /* NOT src AND dst */
  1439.     case GXnoop:    /* dst */
  1440.     case GXor:        /* src OR dst */
  1441.     case GXcopyInverted:/* NOT src */
  1442.     case GXorInverted:    /* NOT src OR dst */
  1443.     case GXset:        /* 1 */
  1444.     spanData = (SpanDataPtr) NULL;
  1445.     break;
  1446.     case GXandReverse:    /* src AND NOT dst */
  1447.     case GXxor:        /* src XOR dst */
  1448.     case GXnor:        /* NOT src AND NOT dst */
  1449.     case GXequiv:    /* NOT src XOR dst */
  1450.     case GXinvert:    /* NOT dst */
  1451.     case GXorReverse:    /* src OR NOT dst */
  1452.     case GXnand:    /* NOT src OR NOT dst */
  1453.     if (pGC->lineStyle == LineDoubleDash)
  1454.         miInitSpanGroup (&spanData->bgGroup);
  1455.     miInitSpanGroup (&spanData->fgGroup);
  1456.     }
  1457.     return spanData;
  1458. }
  1459.  
  1460. void
  1461. miCleanupSpanData (pDrawable, pGC, spanData)
  1462.     DrawablePtr    pDrawable;
  1463.     GCPtr    pGC;
  1464.     SpanDataPtr    spanData;
  1465. {
  1466.     if (pGC->lineStyle == LineDoubleDash)
  1467.     {
  1468.     unsigned long    oldPixel, pixel;
  1469.     
  1470.     pixel = pGC->bgPixel;
  1471.     oldPixel = pGC->fgPixel;
  1472.         if (pixel != oldPixel)
  1473.         {
  1474.             DoChangeGC (pGC, GCForeground, (XID *)&pixel, FALSE);
  1475.             ValidateGC (pDrawable, pGC);
  1476.         }
  1477.     miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
  1478.     miFreeSpanGroup (&spanData->bgGroup);
  1479.         if (pixel != oldPixel)
  1480.         {
  1481.         DoChangeGC (pGC, GCForeground, (XID *)&oldPixel, FALSE);
  1482.         ValidateGC (pDrawable, pGC);
  1483.         }
  1484.     }
  1485.     miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
  1486.     miFreeSpanGroup (&spanData->fgGroup);
  1487. }
  1488.  
  1489. void
  1490. miWideLine (pDrawable, pGC, mode, npt, pPts)
  1491.     DrawablePtr    pDrawable;
  1492.     register GCPtr pGC;
  1493.     int        mode;
  1494.     register int npt;
  1495.     register DDXPointPtr pPts;
  1496. {
  1497.     int            x1, y1, x2, y2;
  1498.     SpanDataRec        spanDataRec;
  1499.     SpanDataPtr        spanData;
  1500.     unsigned long   pixel;
  1501.     Bool        projectLeft, projectRight;
  1502.     LineFaceRec        leftFace, rightFace, prevRightFace;
  1503.     LineFaceRec        firstFace;
  1504.     register int    first;
  1505.     Bool        somethingDrawn = FALSE;
  1506.     Bool        selfJoin;
  1507.  
  1508.     spanData = miSetupSpanData (pGC, &spanDataRec, npt);
  1509.     pixel = pGC->fgPixel;
  1510.     x2 = pPts->x;
  1511.     y2 = pPts->y;
  1512.     first = TRUE;
  1513.     selfJoin = FALSE;
  1514.     if (npt > 1)
  1515.     {
  1516.         if (mode == CoordModePrevious)
  1517.         {
  1518.         int nptTmp;
  1519.         DDXPointPtr pPtsTmp;
  1520.     
  1521.         x1 = x2;
  1522.         y1 = y2;
  1523.         nptTmp = npt;
  1524.         pPtsTmp = pPts + 1;
  1525.         while (--nptTmp)
  1526.         {
  1527.             x1 += pPtsTmp->x;
  1528.             y1 += pPtsTmp->y;
  1529.             ++pPtsTmp;
  1530.         }
  1531.         if (x2 == x1 && y2 == y1)
  1532.             selfJoin = TRUE;
  1533.         }
  1534.         else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
  1535.         {
  1536.         selfJoin = TRUE;
  1537.         }
  1538.     }
  1539.     projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
  1540.     projectRight = FALSE;
  1541.     while (--npt)
  1542.     {
  1543.     x1 = x2;
  1544.     y1 = y2;
  1545.     ++pPts;
  1546.     x2 = pPts->x;
  1547.     y2 = pPts->y;
  1548.     if (mode == CoordModePrevious)
  1549.     {
  1550.         x2 += x1;
  1551.         y2 += y1;
  1552.     }
  1553.     if (x1 != x2 || y1 != y2)
  1554.     {
  1555.         somethingDrawn = TRUE;
  1556.         if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
  1557.             projectRight = TRUE;
  1558.         miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
  1559.                       projectLeft, projectRight, &leftFace, &rightFace);
  1560.         if (first)
  1561.         {
  1562.             if (selfJoin)
  1563.             firstFace = leftFace;
  1564.             else if (pGC->capStyle == CapRound)
  1565.             miLineArc (pDrawable, pGC, pixel, spanData,
  1566.                    &leftFace, (LineFacePtr) NULL,
  1567.                     (double)0.0, (double)0.0,
  1568.                    TRUE);
  1569.         }
  1570.         else
  1571.         {
  1572.             miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
  1573.                     &prevRightFace);
  1574.         }
  1575.         prevRightFace = rightFace;
  1576.         first = FALSE;
  1577.         projectLeft = FALSE;
  1578.     }
  1579.     if (npt == 1 && somethingDrawn)
  1580.      {
  1581.         if (selfJoin)
  1582.         miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
  1583.                 &rightFace);
  1584.         else if (pGC->capStyle == CapRound)
  1585.         miLineArc (pDrawable, pGC, pixel, spanData,
  1586.                (LineFacePtr) NULL, &rightFace,
  1587.                (double)0.0, (double)0.0,
  1588.                TRUE);
  1589.     }
  1590.     }
  1591.     /* handle crock where all points are coincedent */
  1592.     if (!somethingDrawn)
  1593.     {
  1594.     projectLeft = pGC->capStyle == CapProjecting;
  1595.     miWideSegment (pDrawable, pGC, pixel, spanData,
  1596.                x2, y2, x2, y2, projectLeft, projectLeft,
  1597.                &leftFace, &rightFace);
  1598.     if (pGC->capStyle == CapRound)
  1599.     {
  1600.         miLineArc (pDrawable, pGC, pixel, spanData,
  1601.                &leftFace, (LineFacePtr) NULL,
  1602.                (double)0.0, (double)0.0,
  1603.                TRUE);
  1604.         rightFace.dx = -1;    /* sleezy hack to make it work */
  1605.         miLineArc (pDrawable, pGC, pixel, spanData,
  1606.                (LineFacePtr) NULL, &rightFace,
  1607.                 (double)0.0, (double)0.0,
  1608.                TRUE);
  1609.     }
  1610.     }
  1611.     if (spanData)
  1612.     miCleanupSpanData (pDrawable, pGC, spanData);
  1613. }
  1614.  
  1615. #define V_TOP        0
  1616. #define V_RIGHT        1
  1617. #define V_BOTTOM    2
  1618. #define V_LEFT        3
  1619.  
  1620. static void
  1621. miWideDashSegment (pDrawable, pGC, spanData, pDashOffset, pDashIndex,
  1622.        x1, y1, x2, y2, projectLeft, projectRight, leftFace, rightFace)
  1623.     DrawablePtr        pDrawable;
  1624.     register GCPtr  pGC;
  1625.     int            *pDashOffset, *pDashIndex;
  1626.     SpanDataPtr        spanData;
  1627.     int            x1, y1, x2, y2;
  1628.     Bool        projectLeft, projectRight;
  1629.     LineFacePtr        leftFace, rightFace;
  1630. {
  1631.     int            dashIndex, dashRemain;
  1632.     unsigned char   *pDash;
  1633.     double        L, l;
  1634.     double        k;
  1635.     PolyVertexRec   vertices[4];
  1636.     PolyVertexRec   saveRight, saveBottom;
  1637.     PolySlopeRec    slopes[4];
  1638.     PolyEdgeRec        left[2], right[2];
  1639.     LineFaceRec        lcapFace, rcapFace;
  1640.     int            nleft, nright;
  1641.     int            h;
  1642.     int            y;
  1643.     int            dy, dx;
  1644.     unsigned long   pixel;
  1645.     double        LRemain;
  1646.     double        r;
  1647.     double        rdx, rdy;
  1648.     double        dashDx, dashDy;
  1649.     double        saveK;
  1650.     Bool        first = TRUE;
  1651.     double        lcenterx, lcentery, rcenterx, rcentery;
  1652.     unsigned long   fgPixel, bgPixel;
  1653.     
  1654.     dx = x2 - x1;
  1655.     dy = y2 - y1;
  1656.     dashIndex = *pDashIndex;
  1657.     pDash = pGC->dash;
  1658.     dashRemain = pDash[dashIndex] - *pDashOffset;
  1659.     fgPixel = pGC->fgPixel;
  1660.     bgPixel = pGC->bgPixel;
  1661.     if (pGC->fillStyle == FillOpaqueStippled ||
  1662.     pGC->fillStyle == FillTiled)
  1663.     {
  1664.     bgPixel = fgPixel;
  1665.     }
  1666.  
  1667.     l = ((double) pGC->lineWidth) / 2.0;
  1668.     if (dx == 0)
  1669.     {
  1670.     L = dy;
  1671.     rdx = 0;
  1672.     rdy = l;
  1673.     if (dy < 0)
  1674.     {
  1675.         L = -dy;
  1676.         rdy = -l;
  1677.     }
  1678.     }
  1679.     else if (dy == 0)
  1680.     {
  1681.     L = dx;
  1682.     rdx = l;
  1683.     rdy = 0;
  1684.     if (dx < 0)
  1685.     {
  1686.         L = -dx;
  1687.         rdx = -l;
  1688.     }
  1689.     }
  1690.     else
  1691.     {
  1692.     L = hypot ((double) dx, (double) dy);
  1693.     r = l / L;
  1694.  
  1695.     rdx = r * dx;
  1696.     rdy = r * dy;
  1697.     }
  1698.     k = l * L;
  1699.     LRemain = L;
  1700.     /* All position comments are relative to a line with dx and dy > 0,
  1701.      * but the code does not depend on this */
  1702.     /* top */
  1703.     slopes[V_TOP].dx = dx;
  1704.     slopes[V_TOP].dy = dy;
  1705.     slopes[V_TOP].k = k;
  1706.     /* right */
  1707.     slopes[V_RIGHT].dx = -dy;
  1708.     slopes[V_RIGHT].dy = dx;
  1709.     slopes[V_RIGHT].k = 0;
  1710.     /* bottom */
  1711.     slopes[V_BOTTOM].dx = -dx;
  1712.     slopes[V_BOTTOM].dy = -dy;
  1713.     slopes[V_BOTTOM].k = k;
  1714.     /* left */
  1715.     slopes[V_LEFT].dx = dy;
  1716.     slopes[V_LEFT].dy = -dx;
  1717.     slopes[V_LEFT].k = 0;
  1718.  
  1719.     /* preload the start coordinates */
  1720.     vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
  1721.     vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
  1722.  
  1723.     vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
  1724.     vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
  1725.  
  1726.     if (projectLeft)
  1727.     {
  1728.     vertices[V_TOP].x -= rdx;
  1729.     vertices[V_TOP].y -= rdy;
  1730.  
  1731.     vertices[V_LEFT].x -= rdx;
  1732.     vertices[V_LEFT].y -= rdy;
  1733.  
  1734.     slopes[V_LEFT].k = rdx * dx + rdy * dy;
  1735.     }
  1736.  
  1737.     lcenterx = x1;
  1738.     lcentery = y1;
  1739.  
  1740.     if (pGC->capStyle == CapRound)
  1741.     {
  1742.     lcapFace.dx = dx;
  1743.     lcapFace.dy = dy;
  1744.     lcapFace.x = x1;
  1745.     lcapFace.y = y1;
  1746.  
  1747.     rcapFace.dx = -dx;
  1748.     rcapFace.dy = -dy;
  1749.     rcapFace.x = x1;
  1750.     rcapFace.y = y1;
  1751.     }
  1752.     while (LRemain > dashRemain)
  1753.     {
  1754.     dashDx = (dashRemain * dx) / L;
  1755.     dashDy = (dashRemain * dy) / L;
  1756.  
  1757.     rcenterx = lcenterx + dashDx;
  1758.     rcentery = lcentery + dashDy;
  1759.  
  1760.     vertices[V_RIGHT].x += dashDx;
  1761.     vertices[V_RIGHT].y += dashDy;
  1762.  
  1763.     vertices[V_BOTTOM].x += dashDx;
  1764.     vertices[V_BOTTOM].y += dashDy;
  1765.  
  1766.     slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
  1767.  
  1768.     if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
  1769.     {
  1770.         if (pGC->lineStyle == LineOnOffDash &&
  1771.              pGC->capStyle == CapProjecting)
  1772.         {
  1773.         saveRight = vertices[V_RIGHT];
  1774.         saveBottom = vertices[V_BOTTOM];
  1775.         saveK = slopes[V_RIGHT].k;
  1776.         
  1777.         if (!first)
  1778.         {
  1779.             vertices[V_TOP].x -= rdx;
  1780.             vertices[V_TOP].y -= rdy;
  1781.     
  1782.             vertices[V_LEFT].x -= rdx;
  1783.             vertices[V_LEFT].y -= rdy;
  1784.  
  1785.             slopes[V_LEFT].k = vertices[V_LEFT].x *
  1786.                        slopes[V_LEFT].dy -
  1787.                        vertices[V_LEFT].y *
  1788.                        slopes[V_LEFT].dx;
  1789.         }
  1790.         
  1791.         vertices[V_RIGHT].x += rdx;
  1792.         vertices[V_RIGHT].y += rdy;
  1793.  
  1794.         vertices[V_BOTTOM].x += rdx;
  1795.         vertices[V_BOTTOM].y += rdy;
  1796.  
  1797.         slopes[V_RIGHT].k = vertices[V_RIGHT].x *
  1798.                    slopes[V_RIGHT].dy -
  1799.                    vertices[V_RIGHT].y *
  1800.                    slopes[V_RIGHT].dx;
  1801.         }
  1802.         y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
  1803.                       left, right, &nleft, &nright, &h);
  1804.         pixel = (dashIndex & 1) ? bgPixel : fgPixel;
  1805.         miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
  1806.  
  1807.         if (pGC->lineStyle == LineOnOffDash)
  1808.         {
  1809.         switch (pGC->capStyle)
  1810.         {
  1811.         case CapProjecting:
  1812.             vertices[V_BOTTOM] = saveBottom;
  1813.             vertices[V_RIGHT] = saveRight;
  1814.             slopes[V_RIGHT].k = saveK;
  1815.             break;
  1816.         case CapRound:
  1817.             if (!first)
  1818.             {
  1819.                 if (dx < 0)
  1820.                 {
  1821.                     lcapFace.xa = -vertices[V_LEFT].x;
  1822.                     lcapFace.ya = -vertices[V_LEFT].y;
  1823.                 lcapFace.k = slopes[V_LEFT].k;
  1824.                 }
  1825.                 else
  1826.                 {
  1827.                     lcapFace.xa = vertices[V_TOP].x;
  1828.                     lcapFace.ya = vertices[V_TOP].y;
  1829.                 lcapFace.k = -slopes[V_LEFT].k;
  1830.                 }
  1831.                 miLineArc (pDrawable, pGC, pixel, spanData,
  1832.                           &lcapFace, (LineFacePtr) NULL,
  1833.                           lcenterx, lcentery, FALSE);
  1834.             }
  1835.             if (dx < 0)
  1836.             {
  1837.                 rcapFace.xa = vertices[V_BOTTOM].x;
  1838.                 rcapFace.ya = vertices[V_BOTTOM].y;
  1839.             rcapFace.k = slopes[V_RIGHT].k;
  1840.             }
  1841.             else
  1842.             {
  1843.                 rcapFace.xa = -vertices[V_RIGHT].x;
  1844.                 rcapFace.ya = -vertices[V_RIGHT].y;
  1845.             rcapFace.k = -slopes[V_RIGHT].k;
  1846.             }
  1847.             miLineArc (pDrawable, pGC, pixel, spanData,
  1848.                    (LineFacePtr) NULL, &rcapFace,
  1849.                    rcenterx, rcentery, FALSE);
  1850.             break;
  1851.             }
  1852.         }
  1853.     }
  1854.     LRemain -= dashRemain;
  1855.     ++dashIndex;
  1856.     if (dashIndex == pGC->numInDashList)
  1857.         dashIndex = 0;
  1858.     dashRemain = pDash[dashIndex];
  1859.  
  1860.     lcenterx = rcenterx;
  1861.     lcentery = rcentery;
  1862.  
  1863.     vertices[V_TOP] = vertices[V_RIGHT];
  1864.     vertices[V_LEFT] = vertices[V_BOTTOM];
  1865.     slopes[V_LEFT].k = -slopes[V_RIGHT].k;
  1866.     first = FALSE;
  1867.     }
  1868.  
  1869.     if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
  1870.     {
  1871.         vertices[V_TOP].x -= dx;
  1872.         vertices[V_TOP].y -= dy;
  1873.  
  1874.     vertices[V_LEFT].x -= dx;
  1875.     vertices[V_LEFT].y -= dy;
  1876.  
  1877.     vertices[V_RIGHT].x = rdy;
  1878.     vertices[V_RIGHT].y = -rdx;
  1879.  
  1880.     vertices[V_BOTTOM].x = -rdy;
  1881.     vertices[V_BOTTOM].y = rdx;
  1882.  
  1883.     
  1884.     if (projectRight)
  1885.     {
  1886.         vertices[V_RIGHT].x += rdx;
  1887.         vertices[V_RIGHT].y += rdy;
  1888.     
  1889.         vertices[V_BOTTOM].x += rdx;
  1890.         vertices[V_BOTTOM].y += rdy;
  1891.         slopes[V_RIGHT].k = vertices[V_RIGHT].x *
  1892.                 slopes[V_RIGHT].dy -
  1893.                 vertices[V_RIGHT].y *
  1894.                 slopes[V_RIGHT].dx;
  1895.     }
  1896.     else
  1897.         slopes[V_RIGHT].k = 0;
  1898.  
  1899.     if (!first && pGC->lineStyle == LineOnOffDash &&
  1900.         pGC->capStyle == CapProjecting)
  1901.     {
  1902.         vertices[V_TOP].x -= rdx;
  1903.         vertices[V_TOP].y -= rdy;
  1904.  
  1905.         vertices[V_LEFT].x -= rdx;
  1906.         vertices[V_LEFT].y -= rdy;
  1907.         slopes[V_LEFT].k = vertices[V_LEFT].x *
  1908.                    slopes[V_LEFT].dy -
  1909.                    vertices[V_LEFT].y *
  1910.                    slopes[V_LEFT].dx;
  1911.     }
  1912.     else
  1913.         slopes[V_LEFT].k += dx * dx + dy * dy;
  1914.  
  1915.  
  1916.     y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
  1917.                  left, right, &nleft, &nright, &h);
  1918.  
  1919.     pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
  1920.     miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
  1921.     if (!first && pGC->lineStyle == LineOnOffDash &&
  1922.         pGC->capStyle == CapRound)
  1923.     {
  1924.         lcapFace.x = x2;
  1925.         lcapFace.y = y2;
  1926.         if (dx < 0)
  1927.         {
  1928.         lcapFace.xa = -vertices[V_LEFT].x;
  1929.         lcapFace.ya = -vertices[V_LEFT].y;
  1930.         lcapFace.k = slopes[V_LEFT].k;
  1931.         }
  1932.         else
  1933.         {
  1934.         lcapFace.xa = vertices[V_TOP].x;
  1935.         lcapFace.ya = vertices[V_TOP].y;
  1936.         lcapFace.k = -slopes[V_LEFT].k;
  1937.         }
  1938.         miLineArc (pDrawable, pGC, pixel, spanData,
  1939.                &lcapFace, (LineFacePtr) NULL,
  1940.                rcenterx, rcentery, FALSE);
  1941.     }
  1942.     }
  1943.     dashRemain = ((double) dashRemain) - LRemain;
  1944.     if (dashRemain == 0)
  1945.     {
  1946.     dashIndex++;
  1947.     if (dashIndex == pGC->numInDashList)
  1948.         dashIndex = 0;
  1949.     dashRemain = pDash[dashIndex];
  1950.     }
  1951.  
  1952.     leftFace->x = x1;
  1953.     leftFace->y = y1;
  1954.     leftFace->dx = dx;
  1955.     leftFace->dy = dy;
  1956.     leftFace->xa = rdy;
  1957.     leftFace->ya = -rdx;
  1958.     leftFace->k = k;
  1959.  
  1960.     rightFace->x = x2;
  1961.     rightFace->y = y2;
  1962.     rightFace->dx = -dx;
  1963.     rightFace->dy = -dy;
  1964.     rightFace->xa = -rdy;
  1965.     rightFace->ya = rdx;
  1966.     rightFace->k = k;
  1967.  
  1968.     *pDashIndex = dashIndex;
  1969.     *pDashOffset = pDash[dashIndex] - dashRemain;
  1970. }
  1971.  
  1972. void
  1973. miWideDash (pDrawable, pGC, mode, npt, pPts)
  1974.     DrawablePtr    pDrawable;
  1975.     register GCPtr pGC;
  1976.     int        mode;
  1977.     register int npt;
  1978.     register DDXPointPtr pPts;
  1979. {
  1980.     int            x1, y1, x2, y2;
  1981.     unsigned long   pixel;
  1982.     Bool        projectLeft, projectRight;
  1983.     LineFaceRec        leftFace, rightFace, prevRightFace;
  1984.     LineFaceRec        firstFace;
  1985.     int            first;
  1986.     int            dashIndex, dashOffset;
  1987.     register int    prevDashIndex;
  1988.     SpanDataRec        spanDataRec;
  1989.     SpanDataPtr        spanData;
  1990.     Bool        somethingDrawn = FALSE;
  1991.     Bool        selfJoin;
  1992.     Bool        endIsFg, startIsFg, firstIsFg = FALSE, prevIsFg;
  1993.  
  1994.     if (pGC->lineStyle == LineDoubleDash && 
  1995.     (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
  1996.     {
  1997.     miWideLine (pDrawable, pGC, mode, npt, pPts);
  1998.     return;
  1999.     }
  2000.     /* XXX backward compatibility */
  2001.     if (pGC->lineWidth == 0)
  2002.     {
  2003.     miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
  2004.     return;
  2005.     }
  2006.     if (npt == 0)
  2007.     return;
  2008.     spanData = miSetupSpanData (pGC, &spanDataRec, npt);
  2009.     x2 = pPts->x;
  2010.     y2 = pPts->y;
  2011.     first = TRUE;
  2012.     selfJoin = FALSE;
  2013.     if (mode == CoordModePrevious)
  2014.     {
  2015.     int nptTmp;
  2016.     DDXPointPtr pPtsTmp;
  2017.  
  2018.     x1 = x2;
  2019.     y1 = y2;
  2020.     nptTmp = npt;
  2021.     pPtsTmp = pPts + 1;
  2022.     while (--nptTmp)
  2023.     {
  2024.         x1 += pPtsTmp->x;
  2025.         y1 += pPtsTmp->y;
  2026.         ++pPtsTmp;
  2027.     }
  2028.     if (x2 == x1 && y2 == y1)
  2029.         selfJoin = TRUE;
  2030.     }
  2031.     else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
  2032.     {
  2033.     selfJoin = TRUE;
  2034.     }
  2035.     projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
  2036.     projectRight = FALSE;
  2037.     dashIndex = 0;
  2038.     dashOffset = 0;
  2039.     miStepDash ((int)pGC->dashOffset, &dashIndex,
  2040.             pGC->dash, (int)pGC->numInDashList, &dashOffset);
  2041.     while (--npt)
  2042.     {
  2043.     x1 = x2;
  2044.     y1 = y2;
  2045.     ++pPts;
  2046.     x2 = pPts->x;
  2047.     y2 = pPts->y;
  2048.     if (mode == CoordModePrevious)
  2049.     {
  2050.         x2 += x1;
  2051.         y2 += y1;
  2052.     }
  2053.     if (x1 != x2 || y1 != y2)
  2054.     {
  2055.         somethingDrawn = TRUE;
  2056.         if (npt == 1 && pGC->capStyle == CapProjecting && 
  2057.         (!selfJoin || !firstIsFg))
  2058.         projectRight = TRUE;
  2059.         prevDashIndex = dashIndex;
  2060.         miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
  2061.                 x1, y1, x2, y2,
  2062.                 projectLeft, projectRight, &leftFace, &rightFace);
  2063.         startIsFg = !(prevDashIndex & 1);
  2064.         endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
  2065.         if (pGC->lineStyle == LineDoubleDash || startIsFg)
  2066.         {
  2067.             pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
  2068.             if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
  2069.             {
  2070.                 if (first && selfJoin)
  2071.             {
  2072.                 firstFace = leftFace;
  2073.             firstIsFg = startIsFg;
  2074.             }
  2075.                 else if (pGC->capStyle == CapRound)
  2076.                 miLineArc (pDrawable, pGC, pixel, spanData,
  2077.                           &leftFace, (LineFacePtr) NULL,
  2078.                           (double)0.0, (double)0.0, TRUE);
  2079.             }
  2080.             else
  2081.             {
  2082.                 miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
  2083.                         &prevRightFace);
  2084.             }
  2085.         }
  2086.         prevRightFace = rightFace;
  2087.         prevIsFg = endIsFg;
  2088.         first = FALSE;
  2089.         projectLeft = FALSE;
  2090.     }
  2091.     if (npt == 1 && somethingDrawn)
  2092.     {
  2093.         if (pGC->lineStyle == LineDoubleDash || endIsFg)
  2094.         {
  2095.         pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
  2096.         if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
  2097.         {
  2098.             miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
  2099.                 &rightFace);
  2100.         }
  2101.         else 
  2102.         {
  2103.             if (pGC->capStyle == CapRound)
  2104.             miLineArc (pDrawable, pGC, pixel, spanData,
  2105.                     (LineFacePtr) NULL, &rightFace,
  2106.                     (double)0.0, (double)0.0, TRUE);
  2107.         }
  2108.         }
  2109.         else
  2110.         {
  2111.         /* glue a cap to the start of the line if
  2112.          * we're OnOffDash and ended on odd dash
  2113.          */
  2114.         if (selfJoin && firstIsFg)
  2115.         {
  2116.             pixel = pGC->fgPixel;
  2117.             if (pGC->capStyle == CapProjecting)
  2118.             miLineProjectingCap (pDrawable, pGC, pixel, spanData,
  2119.                     &firstFace, TRUE,
  2120.                     (double)0.0, (double)0.0, TRUE);
  2121.             else if (pGC->capStyle == CapRound)
  2122.             miLineArc (pDrawable, pGC, pixel, spanData,
  2123.                     &firstFace, (LineFacePtr) NULL,
  2124.                     (double)0.0, (double)0.0, TRUE);
  2125.         }
  2126.         }
  2127.     }
  2128.     }
  2129.     /* handle crock where all points are coincedent */
  2130.     if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
  2131.     {
  2132.     /* not the same as endIsFg computation above */
  2133.     pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
  2134.     switch (pGC->capStyle) {
  2135.     case CapRound:
  2136.         miLineArc (pDrawable, pGC, pixel, spanData,
  2137.                (LineFacePtr) NULL, (LineFacePtr) NULL,
  2138.                (double)x1, (double)y1,
  2139.                FALSE);
  2140.         break;
  2141.     case CapProjecting:
  2142.         x2 = pGC->lineWidth;
  2143.         miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
  2144.                   x1 - (x2 >> 1), y1 - (x2 >> 1), x2, x2);
  2145.         break;
  2146.     }
  2147.     }
  2148.     if (spanData)
  2149.     miCleanupSpanData (pDrawable, pGC, spanData);
  2150. }
  2151.  
  2152. /* these are stubs to allow old ddx ValidateGCs to work without change */
  2153.  
  2154. void
  2155. miMiter()
  2156. {
  2157. }
  2158.  
  2159. void
  2160. miNotMiter()
  2161. {
  2162. }
  2163.