1982 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1982 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| 
 | |
| Copyright 1988, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included
 | |
| in all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | |
| IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
| OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall
 | |
| not be used in advertising or otherwise to promote the sale, use or
 | |
| other dealings in this Software without prior written authorization
 | |
| from The Open Group.
 | |
| 
 | |
| */
 | |
| 
 | |
| /* Author:  Keith Packard, MIT X Consortium */
 | |
| 
 | |
| /*
 | |
|  * Mostly integer wideline code.  Uses a technique similar to
 | |
|  * bresenham zero-width lines, except walks an X edge
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #ifdef _XOPEN_SOURCE
 | |
| #include <math.h>
 | |
| #else
 | |
| #define _XOPEN_SOURCE           /* to get prototype for hypot on some systems */
 | |
| #include <math.h>
 | |
| #undef _XOPEN_SOURCE
 | |
| #endif
 | |
| #include <X11/X.h>
 | |
| #include "windowstr.h"
 | |
| #include "gcstruct.h"
 | |
| #include "regionstr.h"
 | |
| #include "miwideline.h"
 | |
| #include "mi.h"
 | |
| 
 | |
| static Bool
 | |
| InitSpans(Spans * spans, size_t nspans)
 | |
| {
 | |
|     spans->points = malloc(nspans * sizeof(*spans->points));
 | |
|     if (!spans->points)
 | |
|         return FALSE;
 | |
|     spans->widths = malloc(nspans * sizeof(*spans->widths));
 | |
|     if (!spans->widths) {
 | |
|         free(spans->points);
 | |
|         return FALSE;
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * interface data to span-merging polygon filler
 | |
|  */
 | |
| 
 | |
| typedef struct _SpanData {
 | |
|     SpanGroup fgGroup, bgGroup;
 | |
| } SpanDataRec, *SpanDataPtr;
 | |
| 
 | |
| static void
 | |
| AppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans * spanPtr,
 | |
|                 SpanDataPtr spanData)
 | |
| {
 | |
|     SpanGroup *group, *othergroup = NULL;
 | |
| 
 | |
|     if (pixel == pGC->fgPixel) {
 | |
|         group = &spanData->fgGroup;
 | |
|         if (pGC->lineStyle == LineDoubleDash)
 | |
|             othergroup = &spanData->bgGroup;
 | |
|     }
 | |
|     else {
 | |
|         group = &spanData->bgGroup;
 | |
|         othergroup = &spanData->fgGroup;
 | |
|     }
 | |
|     miAppendSpans(group, othergroup, spanPtr);
 | |
| }
 | |
| 
 | |
| static void miLineArc(DrawablePtr pDraw, GCPtr pGC,
 | |
|                       unsigned long pixel, SpanDataPtr spanData,
 | |
|                       LineFacePtr leftFace,
 | |
|                       LineFacePtr rightFace,
 | |
|                       double xorg, double yorg, Bool isInt);
 | |
| 
 | |
| /*
 | |
|  * spans-based polygon filler
 | |
|  */
 | |
| 
 | |
| static void
 | |
| fillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans * spans,
 | |
|           SpanDataPtr spanData)
 | |
| {
 | |
|     if (!spanData) {
 | |
|         ChangeGCVal oldPixel, tmpPixel;
 | |
| 
 | |
|         oldPixel.val = pGC->fgPixel;
 | |
|         if (pixel != oldPixel.val) {
 | |
|             tmpPixel.val = (XID) pixel;
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &tmpPixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|         (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points,
 | |
|                                 spans->widths, TRUE);
 | |
|         free(spans->widths);
 | |
|         free(spans->points);
 | |
|         if (pixel != oldPixel.val) {
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|         AppendSpanGroup(pGC, pixel, spans, spanData);
 | |
| }
 | |
| 
 | |
| static void
 | |
| miFillPolyHelper(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
 | |
|                  SpanDataPtr spanData, int y, int overall_height,
 | |
|                  PolyEdgePtr left, PolyEdgePtr right,
 | |
|                  int left_count, int right_count)
 | |
| {
 | |
|     int left_x = 0, left_e = 0;
 | |
|     int left_stepx = 0;
 | |
|     int left_signdx = 0;
 | |
|     int left_dy = 0, left_dx = 0;
 | |
| 
 | |
|     int right_x = 0, right_e = 0;
 | |
|     int right_stepx = 0;
 | |
|     int right_signdx = 0;
 | |
|     int right_dy = 0, right_dx = 0;
 | |
| 
 | |
|     int height = 0;
 | |
|     int left_height = 0, right_height = 0;
 | |
| 
 | |
|     DDXPointPtr ppt;
 | |
|     int *pwidth;
 | |
|     int xorg;
 | |
|     Spans spanRec;
 | |
| 
 | |
|     if (!InitSpans(&spanRec, overall_height))
 | |
|         return;
 | |
|     ppt = spanRec.points;
 | |
|     pwidth = spanRec.widths;
 | |
| 
 | |
|     xorg = 0;
 | |
|     if (pGC->miTranslate) {
 | |
|         y += pDrawable->y;
 | |
|         xorg = pDrawable->x;
 | |
|     }
 | |
|     while ((left_count || left_height) && (right_count || right_height)) {
 | |
|         if (!left_height && left_count) {
 | |
|             left_height = left->height;
 | |
|             left_x = left->x;
 | |
|             left_stepx = left->stepx;
 | |
|             left_signdx = left->signdx;
 | |
|             left_e = left->e;
 | |
|             left_dy = left->dy;
 | |
|             left_dx = left->dx;
 | |
|             --left_count;
 | |
|             ++left;
 | |
|         }
 | |
| 
 | |
|         if (!right_height && right_count) {
 | |
|             right_height = right->height;
 | |
|             right_x = right->x;
 | |
|             right_stepx = right->stepx;
 | |
|             right_signdx = right->signdx;
 | |
|             right_e = right->e;
 | |
|             right_dy = right->dy;
 | |
|             right_dx = right->dx;
 | |
|             --right_count;
 | |
|             ++right;
 | |
|         }
 | |
| 
 | |
|         height = left_height;
 | |
|         if (height > right_height)
 | |
|             height = right_height;
 | |
| 
 | |
|         left_height -= height;
 | |
|         right_height -= height;
 | |
| 
 | |
|         while (--height >= 0) {
 | |
|             if (right_x >= left_x) {
 | |
|                 ppt->y = y;
 | |
|                 ppt->x = left_x + xorg;
 | |
|                 ppt++;
 | |
|                 *pwidth++ = right_x - left_x + 1;
 | |
|             }
 | |
|             y++;
 | |
| 
 | |
|             left_x += left_stepx;
 | |
|             left_e += left_dx;
 | |
|             if (left_e > 0) {
 | |
|                 left_x += left_signdx;
 | |
|                 left_e -= left_dy;
 | |
|             }
 | |
| 
 | |
|             right_x += right_stepx;
 | |
|             right_e += right_dx;
 | |
|             if (right_e > 0) {
 | |
|                 right_x += right_signdx;
 | |
|                 right_e -= right_dy;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     spanRec.count = ppt - spanRec.points;
 | |
|     fillSpans(pDrawable, pGC, pixel, &spanRec, spanData);
 | |
| }
 | |
| 
 | |
| static void
 | |
| miFillRectPolyHelper(DrawablePtr pDrawable,
 | |
|                      GCPtr pGC,
 | |
|                      unsigned long pixel,
 | |
|                      SpanDataPtr spanData, int x, int y, int w, int h)
 | |
| {
 | |
|     DDXPointPtr ppt;
 | |
|     int *pwidth;
 | |
|     ChangeGCVal oldPixel, tmpPixel;
 | |
|     Spans spanRec;
 | |
|     xRectangle rect;
 | |
| 
 | |
|     if (!spanData) {
 | |
|         rect.x = x;
 | |
|         rect.y = y;
 | |
|         rect.width = w;
 | |
|         rect.height = h;
 | |
|         oldPixel.val = pGC->fgPixel;
 | |
|         if (pixel != oldPixel.val) {
 | |
|             tmpPixel.val = (XID) pixel;
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &tmpPixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|         (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
 | |
|         if (pixel != oldPixel.val) {
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         if (!InitSpans(&spanRec, h))
 | |
|             return;
 | |
|         ppt = spanRec.points;
 | |
|         pwidth = spanRec.widths;
 | |
| 
 | |
|         if (pGC->miTranslate) {
 | |
|             y += pDrawable->y;
 | |
|             x += pDrawable->x;
 | |
|         }
 | |
|         while (h--) {
 | |
|             ppt->x = x;
 | |
|             ppt->y = y;
 | |
|             ppt++;
 | |
|             *pwidth++ = w;
 | |
|             y++;
 | |
|         }
 | |
|         spanRec.count = ppt - spanRec.points;
 | |
|         AppendSpanGroup(pGC, pixel, &spanRec, spanData);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* static */ int
 | |
| miPolyBuildEdge(double x0, double y0, double k, /* x0 * dy - y0 * dx */
 | |
|                 int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
 | |
| {
 | |
|     int x, y, e;
 | |
|     int xady;
 | |
| 
 | |
|     if (dy < 0) {
 | |
|         dy = -dy;
 | |
|         dx = -dx;
 | |
|         k = -k;
 | |
|     }
 | |
| 
 | |
| #ifdef NOTDEF
 | |
|     {
 | |
|         double realk, kerror;
 | |
| 
 | |
|         realk = x0 * dy - y0 * dx;
 | |
|         kerror = fabs(realk - k);
 | |
|         if (kerror > .1)
 | |
|             printf("realk: %g k: %g\n", realk, k);
 | |
|     }
 | |
| #endif
 | |
|     y = ICEIL(y0);
 | |
|     xady = ICEIL(k) + y * dx;
 | |
| 
 | |
|     if (xady <= 0)
 | |
|         x = -(-xady / dy) - 1;
 | |
|     else
 | |
|         x = (xady - 1) / dy;
 | |
| 
 | |
|     e = xady - x * dy;
 | |
| 
 | |
|     if (dx >= 0) {
 | |
|         edge->signdx = 1;
 | |
|         edge->stepx = dx / dy;
 | |
|         edge->dx = dx % dy;
 | |
|     }
 | |
|     else {
 | |
|         edge->signdx = -1;
 | |
|         edge->stepx = -(-dx / dy);
 | |
|         edge->dx = -dx % dy;
 | |
|         e = dy - e + 1;
 | |
|     }
 | |
|     edge->dy = dy;
 | |
|     edge->x = x + left + xi;
 | |
|     edge->e = e - dy;           /* bias to compare against 0 instead of dy */
 | |
|     return y + yi;
 | |
| }
 | |
| 
 | |
| #define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
 | |
| 
 | |
| /* static */ int
 | |
| miPolyBuildPoly(PolyVertexPtr vertices,
 | |
|                 PolySlopePtr slopes,
 | |
|                 int count,
 | |
|                 int xi,
 | |
|                 int yi,
 | |
|                 PolyEdgePtr left,
 | |
|                 PolyEdgePtr right, int *pnleft, int *pnright, int *h)
 | |
| {
 | |
|     int top, bottom;
 | |
|     double miny, maxy;
 | |
|     int i;
 | |
|     int j;
 | |
|     int clockwise;
 | |
|     int slopeoff;
 | |
|     int s;
 | |
|     int nright, nleft;
 | |
|     int y, lasty = 0, bottomy, topy = 0;
 | |
| 
 | |
|     /* find the top of the polygon */
 | |
|     maxy = miny = vertices[0].y;
 | |
|     bottom = top = 0;
 | |
|     for (i = 1; i < count; i++) {
 | |
|         if (vertices[i].y < miny) {
 | |
|             top = i;
 | |
|             miny = vertices[i].y;
 | |
|         }
 | |
|         if (vertices[i].y >= maxy) {
 | |
|             bottom = i;
 | |
|             maxy = vertices[i].y;
 | |
|         }
 | |
|     }
 | |
|     clockwise = 1;
 | |
|     slopeoff = 0;
 | |
| 
 | |
|     i = top;
 | |
|     j = StepAround(top, -1, count);
 | |
| 
 | |
|     if ((int64_t) slopes[j].dy * slopes[i].dx >
 | |
|         (int64_t) slopes[i].dy * slopes[j].dx) {
 | |
|         clockwise = -1;
 | |
|         slopeoff = -1;
 | |
|     }
 | |
| 
 | |
|     bottomy = ICEIL(maxy) + yi;
 | |
| 
 | |
|     nright = 0;
 | |
| 
 | |
|     s = StepAround(top, slopeoff, count);
 | |
|     i = top;
 | |
|     while (i != bottom) {
 | |
|         if (slopes[s].dy != 0) {
 | |
|             y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
 | |
|                                 slopes[s].k,
 | |
|                                 slopes[s].dx, slopes[s].dy,
 | |
|                                 xi, yi, 0, &right[nright]);
 | |
|             if (nright != 0)
 | |
|                 right[nright - 1].height = y - lasty;
 | |
|             else
 | |
|                 topy = y;
 | |
|             nright++;
 | |
|             lasty = y;
 | |
|         }
 | |
| 
 | |
|         i = StepAround(i, clockwise, count);
 | |
|         s = StepAround(s, clockwise, count);
 | |
|     }
 | |
|     if (nright != 0)
 | |
|         right[nright - 1].height = bottomy - lasty;
 | |
| 
 | |
|     if (slopeoff == 0)
 | |
|         slopeoff = -1;
 | |
|     else
 | |
|         slopeoff = 0;
 | |
| 
 | |
|     nleft = 0;
 | |
|     s = StepAround(top, slopeoff, count);
 | |
|     i = top;
 | |
|     while (i != bottom) {
 | |
|         if (slopes[s].dy != 0) {
 | |
|             y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
 | |
|                                 slopes[s].k,
 | |
|                                 slopes[s].dx, slopes[s].dy, xi, yi, 1,
 | |
|                                 &left[nleft]);
 | |
| 
 | |
|             if (nleft != 0)
 | |
|                 left[nleft - 1].height = y - lasty;
 | |
|             nleft++;
 | |
|             lasty = y;
 | |
|         }
 | |
|         i = StepAround(i, -clockwise, count);
 | |
|         s = StepAround(s, -clockwise, count);
 | |
|     }
 | |
|     if (nleft != 0)
 | |
|         left[nleft - 1].height = bottomy - lasty;
 | |
|     *pnleft = nleft;
 | |
|     *pnright = nright;
 | |
|     *h = bottomy - topy;
 | |
|     return topy;
 | |
| }
 | |
| 
 | |
| static void
 | |
| miLineOnePoint(DrawablePtr pDrawable,
 | |
|                GCPtr pGC,
 | |
|                unsigned long pixel, SpanDataPtr spanData, int x, int y)
 | |
| {
 | |
|     DDXPointRec pt;
 | |
|     int wid;
 | |
|     unsigned long oldPixel;
 | |
| 
 | |
|     MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel);
 | |
|     if (pGC->fillStyle == FillSolid) {
 | |
|         pt.x = x;
 | |
|         pt.y = y;
 | |
|         (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
 | |
|     }
 | |
|     else {
 | |
|         wid = 1;
 | |
|         if (pGC->miTranslate) {
 | |
|             x += pDrawable->x;
 | |
|             y += pDrawable->y;
 | |
|         }
 | |
|         pt.x = x;
 | |
|         pt.y = y;
 | |
|         (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
 | |
|     }
 | |
|     MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel);
 | |
| }
 | |
| 
 | |
| static void
 | |
| miLineJoin(DrawablePtr pDrawable,
 | |
|            GCPtr pGC,
 | |
|            unsigned long pixel,
 | |
|            SpanDataPtr spanData, LineFacePtr pLeft, LineFacePtr pRight)
 | |
| {
 | |
|     double mx = 0, my = 0;
 | |
|     double denom = 0.0;
 | |
|     PolyVertexRec vertices[4];
 | |
|     PolySlopeRec slopes[4];
 | |
|     int edgecount;
 | |
|     PolyEdgeRec left[4], right[4];
 | |
|     int nleft, nright;
 | |
|     int y, height;
 | |
|     int swapslopes;
 | |
|     int joinStyle = pGC->joinStyle;
 | |
|     int lw = pGC->lineWidth;
 | |
| 
 | |
|     if (lw == 1 && !spanData) {
 | |
|         /* See if one of the lines will draw the joining pixel */
 | |
|         if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
 | |
|             return;
 | |
|         if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
 | |
|             return;
 | |
|         if (joinStyle != JoinRound) {
 | |
|             denom =
 | |
|                 -pLeft->dx * (double) pRight->dy +
 | |
|                 pRight->dx * (double) pLeft->dy;
 | |
|             if (denom == 0)
 | |
|                 return;         /* no join to draw */
 | |
|         }
 | |
|         if (joinStyle != JoinMiter) {
 | |
|             miLineOnePoint(pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         if (joinStyle == JoinRound) {
 | |
|             miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                       pLeft, pRight, (double) 0.0, (double) 0.0, TRUE);
 | |
|             return;
 | |
|         }
 | |
|         denom =
 | |
|             -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
 | |
|         if (denom == 0.0)
 | |
|             return;             /* no join to draw */
 | |
|     }
 | |
| 
 | |
|     swapslopes = 0;
 | |
|     if (denom > 0) {
 | |
|         pLeft->xa = -pLeft->xa;
 | |
|         pLeft->ya = -pLeft->ya;
 | |
|         pLeft->dx = -pLeft->dx;
 | |
|         pLeft->dy = -pLeft->dy;
 | |
|     }
 | |
|     else {
 | |
|         swapslopes = 1;
 | |
|         pRight->xa = -pRight->xa;
 | |
|         pRight->ya = -pRight->ya;
 | |
|         pRight->dx = -pRight->dx;
 | |
|         pRight->dy = -pRight->dy;
 | |
|     }
 | |
| 
 | |
|     vertices[0].x = pRight->xa;
 | |
|     vertices[0].y = pRight->ya;
 | |
|     slopes[0].dx = -pRight->dy;
 | |
|     slopes[0].dy = pRight->dx;
 | |
|     slopes[0].k = 0;
 | |
| 
 | |
|     vertices[1].x = 0;
 | |
|     vertices[1].y = 0;
 | |
|     slopes[1].dx = pLeft->dy;
 | |
|     slopes[1].dy = -pLeft->dx;
 | |
|     slopes[1].k = 0;
 | |
| 
 | |
|     vertices[2].x = pLeft->xa;
 | |
|     vertices[2].y = pLeft->ya;
 | |
| 
 | |
|     if (joinStyle == JoinMiter) {
 | |
|         my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
 | |
|               pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx)) /
 | |
|             denom;
 | |
|         if (pLeft->dy != 0) {
 | |
|             mx = pLeft->xa + (my - pLeft->ya) *
 | |
|                 (double) pLeft->dx / (double) pLeft->dy;
 | |
|         }
 | |
|         else {
 | |
|             mx = pRight->xa + (my - pRight->ya) *
 | |
|                 (double) pRight->dx / (double) pRight->dy;
 | |
|         }
 | |
|         /* check miter limit */
 | |
|         if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
 | |
|             joinStyle = JoinBevel;
 | |
|     }
 | |
| 
 | |
|     if (joinStyle == JoinMiter) {
 | |
|         slopes[2].dx = pLeft->dx;
 | |
|         slopes[2].dy = pLeft->dy;
 | |
|         slopes[2].k = pLeft->k;
 | |
|         if (swapslopes) {
 | |
|             slopes[2].dx = -slopes[2].dx;
 | |
|             slopes[2].dy = -slopes[2].dy;
 | |
|             slopes[2].k = -slopes[2].k;
 | |
|         }
 | |
|         vertices[3].x = mx;
 | |
|         vertices[3].y = my;
 | |
|         slopes[3].dx = pRight->dx;
 | |
|         slopes[3].dy = pRight->dy;
 | |
|         slopes[3].k = pRight->k;
 | |
|         if (swapslopes) {
 | |
|             slopes[3].dx = -slopes[3].dx;
 | |
|             slopes[3].dy = -slopes[3].dy;
 | |
|             slopes[3].k = -slopes[3].k;
 | |
|         }
 | |
|         edgecount = 4;
 | |
|     }
 | |
|     else {
 | |
|         double scale, dx, dy, adx, ady;
 | |
| 
 | |
|         adx = dx = pRight->xa - pLeft->xa;
 | |
|         ady = dy = pRight->ya - pLeft->ya;
 | |
|         if (adx < 0)
 | |
|             adx = -adx;
 | |
|         if (ady < 0)
 | |
|             ady = -ady;
 | |
|         scale = ady;
 | |
|         if (adx > ady)
 | |
|             scale = adx;
 | |
|         slopes[2].dx = (dx * 65536) / scale;
 | |
|         slopes[2].dy = (dy * 65536) / scale;
 | |
|         slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
 | |
|                        (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
 | |
|         edgecount = 3;
 | |
|     }
 | |
| 
 | |
|     y = miPolyBuildPoly(vertices, slopes, edgecount, pLeft->x, pLeft->y,
 | |
|                         left, right, &nleft, &nright, &height);
 | |
|     miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, height, left, right,
 | |
|                      nleft, nright);
 | |
| }
 | |
| 
 | |
| static int
 | |
| miLineArcI(DrawablePtr pDraw,
 | |
|            GCPtr pGC, int xorg, int yorg, DDXPointPtr points, int *widths)
 | |
| {
 | |
|     DDXPointPtr tpts, bpts;
 | |
|     int *twids, *bwids;
 | |
|     int x, y, e, ex, slw;
 | |
| 
 | |
|     tpts = points;
 | |
|     twids = widths;
 | |
|     if (pGC->miTranslate) {
 | |
|         xorg += pDraw->x;
 | |
|         yorg += pDraw->y;
 | |
|     }
 | |
|     slw = pGC->lineWidth;
 | |
|     if (slw == 1) {
 | |
|         tpts->x = xorg;
 | |
|         tpts->y = yorg;
 | |
|         *twids = 1;
 | |
|         return 1;
 | |
|     }
 | |
|     bpts = tpts + slw;
 | |
|     bwids = twids + slw;
 | |
|     y = (slw >> 1) + 1;
 | |
|     if (slw & 1)
 | |
|         e = -((y << 2) + 3);
 | |
|     else
 | |
|         e = -(y << 3);
 | |
|     ex = -4;
 | |
|     x = 0;
 | |
|     while (y) {
 | |
|         e += (y << 3) - 4;
 | |
|         while (e >= 0) {
 | |
|             x++;
 | |
|             e += (ex = -((x << 3) + 4));
 | |
|         }
 | |
|         y--;
 | |
|         slw = (x << 1) + 1;
 | |
|         if ((e == ex) && (slw > 1))
 | |
|             slw--;
 | |
|         tpts->x = xorg - x;
 | |
|         tpts->y = yorg - y;
 | |
|         tpts++;
 | |
|         *twids++ = slw;
 | |
|         if ((y != 0) && ((slw > 1) || (e != ex))) {
 | |
|             bpts--;
 | |
|             bpts->x = xorg - x;
 | |
|             bpts->y = yorg + y;
 | |
|             *--bwids = slw;
 | |
|         }
 | |
|     }
 | |
|     return pGC->lineWidth;
 | |
| }
 | |
| 
 | |
| #define CLIPSTEPEDGE(edgey,edge,edgeleft) \
 | |
|     if (ybase == edgey) \
 | |
|     { \
 | |
| 	if (edgeleft) \
 | |
| 	{ \
 | |
| 	    if (edge->x > xcl) \
 | |
| 		xcl = edge->x; \
 | |
| 	} \
 | |
| 	else \
 | |
| 	{ \
 | |
| 	    if (edge->x < xcr) \
 | |
| 		xcr = edge->x; \
 | |
| 	} \
 | |
| 	edgey++; \
 | |
| 	edge->x += edge->stepx; \
 | |
| 	edge->e += edge->dx; \
 | |
| 	if (edge->e > 0) \
 | |
| 	{ \
 | |
| 	    edge->x += edge->signdx; \
 | |
| 	    edge->e -= edge->dy; \
 | |
| 	} \
 | |
|     }
 | |
| 
 | |
| static int
 | |
| miLineArcD(DrawablePtr pDraw,
 | |
|            GCPtr pGC,
 | |
|            double xorg,
 | |
|            double yorg,
 | |
|            DDXPointPtr points,
 | |
|            int *widths,
 | |
|            PolyEdgePtr edge1,
 | |
|            int edgey1,
 | |
|            Bool edgeleft1, PolyEdgePtr edge2, int edgey2, Bool edgeleft2)
 | |
| {
 | |
|     DDXPointPtr pts;
 | |
|     int *wids;
 | |
|     double radius, x0, y0, el, er, yk, xlk, xrk, k;
 | |
|     int xbase, ybase, y, boty, xl, xr, xcl, xcr;
 | |
|     int ymin, ymax;
 | |
|     Bool edge1IsMin, edge2IsMin;
 | |
|     int ymin1, ymin2;
 | |
| 
 | |
|     pts = points;
 | |
|     wids = widths;
 | |
|     xbase = floor(xorg);
 | |
|     x0 = xorg - xbase;
 | |
|     ybase = ICEIL(yorg);
 | |
|     y0 = yorg - ybase;
 | |
|     if (pGC->miTranslate) {
 | |
|         xbase += pDraw->x;
 | |
|         ybase += pDraw->y;
 | |
|         edge1->x += pDraw->x;
 | |
|         edge2->x += pDraw->x;
 | |
|         edgey1 += pDraw->y;
 | |
|         edgey2 += pDraw->y;
 | |
|     }
 | |
|     xlk = x0 + x0 + 1.0;
 | |
|     xrk = x0 + x0 - 1.0;
 | |
|     yk = y0 + y0 - 1.0;
 | |
|     radius = ((double) pGC->lineWidth) / 2.0;
 | |
|     y = floor(radius - y0 + 1.0);
 | |
|     ybase -= y;
 | |
|     ymin = ybase;
 | |
|     ymax = 65536;
 | |
|     edge1IsMin = FALSE;
 | |
|     ymin1 = edgey1;
 | |
|     if (edge1->dy >= 0) {
 | |
|         if (!edge1->dy) {
 | |
|             if (edgeleft1)
 | |
|                 edge1IsMin = TRUE;
 | |
|             else
 | |
|                 ymax = edgey1;
 | |
|             edgey1 = 65536;
 | |
|         }
 | |
|         else {
 | |
|             if ((edge1->signdx < 0) == edgeleft1)
 | |
|                 edge1IsMin = TRUE;
 | |
|         }
 | |
|     }
 | |
|     edge2IsMin = FALSE;
 | |
|     ymin2 = edgey2;
 | |
|     if (edge2->dy >= 0) {
 | |
|         if (!edge2->dy) {
 | |
|             if (edgeleft2)
 | |
|                 edge2IsMin = TRUE;
 | |
|             else
 | |
|                 ymax = edgey2;
 | |
|             edgey2 = 65536;
 | |
|         }
 | |
|         else {
 | |
|             if ((edge2->signdx < 0) == edgeleft2)
 | |
|                 edge2IsMin = TRUE;
 | |
|         }
 | |
|     }
 | |
|     if (edge1IsMin) {
 | |
|         ymin = ymin1;
 | |
|         if (edge2IsMin && ymin1 > ymin2)
 | |
|             ymin = ymin2;
 | |
|     }
 | |
|     else if (edge2IsMin)
 | |
|         ymin = ymin2;
 | |
|     el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
 | |
|     er = el + xrk;
 | |
|     xl = 1;
 | |
|     xr = 0;
 | |
|     if (x0 < 0.5) {
 | |
|         xl = 0;
 | |
|         el -= xlk;
 | |
|     }
 | |
|     boty = (y0 < -0.5) ? 1 : 0;
 | |
|     if (ybase + y - boty > ymax)
 | |
|         boty = ymax - ybase - y;
 | |
|     while (y > boty) {
 | |
|         k = (y << 1) + yk;
 | |
|         er += k;
 | |
|         while (er > 0.0) {
 | |
|             xr++;
 | |
|             er += xrk - (xr << 1);
 | |
|         }
 | |
|         el += k;
 | |
|         while (el >= 0.0) {
 | |
|             xl--;
 | |
|             el += (xl << 1) - xlk;
 | |
|         }
 | |
|         y--;
 | |
|         ybase++;
 | |
|         if (ybase < ymin)
 | |
|             continue;
 | |
|         xcl = xl + xbase;
 | |
|         xcr = xr + xbase;
 | |
|         CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
 | |
|         CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
 | |
|         if (xcr >= xcl) {
 | |
|             pts->x = xcl;
 | |
|             pts->y = ybase;
 | |
|             pts++;
 | |
|             *wids++ = xcr - xcl + 1;
 | |
|         }
 | |
|     }
 | |
|     er = xrk - (xr << 1) - er;
 | |
|     el = (xl << 1) - xlk - el;
 | |
|     boty = floor(-y0 - radius + 1.0);
 | |
|     if (ybase + y - boty > ymax)
 | |
|         boty = ymax - ybase - y;
 | |
|     while (y > boty) {
 | |
|         k = (y << 1) + yk;
 | |
|         er -= k;
 | |
|         while ((er >= 0.0) && (xr >= 0)) {
 | |
|             xr--;
 | |
|             er += xrk - (xr << 1);
 | |
|         }
 | |
|         el -= k;
 | |
|         while ((el > 0.0) && (xl <= 0)) {
 | |
|             xl++;
 | |
|             el += (xl << 1) - xlk;
 | |
|         }
 | |
|         y--;
 | |
|         ybase++;
 | |
|         if (ybase < ymin)
 | |
|             continue;
 | |
|         xcl = xl + xbase;
 | |
|         xcr = xr + xbase;
 | |
|         CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
 | |
|         CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
 | |
|         if (xcr >= xcl) {
 | |
|             pts->x = xcl;
 | |
|             pts->y = ybase;
 | |
|             pts++;
 | |
|             *wids++ = xcr - xcl + 1;
 | |
|         }
 | |
|     }
 | |
|     return pts - points;
 | |
| }
 | |
| 
 | |
| static int
 | |
| miRoundJoinFace(LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
 | |
| {
 | |
|     int y;
 | |
|     int dx, dy;
 | |
|     double xa, ya;
 | |
|     Bool left;
 | |
| 
 | |
|     dx = -face->dy;
 | |
|     dy = face->dx;
 | |
|     xa = face->xa;
 | |
|     ya = face->ya;
 | |
|     left = 1;
 | |
|     if (ya > 0) {
 | |
|         ya = 0.0;
 | |
|         xa = 0.0;
 | |
|     }
 | |
|     if (dy < 0 || (dy == 0 && dx > 0)) {
 | |
|         dx = -dx;
 | |
|         dy = -dy;
 | |
|         left = !left;
 | |
|     }
 | |
|     if (dx == 0 && dy == 0)
 | |
|         dy = 1;
 | |
|     if (dy == 0) {
 | |
|         y = ICEIL(face->ya) + face->y;
 | |
|         edge->x = -32767;
 | |
|         edge->stepx = 0;
 | |
|         edge->signdx = 0;
 | |
|         edge->e = -1;
 | |
|         edge->dy = 0;
 | |
|         edge->dx = 0;
 | |
|         edge->height = 0;
 | |
|     }
 | |
|     else {
 | |
|         y = miPolyBuildEdge(xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
 | |
|         edge->height = 32767;
 | |
|     }
 | |
|     *leftEdge = !left;
 | |
|     return y;
 | |
| }
 | |
| 
 | |
| void
 | |
| miRoundJoinClip(LineFacePtr pLeft, LineFacePtr pRight,
 | |
|                 PolyEdgePtr edge1, PolyEdgePtr edge2,
 | |
|                 int *y1, int *y2, Bool *left1, Bool *left2)
 | |
| {
 | |
|     double denom;
 | |
| 
 | |
|     denom = -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
 | |
| 
 | |
|     if (denom >= 0) {
 | |
|         pLeft->xa = -pLeft->xa;
 | |
|         pLeft->ya = -pLeft->ya;
 | |
|     }
 | |
|     else {
 | |
|         pRight->xa = -pRight->xa;
 | |
|         pRight->ya = -pRight->ya;
 | |
|     }
 | |
|     *y1 = miRoundJoinFace(pLeft, edge1, left1);
 | |
|     *y2 = miRoundJoinFace(pRight, edge2, left2);
 | |
| }
 | |
| 
 | |
| int
 | |
| miRoundCapClip(LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
 | |
| {
 | |
|     int y;
 | |
|     int dx, dy;
 | |
|     double xa, ya, k;
 | |
|     Bool left;
 | |
| 
 | |
|     dx = -face->dy;
 | |
|     dy = face->dx;
 | |
|     xa = face->xa;
 | |
|     ya = face->ya;
 | |
|     k = 0.0;
 | |
|     if (!isInt)
 | |
|         k = face->k;
 | |
|     left = 1;
 | |
|     if (dy < 0 || (dy == 0 && dx > 0)) {
 | |
|         dx = -dx;
 | |
|         dy = -dy;
 | |
|         xa = -xa;
 | |
|         ya = -ya;
 | |
|         left = !left;
 | |
|     }
 | |
|     if (dx == 0 && dy == 0)
 | |
|         dy = 1;
 | |
|     if (dy == 0) {
 | |
|         y = ICEIL(face->ya) + face->y;
 | |
|         edge->x = -32767;
 | |
|         edge->stepx = 0;
 | |
|         edge->signdx = 0;
 | |
|         edge->e = -1;
 | |
|         edge->dy = 0;
 | |
|         edge->dx = 0;
 | |
|         edge->height = 0;
 | |
|     }
 | |
|     else {
 | |
|         y = miPolyBuildEdge(xa, ya, k, dx, dy, face->x, face->y, !left, edge);
 | |
|         edge->height = 32767;
 | |
|     }
 | |
|     *leftEdge = !left;
 | |
|     return y;
 | |
| }
 | |
| 
 | |
| static void
 | |
| miLineArc(DrawablePtr pDraw,
 | |
|           GCPtr pGC,
 | |
|           unsigned long pixel,
 | |
|           SpanDataPtr spanData,
 | |
|           LineFacePtr leftFace,
 | |
|           LineFacePtr rightFace, double xorg, double yorg, Bool isInt)
 | |
| {
 | |
|     int xorgi = 0, yorgi = 0;
 | |
|     Spans spanRec;
 | |
|     int n;
 | |
|     PolyEdgeRec edge1, edge2;
 | |
|     int edgey1, edgey2;
 | |
|     Bool edgeleft1, edgeleft2;
 | |
| 
 | |
|     if (isInt) {
 | |
|         xorgi = leftFace ? leftFace->x : rightFace->x;
 | |
|         yorgi = leftFace ? leftFace->y : rightFace->y;
 | |
|     }
 | |
|     edgey1 = 65536;
 | |
|     edgey2 = 65536;
 | |
|     edge1.x = 0;                /* not used, keep memory checkers happy */
 | |
|     edge1.dy = -1;
 | |
|     edge2.x = 0;                /* not used, keep memory checkers happy */
 | |
|     edge2.dy = -1;
 | |
|     edgeleft1 = FALSE;
 | |
|     edgeleft2 = FALSE;
 | |
|     if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
 | |
|         ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
 | |
|          (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) {
 | |
|         if (isInt) {
 | |
|             xorg = (double) xorgi;
 | |
|             yorg = (double) yorgi;
 | |
|         }
 | |
|         if (leftFace && rightFace) {
 | |
|             miRoundJoinClip(leftFace, rightFace, &edge1, &edge2,
 | |
|                             &edgey1, &edgey2, &edgeleft1, &edgeleft2);
 | |
|         }
 | |
|         else if (leftFace) {
 | |
|             edgey1 = miRoundCapClip(leftFace, isInt, &edge1, &edgeleft1);
 | |
|         }
 | |
|         else if (rightFace) {
 | |
|             edgey2 = miRoundCapClip(rightFace, isInt, &edge2, &edgeleft2);
 | |
|         }
 | |
|         isInt = FALSE;
 | |
|     }
 | |
|     if (!InitSpans(&spanRec, pGC->lineWidth))
 | |
|         return;
 | |
|     if (isInt)
 | |
|         n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points,
 | |
|                        spanRec.widths);
 | |
|     else
 | |
|         n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths,
 | |
|                        &edge1, edgey1, edgeleft1, &edge2, edgey2, edgeleft2);
 | |
|     spanRec.count = n;
 | |
|     fillSpans(pDraw, pGC, pixel, &spanRec, spanData);
 | |
| }
 | |
| 
 | |
| static void
 | |
| miLineProjectingCap(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
 | |
|                     SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
 | |
|                     double xorg, double yorg, Bool isInt)
 | |
| {
 | |
|     int xorgi = 0, yorgi = 0;
 | |
|     int lw;
 | |
|     PolyEdgeRec lefts[4], rights[4];
 | |
|     int lefty, righty, topy, bottomy;
 | |
|     PolyEdgePtr left, right;
 | |
|     PolyEdgePtr top, bottom;
 | |
|     double xa, ya;
 | |
|     double k;
 | |
|     double xap, yap;
 | |
|     int dx, dy;
 | |
|     double projectXoff, projectYoff;
 | |
|     double maxy;
 | |
|     int finaly;
 | |
| 
 | |
|     if (isInt) {
 | |
|         xorgi = face->x;
 | |
|         yorgi = face->y;
 | |
|     }
 | |
|     lw = pGC->lineWidth;
 | |
|     dx = face->dx;
 | |
|     dy = face->dy;
 | |
|     k = face->k;
 | |
|     if (dy == 0) {
 | |
|         lefts[0].height = lw;
 | |
|         lefts[0].x = xorgi;
 | |
|         if (isLeft)
 | |
|             lefts[0].x -= (lw >> 1);
 | |
|         lefts[0].stepx = 0;
 | |
|         lefts[0].signdx = 1;
 | |
|         lefts[0].e = -lw;
 | |
|         lefts[0].dx = 0;
 | |
|         lefts[0].dy = lw;
 | |
|         rights[0].height = lw;
 | |
|         rights[0].x = xorgi;
 | |
|         if (!isLeft)
 | |
|             rights[0].x += ((lw + 1) >> 1);
 | |
|         rights[0].stepx = 0;
 | |
|         rights[0].signdx = 1;
 | |
|         rights[0].e = -lw;
 | |
|         rights[0].dx = 0;
 | |
|         rights[0].dy = lw;
 | |
|         miFillPolyHelper(pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
 | |
|                          lefts, rights, 1, 1);
 | |
|     }
 | |
|     else if (dx == 0) {
 | |
|         if (dy < 0) {
 | |
|             dy = -dy;
 | |
|             isLeft = !isLeft;
 | |
|         }
 | |
|         topy = yorgi;
 | |
|         bottomy = yorgi + dy;
 | |
|         if (isLeft)
 | |
|             topy -= (lw >> 1);
 | |
|         else
 | |
|             bottomy += (lw >> 1);
 | |
|         lefts[0].height = bottomy - topy;
 | |
|         lefts[0].x = xorgi - (lw >> 1);
 | |
|         lefts[0].stepx = 0;
 | |
|         lefts[0].signdx = 1;
 | |
|         lefts[0].e = -dy;
 | |
|         lefts[0].dx = dx;
 | |
|         lefts[0].dy = dy;
 | |
| 
 | |
|         rights[0].height = bottomy - topy;
 | |
|         rights[0].x = lefts[0].x + (lw - 1);
 | |
|         rights[0].stepx = 0;
 | |
|         rights[0].signdx = 1;
 | |
|         rights[0].e = -dy;
 | |
|         rights[0].dx = dx;
 | |
|         rights[0].dy = dy;
 | |
|         miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, bottomy - topy,
 | |
|                          lefts, rights, 1, 1);
 | |
|     }
 | |
|     else {
 | |
|         xa = face->xa;
 | |
|         ya = face->ya;
 | |
|         projectXoff = -ya;
 | |
|         projectYoff = xa;
 | |
|         if (dx < 0) {
 | |
|             right = &rights[1];
 | |
|             left = &lefts[0];
 | |
|             top = &rights[0];
 | |
|             bottom = &lefts[1];
 | |
|         }
 | |
|         else {
 | |
|             right = &rights[0];
 | |
|             left = &lefts[1];
 | |
|             top = &lefts[0];
 | |
|             bottom = &rights[1];
 | |
|         }
 | |
|         if (isLeft) {
 | |
|             righty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 0, right);
 | |
| 
 | |
|             xa = -xa;
 | |
|             ya = -ya;
 | |
|             k = -k;
 | |
|             lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
 | |
|                                     k, dx, dy, xorgi, yorgi, 1, left);
 | |
|             if (dx > 0) {
 | |
|                 ya = -ya;
 | |
|                 xa = -xa;
 | |
|             }
 | |
|             xap = xa - projectXoff;
 | |
|             yap = ya - projectYoff;
 | |
|             topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
 | |
|                                    -dy, dx, xorgi, yorgi, dx > 0, top);
 | |
|             bottomy = miPolyBuildEdge(xa, ya,
 | |
|                                       0.0, -dy, dx, xorgi, yorgi, dx < 0,
 | |
|                                       bottom);
 | |
|             maxy = -ya;
 | |
|         }
 | |
|         else {
 | |
|             righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
 | |
|                                      k, dx, dy, xorgi, yorgi, 0, right);
 | |
| 
 | |
|             xa = -xa;
 | |
|             ya = -ya;
 | |
|             k = -k;
 | |
|             lefty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 1, left);
 | |
|             if (dx > 0) {
 | |
|                 ya = -ya;
 | |
|                 xa = -xa;
 | |
|             }
 | |
|             xap = xa - projectXoff;
 | |
|             yap = ya - projectYoff;
 | |
|             topy =
 | |
|                 miPolyBuildEdge(xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0,
 | |
|                                 top);
 | |
|             bottomy =
 | |
|                 miPolyBuildEdge(xap, yap, xap * dx + yap * dy, -dy, dx, xorgi,
 | |
|                                 xorgi, dx < 0, bottom);
 | |
|             maxy = -ya + projectYoff;
 | |
|         }
 | |
|         finaly = ICEIL(maxy) + yorgi;
 | |
|         if (dx < 0) {
 | |
|             left->height = bottomy - lefty;
 | |
|             right->height = finaly - righty;
 | |
|             top->height = righty - topy;
 | |
|         }
 | |
|         else {
 | |
|             right->height = bottomy - righty;
 | |
|             left->height = finaly - lefty;
 | |
|             top->height = lefty - topy;
 | |
|         }
 | |
|         bottom->height = finaly - bottomy;
 | |
|         miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
 | |
|                          bottom->height + bottomy - topy, lefts, rights, 2, 2);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| miWideSegment(DrawablePtr pDrawable,
 | |
|               GCPtr pGC,
 | |
|               unsigned long pixel,
 | |
|               SpanDataPtr spanData,
 | |
|               int x1,
 | |
|               int y1,
 | |
|               int x2,
 | |
|               int y2,
 | |
|               Bool projectLeft,
 | |
|               Bool projectRight, LineFacePtr leftFace, LineFacePtr rightFace)
 | |
| {
 | |
|     double l, L, r;
 | |
|     double xa, ya;
 | |
|     double projectXoff = 0.0, projectYoff = 0.0;
 | |
|     double k;
 | |
|     double maxy;
 | |
|     int x, y;
 | |
|     int dx, dy;
 | |
|     int finaly;
 | |
|     PolyEdgePtr left, right;
 | |
|     PolyEdgePtr top, bottom;
 | |
|     int lefty, righty, topy, bottomy;
 | |
|     int signdx;
 | |
|     PolyEdgeRec lefts[4], rights[4];
 | |
|     LineFacePtr tface;
 | |
|     int lw = pGC->lineWidth;
 | |
| 
 | |
|     /* draw top-to-bottom always */
 | |
|     if (y2 < y1 || (y2 == y1 && x2 < x1)) {
 | |
|         x = x1;
 | |
|         x1 = x2;
 | |
|         x2 = x;
 | |
| 
 | |
|         y = y1;
 | |
|         y1 = y2;
 | |
|         y2 = y;
 | |
| 
 | |
|         x = projectLeft;
 | |
|         projectLeft = projectRight;
 | |
|         projectRight = x;
 | |
| 
 | |
|         tface = leftFace;
 | |
|         leftFace = rightFace;
 | |
|         rightFace = tface;
 | |
|     }
 | |
| 
 | |
|     dy = y2 - y1;
 | |
|     signdx = 1;
 | |
|     dx = x2 - x1;
 | |
|     if (dx < 0)
 | |
|         signdx = -1;
 | |
| 
 | |
|     leftFace->x = x1;
 | |
|     leftFace->y = y1;
 | |
|     leftFace->dx = dx;
 | |
|     leftFace->dy = dy;
 | |
| 
 | |
|     rightFace->x = x2;
 | |
|     rightFace->y = y2;
 | |
|     rightFace->dx = -dx;
 | |
|     rightFace->dy = -dy;
 | |
| 
 | |
|     if (dy == 0) {
 | |
|         rightFace->xa = 0;
 | |
|         rightFace->ya = (double) lw / 2.0;
 | |
|         rightFace->k = -(double) (lw * dx) / 2.0;
 | |
|         leftFace->xa = 0;
 | |
|         leftFace->ya = -rightFace->ya;
 | |
|         leftFace->k = rightFace->k;
 | |
|         x = x1;
 | |
|         if (projectLeft)
 | |
|             x -= (lw >> 1);
 | |
|         y = y1 - (lw >> 1);
 | |
|         dx = x2 - x;
 | |
|         if (projectRight)
 | |
|             dx += ((lw + 1) >> 1);
 | |
|         dy = lw;
 | |
|         miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
 | |
|     }
 | |
|     else if (dx == 0) {
 | |
|         leftFace->xa = (double) lw / 2.0;
 | |
|         leftFace->ya = 0;
 | |
|         leftFace->k = (double) (lw * dy) / 2.0;
 | |
|         rightFace->xa = -leftFace->xa;
 | |
|         rightFace->ya = 0;
 | |
|         rightFace->k = leftFace->k;
 | |
|         y = y1;
 | |
|         if (projectLeft)
 | |
|             y -= lw >> 1;
 | |
|         x = x1 - (lw >> 1);
 | |
|         dy = y2 - y;
 | |
|         if (projectRight)
 | |
|             dy += ((lw + 1) >> 1);
 | |
|         dx = lw;
 | |
|         miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
 | |
|     }
 | |
|     else {
 | |
|         l = ((double) lw) / 2.0;
 | |
|         L = hypot((double) dx, (double) dy);
 | |
| 
 | |
|         if (dx < 0) {
 | |
|             right = &rights[1];
 | |
|             left = &lefts[0];
 | |
|             top = &rights[0];
 | |
|             bottom = &lefts[1];
 | |
|         }
 | |
|         else {
 | |
|             right = &rights[0];
 | |
|             left = &lefts[1];
 | |
|             top = &lefts[0];
 | |
|             bottom = &rights[1];
 | |
|         }
 | |
|         r = l / L;
 | |
| 
 | |
|         /* coord of upper bound at integral y */
 | |
|         ya = -r * dx;
 | |
|         xa = r * dy;
 | |
| 
 | |
|         if (projectLeft | projectRight) {
 | |
|             projectXoff = -ya;
 | |
|             projectYoff = xa;
 | |
|         }
 | |
| 
 | |
|         /* xa * dy - ya * dx */
 | |
|         k = l * L;
 | |
| 
 | |
|         leftFace->xa = xa;
 | |
|         leftFace->ya = ya;
 | |
|         leftFace->k = k;
 | |
|         rightFace->xa = -xa;
 | |
|         rightFace->ya = -ya;
 | |
|         rightFace->k = k;
 | |
| 
 | |
|         if (projectLeft)
 | |
|             righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
 | |
|                                      k, dx, dy, x1, y1, 0, right);
 | |
|         else
 | |
|             righty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 0, right);
 | |
| 
 | |
|         /* coord of lower bound at integral y */
 | |
|         ya = -ya;
 | |
|         xa = -xa;
 | |
| 
 | |
|         /* xa * dy - ya * dx */
 | |
|         k = -k;
 | |
| 
 | |
|         if (projectLeft)
 | |
|             lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
 | |
|                                     k, dx, dy, x1, y1, 1, left);
 | |
|         else
 | |
|             lefty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 1, left);
 | |
| 
 | |
|         /* coord of top face at integral y */
 | |
| 
 | |
|         if (signdx > 0) {
 | |
|             ya = -ya;
 | |
|             xa = -xa;
 | |
|         }
 | |
| 
 | |
|         if (projectLeft) {
 | |
|             double xap = xa - projectXoff;
 | |
|             double yap = ya - projectYoff;
 | |
| 
 | |
|             topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
 | |
|                                    -dy, dx, x1, y1, dx > 0, top);
 | |
|         }
 | |
|         else
 | |
|             topy = miPolyBuildEdge(xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
 | |
| 
 | |
|         /* coord of bottom face at integral y */
 | |
| 
 | |
|         if (projectRight) {
 | |
|             double xap = xa + projectXoff;
 | |
|             double yap = ya + projectYoff;
 | |
| 
 | |
|             bottomy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
 | |
|                                       -dy, dx, x2, y2, dx < 0, bottom);
 | |
|             maxy = -ya + projectYoff;
 | |
|         }
 | |
|         else {
 | |
|             bottomy = miPolyBuildEdge(xa, ya,
 | |
|                                       0.0, -dy, dx, x2, y2, dx < 0, bottom);
 | |
|             maxy = -ya;
 | |
|         }
 | |
| 
 | |
|         finaly = ICEIL(maxy) + y2;
 | |
| 
 | |
|         if (dx < 0) {
 | |
|             left->height = bottomy - lefty;
 | |
|             right->height = finaly - righty;
 | |
|             top->height = righty - topy;
 | |
|         }
 | |
|         else {
 | |
|             right->height = bottomy - righty;
 | |
|             left->height = finaly - lefty;
 | |
|             top->height = lefty - topy;
 | |
|         }
 | |
|         bottom->height = finaly - bottomy;
 | |
|         miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
 | |
|                          bottom->height + bottomy - topy, lefts, rights, 2, 2);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static SpanDataPtr
 | |
| miSetupSpanData(GCPtr pGC, SpanDataPtr spanData, int npt)
 | |
| {
 | |
|     if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
 | |
|         return (SpanDataPtr) NULL;
 | |
|     if (pGC->lineStyle == LineDoubleDash)
 | |
|         miInitSpanGroup(&spanData->bgGroup);
 | |
|     miInitSpanGroup(&spanData->fgGroup);
 | |
|     return spanData;
 | |
| }
 | |
| 
 | |
| static void
 | |
| miCleanupSpanData(DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
 | |
| {
 | |
|     if (pGC->lineStyle == LineDoubleDash) {
 | |
|         ChangeGCVal oldPixel, pixel;
 | |
| 
 | |
|         pixel.val = pGC->bgPixel;
 | |
|         oldPixel.val = pGC->fgPixel;
 | |
|         if (pixel.val != oldPixel.val) {
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &pixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|         miFillUniqueSpanGroup(pDrawable, pGC, &spanData->bgGroup);
 | |
|         miFreeSpanGroup(&spanData->bgGroup);
 | |
|         if (pixel.val != oldPixel.val) {
 | |
|             ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
 | |
|             ValidateGC(pDrawable, pGC);
 | |
|         }
 | |
|     }
 | |
|     miFillUniqueSpanGroup(pDrawable, pGC, &spanData->fgGroup);
 | |
|     miFreeSpanGroup(&spanData->fgGroup);
 | |
| }
 | |
| 
 | |
| void
 | |
| miWideLine(DrawablePtr pDrawable, GCPtr pGC,
 | |
|            int mode, int npt, DDXPointPtr pPts)
 | |
| {
 | |
|     int x1, y1, x2, y2;
 | |
|     SpanDataRec spanDataRec;
 | |
|     SpanDataPtr spanData;
 | |
|     long pixel;
 | |
|     Bool projectLeft, projectRight;
 | |
|     LineFaceRec leftFace, rightFace, prevRightFace;
 | |
|     LineFaceRec firstFace;
 | |
|     int first;
 | |
|     Bool somethingDrawn = FALSE;
 | |
|     Bool selfJoin;
 | |
| 
 | |
|     spanData = miSetupSpanData(pGC, &spanDataRec, npt);
 | |
|     pixel = pGC->fgPixel;
 | |
|     x2 = pPts->x;
 | |
|     y2 = pPts->y;
 | |
|     first = TRUE;
 | |
|     selfJoin = FALSE;
 | |
|     if (npt > 1) {
 | |
|         if (mode == CoordModePrevious) {
 | |
|             int nptTmp;
 | |
|             DDXPointPtr pPtsTmp;
 | |
| 
 | |
|             x1 = x2;
 | |
|             y1 = y2;
 | |
|             nptTmp = npt;
 | |
|             pPtsTmp = pPts + 1;
 | |
|             while (--nptTmp) {
 | |
|                 x1 += pPtsTmp->x;
 | |
|                 y1 += pPtsTmp->y;
 | |
|                 ++pPtsTmp;
 | |
|             }
 | |
|             if (x2 == x1 && y2 == y1)
 | |
|                 selfJoin = TRUE;
 | |
|         }
 | |
|         else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
 | |
|             selfJoin = TRUE;
 | |
|         }
 | |
|     }
 | |
|     projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
 | |
|     projectRight = FALSE;
 | |
|     while (--npt) {
 | |
|         x1 = x2;
 | |
|         y1 = y2;
 | |
|         ++pPts;
 | |
|         x2 = pPts->x;
 | |
|         y2 = pPts->y;
 | |
|         if (mode == CoordModePrevious) {
 | |
|             x2 += x1;
 | |
|             y2 += y1;
 | |
|         }
 | |
|         if (x1 != x2 || y1 != y2) {
 | |
|             somethingDrawn = TRUE;
 | |
|             if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
 | |
|                 projectRight = TRUE;
 | |
|             miWideSegment(pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
 | |
|                           projectLeft, projectRight, &leftFace, &rightFace);
 | |
|             if (first) {
 | |
|                 if (selfJoin)
 | |
|                     firstFace = leftFace;
 | |
|                 else if (pGC->capStyle == CapRound) {
 | |
|                     if (pGC->lineWidth == 1 && !spanData)
 | |
|                         miLineOnePoint(pDrawable, pGC, pixel, spanData, x1, y1);
 | |
|                     else
 | |
|                         miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                                   &leftFace, (LineFacePtr) NULL,
 | |
|                                   (double) 0.0, (double) 0.0, TRUE);
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
 | |
|                            &prevRightFace);
 | |
|             }
 | |
|             prevRightFace = rightFace;
 | |
|             first = FALSE;
 | |
|             projectLeft = FALSE;
 | |
|         }
 | |
|         if (npt == 1 && somethingDrawn) {
 | |
|             if (selfJoin)
 | |
|                 miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
 | |
|                            &rightFace);
 | |
|             else if (pGC->capStyle == CapRound) {
 | |
|                 if (pGC->lineWidth == 1 && !spanData)
 | |
|                     miLineOnePoint(pDrawable, pGC, pixel, spanData, x2, y2);
 | |
|                 else
 | |
|                     miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                               (LineFacePtr) NULL, &rightFace,
 | |
|                               (double) 0.0, (double) 0.0, TRUE);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /* handle crock where all points are coincedent */
 | |
|     if (!somethingDrawn) {
 | |
|         projectLeft = pGC->capStyle == CapProjecting;
 | |
|         miWideSegment(pDrawable, pGC, pixel, spanData,
 | |
|                       x2, y2, x2, y2, projectLeft, projectLeft,
 | |
|                       &leftFace, &rightFace);
 | |
|         if (pGC->capStyle == CapRound) {
 | |
|             miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                       &leftFace, (LineFacePtr) NULL,
 | |
|                       (double) 0.0, (double) 0.0, TRUE);
 | |
|             rightFace.dx = -1;  /* sleezy hack to make it work */
 | |
|             miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                       (LineFacePtr) NULL, &rightFace,
 | |
|                       (double) 0.0, (double) 0.0, TRUE);
 | |
|         }
 | |
|     }
 | |
|     if (spanData)
 | |
|         miCleanupSpanData(pDrawable, pGC, spanData);
 | |
| }
 | |
| 
 | |
| #define V_TOP	    0
 | |
| #define V_RIGHT	    1
 | |
| #define V_BOTTOM    2
 | |
| #define V_LEFT	    3
 | |
| 
 | |
| static void
 | |
| miWideDashSegment(DrawablePtr pDrawable,
 | |
|                   GCPtr pGC,
 | |
|                   SpanDataPtr spanData,
 | |
|                   int *pDashOffset,
 | |
|                   int *pDashIndex,
 | |
|                   int x1,
 | |
|                   int y1,
 | |
|                   int x2,
 | |
|                   int y2,
 | |
|                   Bool projectLeft,
 | |
|                   Bool projectRight,
 | |
|                   LineFacePtr leftFace, LineFacePtr rightFace)
 | |
| {
 | |
|     int dashIndex, dashRemain;
 | |
|     unsigned char *pDash;
 | |
|     double L, l;
 | |
|     double k;
 | |
|     PolyVertexRec vertices[4];
 | |
|     PolyVertexRec saveRight, saveBottom;
 | |
|     PolySlopeRec slopes[4];
 | |
|     PolyEdgeRec left[4], right[4];
 | |
|     LineFaceRec lcapFace, rcapFace;
 | |
|     int nleft, nright;
 | |
|     int h;
 | |
|     int y;
 | |
|     int dy, dx;
 | |
|     unsigned long pixel;
 | |
|     double LRemain;
 | |
|     double r;
 | |
|     double rdx, rdy;
 | |
|     double dashDx, dashDy;
 | |
|     double saveK = 0.0;
 | |
|     Bool first = TRUE;
 | |
|     double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
 | |
|     unsigned long fgPixel, bgPixel;
 | |
| 
 | |
|     dx = x2 - x1;
 | |
|     dy = y2 - y1;
 | |
|     dashIndex = *pDashIndex;
 | |
|     pDash = pGC->dash;
 | |
|     dashRemain = pDash[dashIndex] - *pDashOffset;
 | |
|     fgPixel = pGC->fgPixel;
 | |
|     bgPixel = pGC->bgPixel;
 | |
|     if (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled) {
 | |
|         bgPixel = fgPixel;
 | |
|     }
 | |
| 
 | |
|     l = ((double) pGC->lineWidth) / 2.0;
 | |
|     if (dx == 0) {
 | |
|         L = dy;
 | |
|         rdx = 0;
 | |
|         rdy = l;
 | |
|         if (dy < 0) {
 | |
|             L = -dy;
 | |
|             rdy = -l;
 | |
|         }
 | |
|     }
 | |
|     else if (dy == 0) {
 | |
|         L = dx;
 | |
|         rdx = l;
 | |
|         rdy = 0;
 | |
|         if (dx < 0) {
 | |
|             L = -dx;
 | |
|             rdx = -l;
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         L = hypot((double) dx, (double) dy);
 | |
|         r = l / L;
 | |
| 
 | |
|         rdx = r * dx;
 | |
|         rdy = r * dy;
 | |
|     }
 | |
|     k = l * L;
 | |
|     LRemain = L;
 | |
|     /* All position comments are relative to a line with dx and dy > 0,
 | |
|      * but the code does not depend on this */
 | |
|     /* top */
 | |
|     slopes[V_TOP].dx = dx;
 | |
|     slopes[V_TOP].dy = dy;
 | |
|     slopes[V_TOP].k = k;
 | |
|     /* right */
 | |
|     slopes[V_RIGHT].dx = -dy;
 | |
|     slopes[V_RIGHT].dy = dx;
 | |
|     slopes[V_RIGHT].k = 0;
 | |
|     /* bottom */
 | |
|     slopes[V_BOTTOM].dx = -dx;
 | |
|     slopes[V_BOTTOM].dy = -dy;
 | |
|     slopes[V_BOTTOM].k = k;
 | |
|     /* left */
 | |
|     slopes[V_LEFT].dx = dy;
 | |
|     slopes[V_LEFT].dy = -dx;
 | |
|     slopes[V_LEFT].k = 0;
 | |
| 
 | |
|     /* preload the start coordinates */
 | |
|     vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
 | |
|     vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
 | |
| 
 | |
|     vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
 | |
|     vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
 | |
| 
 | |
|     if (projectLeft) {
 | |
|         vertices[V_TOP].x -= rdx;
 | |
|         vertices[V_TOP].y -= rdy;
 | |
| 
 | |
|         vertices[V_LEFT].x -= rdx;
 | |
|         vertices[V_LEFT].y -= rdy;
 | |
| 
 | |
|         slopes[V_LEFT].k = rdx * dx + rdy * dy;
 | |
|     }
 | |
| 
 | |
|     lcenterx = x1;
 | |
|     lcentery = y1;
 | |
| 
 | |
|     if (pGC->capStyle == CapRound) {
 | |
|         lcapFace.dx = dx;
 | |
|         lcapFace.dy = dy;
 | |
|         lcapFace.x = x1;
 | |
|         lcapFace.y = y1;
 | |
| 
 | |
|         rcapFace.dx = -dx;
 | |
|         rcapFace.dy = -dy;
 | |
|         rcapFace.x = x1;
 | |
|         rcapFace.y = y1;
 | |
|     }
 | |
|     while (LRemain > dashRemain) {
 | |
|         dashDx = (dashRemain * dx) / L;
 | |
|         dashDy = (dashRemain * dy) / L;
 | |
| 
 | |
|         rcenterx = lcenterx + dashDx;
 | |
|         rcentery = lcentery + dashDy;
 | |
| 
 | |
|         vertices[V_RIGHT].x += dashDx;
 | |
|         vertices[V_RIGHT].y += dashDy;
 | |
| 
 | |
|         vertices[V_BOTTOM].x += dashDx;
 | |
|         vertices[V_BOTTOM].y += dashDy;
 | |
| 
 | |
|         slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
 | |
| 
 | |
|         if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) {
 | |
|             if (pGC->lineStyle == LineOnOffDash &&
 | |
|                 pGC->capStyle == CapProjecting) {
 | |
|                 saveRight = vertices[V_RIGHT];
 | |
|                 saveBottom = vertices[V_BOTTOM];
 | |
|                 saveK = slopes[V_RIGHT].k;
 | |
| 
 | |
|                 if (!first) {
 | |
|                     vertices[V_TOP].x -= rdx;
 | |
|                     vertices[V_TOP].y -= rdy;
 | |
| 
 | |
|                     vertices[V_LEFT].x -= rdx;
 | |
|                     vertices[V_LEFT].y -= rdy;
 | |
| 
 | |
|                     slopes[V_LEFT].k = vertices[V_LEFT].x *
 | |
|                         slopes[V_LEFT].dy -
 | |
|                         vertices[V_LEFT].y * slopes[V_LEFT].dx;
 | |
|                 }
 | |
| 
 | |
|                 vertices[V_RIGHT].x += rdx;
 | |
|                 vertices[V_RIGHT].y += rdy;
 | |
| 
 | |
|                 vertices[V_BOTTOM].x += rdx;
 | |
|                 vertices[V_BOTTOM].y += rdy;
 | |
| 
 | |
|                 slopes[V_RIGHT].k = vertices[V_RIGHT].x *
 | |
|                     slopes[V_RIGHT].dy -
 | |
|                     vertices[V_RIGHT].y * slopes[V_RIGHT].dx;
 | |
|             }
 | |
|             y = miPolyBuildPoly(vertices, slopes, 4, x1, y1,
 | |
|                                 left, right, &nleft, &nright, &h);
 | |
|             pixel = (dashIndex & 1) ? bgPixel : fgPixel;
 | |
|             miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
 | |
|                              nleft, nright);
 | |
| 
 | |
|             if (pGC->lineStyle == LineOnOffDash) {
 | |
|                 switch (pGC->capStyle) {
 | |
|                 case CapProjecting:
 | |
|                     vertices[V_BOTTOM] = saveBottom;
 | |
|                     vertices[V_RIGHT] = saveRight;
 | |
|                     slopes[V_RIGHT].k = saveK;
 | |
|                     break;
 | |
|                 case CapRound:
 | |
|                     if (!first) {
 | |
|                         if (dx < 0) {
 | |
|                             lcapFace.xa = -vertices[V_LEFT].x;
 | |
|                             lcapFace.ya = -vertices[V_LEFT].y;
 | |
|                             lcapFace.k = slopes[V_LEFT].k;
 | |
|                         }
 | |
|                         else {
 | |
|                             lcapFace.xa = vertices[V_TOP].x;
 | |
|                             lcapFace.ya = vertices[V_TOP].y;
 | |
|                             lcapFace.k = -slopes[V_LEFT].k;
 | |
|                         }
 | |
|                         miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                                   &lcapFace, (LineFacePtr) NULL,
 | |
|                                   lcenterx, lcentery, FALSE);
 | |
|                     }
 | |
|                     if (dx < 0) {
 | |
|                         rcapFace.xa = vertices[V_BOTTOM].x;
 | |
|                         rcapFace.ya = vertices[V_BOTTOM].y;
 | |
|                         rcapFace.k = slopes[V_RIGHT].k;
 | |
|                     }
 | |
|                     else {
 | |
|                         rcapFace.xa = -vertices[V_RIGHT].x;
 | |
|                         rcapFace.ya = -vertices[V_RIGHT].y;
 | |
|                         rcapFace.k = -slopes[V_RIGHT].k;
 | |
|                     }
 | |
|                     miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                               (LineFacePtr) NULL, &rcapFace,
 | |
|                               rcenterx, rcentery, FALSE);
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         LRemain -= dashRemain;
 | |
|         ++dashIndex;
 | |
|         if (dashIndex == pGC->numInDashList)
 | |
|             dashIndex = 0;
 | |
|         dashRemain = pDash[dashIndex];
 | |
| 
 | |
|         lcenterx = rcenterx;
 | |
|         lcentery = rcentery;
 | |
| 
 | |
|         vertices[V_TOP] = vertices[V_RIGHT];
 | |
|         vertices[V_LEFT] = vertices[V_BOTTOM];
 | |
|         slopes[V_LEFT].k = -slopes[V_RIGHT].k;
 | |
|         first = FALSE;
 | |
|     }
 | |
| 
 | |
|     if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) {
 | |
|         vertices[V_TOP].x -= dx;
 | |
|         vertices[V_TOP].y -= dy;
 | |
| 
 | |
|         vertices[V_LEFT].x -= dx;
 | |
|         vertices[V_LEFT].y -= dy;
 | |
| 
 | |
|         vertices[V_RIGHT].x = rdy;
 | |
|         vertices[V_RIGHT].y = -rdx;
 | |
| 
 | |
|         vertices[V_BOTTOM].x = -rdy;
 | |
|         vertices[V_BOTTOM].y = rdx;
 | |
| 
 | |
|         if (projectRight) {
 | |
|             vertices[V_RIGHT].x += rdx;
 | |
|             vertices[V_RIGHT].y += rdy;
 | |
| 
 | |
|             vertices[V_BOTTOM].x += rdx;
 | |
|             vertices[V_BOTTOM].y += rdy;
 | |
|             slopes[V_RIGHT].k = vertices[V_RIGHT].x *
 | |
|                 slopes[V_RIGHT].dy - vertices[V_RIGHT].y * slopes[V_RIGHT].dx;
 | |
|         }
 | |
|         else
 | |
|             slopes[V_RIGHT].k = 0;
 | |
| 
 | |
|         if (!first && pGC->lineStyle == LineOnOffDash &&
 | |
|             pGC->capStyle == CapProjecting) {
 | |
|             vertices[V_TOP].x -= rdx;
 | |
|             vertices[V_TOP].y -= rdy;
 | |
| 
 | |
|             vertices[V_LEFT].x -= rdx;
 | |
|             vertices[V_LEFT].y -= rdy;
 | |
|             slopes[V_LEFT].k = vertices[V_LEFT].x *
 | |
|                 slopes[V_LEFT].dy - vertices[V_LEFT].y * slopes[V_LEFT].dx;
 | |
|         }
 | |
|         else
 | |
|             slopes[V_LEFT].k += dx * dx + dy * dy;
 | |
| 
 | |
|         y = miPolyBuildPoly(vertices, slopes, 4, x2, y2,
 | |
|                             left, right, &nleft, &nright, &h);
 | |
| 
 | |
|         pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
 | |
|         miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
 | |
|                          nleft, nright);
 | |
|         if (!first && pGC->lineStyle == LineOnOffDash &&
 | |
|             pGC->capStyle == CapRound) {
 | |
|             lcapFace.x = x2;
 | |
|             lcapFace.y = y2;
 | |
|             if (dx < 0) {
 | |
|                 lcapFace.xa = -vertices[V_LEFT].x;
 | |
|                 lcapFace.ya = -vertices[V_LEFT].y;
 | |
|                 lcapFace.k = slopes[V_LEFT].k;
 | |
|             }
 | |
|             else {
 | |
|                 lcapFace.xa = vertices[V_TOP].x;
 | |
|                 lcapFace.ya = vertices[V_TOP].y;
 | |
|                 lcapFace.k = -slopes[V_LEFT].k;
 | |
|             }
 | |
|             miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                       &lcapFace, (LineFacePtr) NULL, rcenterx, rcentery, FALSE);
 | |
|         }
 | |
|     }
 | |
|     dashRemain = ((double) dashRemain) - LRemain;
 | |
|     if (dashRemain == 0) {
 | |
|         dashIndex++;
 | |
|         if (dashIndex == pGC->numInDashList)
 | |
|             dashIndex = 0;
 | |
|         dashRemain = pDash[dashIndex];
 | |
|     }
 | |
| 
 | |
|     leftFace->x = x1;
 | |
|     leftFace->y = y1;
 | |
|     leftFace->dx = dx;
 | |
|     leftFace->dy = dy;
 | |
|     leftFace->xa = rdy;
 | |
|     leftFace->ya = -rdx;
 | |
|     leftFace->k = k;
 | |
| 
 | |
|     rightFace->x = x2;
 | |
|     rightFace->y = y2;
 | |
|     rightFace->dx = -dx;
 | |
|     rightFace->dy = -dy;
 | |
|     rightFace->xa = -rdy;
 | |
|     rightFace->ya = rdx;
 | |
|     rightFace->k = k;
 | |
| 
 | |
|     *pDashIndex = dashIndex;
 | |
|     *pDashOffset = pDash[dashIndex] - dashRemain;
 | |
| }
 | |
| 
 | |
| void
 | |
| miWideDash(DrawablePtr pDrawable, GCPtr pGC,
 | |
|            int mode, int npt, DDXPointPtr pPts)
 | |
| {
 | |
|     int x1, y1, x2, y2;
 | |
|     unsigned long pixel;
 | |
|     Bool projectLeft, projectRight;
 | |
|     LineFaceRec leftFace, rightFace, prevRightFace;
 | |
|     LineFaceRec firstFace;
 | |
|     int first;
 | |
|     int dashIndex, dashOffset;
 | |
|     int prevDashIndex;
 | |
|     SpanDataRec spanDataRec;
 | |
|     SpanDataPtr spanData;
 | |
|     Bool somethingDrawn = FALSE;
 | |
|     Bool selfJoin;
 | |
|     Bool endIsFg = FALSE, startIsFg = FALSE;
 | |
|     Bool firstIsFg = FALSE, prevIsFg = FALSE;
 | |
| 
 | |
| #if 0
 | |
|     /* XXX backward compatibility */
 | |
|     if (pGC->lineWidth == 0) {
 | |
|         miZeroDashLine(pDrawable, pGC, mode, npt, pPts);
 | |
|         return;
 | |
|     }
 | |
| #endif
 | |
|     if (pGC->lineStyle == LineDoubleDash &&
 | |
|         (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) {
 | |
|         miWideLine(pDrawable, pGC, mode, npt, pPts);
 | |
|         return;
 | |
|     }
 | |
|     if (npt == 0)
 | |
|         return;
 | |
|     spanData = miSetupSpanData(pGC, &spanDataRec, npt);
 | |
|     x2 = pPts->x;
 | |
|     y2 = pPts->y;
 | |
|     first = TRUE;
 | |
|     selfJoin = FALSE;
 | |
|     if (mode == CoordModePrevious) {
 | |
|         int nptTmp;
 | |
|         DDXPointPtr pPtsTmp;
 | |
| 
 | |
|         x1 = x2;
 | |
|         y1 = y2;
 | |
|         nptTmp = npt;
 | |
|         pPtsTmp = pPts + 1;
 | |
|         while (--nptTmp) {
 | |
|             x1 += pPtsTmp->x;
 | |
|             y1 += pPtsTmp->y;
 | |
|             ++pPtsTmp;
 | |
|         }
 | |
|         if (x2 == x1 && y2 == y1)
 | |
|             selfJoin = TRUE;
 | |
|     }
 | |
|     else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
 | |
|         selfJoin = TRUE;
 | |
|     }
 | |
|     projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
 | |
|     projectRight = FALSE;
 | |
|     dashIndex = 0;
 | |
|     dashOffset = 0;
 | |
|     miStepDash((int) pGC->dashOffset, &dashIndex,
 | |
|                pGC->dash, (int) pGC->numInDashList, &dashOffset);
 | |
|     while (--npt) {
 | |
|         x1 = x2;
 | |
|         y1 = y2;
 | |
|         ++pPts;
 | |
|         x2 = pPts->x;
 | |
|         y2 = pPts->y;
 | |
|         if (mode == CoordModePrevious) {
 | |
|             x2 += x1;
 | |
|             y2 += y1;
 | |
|         }
 | |
|         if (x1 != x2 || y1 != y2) {
 | |
|             somethingDrawn = TRUE;
 | |
|             if (npt == 1 && pGC->capStyle == CapProjecting &&
 | |
|                 (!selfJoin || !firstIsFg))
 | |
|                 projectRight = TRUE;
 | |
|             prevDashIndex = dashIndex;
 | |
|             miWideDashSegment(pDrawable, pGC, spanData, &dashOffset, &dashIndex,
 | |
|                               x1, y1, x2, y2,
 | |
|                               projectLeft, projectRight, &leftFace, &rightFace);
 | |
|             startIsFg = !(prevDashIndex & 1);
 | |
|             endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
 | |
|             if (pGC->lineStyle == LineDoubleDash || startIsFg) {
 | |
|                 pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
 | |
|                 if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) {
 | |
|                     if (first && selfJoin) {
 | |
|                         firstFace = leftFace;
 | |
|                         firstIsFg = startIsFg;
 | |
|                     }
 | |
|                     else if (pGC->capStyle == CapRound)
 | |
|                         miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                                   &leftFace, (LineFacePtr) NULL,
 | |
|                                   (double) 0.0, (double) 0.0, TRUE);
 | |
|                 }
 | |
|                 else {
 | |
|                     miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
 | |
|                                &prevRightFace);
 | |
|                 }
 | |
|             }
 | |
|             prevRightFace = rightFace;
 | |
|             prevIsFg = endIsFg;
 | |
|             first = FALSE;
 | |
|             projectLeft = FALSE;
 | |
|         }
 | |
|         if (npt == 1 && somethingDrawn) {
 | |
|             if (pGC->lineStyle == LineDoubleDash || endIsFg) {
 | |
|                 pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
 | |
|                 if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) {
 | |
|                     miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
 | |
|                                &rightFace);
 | |
|                 }
 | |
|                 else {
 | |
|                     if (pGC->capStyle == CapRound)
 | |
|                         miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                                   (LineFacePtr) NULL, &rightFace,
 | |
|                                   (double) 0.0, (double) 0.0, TRUE);
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 /* glue a cap to the start of the line if
 | |
|                  * we're OnOffDash and ended on odd dash
 | |
|                  */
 | |
|                 if (selfJoin && firstIsFg) {
 | |
|                     pixel = pGC->fgPixel;
 | |
|                     if (pGC->capStyle == CapProjecting)
 | |
|                         miLineProjectingCap(pDrawable, pGC, pixel, spanData,
 | |
|                                             &firstFace, TRUE,
 | |
|                                             (double) 0.0, (double) 0.0, TRUE);
 | |
|                     else if (pGC->capStyle == CapRound)
 | |
|                         miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                                   &firstFace, (LineFacePtr) NULL,
 | |
|                                   (double) 0.0, (double) 0.0, TRUE);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     /* handle crock where all points are coincident */
 | |
|     if (!somethingDrawn &&
 | |
|         (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) {
 | |
|         /* not the same as endIsFg computation above */
 | |
|         pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
 | |
|         switch (pGC->capStyle) {
 | |
|         case CapRound:
 | |
|             miLineArc(pDrawable, pGC, pixel, spanData,
 | |
|                       (LineFacePtr) NULL, (LineFacePtr) NULL,
 | |
|                       (double) x2, (double) y2, FALSE);
 | |
|             break;
 | |
|         case CapProjecting:
 | |
|             x1 = pGC->lineWidth;
 | |
|             miFillRectPolyHelper(pDrawable, pGC, pixel, spanData,
 | |
|                                  x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     if (spanData)
 | |
|         miCleanupSpanData(pDrawable, pGC, spanData);
 | |
| }
 |