105b261ecSmrg/* 205b261ecSmrg 305b261ecSmrgCopyright 1988, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included 1205b261ecSmrgin all copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg 2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall 2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or 2405b261ecSmrgother dealings in this Software without prior written authorization 2505b261ecSmrgfrom The Open Group. 2605b261ecSmrg 2735c4bbdfSmrgCopyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 2835c4bbdfSmrg 2935c4bbdfSmrg All Rights Reserved 3035c4bbdfSmrg 3135c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its 3235c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted, 3335c4bbdfSmrgprovided that the above copyright notice appear in all copies and that 3435c4bbdfSmrgboth that copyright notice and this permission notice appear in 3535c4bbdfSmrgsupporting documentation, and that the name of Digital not be 3635c4bbdfSmrgused in advertising or publicity pertaining to distribution of the 3735c4bbdfSmrgsoftware without specific, written prior permission. 3835c4bbdfSmrg 3935c4bbdfSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 4035c4bbdfSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 4135c4bbdfSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 4235c4bbdfSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 4335c4bbdfSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 4435c4bbdfSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 4535c4bbdfSmrgSOFTWARE. 4605b261ecSmrg*/ 4705b261ecSmrg 4805b261ecSmrg/* Author: Keith Packard, MIT X Consortium */ 4905b261ecSmrg 5005b261ecSmrg/* 5105b261ecSmrg * Mostly integer wideline code. Uses a technique similar to 5205b261ecSmrg * bresenham zero-width lines, except walks an X edge 5305b261ecSmrg */ 5405b261ecSmrg 5505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 5605b261ecSmrg#include <dix-config.h> 5705b261ecSmrg#endif 5805b261ecSmrg 5905b261ecSmrg#include <stdio.h> 6005b261ecSmrg#ifdef _XOPEN_SOURCE 6105b261ecSmrg#include <math.h> 6205b261ecSmrg#else 6335c4bbdfSmrg#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ 6405b261ecSmrg#include <math.h> 6505b261ecSmrg#undef _XOPEN_SOURCE 6605b261ecSmrg#endif 6705b261ecSmrg#include <X11/X.h> 6805b261ecSmrg#include "windowstr.h" 6905b261ecSmrg#include "gcstruct.h" 7005b261ecSmrg#include "regionstr.h" 7105b261ecSmrg#include "miwideline.h" 7205b261ecSmrg#include "mi.h" 7305b261ecSmrg 7435c4bbdfSmrg#if 0 7535c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H 7635c4bbdfSmrg#include <dix-config.h> 7735c4bbdfSmrg#endif 7835c4bbdfSmrg 7935c4bbdfSmrg#include "misc.h" 8035c4bbdfSmrg#include "pixmapstr.h" 8135c4bbdfSmrg#include "gcstruct.h" 8235c4bbdfSmrg#endif 8335c4bbdfSmrg 8435c4bbdfSmrgtypedef struct { 8535c4bbdfSmrg int count; /* number of spans */ 8635c4bbdfSmrg DDXPointPtr points; /* pointer to list of start points */ 8735c4bbdfSmrg int *widths; /* pointer to list of widths */ 8835c4bbdfSmrg} Spans; 8935c4bbdfSmrg 9035c4bbdfSmrgtypedef struct { 9135c4bbdfSmrg int size; /* Total number of *Spans allocated */ 9235c4bbdfSmrg int count; /* Number of *Spans actually in group */ 9335c4bbdfSmrg Spans *group; /* List of Spans */ 9435c4bbdfSmrg int ymin, ymax; /* Min, max y values encountered */ 9535c4bbdfSmrg} SpanGroup; 9635c4bbdfSmrg 9735c4bbdfSmrg/* Rops which must use span groups */ 9835c4bbdfSmrg#define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2) 9935c4bbdfSmrg#define miSpansEasyRop(rop) (!miSpansCarefulRop(rop)) 10035c4bbdfSmrg 10135c4bbdfSmrg/* 10235c4bbdfSmrg 10335c4bbdfSmrgThese routines maintain lists of Spans, in order to implement the 10435c4bbdfSmrg``touch-each-pixel-once'' rules of wide lines and arcs. 10535c4bbdfSmrg 10635c4bbdfSmrgWritten by Joel McCormack, Summer 1989. 10735c4bbdfSmrg 10835c4bbdfSmrg*/ 10935c4bbdfSmrg 11035c4bbdfSmrgstatic void 11135c4bbdfSmrgmiInitSpanGroup(SpanGroup * spanGroup) 11235c4bbdfSmrg{ 11335c4bbdfSmrg spanGroup->size = 0; 11435c4bbdfSmrg spanGroup->count = 0; 11535c4bbdfSmrg spanGroup->group = NULL; 11635c4bbdfSmrg spanGroup->ymin = MAXSHORT; 11735c4bbdfSmrg spanGroup->ymax = MINSHORT; 11835c4bbdfSmrg} /* InitSpanGroup */ 11935c4bbdfSmrg 12035c4bbdfSmrg#define YMIN(spans) (spans->points[0].y) 12135c4bbdfSmrg#define YMAX(spans) (spans->points[spans->count-1].y) 12235c4bbdfSmrg 12335c4bbdfSmrgstatic void 12435c4bbdfSmrgmiSubtractSpans(SpanGroup * spanGroup, Spans * sub) 12535c4bbdfSmrg{ 12635c4bbdfSmrg int i, subCount, spansCount; 12735c4bbdfSmrg int ymin, ymax, xmin, xmax; 12835c4bbdfSmrg Spans *spans; 12935c4bbdfSmrg DDXPointPtr subPt, spansPt; 13035c4bbdfSmrg int *subWid, *spansWid; 13135c4bbdfSmrg int extra; 13235c4bbdfSmrg 13335c4bbdfSmrg ymin = YMIN(sub); 13435c4bbdfSmrg ymax = YMAX(sub); 13535c4bbdfSmrg spans = spanGroup->group; 13635c4bbdfSmrg for (i = spanGroup->count; i; i--, spans++) { 13735c4bbdfSmrg if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) { 13835c4bbdfSmrg subCount = sub->count; 13935c4bbdfSmrg subPt = sub->points; 14035c4bbdfSmrg subWid = sub->widths; 14135c4bbdfSmrg spansCount = spans->count; 14235c4bbdfSmrg spansPt = spans->points; 14335c4bbdfSmrg spansWid = spans->widths; 14435c4bbdfSmrg extra = 0; 14535c4bbdfSmrg for (;;) { 14635c4bbdfSmrg while (spansCount && spansPt->y < subPt->y) { 14735c4bbdfSmrg spansPt++; 14835c4bbdfSmrg spansWid++; 14935c4bbdfSmrg spansCount--; 15035c4bbdfSmrg } 15135c4bbdfSmrg if (!spansCount) 15235c4bbdfSmrg break; 15335c4bbdfSmrg while (subCount && subPt->y < spansPt->y) { 15435c4bbdfSmrg subPt++; 15535c4bbdfSmrg subWid++; 15635c4bbdfSmrg subCount--; 15735c4bbdfSmrg } 15835c4bbdfSmrg if (!subCount) 15935c4bbdfSmrg break; 16035c4bbdfSmrg if (subPt->y == spansPt->y) { 16135c4bbdfSmrg xmin = subPt->x; 16235c4bbdfSmrg xmax = xmin + *subWid; 16335c4bbdfSmrg if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) { 16435c4bbdfSmrg ; 16535c4bbdfSmrg } 16635c4bbdfSmrg else if (xmin <= spansPt->x) { 16735c4bbdfSmrg if (xmax >= spansPt->x + *spansWid) { 16835c4bbdfSmrg memmove(spansPt, spansPt + 1, 16935c4bbdfSmrg sizeof *spansPt * (spansCount - 1)); 17035c4bbdfSmrg memmove(spansWid, spansWid + 1, 17135c4bbdfSmrg sizeof *spansWid * (spansCount - 1)); 17235c4bbdfSmrg spansPt--; 17335c4bbdfSmrg spansWid--; 17435c4bbdfSmrg spans->count--; 17535c4bbdfSmrg extra++; 17635c4bbdfSmrg } 17735c4bbdfSmrg else { 17835c4bbdfSmrg *spansWid = *spansWid - (xmax - spansPt->x); 17935c4bbdfSmrg spansPt->x = xmax; 18035c4bbdfSmrg } 18135c4bbdfSmrg } 18235c4bbdfSmrg else { 18335c4bbdfSmrg if (xmax >= spansPt->x + *spansWid) { 18435c4bbdfSmrg *spansWid = xmin - spansPt->x; 18535c4bbdfSmrg } 18635c4bbdfSmrg else { 18735c4bbdfSmrg if (!extra) { 18835c4bbdfSmrg DDXPointPtr newPt; 18935c4bbdfSmrg int *newwid; 19035c4bbdfSmrg 19135c4bbdfSmrg#define EXTRA 8 19235c4bbdfSmrg newPt = reallocarray(spans->points, 19335c4bbdfSmrg spans->count + EXTRA, 19435c4bbdfSmrg sizeof(DDXPointRec)); 19535c4bbdfSmrg if (!newPt) 19635c4bbdfSmrg break; 19735c4bbdfSmrg spansPt = newPt + (spansPt - spans->points); 19835c4bbdfSmrg spans->points = newPt; 19935c4bbdfSmrg newwid = reallocarray(spans->widths, 20035c4bbdfSmrg spans->count + EXTRA, 20135c4bbdfSmrg sizeof(int)); 20235c4bbdfSmrg if (!newwid) 20335c4bbdfSmrg break; 20435c4bbdfSmrg spansWid = newwid + (spansWid - spans->widths); 20535c4bbdfSmrg spans->widths = newwid; 20635c4bbdfSmrg extra = EXTRA; 20735c4bbdfSmrg } 20835c4bbdfSmrg memmove(spansPt + 1, spansPt, 20935c4bbdfSmrg sizeof *spansPt * (spansCount)); 21035c4bbdfSmrg memmove(spansWid + 1, spansWid, 21135c4bbdfSmrg sizeof *spansWid * (spansCount)); 21235c4bbdfSmrg spans->count++; 21335c4bbdfSmrg extra--; 21435c4bbdfSmrg *spansWid = xmin - spansPt->x; 21535c4bbdfSmrg spansWid++; 21635c4bbdfSmrg spansPt++; 21735c4bbdfSmrg *spansWid = *spansWid - (xmax - spansPt->x); 21835c4bbdfSmrg spansPt->x = xmax; 21935c4bbdfSmrg } 22035c4bbdfSmrg } 22135c4bbdfSmrg } 22235c4bbdfSmrg spansPt++; 22335c4bbdfSmrg spansWid++; 22435c4bbdfSmrg spansCount--; 22535c4bbdfSmrg } 22635c4bbdfSmrg } 22735c4bbdfSmrg } 22835c4bbdfSmrg} 22935c4bbdfSmrg 23035c4bbdfSmrgstatic void 23135c4bbdfSmrgmiAppendSpans(SpanGroup * spanGroup, SpanGroup * otherGroup, Spans * spans) 23235c4bbdfSmrg{ 23335c4bbdfSmrg int ymin, ymax; 23435c4bbdfSmrg int spansCount; 23535c4bbdfSmrg 23635c4bbdfSmrg spansCount = spans->count; 23735c4bbdfSmrg if (spansCount > 0) { 23835c4bbdfSmrg if (spanGroup->size == spanGroup->count) { 23935c4bbdfSmrg spanGroup->size = (spanGroup->size + 8) * 2; 24035c4bbdfSmrg spanGroup->group = 24135c4bbdfSmrg reallocarray(spanGroup->group, sizeof(Spans), spanGroup->size); 24235c4bbdfSmrg } 24335c4bbdfSmrg 24435c4bbdfSmrg spanGroup->group[spanGroup->count] = *spans; 24535c4bbdfSmrg (spanGroup->count)++; 24635c4bbdfSmrg ymin = spans->points[0].y; 24735c4bbdfSmrg if (ymin < spanGroup->ymin) 24835c4bbdfSmrg spanGroup->ymin = ymin; 24935c4bbdfSmrg ymax = spans->points[spansCount - 1].y; 25035c4bbdfSmrg if (ymax > spanGroup->ymax) 25135c4bbdfSmrg spanGroup->ymax = ymax; 25235c4bbdfSmrg if (otherGroup && otherGroup->ymin < ymax && ymin < otherGroup->ymax) { 25335c4bbdfSmrg miSubtractSpans(otherGroup, spans); 25435c4bbdfSmrg } 25535c4bbdfSmrg } 25635c4bbdfSmrg else { 25735c4bbdfSmrg free(spans->points); 25835c4bbdfSmrg free(spans->widths); 25935c4bbdfSmrg } 26035c4bbdfSmrg} /* AppendSpans */ 26135c4bbdfSmrg 26235c4bbdfSmrgstatic void 26335c4bbdfSmrgmiFreeSpanGroup(SpanGroup * spanGroup) 26435c4bbdfSmrg{ 26535c4bbdfSmrg free(spanGroup->group); 26635c4bbdfSmrg} 26735c4bbdfSmrg 26835c4bbdfSmrgstatic void 26935c4bbdfSmrgQuickSortSpansX(DDXPointRec points[], int widths[], int numSpans) 27035c4bbdfSmrg{ 27135c4bbdfSmrg int x; 27235c4bbdfSmrg int i, j, m; 27335c4bbdfSmrg DDXPointPtr r; 27435c4bbdfSmrg 27535c4bbdfSmrg/* Always called with numSpans > 1 */ 27635c4bbdfSmrg/* Sorts only by x, as all y should be the same */ 27735c4bbdfSmrg 27835c4bbdfSmrg#define ExchangeSpans(a, b) \ 27935c4bbdfSmrg{ \ 28035c4bbdfSmrg DDXPointRec tpt; \ 28135c4bbdfSmrg int tw; \ 28235c4bbdfSmrg \ 28335c4bbdfSmrg tpt = points[a]; points[a] = points[b]; points[b] = tpt; \ 28435c4bbdfSmrg tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ 28535c4bbdfSmrg} 28635c4bbdfSmrg 28735c4bbdfSmrg do { 28835c4bbdfSmrg if (numSpans < 9) { 28935c4bbdfSmrg /* Do insertion sort */ 29035c4bbdfSmrg int xprev; 29135c4bbdfSmrg 29235c4bbdfSmrg xprev = points[0].x; 29335c4bbdfSmrg i = 1; 29435c4bbdfSmrg do { /* while i != numSpans */ 29535c4bbdfSmrg x = points[i].x; 29635c4bbdfSmrg if (xprev > x) { 29735c4bbdfSmrg /* points[i] is out of order. Move into proper location. */ 29835c4bbdfSmrg DDXPointRec tpt; 29935c4bbdfSmrg int tw, k; 30035c4bbdfSmrg 30135c4bbdfSmrg for (j = 0; x >= points[j].x; j++) { 30235c4bbdfSmrg } 30335c4bbdfSmrg tpt = points[i]; 30435c4bbdfSmrg tw = widths[i]; 30535c4bbdfSmrg for (k = i; k != j; k--) { 30635c4bbdfSmrg points[k] = points[k - 1]; 30735c4bbdfSmrg widths[k] = widths[k - 1]; 30835c4bbdfSmrg } 30935c4bbdfSmrg points[j] = tpt; 31035c4bbdfSmrg widths[j] = tw; 31135c4bbdfSmrg x = points[i].x; 31235c4bbdfSmrg } /* if out of order */ 31335c4bbdfSmrg xprev = x; 31435c4bbdfSmrg i++; 31535c4bbdfSmrg } while (i != numSpans); 31635c4bbdfSmrg return; 31735c4bbdfSmrg } 31835c4bbdfSmrg 31935c4bbdfSmrg /* Choose partition element, stick in location 0 */ 32035c4bbdfSmrg m = numSpans / 2; 32135c4bbdfSmrg if (points[m].x > points[0].x) 32235c4bbdfSmrg ExchangeSpans(m, 0); 32335c4bbdfSmrg if (points[m].x > points[numSpans - 1].x) 32435c4bbdfSmrg ExchangeSpans(m, numSpans - 1); 32535c4bbdfSmrg if (points[m].x > points[0].x) 32635c4bbdfSmrg ExchangeSpans(m, 0); 32735c4bbdfSmrg x = points[0].x; 32835c4bbdfSmrg 32935c4bbdfSmrg /* Partition array */ 33035c4bbdfSmrg i = 0; 33135c4bbdfSmrg j = numSpans; 33235c4bbdfSmrg do { 33335c4bbdfSmrg r = &(points[i]); 33435c4bbdfSmrg do { 33535c4bbdfSmrg r++; 33635c4bbdfSmrg i++; 33735c4bbdfSmrg } while (i != numSpans && r->x < x); 33835c4bbdfSmrg r = &(points[j]); 33935c4bbdfSmrg do { 34035c4bbdfSmrg r--; 34135c4bbdfSmrg j--; 34235c4bbdfSmrg } while (x < r->x); 34335c4bbdfSmrg if (i < j) 34435c4bbdfSmrg ExchangeSpans(i, j); 34535c4bbdfSmrg } while (i < j); 34635c4bbdfSmrg 34735c4bbdfSmrg /* Move partition element back to middle */ 34835c4bbdfSmrg ExchangeSpans(0, j); 34935c4bbdfSmrg 35035c4bbdfSmrg /* Recurse */ 35135c4bbdfSmrg if (numSpans - j - 1 > 1) 35235c4bbdfSmrg QuickSortSpansX(&points[j + 1], &widths[j + 1], numSpans - j - 1); 35335c4bbdfSmrg numSpans = j; 35435c4bbdfSmrg } while (numSpans > 1); 35535c4bbdfSmrg} /* QuickSortSpans */ 35635c4bbdfSmrg 35735c4bbdfSmrgstatic int 35835c4bbdfSmrgUniquifySpansX(Spans * spans, DDXPointRec * newPoints, int *newWidths) 35935c4bbdfSmrg{ 36035c4bbdfSmrg int newx1, newx2, oldpt, i, y; 36135c4bbdfSmrg DDXPointRec *oldPoints; 36235c4bbdfSmrg int *oldWidths; 36335c4bbdfSmrg int *startNewWidths; 36435c4bbdfSmrg 36535c4bbdfSmrg/* Always called with numSpans > 1 */ 36635c4bbdfSmrg/* Uniquify the spans, and stash them into newPoints and newWidths. Return the 36735c4bbdfSmrg number of unique spans. */ 36835c4bbdfSmrg 36935c4bbdfSmrg startNewWidths = newWidths; 37035c4bbdfSmrg 37135c4bbdfSmrg oldPoints = spans->points; 37235c4bbdfSmrg oldWidths = spans->widths; 37335c4bbdfSmrg 37435c4bbdfSmrg y = oldPoints->y; 37535c4bbdfSmrg newx1 = oldPoints->x; 37635c4bbdfSmrg newx2 = newx1 + *oldWidths; 37735c4bbdfSmrg 37835c4bbdfSmrg for (i = spans->count - 1; i != 0; i--) { 37935c4bbdfSmrg oldPoints++; 38035c4bbdfSmrg oldWidths++; 38135c4bbdfSmrg oldpt = oldPoints->x; 38235c4bbdfSmrg if (oldpt > newx2) { 38335c4bbdfSmrg /* Write current span, start a new one */ 38435c4bbdfSmrg newPoints->x = newx1; 38535c4bbdfSmrg newPoints->y = y; 38635c4bbdfSmrg *newWidths = newx2 - newx1; 38735c4bbdfSmrg newPoints++; 38835c4bbdfSmrg newWidths++; 38935c4bbdfSmrg newx1 = oldpt; 39035c4bbdfSmrg newx2 = oldpt + *oldWidths; 39135c4bbdfSmrg } 39235c4bbdfSmrg else { 39335c4bbdfSmrg /* extend current span, if old extends beyond new */ 39435c4bbdfSmrg oldpt = oldpt + *oldWidths; 39535c4bbdfSmrg if (oldpt > newx2) 39635c4bbdfSmrg newx2 = oldpt; 39735c4bbdfSmrg } 39835c4bbdfSmrg } /* for */ 39935c4bbdfSmrg 40035c4bbdfSmrg /* Write final span */ 40135c4bbdfSmrg newPoints->x = newx1; 40235c4bbdfSmrg *newWidths = newx2 - newx1; 40335c4bbdfSmrg newPoints->y = y; 40435c4bbdfSmrg 40535c4bbdfSmrg return (newWidths - startNewWidths) + 1; 40635c4bbdfSmrg} /* UniquifySpansX */ 40735c4bbdfSmrg 40835c4bbdfSmrgstatic void 40935c4bbdfSmrgmiDisposeSpanGroup(SpanGroup * spanGroup) 41035c4bbdfSmrg{ 41135c4bbdfSmrg int i; 41235c4bbdfSmrg Spans *spans; 41335c4bbdfSmrg 41435c4bbdfSmrg for (i = 0; i < spanGroup->count; i++) { 41535c4bbdfSmrg spans = spanGroup->group + i; 41635c4bbdfSmrg free(spans->points); 41735c4bbdfSmrg free(spans->widths); 41835c4bbdfSmrg } 41935c4bbdfSmrg} 42035c4bbdfSmrg 42135c4bbdfSmrgstatic void 42235c4bbdfSmrgmiFillUniqueSpanGroup(DrawablePtr pDraw, GCPtr pGC, SpanGroup * spanGroup) 42335c4bbdfSmrg{ 42435c4bbdfSmrg int i; 42535c4bbdfSmrg Spans *spans; 42635c4bbdfSmrg Spans *yspans; 42735c4bbdfSmrg int *ysizes; 42835c4bbdfSmrg int ymin, ylength; 42935c4bbdfSmrg 43035c4bbdfSmrg /* Outgoing spans for one big call to FillSpans */ 43135c4bbdfSmrg DDXPointPtr points; 43235c4bbdfSmrg int *widths; 43335c4bbdfSmrg int count; 43435c4bbdfSmrg 43535c4bbdfSmrg if (spanGroup->count == 0) 43635c4bbdfSmrg return; 43735c4bbdfSmrg 43835c4bbdfSmrg if (spanGroup->count == 1) { 43935c4bbdfSmrg /* Already should be sorted, unique */ 44035c4bbdfSmrg spans = spanGroup->group; 44135c4bbdfSmrg (*pGC->ops->FillSpans) 44235c4bbdfSmrg (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE); 44335c4bbdfSmrg free(spans->points); 44435c4bbdfSmrg free(spans->widths); 44535c4bbdfSmrg } 44635c4bbdfSmrg else { 44735c4bbdfSmrg /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */ 44835c4bbdfSmrg /* This seems to be the fastest thing to do. I've tried sorting on 44935c4bbdfSmrg both x and y at the same time rather than creating into all those 45035c4bbdfSmrg y buckets, but it was somewhat slower. */ 45135c4bbdfSmrg 45235c4bbdfSmrg ymin = spanGroup->ymin; 45335c4bbdfSmrg ylength = spanGroup->ymax - ymin + 1; 45435c4bbdfSmrg 45535c4bbdfSmrg /* Allocate Spans for y buckets */ 45635c4bbdfSmrg yspans = xallocarray(ylength, sizeof(Spans)); 45735c4bbdfSmrg ysizes = xallocarray(ylength, sizeof(int)); 45835c4bbdfSmrg 45935c4bbdfSmrg if (!yspans || !ysizes) { 46035c4bbdfSmrg free(yspans); 46135c4bbdfSmrg free(ysizes); 46235c4bbdfSmrg miDisposeSpanGroup(spanGroup); 46335c4bbdfSmrg return; 46435c4bbdfSmrg } 46535c4bbdfSmrg 46635c4bbdfSmrg for (i = 0; i != ylength; i++) { 46735c4bbdfSmrg ysizes[i] = 0; 46835c4bbdfSmrg yspans[i].count = 0; 46935c4bbdfSmrg yspans[i].points = NULL; 47035c4bbdfSmrg yspans[i].widths = NULL; 47135c4bbdfSmrg } 47235c4bbdfSmrg 47335c4bbdfSmrg /* Go through every single span and put it into the correct bucket */ 47435c4bbdfSmrg count = 0; 47535c4bbdfSmrg for (i = 0, spans = spanGroup->group; 47635c4bbdfSmrg i != spanGroup->count; i++, spans++) { 47735c4bbdfSmrg int index; 47835c4bbdfSmrg int j; 47935c4bbdfSmrg 48035c4bbdfSmrg for (j = 0, points = spans->points, widths = spans->widths; 48135c4bbdfSmrg j != spans->count; j++, points++, widths++) { 48235c4bbdfSmrg index = points->y - ymin; 48335c4bbdfSmrg if (index >= 0 && index < ylength) { 48435c4bbdfSmrg Spans *newspans = &(yspans[index]); 48535c4bbdfSmrg 48635c4bbdfSmrg if (newspans->count == ysizes[index]) { 48735c4bbdfSmrg DDXPointPtr newpoints; 48835c4bbdfSmrg int *newwidths; 48935c4bbdfSmrg 49035c4bbdfSmrg ysizes[index] = (ysizes[index] + 8) * 2; 49135c4bbdfSmrg newpoints = reallocarray(newspans->points, 49235c4bbdfSmrg ysizes[index], 49335c4bbdfSmrg sizeof(DDXPointRec)); 49435c4bbdfSmrg newwidths = reallocarray(newspans->widths, 49535c4bbdfSmrg ysizes[index], sizeof(int)); 49635c4bbdfSmrg if (!newpoints || !newwidths) { 49735c4bbdfSmrg for (i = 0; i < ylength; i++) { 49835c4bbdfSmrg free(yspans[i].points); 49935c4bbdfSmrg free(yspans[i].widths); 50035c4bbdfSmrg } 50135c4bbdfSmrg free(yspans); 50235c4bbdfSmrg free(ysizes); 50335c4bbdfSmrg free(newpoints); 50435c4bbdfSmrg free(newwidths); 50535c4bbdfSmrg miDisposeSpanGroup(spanGroup); 50635c4bbdfSmrg return; 50735c4bbdfSmrg } 50835c4bbdfSmrg newspans->points = newpoints; 50935c4bbdfSmrg newspans->widths = newwidths; 51035c4bbdfSmrg } 51135c4bbdfSmrg newspans->points[newspans->count] = *points; 51235c4bbdfSmrg newspans->widths[newspans->count] = *widths; 51335c4bbdfSmrg (newspans->count)++; 51435c4bbdfSmrg } /* if y value of span in range */ 51535c4bbdfSmrg } /* for j through spans */ 51635c4bbdfSmrg count += spans->count; 51735c4bbdfSmrg free(spans->points); 51835c4bbdfSmrg spans->points = NULL; 51935c4bbdfSmrg free(spans->widths); 52035c4bbdfSmrg spans->widths = NULL; 52135c4bbdfSmrg } /* for i thorough Spans */ 52235c4bbdfSmrg 52335c4bbdfSmrg /* Now sort by x and uniquify each bucket into the final array */ 52435c4bbdfSmrg points = xallocarray(count, sizeof(DDXPointRec)); 52535c4bbdfSmrg widths = xallocarray(count, sizeof(int)); 52635c4bbdfSmrg if (!points || !widths) { 52735c4bbdfSmrg for (i = 0; i < ylength; i++) { 52835c4bbdfSmrg free(yspans[i].points); 52935c4bbdfSmrg free(yspans[i].widths); 53035c4bbdfSmrg } 53135c4bbdfSmrg free(yspans); 53235c4bbdfSmrg free(ysizes); 53335c4bbdfSmrg free(points); 53435c4bbdfSmrg free(widths); 53535c4bbdfSmrg return; 53635c4bbdfSmrg } 53735c4bbdfSmrg count = 0; 53835c4bbdfSmrg for (i = 0; i != ylength; i++) { 53935c4bbdfSmrg int ycount = yspans[i].count; 54035c4bbdfSmrg 54135c4bbdfSmrg if (ycount > 0) { 54235c4bbdfSmrg if (ycount > 1) { 54335c4bbdfSmrg QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount); 54435c4bbdfSmrg count += UniquifySpansX 54535c4bbdfSmrg (&(yspans[i]), &(points[count]), &(widths[count])); 54635c4bbdfSmrg } 54735c4bbdfSmrg else { 54835c4bbdfSmrg points[count] = yspans[i].points[0]; 54935c4bbdfSmrg widths[count] = yspans[i].widths[0]; 55035c4bbdfSmrg count++; 55135c4bbdfSmrg } 55235c4bbdfSmrg free(yspans[i].points); 55335c4bbdfSmrg free(yspans[i].widths); 55435c4bbdfSmrg } 55535c4bbdfSmrg } 55635c4bbdfSmrg 55735c4bbdfSmrg (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE); 55835c4bbdfSmrg free(points); 55935c4bbdfSmrg free(widths); 56035c4bbdfSmrg free(yspans); 56135c4bbdfSmrg free(ysizes); /* use (DE)xalloc for these? */ 56235c4bbdfSmrg } 56335c4bbdfSmrg 56435c4bbdfSmrg spanGroup->count = 0; 56535c4bbdfSmrg spanGroup->ymin = MAXSHORT; 56635c4bbdfSmrg spanGroup->ymax = MINSHORT; 56735c4bbdfSmrg} 56835c4bbdfSmrg 5696747b715Smrgstatic Bool 57035c4bbdfSmrgInitSpans(Spans * spans, size_t nspans) 5716747b715Smrg{ 57235c4bbdfSmrg spans->points = xallocarray(nspans, sizeof(*spans->points)); 5736747b715Smrg if (!spans->points) 57435c4bbdfSmrg return FALSE; 57535c4bbdfSmrg spans->widths = xallocarray(nspans, sizeof(*spans->widths)); 57635c4bbdfSmrg if (!spans->widths) { 57735c4bbdfSmrg free(spans->points); 57835c4bbdfSmrg return FALSE; 5796747b715Smrg } 5806747b715Smrg return TRUE; 5816747b715Smrg} 5826747b715Smrg 5836747b715Smrg/* 5846747b715Smrg * interface data to span-merging polygon filler 5856747b715Smrg */ 5866747b715Smrg 5876747b715Smrgtypedef struct _SpanData { 58835c4bbdfSmrg SpanGroup fgGroup, bgGroup; 5896747b715Smrg} SpanDataRec, *SpanDataPtr; 5906747b715Smrg 5916747b715Smrgstatic void 59235c4bbdfSmrgAppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans * spanPtr, 59335c4bbdfSmrg SpanDataPtr spanData) 5946747b715Smrg{ 5956747b715Smrg SpanGroup *group, *othergroup = NULL; 59635c4bbdfSmrg 59735c4bbdfSmrg if (pixel == pGC->fgPixel) { 59835c4bbdfSmrg group = &spanData->fgGroup; 59935c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash) 60035c4bbdfSmrg othergroup = &spanData->bgGroup; 6016747b715Smrg } 60235c4bbdfSmrg else { 60335c4bbdfSmrg group = &spanData->bgGroup; 60435c4bbdfSmrg othergroup = &spanData->fgGroup; 6056747b715Smrg } 60635c4bbdfSmrg miAppendSpans(group, othergroup, spanPtr); 6076747b715Smrg} 6086747b715Smrg 60905b261ecSmrgstatic void miLineArc(DrawablePtr pDraw, GCPtr pGC, 61035c4bbdfSmrg unsigned long pixel, SpanDataPtr spanData, 61135c4bbdfSmrg LineFacePtr leftFace, 61235c4bbdfSmrg LineFacePtr rightFace, 61335c4bbdfSmrg double xorg, double yorg, Bool isInt); 61405b261ecSmrg 61505b261ecSmrg/* 61605b261ecSmrg * spans-based polygon filler 61705b261ecSmrg */ 61805b261ecSmrg 6196747b715Smrgstatic void 62035c4bbdfSmrgfillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans * spans, 62135c4bbdfSmrg SpanDataPtr spanData) 6226747b715Smrg{ 62335c4bbdfSmrg if (!spanData) { 62435c4bbdfSmrg ChangeGCVal oldPixel, tmpPixel; 62535c4bbdfSmrg 62635c4bbdfSmrg oldPixel.val = pGC->fgPixel; 62735c4bbdfSmrg if (pixel != oldPixel.val) { 62835c4bbdfSmrg tmpPixel.val = (XID) pixel; 62935c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &tmpPixel); 63035c4bbdfSmrg ValidateGC(pDrawable, pGC); 63135c4bbdfSmrg } 63235c4bbdfSmrg (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points, 63335c4bbdfSmrg spans->widths, TRUE); 63435c4bbdfSmrg free(spans->widths); 63535c4bbdfSmrg free(spans->points); 63635c4bbdfSmrg if (pixel != oldPixel.val) { 63735c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &oldPixel); 63835c4bbdfSmrg ValidateGC(pDrawable, pGC); 63935c4bbdfSmrg } 6406747b715Smrg } 6416747b715Smrg else 64235c4bbdfSmrg AppendSpanGroup(pGC, pixel, spans, spanData); 6436747b715Smrg} 6446747b715Smrg 64505b261ecSmrgstatic void 64635c4bbdfSmrgmiFillPolyHelper(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, 64735c4bbdfSmrg SpanDataPtr spanData, int y, int overall_height, 64835c4bbdfSmrg PolyEdgePtr left, PolyEdgePtr right, 64935c4bbdfSmrg int left_count, int right_count) 65005b261ecSmrg{ 65105b261ecSmrg int left_x = 0, left_e = 0; 65235c4bbdfSmrg int left_stepx = 0; 65335c4bbdfSmrg int left_signdx = 0; 65435c4bbdfSmrg int left_dy = 0, left_dx = 0; 65505b261ecSmrg 65605b261ecSmrg int right_x = 0, right_e = 0; 65735c4bbdfSmrg int right_stepx = 0; 65835c4bbdfSmrg int right_signdx = 0; 65935c4bbdfSmrg int right_dy = 0, right_dx = 0; 66005b261ecSmrg 66135c4bbdfSmrg int height = 0; 66235c4bbdfSmrg int left_height = 0, right_height = 0; 66305b261ecSmrg 66405b261ecSmrg DDXPointPtr ppt; 66535c4bbdfSmrg int *pwidth; 66635c4bbdfSmrg int xorg; 66735c4bbdfSmrg Spans spanRec; 66805b261ecSmrg 6696747b715Smrg if (!InitSpans(&spanRec, overall_height)) 67035c4bbdfSmrg return; 6716747b715Smrg ppt = spanRec.points; 6726747b715Smrg pwidth = spanRec.widths; 67305b261ecSmrg 67405b261ecSmrg xorg = 0; 67535c4bbdfSmrg if (pGC->miTranslate) { 67635c4bbdfSmrg y += pDrawable->y; 67735c4bbdfSmrg xorg = pDrawable->x; 67835c4bbdfSmrg } 67935c4bbdfSmrg while ((left_count || left_height) && (right_count || right_height)) { 68035c4bbdfSmrg if (!left_height && left_count) { 68135c4bbdfSmrg left_height = left->height; 68235c4bbdfSmrg left_x = left->x; 68335c4bbdfSmrg left_stepx = left->stepx; 68435c4bbdfSmrg left_signdx = left->signdx; 68535c4bbdfSmrg left_e = left->e; 68635c4bbdfSmrg left_dy = left->dy; 68735c4bbdfSmrg left_dx = left->dx; 68835c4bbdfSmrg --left_count; 68935c4bbdfSmrg ++left; 69035c4bbdfSmrg } 69135c4bbdfSmrg 69235c4bbdfSmrg if (!right_height && right_count) { 69335c4bbdfSmrg right_height = right->height; 69435c4bbdfSmrg right_x = right->x; 69535c4bbdfSmrg right_stepx = right->stepx; 69635c4bbdfSmrg right_signdx = right->signdx; 69735c4bbdfSmrg right_e = right->e; 69835c4bbdfSmrg right_dy = right->dy; 69935c4bbdfSmrg right_dx = right->dx; 70035c4bbdfSmrg --right_count; 70135c4bbdfSmrg ++right; 70235c4bbdfSmrg } 70335c4bbdfSmrg 70435c4bbdfSmrg height = left_height; 70535c4bbdfSmrg if (height > right_height) 70635c4bbdfSmrg height = right_height; 70735c4bbdfSmrg 70835c4bbdfSmrg left_height -= height; 70935c4bbdfSmrg right_height -= height; 71035c4bbdfSmrg 71135c4bbdfSmrg while (--height >= 0) { 71235c4bbdfSmrg if (right_x >= left_x) { 71335c4bbdfSmrg ppt->y = y; 71435c4bbdfSmrg ppt->x = left_x + xorg; 71535c4bbdfSmrg ppt++; 71635c4bbdfSmrg *pwidth++ = right_x - left_x + 1; 71735c4bbdfSmrg } 71835c4bbdfSmrg y++; 71935c4bbdfSmrg 72035c4bbdfSmrg left_x += left_stepx; 72135c4bbdfSmrg left_e += left_dx; 72235c4bbdfSmrg if (left_e > 0) { 72335c4bbdfSmrg left_x += left_signdx; 72435c4bbdfSmrg left_e -= left_dy; 72535c4bbdfSmrg } 72635c4bbdfSmrg 72735c4bbdfSmrg right_x += right_stepx; 72835c4bbdfSmrg right_e += right_dx; 72935c4bbdfSmrg if (right_e > 0) { 73035c4bbdfSmrg right_x += right_signdx; 73135c4bbdfSmrg right_e -= right_dy; 73235c4bbdfSmrg } 73335c4bbdfSmrg } 73405b261ecSmrg } 7356747b715Smrg spanRec.count = ppt - spanRec.points; 73635c4bbdfSmrg fillSpans(pDrawable, pGC, pixel, &spanRec, spanData); 73705b261ecSmrg} 73805b261ecSmrg 73905b261ecSmrgstatic void 74035c4bbdfSmrgmiFillRectPolyHelper(DrawablePtr pDrawable, 74135c4bbdfSmrg GCPtr pGC, 74235c4bbdfSmrg unsigned long pixel, 74335c4bbdfSmrg SpanDataPtr spanData, int x, int y, int w, int h) 74405b261ecSmrg{ 74505b261ecSmrg DDXPointPtr ppt; 74635c4bbdfSmrg int *pwidth; 74735c4bbdfSmrg ChangeGCVal oldPixel, tmpPixel; 74835c4bbdfSmrg Spans spanRec; 74935c4bbdfSmrg xRectangle rect; 75035c4bbdfSmrg 75135c4bbdfSmrg if (!spanData) { 75235c4bbdfSmrg rect.x = x; 75335c4bbdfSmrg rect.y = y; 75435c4bbdfSmrg rect.width = w; 75535c4bbdfSmrg rect.height = h; 75635c4bbdfSmrg oldPixel.val = pGC->fgPixel; 75735c4bbdfSmrg if (pixel != oldPixel.val) { 75835c4bbdfSmrg tmpPixel.val = (XID) pixel; 75935c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &tmpPixel); 76035c4bbdfSmrg ValidateGC(pDrawable, pGC); 76135c4bbdfSmrg } 76235c4bbdfSmrg (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect); 76335c4bbdfSmrg if (pixel != oldPixel.val) { 76435c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &oldPixel); 76535c4bbdfSmrg ValidateGC(pDrawable, pGC); 76635c4bbdfSmrg } 76735c4bbdfSmrg } 76835c4bbdfSmrg else { 76935c4bbdfSmrg if (!InitSpans(&spanRec, h)) 77035c4bbdfSmrg return; 77135c4bbdfSmrg ppt = spanRec.points; 77235c4bbdfSmrg pwidth = spanRec.widths; 77335c4bbdfSmrg 77435c4bbdfSmrg if (pGC->miTranslate) { 77535c4bbdfSmrg y += pDrawable->y; 77635c4bbdfSmrg x += pDrawable->x; 77735c4bbdfSmrg } 77835c4bbdfSmrg while (h--) { 77935c4bbdfSmrg ppt->x = x; 78035c4bbdfSmrg ppt->y = y; 78135c4bbdfSmrg ppt++; 78235c4bbdfSmrg *pwidth++ = w; 78335c4bbdfSmrg y++; 78435c4bbdfSmrg } 78535c4bbdfSmrg spanRec.count = ppt - spanRec.points; 78635c4bbdfSmrg AppendSpanGroup(pGC, pixel, &spanRec, spanData); 78705b261ecSmrg } 78805b261ecSmrg} 78905b261ecSmrg 79035c4bbdfSmrgstatic int 79135c4bbdfSmrgmiPolyBuildEdge(double x0, double y0, double k, /* x0 * dy - y0 * dx */ 79235c4bbdfSmrg int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge) 79305b261ecSmrg{ 79435c4bbdfSmrg int x, y, e; 79535c4bbdfSmrg int xady; 79605b261ecSmrg 79735c4bbdfSmrg if (dy < 0) { 79835c4bbdfSmrg dy = -dy; 79935c4bbdfSmrg dx = -dx; 80035c4bbdfSmrg k = -k; 80105b261ecSmrg } 80205b261ecSmrg 80305b261ecSmrg#ifdef NOTDEF 80405b261ecSmrg { 80535c4bbdfSmrg double realk, kerror; 80635c4bbdfSmrg 80735c4bbdfSmrg realk = x0 * dy - y0 * dx; 80835c4bbdfSmrg kerror = fabs(realk - k); 80935c4bbdfSmrg if (kerror > .1) 81035c4bbdfSmrg printf("realk: %g k: %g\n", realk, k); 81105b261ecSmrg } 81205b261ecSmrg#endif 81335c4bbdfSmrg y = ICEIL(y0); 81435c4bbdfSmrg xady = ICEIL(k) + y * dx; 81505b261ecSmrg 81605b261ecSmrg if (xady <= 0) 81735c4bbdfSmrg x = -(-xady / dy) - 1; 81805b261ecSmrg else 81935c4bbdfSmrg x = (xady - 1) / dy; 82005b261ecSmrg 82105b261ecSmrg e = xady - x * dy; 82205b261ecSmrg 82335c4bbdfSmrg if (dx >= 0) { 82435c4bbdfSmrg edge->signdx = 1; 82535c4bbdfSmrg edge->stepx = dx / dy; 82635c4bbdfSmrg edge->dx = dx % dy; 82705b261ecSmrg } 82835c4bbdfSmrg else { 82935c4bbdfSmrg edge->signdx = -1; 83035c4bbdfSmrg edge->stepx = -(-dx / dy); 83135c4bbdfSmrg edge->dx = -dx % dy; 83235c4bbdfSmrg e = dy - e + 1; 83305b261ecSmrg } 83405b261ecSmrg edge->dy = dy; 83505b261ecSmrg edge->x = x + left + xi; 83635c4bbdfSmrg edge->e = e - dy; /* bias to compare against 0 instead of dy */ 83705b261ecSmrg return y + yi; 83805b261ecSmrg} 83905b261ecSmrg 84005b261ecSmrg#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr))) 84105b261ecSmrg 84235c4bbdfSmrgstatic int 84335c4bbdfSmrgmiPolyBuildPoly(PolyVertexPtr vertices, 84435c4bbdfSmrg PolySlopePtr slopes, 84535c4bbdfSmrg int count, 84635c4bbdfSmrg int xi, 84735c4bbdfSmrg int yi, 84835c4bbdfSmrg PolyEdgePtr left, 84935c4bbdfSmrg PolyEdgePtr right, int *pnleft, int *pnright, int *h) 85005b261ecSmrg{ 85135c4bbdfSmrg int top, bottom; 85235c4bbdfSmrg double miny, maxy; 85335c4bbdfSmrg int i; 85435c4bbdfSmrg int j; 85535c4bbdfSmrg int clockwise; 85635c4bbdfSmrg int slopeoff; 85735c4bbdfSmrg int s; 85835c4bbdfSmrg int nright, nleft; 85935c4bbdfSmrg int y, lasty = 0, bottomy, topy = 0; 86005b261ecSmrg 86105b261ecSmrg /* find the top of the polygon */ 86205b261ecSmrg maxy = miny = vertices[0].y; 86305b261ecSmrg bottom = top = 0; 86435c4bbdfSmrg for (i = 1; i < count; i++) { 86535c4bbdfSmrg if (vertices[i].y < miny) { 86635c4bbdfSmrg top = i; 86735c4bbdfSmrg miny = vertices[i].y; 86835c4bbdfSmrg } 86935c4bbdfSmrg if (vertices[i].y >= maxy) { 87035c4bbdfSmrg bottom = i; 87135c4bbdfSmrg maxy = vertices[i].y; 87235c4bbdfSmrg } 87305b261ecSmrg } 87405b261ecSmrg clockwise = 1; 87505b261ecSmrg slopeoff = 0; 87605b261ecSmrg 87705b261ecSmrg i = top; 87835c4bbdfSmrg j = StepAround(top, -1, count); 87905b261ecSmrg 88035c4bbdfSmrg if ((int64_t) slopes[j].dy * slopes[i].dx > 88135c4bbdfSmrg (int64_t) slopes[i].dy * slopes[j].dx) { 88235c4bbdfSmrg clockwise = -1; 88335c4bbdfSmrg slopeoff = -1; 88405b261ecSmrg } 88505b261ecSmrg 88635c4bbdfSmrg bottomy = ICEIL(maxy) + yi; 88705b261ecSmrg 88805b261ecSmrg nright = 0; 88905b261ecSmrg 89035c4bbdfSmrg s = StepAround(top, slopeoff, count); 89105b261ecSmrg i = top; 89235c4bbdfSmrg while (i != bottom) { 89335c4bbdfSmrg if (slopes[s].dy != 0) { 89435c4bbdfSmrg y = miPolyBuildEdge(vertices[i].x, vertices[i].y, 89535c4bbdfSmrg slopes[s].k, 89635c4bbdfSmrg slopes[s].dx, slopes[s].dy, 89735c4bbdfSmrg xi, yi, 0, &right[nright]); 89835c4bbdfSmrg if (nright != 0) 89935c4bbdfSmrg right[nright - 1].height = y - lasty; 90035c4bbdfSmrg else 90135c4bbdfSmrg topy = y; 90235c4bbdfSmrg nright++; 90335c4bbdfSmrg lasty = y; 90435c4bbdfSmrg } 90535c4bbdfSmrg 90635c4bbdfSmrg i = StepAround(i, clockwise, count); 90735c4bbdfSmrg s = StepAround(s, clockwise, count); 90805b261ecSmrg } 90905b261ecSmrg if (nright != 0) 91035c4bbdfSmrg right[nright - 1].height = bottomy - lasty; 91105b261ecSmrg 91205b261ecSmrg if (slopeoff == 0) 91335c4bbdfSmrg slopeoff = -1; 91405b261ecSmrg else 91535c4bbdfSmrg slopeoff = 0; 91605b261ecSmrg 91705b261ecSmrg nleft = 0; 91835c4bbdfSmrg s = StepAround(top, slopeoff, count); 91905b261ecSmrg i = top; 92035c4bbdfSmrg while (i != bottom) { 92135c4bbdfSmrg if (slopes[s].dy != 0) { 92235c4bbdfSmrg y = miPolyBuildEdge(vertices[i].x, vertices[i].y, 92335c4bbdfSmrg slopes[s].k, 92435c4bbdfSmrg slopes[s].dx, slopes[s].dy, xi, yi, 1, 92535c4bbdfSmrg &left[nleft]); 92635c4bbdfSmrg 92735c4bbdfSmrg if (nleft != 0) 92835c4bbdfSmrg left[nleft - 1].height = y - lasty; 92935c4bbdfSmrg nleft++; 93035c4bbdfSmrg lasty = y; 93135c4bbdfSmrg } 93235c4bbdfSmrg i = StepAround(i, -clockwise, count); 93335c4bbdfSmrg s = StepAround(s, -clockwise, count); 93405b261ecSmrg } 93505b261ecSmrg if (nleft != 0) 93635c4bbdfSmrg left[nleft - 1].height = bottomy - lasty; 93705b261ecSmrg *pnleft = nleft; 93805b261ecSmrg *pnright = nright; 93905b261ecSmrg *h = bottomy - topy; 94005b261ecSmrg return topy; 94105b261ecSmrg} 94205b261ecSmrg 94305b261ecSmrgstatic void 94435c4bbdfSmrgmiLineOnePoint(DrawablePtr pDrawable, 94535c4bbdfSmrg GCPtr pGC, 94635c4bbdfSmrg unsigned long pixel, SpanDataPtr spanData, int x, int y) 94705b261ecSmrg{ 94805b261ecSmrg DDXPointRec pt; 94935c4bbdfSmrg int wid; 95035c4bbdfSmrg unsigned long oldPixel; 95135c4bbdfSmrg 95235c4bbdfSmrg MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel); 95335c4bbdfSmrg if (pGC->fillStyle == FillSolid) { 95435c4bbdfSmrg pt.x = x; 95535c4bbdfSmrg pt.y = y; 95635c4bbdfSmrg (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt); 95735c4bbdfSmrg } 95835c4bbdfSmrg else { 95935c4bbdfSmrg wid = 1; 96035c4bbdfSmrg if (pGC->miTranslate) { 96135c4bbdfSmrg x += pDrawable->x; 96235c4bbdfSmrg y += pDrawable->y; 96335c4bbdfSmrg } 96435c4bbdfSmrg pt.x = x; 96535c4bbdfSmrg pt.y = y; 96635c4bbdfSmrg (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE); 96735c4bbdfSmrg } 96835c4bbdfSmrg MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel); 96905b261ecSmrg} 97005b261ecSmrg 97105b261ecSmrgstatic void 97235c4bbdfSmrgmiLineJoin(DrawablePtr pDrawable, 97335c4bbdfSmrg GCPtr pGC, 97435c4bbdfSmrg unsigned long pixel, 97535c4bbdfSmrg SpanDataPtr spanData, LineFacePtr pLeft, LineFacePtr pRight) 97605b261ecSmrg{ 97735c4bbdfSmrg double mx = 0, my = 0; 97835c4bbdfSmrg double denom = 0.0; 97935c4bbdfSmrg PolyVertexRec vertices[4]; 98035c4bbdfSmrg PolySlopeRec slopes[4]; 98135c4bbdfSmrg int edgecount; 98235c4bbdfSmrg PolyEdgeRec left[4], right[4]; 98335c4bbdfSmrg int nleft, nright; 98435c4bbdfSmrg int y, height; 98535c4bbdfSmrg int swapslopes; 98635c4bbdfSmrg int joinStyle = pGC->joinStyle; 98735c4bbdfSmrg int lw = pGC->lineWidth; 98805b261ecSmrg 98905b261ecSmrg if (lw == 1 && !spanData) { 99035c4bbdfSmrg /* See if one of the lines will draw the joining pixel */ 99135c4bbdfSmrg if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0)) 99235c4bbdfSmrg return; 99335c4bbdfSmrg if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0)) 99435c4bbdfSmrg return; 99535c4bbdfSmrg if (joinStyle != JoinRound) { 99635c4bbdfSmrg denom = 99735c4bbdfSmrg -pLeft->dx * (double) pRight->dy + 99835c4bbdfSmrg pRight->dx * (double) pLeft->dy; 99935c4bbdfSmrg if (denom == 0) 100035c4bbdfSmrg return; /* no join to draw */ 100135c4bbdfSmrg } 100235c4bbdfSmrg if (joinStyle != JoinMiter) { 100335c4bbdfSmrg miLineOnePoint(pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y); 100435c4bbdfSmrg return; 100535c4bbdfSmrg } 100635c4bbdfSmrg } 100735c4bbdfSmrg else { 100835c4bbdfSmrg if (joinStyle == JoinRound) { 100935c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 101035c4bbdfSmrg pLeft, pRight, (double) 0.0, (double) 0.0, TRUE); 101135c4bbdfSmrg return; 101235c4bbdfSmrg } 101335c4bbdfSmrg denom = 101435c4bbdfSmrg -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy; 101535c4bbdfSmrg if (denom == 0.0) 101635c4bbdfSmrg return; /* no join to draw */ 101705b261ecSmrg } 101805b261ecSmrg 101905b261ecSmrg swapslopes = 0; 102035c4bbdfSmrg if (denom > 0) { 102135c4bbdfSmrg pLeft->xa = -pLeft->xa; 102235c4bbdfSmrg pLeft->ya = -pLeft->ya; 102335c4bbdfSmrg pLeft->dx = -pLeft->dx; 102435c4bbdfSmrg pLeft->dy = -pLeft->dy; 102505b261ecSmrg } 102635c4bbdfSmrg else { 102735c4bbdfSmrg swapslopes = 1; 102835c4bbdfSmrg pRight->xa = -pRight->xa; 102935c4bbdfSmrg pRight->ya = -pRight->ya; 103035c4bbdfSmrg pRight->dx = -pRight->dx; 103135c4bbdfSmrg pRight->dy = -pRight->dy; 103205b261ecSmrg } 103305b261ecSmrg 103405b261ecSmrg vertices[0].x = pRight->xa; 103505b261ecSmrg vertices[0].y = pRight->ya; 103605b261ecSmrg slopes[0].dx = -pRight->dy; 103735c4bbdfSmrg slopes[0].dy = pRight->dx; 103805b261ecSmrg slopes[0].k = 0; 103905b261ecSmrg 104005b261ecSmrg vertices[1].x = 0; 104105b261ecSmrg vertices[1].y = 0; 104235c4bbdfSmrg slopes[1].dx = pLeft->dy; 104305b261ecSmrg slopes[1].dy = -pLeft->dx; 104405b261ecSmrg slopes[1].k = 0; 104505b261ecSmrg 104605b261ecSmrg vertices[2].x = pLeft->xa; 104705b261ecSmrg vertices[2].y = pLeft->ya; 104805b261ecSmrg 104935c4bbdfSmrg if (joinStyle == JoinMiter) { 105035c4bbdfSmrg my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) - 105135c4bbdfSmrg pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx)) / 105235c4bbdfSmrg denom; 105335c4bbdfSmrg if (pLeft->dy != 0) { 105435c4bbdfSmrg mx = pLeft->xa + (my - pLeft->ya) * 105535c4bbdfSmrg (double) pLeft->dx / (double) pLeft->dy; 105635c4bbdfSmrg } 105735c4bbdfSmrg else { 105835c4bbdfSmrg mx = pRight->xa + (my - pRight->ya) * 105935c4bbdfSmrg (double) pRight->dx / (double) pRight->dy; 106035c4bbdfSmrg } 106135c4bbdfSmrg /* check miter limit */ 106235c4bbdfSmrg if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw) 106335c4bbdfSmrg joinStyle = JoinBevel; 106435c4bbdfSmrg } 106535c4bbdfSmrg 106635c4bbdfSmrg if (joinStyle == JoinMiter) { 106735c4bbdfSmrg slopes[2].dx = pLeft->dx; 106835c4bbdfSmrg slopes[2].dy = pLeft->dy; 106935c4bbdfSmrg slopes[2].k = pLeft->k; 107035c4bbdfSmrg if (swapslopes) { 107135c4bbdfSmrg slopes[2].dx = -slopes[2].dx; 107235c4bbdfSmrg slopes[2].dy = -slopes[2].dy; 107335c4bbdfSmrg slopes[2].k = -slopes[2].k; 107435c4bbdfSmrg } 107535c4bbdfSmrg vertices[3].x = mx; 107635c4bbdfSmrg vertices[3].y = my; 107735c4bbdfSmrg slopes[3].dx = pRight->dx; 107835c4bbdfSmrg slopes[3].dy = pRight->dy; 107935c4bbdfSmrg slopes[3].k = pRight->k; 108035c4bbdfSmrg if (swapslopes) { 108135c4bbdfSmrg slopes[3].dx = -slopes[3].dx; 108235c4bbdfSmrg slopes[3].dy = -slopes[3].dy; 108335c4bbdfSmrg slopes[3].k = -slopes[3].k; 108435c4bbdfSmrg } 108535c4bbdfSmrg edgecount = 4; 108635c4bbdfSmrg } 108735c4bbdfSmrg else { 108835c4bbdfSmrg double scale, dx, dy, adx, ady; 108935c4bbdfSmrg 109035c4bbdfSmrg adx = dx = pRight->xa - pLeft->xa; 109135c4bbdfSmrg ady = dy = pRight->ya - pLeft->ya; 109235c4bbdfSmrg if (adx < 0) 109335c4bbdfSmrg adx = -adx; 109435c4bbdfSmrg if (ady < 0) 109535c4bbdfSmrg ady = -ady; 109635c4bbdfSmrg scale = ady; 109735c4bbdfSmrg if (adx > ady) 109835c4bbdfSmrg scale = adx; 109935c4bbdfSmrg slopes[2].dx = (dx * 65536) / scale; 110035c4bbdfSmrg slopes[2].dy = (dy * 65536) / scale; 110135c4bbdfSmrg slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy - 110235c4bbdfSmrg (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0; 110335c4bbdfSmrg edgecount = 3; 110435c4bbdfSmrg } 110535c4bbdfSmrg 110635c4bbdfSmrg y = miPolyBuildPoly(vertices, slopes, edgecount, pLeft->x, pLeft->y, 110735c4bbdfSmrg left, right, &nleft, &nright, &height); 110835c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, height, left, right, 110935c4bbdfSmrg nleft, nright); 111005b261ecSmrg} 111105b261ecSmrg 111205b261ecSmrgstatic int 111335c4bbdfSmrgmiLineArcI(DrawablePtr pDraw, 111435c4bbdfSmrg GCPtr pGC, int xorg, int yorg, DDXPointPtr points, int *widths) 111505b261ecSmrg{ 111605b261ecSmrg DDXPointPtr tpts, bpts; 111705b261ecSmrg int *twids, *bwids; 111805b261ecSmrg int x, y, e, ex, slw; 111905b261ecSmrg 112005b261ecSmrg tpts = points; 112105b261ecSmrg twids = widths; 112235c4bbdfSmrg if (pGC->miTranslate) { 112335c4bbdfSmrg xorg += pDraw->x; 112435c4bbdfSmrg yorg += pDraw->y; 112505b261ecSmrg } 112605b261ecSmrg slw = pGC->lineWidth; 112735c4bbdfSmrg if (slw == 1) { 112835c4bbdfSmrg tpts->x = xorg; 112935c4bbdfSmrg tpts->y = yorg; 113035c4bbdfSmrg *twids = 1; 113135c4bbdfSmrg return 1; 113205b261ecSmrg } 113305b261ecSmrg bpts = tpts + slw; 113405b261ecSmrg bwids = twids + slw; 113505b261ecSmrg y = (slw >> 1) + 1; 113605b261ecSmrg if (slw & 1) 113735c4bbdfSmrg e = -((y << 2) + 3); 113805b261ecSmrg else 113935c4bbdfSmrg e = -(y << 3); 114005b261ecSmrg ex = -4; 114105b261ecSmrg x = 0; 114235c4bbdfSmrg while (y) { 114335c4bbdfSmrg e += (y << 3) - 4; 114435c4bbdfSmrg while (e >= 0) { 114535c4bbdfSmrg x++; 114635c4bbdfSmrg e += (ex = -((x << 3) + 4)); 114735c4bbdfSmrg } 114835c4bbdfSmrg y--; 114935c4bbdfSmrg slw = (x << 1) + 1; 115035c4bbdfSmrg if ((e == ex) && (slw > 1)) 115135c4bbdfSmrg slw--; 115235c4bbdfSmrg tpts->x = xorg - x; 115335c4bbdfSmrg tpts->y = yorg - y; 115435c4bbdfSmrg tpts++; 115535c4bbdfSmrg *twids++ = slw; 115635c4bbdfSmrg if ((y != 0) && ((slw > 1) || (e != ex))) { 115735c4bbdfSmrg bpts--; 115835c4bbdfSmrg bpts->x = xorg - x; 115935c4bbdfSmrg bpts->y = yorg + y; 116035c4bbdfSmrg *--bwids = slw; 116135c4bbdfSmrg } 116205b261ecSmrg } 11636747b715Smrg return pGC->lineWidth; 116405b261ecSmrg} 116505b261ecSmrg 116605b261ecSmrg#define CLIPSTEPEDGE(edgey,edge,edgeleft) \ 116705b261ecSmrg if (ybase == edgey) \ 116805b261ecSmrg { \ 116905b261ecSmrg if (edgeleft) \ 117005b261ecSmrg { \ 117105b261ecSmrg if (edge->x > xcl) \ 117205b261ecSmrg xcl = edge->x; \ 117305b261ecSmrg } \ 117405b261ecSmrg else \ 117505b261ecSmrg { \ 117605b261ecSmrg if (edge->x < xcr) \ 117705b261ecSmrg xcr = edge->x; \ 117805b261ecSmrg } \ 117905b261ecSmrg edgey++; \ 118005b261ecSmrg edge->x += edge->stepx; \ 118105b261ecSmrg edge->e += edge->dx; \ 118205b261ecSmrg if (edge->e > 0) \ 118305b261ecSmrg { \ 118405b261ecSmrg edge->x += edge->signdx; \ 118505b261ecSmrg edge->e -= edge->dy; \ 118605b261ecSmrg } \ 118705b261ecSmrg } 118805b261ecSmrg 118905b261ecSmrgstatic int 119035c4bbdfSmrgmiLineArcD(DrawablePtr pDraw, 119135c4bbdfSmrg GCPtr pGC, 119235c4bbdfSmrg double xorg, 119335c4bbdfSmrg double yorg, 119435c4bbdfSmrg DDXPointPtr points, 119535c4bbdfSmrg int *widths, 119635c4bbdfSmrg PolyEdgePtr edge1, 119735c4bbdfSmrg int edgey1, 119835c4bbdfSmrg Bool edgeleft1, PolyEdgePtr edge2, int edgey2, Bool edgeleft2) 119905b261ecSmrg{ 120005b261ecSmrg DDXPointPtr pts; 120105b261ecSmrg int *wids; 120205b261ecSmrg double radius, x0, y0, el, er, yk, xlk, xrk, k; 120305b261ecSmrg int xbase, ybase, y, boty, xl, xr, xcl, xcr; 120405b261ecSmrg int ymin, ymax; 120505b261ecSmrg Bool edge1IsMin, edge2IsMin; 120605b261ecSmrg int ymin1, ymin2; 120705b261ecSmrg 120805b261ecSmrg pts = points; 120905b261ecSmrg wids = widths; 121005b261ecSmrg xbase = floor(xorg); 121105b261ecSmrg x0 = xorg - xbase; 121235c4bbdfSmrg ybase = ICEIL(yorg); 121305b261ecSmrg y0 = yorg - ybase; 121435c4bbdfSmrg if (pGC->miTranslate) { 121535c4bbdfSmrg xbase += pDraw->x; 121635c4bbdfSmrg ybase += pDraw->y; 121735c4bbdfSmrg edge1->x += pDraw->x; 121835c4bbdfSmrg edge2->x += pDraw->x; 121935c4bbdfSmrg edgey1 += pDraw->y; 122035c4bbdfSmrg edgey2 += pDraw->y; 122105b261ecSmrg } 122205b261ecSmrg xlk = x0 + x0 + 1.0; 122305b261ecSmrg xrk = x0 + x0 - 1.0; 122405b261ecSmrg yk = y0 + y0 - 1.0; 122535c4bbdfSmrg radius = ((double) pGC->lineWidth) / 2.0; 122605b261ecSmrg y = floor(radius - y0 + 1.0); 122705b261ecSmrg ybase -= y; 122805b261ecSmrg ymin = ybase; 122905b261ecSmrg ymax = 65536; 123005b261ecSmrg edge1IsMin = FALSE; 123105b261ecSmrg ymin1 = edgey1; 123235c4bbdfSmrg if (edge1->dy >= 0) { 123335c4bbdfSmrg if (!edge1->dy) { 123435c4bbdfSmrg if (edgeleft1) 123535c4bbdfSmrg edge1IsMin = TRUE; 123635c4bbdfSmrg else 123735c4bbdfSmrg ymax = edgey1; 123835c4bbdfSmrg edgey1 = 65536; 123935c4bbdfSmrg } 124035c4bbdfSmrg else { 124135c4bbdfSmrg if ((edge1->signdx < 0) == edgeleft1) 124235c4bbdfSmrg edge1IsMin = TRUE; 124335c4bbdfSmrg } 124405b261ecSmrg } 124505b261ecSmrg edge2IsMin = FALSE; 124605b261ecSmrg ymin2 = edgey2; 124735c4bbdfSmrg if (edge2->dy >= 0) { 124835c4bbdfSmrg if (!edge2->dy) { 124935c4bbdfSmrg if (edgeleft2) 125035c4bbdfSmrg edge2IsMin = TRUE; 125135c4bbdfSmrg else 125235c4bbdfSmrg ymax = edgey2; 125335c4bbdfSmrg edgey2 = 65536; 125435c4bbdfSmrg } 125535c4bbdfSmrg else { 125635c4bbdfSmrg if ((edge2->signdx < 0) == edgeleft2) 125735c4bbdfSmrg edge2IsMin = TRUE; 125835c4bbdfSmrg } 125935c4bbdfSmrg } 126035c4bbdfSmrg if (edge1IsMin) { 126135c4bbdfSmrg ymin = ymin1; 126235c4bbdfSmrg if (edge2IsMin && ymin1 > ymin2) 126335c4bbdfSmrg ymin = ymin2; 126435c4bbdfSmrg } 126535c4bbdfSmrg else if (edge2IsMin) 126635c4bbdfSmrg ymin = ymin2; 126705b261ecSmrg el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0); 126805b261ecSmrg er = el + xrk; 126905b261ecSmrg xl = 1; 127005b261ecSmrg xr = 0; 127135c4bbdfSmrg if (x0 < 0.5) { 127235c4bbdfSmrg xl = 0; 127335c4bbdfSmrg el -= xlk; 127405b261ecSmrg } 127505b261ecSmrg boty = (y0 < -0.5) ? 1 : 0; 127605b261ecSmrg if (ybase + y - boty > ymax) 127735c4bbdfSmrg boty = ymax - ybase - y; 127835c4bbdfSmrg while (y > boty) { 127935c4bbdfSmrg k = (y << 1) + yk; 128035c4bbdfSmrg er += k; 128135c4bbdfSmrg while (er > 0.0) { 128235c4bbdfSmrg xr++; 128335c4bbdfSmrg er += xrk - (xr << 1); 128435c4bbdfSmrg } 128535c4bbdfSmrg el += k; 128635c4bbdfSmrg while (el >= 0.0) { 128735c4bbdfSmrg xl--; 128835c4bbdfSmrg el += (xl << 1) - xlk; 128935c4bbdfSmrg } 129035c4bbdfSmrg y--; 129135c4bbdfSmrg ybase++; 129235c4bbdfSmrg if (ybase < ymin) 129335c4bbdfSmrg continue; 129435c4bbdfSmrg xcl = xl + xbase; 129535c4bbdfSmrg xcr = xr + xbase; 129635c4bbdfSmrg CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 129735c4bbdfSmrg CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 129835c4bbdfSmrg if (xcr >= xcl) { 129935c4bbdfSmrg pts->x = xcl; 130035c4bbdfSmrg pts->y = ybase; 130135c4bbdfSmrg pts++; 130235c4bbdfSmrg *wids++ = xcr - xcl + 1; 130335c4bbdfSmrg } 130405b261ecSmrg } 130505b261ecSmrg er = xrk - (xr << 1) - er; 130605b261ecSmrg el = (xl << 1) - xlk - el; 130705b261ecSmrg boty = floor(-y0 - radius + 1.0); 130805b261ecSmrg if (ybase + y - boty > ymax) 130935c4bbdfSmrg boty = ymax - ybase - y; 131035c4bbdfSmrg while (y > boty) { 131135c4bbdfSmrg k = (y << 1) + yk; 131235c4bbdfSmrg er -= k; 131335c4bbdfSmrg while ((er >= 0.0) && (xr >= 0)) { 131435c4bbdfSmrg xr--; 131535c4bbdfSmrg er += xrk - (xr << 1); 131635c4bbdfSmrg } 131735c4bbdfSmrg el -= k; 131835c4bbdfSmrg while ((el > 0.0) && (xl <= 0)) { 131935c4bbdfSmrg xl++; 132035c4bbdfSmrg el += (xl << 1) - xlk; 132135c4bbdfSmrg } 132235c4bbdfSmrg y--; 132335c4bbdfSmrg ybase++; 132435c4bbdfSmrg if (ybase < ymin) 132535c4bbdfSmrg continue; 132635c4bbdfSmrg xcl = xl + xbase; 132735c4bbdfSmrg xcr = xr + xbase; 132835c4bbdfSmrg CLIPSTEPEDGE(edgey1, edge1, edgeleft1); 132935c4bbdfSmrg CLIPSTEPEDGE(edgey2, edge2, edgeleft2); 133035c4bbdfSmrg if (xcr >= xcl) { 133135c4bbdfSmrg pts->x = xcl; 133235c4bbdfSmrg pts->y = ybase; 133335c4bbdfSmrg pts++; 133435c4bbdfSmrg *wids++ = xcr - xcl + 1; 133535c4bbdfSmrg } 133605b261ecSmrg } 13376747b715Smrg return pts - points; 133805b261ecSmrg} 133905b261ecSmrg 134005b261ecSmrgstatic int 134135c4bbdfSmrgmiRoundJoinFace(LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge) 134205b261ecSmrg{ 134335c4bbdfSmrg int y; 134435c4bbdfSmrg int dx, dy; 134535c4bbdfSmrg double xa, ya; 134635c4bbdfSmrg Bool left; 134705b261ecSmrg 134805b261ecSmrg dx = -face->dy; 134905b261ecSmrg dy = face->dx; 135005b261ecSmrg xa = face->xa; 135105b261ecSmrg ya = face->ya; 135205b261ecSmrg left = 1; 135335c4bbdfSmrg if (ya > 0) { 135435c4bbdfSmrg ya = 0.0; 135535c4bbdfSmrg xa = 0.0; 135605b261ecSmrg } 135735c4bbdfSmrg if (dy < 0 || (dy == 0 && dx > 0)) { 135835c4bbdfSmrg dx = -dx; 135935c4bbdfSmrg dy = -dy; 136035c4bbdfSmrg left = !left; 136105b261ecSmrg } 136205b261ecSmrg if (dx == 0 && dy == 0) 136335c4bbdfSmrg dy = 1; 136435c4bbdfSmrg if (dy == 0) { 136535c4bbdfSmrg y = ICEIL(face->ya) + face->y; 136635c4bbdfSmrg edge->x = -32767; 136735c4bbdfSmrg edge->stepx = 0; 136835c4bbdfSmrg edge->signdx = 0; 136935c4bbdfSmrg edge->e = -1; 137035c4bbdfSmrg edge->dy = 0; 137135c4bbdfSmrg edge->dx = 0; 137235c4bbdfSmrg edge->height = 0; 137335c4bbdfSmrg } 137435c4bbdfSmrg else { 137535c4bbdfSmrg y = miPolyBuildEdge(xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge); 137635c4bbdfSmrg edge->height = 32767; 137705b261ecSmrg } 137805b261ecSmrg *leftEdge = !left; 137905b261ecSmrg return y; 138005b261ecSmrg} 138105b261ecSmrg 138235c4bbdfSmrgstatic void 138335c4bbdfSmrgmiRoundJoinClip(LineFacePtr pLeft, LineFacePtr pRight, 138435c4bbdfSmrg PolyEdgePtr edge1, PolyEdgePtr edge2, 138535c4bbdfSmrg int *y1, int *y2, Bool *left1, Bool *left2) 138605b261ecSmrg{ 138735c4bbdfSmrg double denom; 138805b261ecSmrg 138935c4bbdfSmrg denom = -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy; 139005b261ecSmrg 139135c4bbdfSmrg if (denom >= 0) { 139235c4bbdfSmrg pLeft->xa = -pLeft->xa; 139335c4bbdfSmrg pLeft->ya = -pLeft->ya; 139405b261ecSmrg } 139535c4bbdfSmrg else { 139635c4bbdfSmrg pRight->xa = -pRight->xa; 139735c4bbdfSmrg pRight->ya = -pRight->ya; 139805b261ecSmrg } 139935c4bbdfSmrg *y1 = miRoundJoinFace(pLeft, edge1, left1); 140035c4bbdfSmrg *y2 = miRoundJoinFace(pRight, edge2, left2); 140105b261ecSmrg} 140205b261ecSmrg 140335c4bbdfSmrgstatic int 140435c4bbdfSmrgmiRoundCapClip(LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge) 140505b261ecSmrg{ 140635c4bbdfSmrg int y; 140735c4bbdfSmrg int dx, dy; 140835c4bbdfSmrg double xa, ya, k; 140935c4bbdfSmrg Bool left; 141005b261ecSmrg 141105b261ecSmrg dx = -face->dy; 141205b261ecSmrg dy = face->dx; 141305b261ecSmrg xa = face->xa; 141405b261ecSmrg ya = face->ya; 141505b261ecSmrg k = 0.0; 141605b261ecSmrg if (!isInt) 141735c4bbdfSmrg k = face->k; 141805b261ecSmrg left = 1; 141935c4bbdfSmrg if (dy < 0 || (dy == 0 && dx > 0)) { 142035c4bbdfSmrg dx = -dx; 142135c4bbdfSmrg dy = -dy; 142235c4bbdfSmrg xa = -xa; 142335c4bbdfSmrg ya = -ya; 142435c4bbdfSmrg left = !left; 142505b261ecSmrg } 142605b261ecSmrg if (dx == 0 && dy == 0) 142735c4bbdfSmrg dy = 1; 142835c4bbdfSmrg if (dy == 0) { 142935c4bbdfSmrg y = ICEIL(face->ya) + face->y; 143035c4bbdfSmrg edge->x = -32767; 143135c4bbdfSmrg edge->stepx = 0; 143235c4bbdfSmrg edge->signdx = 0; 143335c4bbdfSmrg edge->e = -1; 143435c4bbdfSmrg edge->dy = 0; 143535c4bbdfSmrg edge->dx = 0; 143635c4bbdfSmrg edge->height = 0; 143735c4bbdfSmrg } 143835c4bbdfSmrg else { 143935c4bbdfSmrg y = miPolyBuildEdge(xa, ya, k, dx, dy, face->x, face->y, !left, edge); 144035c4bbdfSmrg edge->height = 32767; 144105b261ecSmrg } 144205b261ecSmrg *leftEdge = !left; 144305b261ecSmrg return y; 144405b261ecSmrg} 144505b261ecSmrg 144605b261ecSmrgstatic void 144735c4bbdfSmrgmiLineArc(DrawablePtr pDraw, 144835c4bbdfSmrg GCPtr pGC, 144935c4bbdfSmrg unsigned long pixel, 145035c4bbdfSmrg SpanDataPtr spanData, 145135c4bbdfSmrg LineFacePtr leftFace, 145235c4bbdfSmrg LineFacePtr rightFace, double xorg, double yorg, Bool isInt) 145305b261ecSmrg{ 145405b261ecSmrg int xorgi = 0, yorgi = 0; 145505b261ecSmrg Spans spanRec; 145605b261ecSmrg int n; 145735c4bbdfSmrg PolyEdgeRec edge1 = { 0 }, edge2 = { 0 }; 145835c4bbdfSmrg int edgey1, edgey2; 145935c4bbdfSmrg Bool edgeleft1, edgeleft2; 146005b261ecSmrg 146135c4bbdfSmrg if (isInt) { 146235c4bbdfSmrg xorgi = leftFace ? leftFace->x : rightFace->x; 146335c4bbdfSmrg yorgi = leftFace ? leftFace->y : rightFace->y; 146405b261ecSmrg } 146505b261ecSmrg edgey1 = 65536; 146605b261ecSmrg edgey2 = 65536; 146735c4bbdfSmrg edge1.x = 0; /* not used, keep memory checkers happy */ 146805b261ecSmrg edge1.dy = -1; 146935c4bbdfSmrg edge2.x = 0; /* not used, keep memory checkers happy */ 147005b261ecSmrg edge2.dy = -1; 147105b261ecSmrg edgeleft1 = FALSE; 147205b261ecSmrg edgeleft2 = FALSE; 147305b261ecSmrg if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) && 147435c4bbdfSmrg ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) || 147535c4bbdfSmrg (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) { 147635c4bbdfSmrg if (isInt) { 147735c4bbdfSmrg xorg = (double) xorgi; 147835c4bbdfSmrg yorg = (double) yorgi; 147935c4bbdfSmrg } 148035c4bbdfSmrg if (leftFace && rightFace) { 148135c4bbdfSmrg miRoundJoinClip(leftFace, rightFace, &edge1, &edge2, 148235c4bbdfSmrg &edgey1, &edgey2, &edgeleft1, &edgeleft2); 148335c4bbdfSmrg } 148435c4bbdfSmrg else if (leftFace) { 148535c4bbdfSmrg edgey1 = miRoundCapClip(leftFace, isInt, &edge1, &edgeleft1); 148635c4bbdfSmrg } 148735c4bbdfSmrg else if (rightFace) { 148835c4bbdfSmrg edgey2 = miRoundCapClip(rightFace, isInt, &edge2, &edgeleft2); 148935c4bbdfSmrg } 149035c4bbdfSmrg isInt = FALSE; 149105b261ecSmrg } 14926747b715Smrg if (!InitSpans(&spanRec, pGC->lineWidth)) 149335c4bbdfSmrg return; 149405b261ecSmrg if (isInt) 149535c4bbdfSmrg n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points, 149635c4bbdfSmrg spanRec.widths); 149705b261ecSmrg else 149835c4bbdfSmrg n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths, 149935c4bbdfSmrg &edge1, edgey1, edgeleft1, &edge2, edgey2, edgeleft2); 15006747b715Smrg spanRec.count = n; 150135c4bbdfSmrg fillSpans(pDraw, pGC, pixel, &spanRec, spanData); 150205b261ecSmrg} 150305b261ecSmrg 150405b261ecSmrgstatic void 150535c4bbdfSmrgmiLineProjectingCap(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, 150635c4bbdfSmrg SpanDataPtr spanData, LineFacePtr face, Bool isLeft, 150735c4bbdfSmrg double xorg, double yorg, Bool isInt) 150805b261ecSmrg{ 150935c4bbdfSmrg int xorgi = 0, yorgi = 0; 151035c4bbdfSmrg int lw; 151135c4bbdfSmrg PolyEdgeRec lefts[4], rights[4]; 151235c4bbdfSmrg int lefty, righty, topy, bottomy; 151305b261ecSmrg PolyEdgePtr left, right; 151435c4bbdfSmrg PolyEdgePtr top, bottom; 151535c4bbdfSmrg double xa, ya; 151635c4bbdfSmrg double k; 151735c4bbdfSmrg double xap, yap; 151835c4bbdfSmrg int dx, dy; 151935c4bbdfSmrg double projectXoff, projectYoff; 152035c4bbdfSmrg double maxy; 152135c4bbdfSmrg int finaly; 152235c4bbdfSmrg 152335c4bbdfSmrg if (isInt) { 152435c4bbdfSmrg xorgi = face->x; 152535c4bbdfSmrg yorgi = face->y; 152605b261ecSmrg } 152705b261ecSmrg lw = pGC->lineWidth; 152805b261ecSmrg dx = face->dx; 152905b261ecSmrg dy = face->dy; 153005b261ecSmrg k = face->k; 153135c4bbdfSmrg if (dy == 0) { 153235c4bbdfSmrg lefts[0].height = lw; 153335c4bbdfSmrg lefts[0].x = xorgi; 153435c4bbdfSmrg if (isLeft) 153535c4bbdfSmrg lefts[0].x -= (lw >> 1); 153635c4bbdfSmrg lefts[0].stepx = 0; 153735c4bbdfSmrg lefts[0].signdx = 1; 153835c4bbdfSmrg lefts[0].e = -lw; 153935c4bbdfSmrg lefts[0].dx = 0; 154035c4bbdfSmrg lefts[0].dy = lw; 154135c4bbdfSmrg rights[0].height = lw; 154235c4bbdfSmrg rights[0].x = xorgi; 154335c4bbdfSmrg if (!isLeft) 154435c4bbdfSmrg rights[0].x += ((lw + 1) >> 1); 154535c4bbdfSmrg rights[0].stepx = 0; 154635c4bbdfSmrg rights[0].signdx = 1; 154735c4bbdfSmrg rights[0].e = -lw; 154835c4bbdfSmrg rights[0].dx = 0; 154935c4bbdfSmrg rights[0].dy = lw; 155035c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw, 155135c4bbdfSmrg lefts, rights, 1, 1); 155235c4bbdfSmrg } 155335c4bbdfSmrg else if (dx == 0) { 155435c4bbdfSmrg if (dy < 0) { 155535c4bbdfSmrg dy = -dy; 155635c4bbdfSmrg isLeft = !isLeft; 155735c4bbdfSmrg } 155835c4bbdfSmrg topy = yorgi; 155935c4bbdfSmrg bottomy = yorgi + dy; 156035c4bbdfSmrg if (isLeft) 156135c4bbdfSmrg topy -= (lw >> 1); 156235c4bbdfSmrg else 156335c4bbdfSmrg bottomy += (lw >> 1); 156435c4bbdfSmrg lefts[0].height = bottomy - topy; 156535c4bbdfSmrg lefts[0].x = xorgi - (lw >> 1); 156635c4bbdfSmrg lefts[0].stepx = 0; 156735c4bbdfSmrg lefts[0].signdx = 1; 156835c4bbdfSmrg lefts[0].e = -dy; 156935c4bbdfSmrg lefts[0].dx = dx; 157035c4bbdfSmrg lefts[0].dy = dy; 157135c4bbdfSmrg 157235c4bbdfSmrg rights[0].height = bottomy - topy; 157335c4bbdfSmrg rights[0].x = lefts[0].x + (lw - 1); 157435c4bbdfSmrg rights[0].stepx = 0; 157535c4bbdfSmrg rights[0].signdx = 1; 157635c4bbdfSmrg rights[0].e = -dy; 157735c4bbdfSmrg rights[0].dx = dx; 157835c4bbdfSmrg rights[0].dy = dy; 157935c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, bottomy - topy, 158035c4bbdfSmrg lefts, rights, 1, 1); 158135c4bbdfSmrg } 158235c4bbdfSmrg else { 158335c4bbdfSmrg xa = face->xa; 158435c4bbdfSmrg ya = face->ya; 158535c4bbdfSmrg projectXoff = -ya; 158635c4bbdfSmrg projectYoff = xa; 158735c4bbdfSmrg if (dx < 0) { 158835c4bbdfSmrg right = &rights[1]; 158935c4bbdfSmrg left = &lefts[0]; 159035c4bbdfSmrg top = &rights[0]; 159135c4bbdfSmrg bottom = &lefts[1]; 159235c4bbdfSmrg } 159335c4bbdfSmrg else { 159435c4bbdfSmrg right = &rights[0]; 159535c4bbdfSmrg left = &lefts[1]; 159635c4bbdfSmrg top = &lefts[0]; 159735c4bbdfSmrg bottom = &rights[1]; 159835c4bbdfSmrg } 159935c4bbdfSmrg if (isLeft) { 160035c4bbdfSmrg righty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 0, right); 160135c4bbdfSmrg 160235c4bbdfSmrg xa = -xa; 160335c4bbdfSmrg ya = -ya; 160435c4bbdfSmrg k = -k; 160535c4bbdfSmrg lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff, 160635c4bbdfSmrg k, dx, dy, xorgi, yorgi, 1, left); 160735c4bbdfSmrg if (dx > 0) { 160835c4bbdfSmrg ya = -ya; 160935c4bbdfSmrg xa = -xa; 161035c4bbdfSmrg } 161135c4bbdfSmrg xap = xa - projectXoff; 161235c4bbdfSmrg yap = ya - projectYoff; 161335c4bbdfSmrg topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy, 161435c4bbdfSmrg -dy, dx, xorgi, yorgi, dx > 0, top); 161535c4bbdfSmrg bottomy = miPolyBuildEdge(xa, ya, 161635c4bbdfSmrg 0.0, -dy, dx, xorgi, yorgi, dx < 0, 161735c4bbdfSmrg bottom); 161835c4bbdfSmrg maxy = -ya; 161935c4bbdfSmrg } 162035c4bbdfSmrg else { 162135c4bbdfSmrg righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff, 162235c4bbdfSmrg k, dx, dy, xorgi, yorgi, 0, right); 162335c4bbdfSmrg 162435c4bbdfSmrg xa = -xa; 162535c4bbdfSmrg ya = -ya; 162635c4bbdfSmrg k = -k; 162735c4bbdfSmrg lefty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 1, left); 162835c4bbdfSmrg if (dx > 0) { 162935c4bbdfSmrg ya = -ya; 163035c4bbdfSmrg xa = -xa; 163135c4bbdfSmrg } 163235c4bbdfSmrg xap = xa - projectXoff; 163335c4bbdfSmrg yap = ya - projectYoff; 163435c4bbdfSmrg topy = 163535c4bbdfSmrg miPolyBuildEdge(xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, 163635c4bbdfSmrg top); 163735c4bbdfSmrg bottomy = 163835c4bbdfSmrg miPolyBuildEdge(xap, yap, xap * dx + yap * dy, -dy, dx, xorgi, 163935c4bbdfSmrg xorgi, dx < 0, bottom); 164035c4bbdfSmrg maxy = -ya + projectYoff; 164135c4bbdfSmrg } 164235c4bbdfSmrg finaly = ICEIL(maxy) + yorgi; 164335c4bbdfSmrg if (dx < 0) { 164435c4bbdfSmrg left->height = bottomy - lefty; 164535c4bbdfSmrg right->height = finaly - righty; 164635c4bbdfSmrg top->height = righty - topy; 164735c4bbdfSmrg } 164835c4bbdfSmrg else { 164935c4bbdfSmrg right->height = bottomy - righty; 165035c4bbdfSmrg left->height = finaly - lefty; 165135c4bbdfSmrg top->height = lefty - topy; 165235c4bbdfSmrg } 165335c4bbdfSmrg bottom->height = finaly - bottomy; 165435c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, 165535c4bbdfSmrg bottom->height + bottomy - topy, lefts, rights, 2, 2); 165605b261ecSmrg } 165705b261ecSmrg} 165805b261ecSmrg 165905b261ecSmrgstatic void 166035c4bbdfSmrgmiWideSegment(DrawablePtr pDrawable, 166135c4bbdfSmrg GCPtr pGC, 166235c4bbdfSmrg unsigned long pixel, 166335c4bbdfSmrg SpanDataPtr spanData, 166435c4bbdfSmrg int x1, 166535c4bbdfSmrg int y1, 166635c4bbdfSmrg int x2, 166735c4bbdfSmrg int y2, 166835c4bbdfSmrg Bool projectLeft, 166935c4bbdfSmrg Bool projectRight, LineFacePtr leftFace, LineFacePtr rightFace) 167005b261ecSmrg{ 167135c4bbdfSmrg double l, L, r; 167235c4bbdfSmrg double xa, ya; 167335c4bbdfSmrg double projectXoff = 0.0, projectYoff = 0.0; 167435c4bbdfSmrg double k; 167535c4bbdfSmrg double maxy; 167635c4bbdfSmrg int x, y; 167735c4bbdfSmrg int dx, dy; 167835c4bbdfSmrg int finaly; 167905b261ecSmrg PolyEdgePtr left, right; 168035c4bbdfSmrg PolyEdgePtr top, bottom; 168135c4bbdfSmrg int lefty, righty, topy, bottomy; 168235c4bbdfSmrg int signdx; 168335c4bbdfSmrg PolyEdgeRec lefts[4], rights[4]; 168435c4bbdfSmrg LineFacePtr tface; 168535c4bbdfSmrg int lw = pGC->lineWidth; 168605b261ecSmrg 168705b261ecSmrg /* draw top-to-bottom always */ 168835c4bbdfSmrg if (y2 < y1 || (y2 == y1 && x2 < x1)) { 168935c4bbdfSmrg x = x1; 169035c4bbdfSmrg x1 = x2; 169135c4bbdfSmrg x2 = x; 169205b261ecSmrg 169335c4bbdfSmrg y = y1; 169435c4bbdfSmrg y1 = y2; 169535c4bbdfSmrg y2 = y; 169605b261ecSmrg 169735c4bbdfSmrg x = projectLeft; 169835c4bbdfSmrg projectLeft = projectRight; 169935c4bbdfSmrg projectRight = x; 170005b261ecSmrg 170135c4bbdfSmrg tface = leftFace; 170235c4bbdfSmrg leftFace = rightFace; 170335c4bbdfSmrg rightFace = tface; 170405b261ecSmrg } 170505b261ecSmrg 170605b261ecSmrg dy = y2 - y1; 170705b261ecSmrg signdx = 1; 170805b261ecSmrg dx = x2 - x1; 170905b261ecSmrg if (dx < 0) 171035c4bbdfSmrg signdx = -1; 171105b261ecSmrg 171205b261ecSmrg leftFace->x = x1; 171305b261ecSmrg leftFace->y = y1; 171405b261ecSmrg leftFace->dx = dx; 171505b261ecSmrg leftFace->dy = dy; 171605b261ecSmrg 171705b261ecSmrg rightFace->x = x2; 171805b261ecSmrg rightFace->y = y2; 171905b261ecSmrg rightFace->dx = -dx; 172005b261ecSmrg rightFace->dy = -dy; 172105b261ecSmrg 172235c4bbdfSmrg if (dy == 0) { 172335c4bbdfSmrg rightFace->xa = 0; 172435c4bbdfSmrg rightFace->ya = (double) lw / 2.0; 172535c4bbdfSmrg rightFace->k = -(double) (lw * dx) / 2.0; 172635c4bbdfSmrg leftFace->xa = 0; 172735c4bbdfSmrg leftFace->ya = -rightFace->ya; 172835c4bbdfSmrg leftFace->k = rightFace->k; 172935c4bbdfSmrg x = x1; 173035c4bbdfSmrg if (projectLeft) 173135c4bbdfSmrg x -= (lw >> 1); 173235c4bbdfSmrg y = y1 - (lw >> 1); 173335c4bbdfSmrg dx = x2 - x; 173435c4bbdfSmrg if (projectRight) 173535c4bbdfSmrg dx += ((lw + 1) >> 1); 173635c4bbdfSmrg dy = lw; 173735c4bbdfSmrg miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy); 173835c4bbdfSmrg } 173935c4bbdfSmrg else if (dx == 0) { 174035c4bbdfSmrg leftFace->xa = (double) lw / 2.0; 174135c4bbdfSmrg leftFace->ya = 0; 174235c4bbdfSmrg leftFace->k = (double) (lw * dy) / 2.0; 174335c4bbdfSmrg rightFace->xa = -leftFace->xa; 174435c4bbdfSmrg rightFace->ya = 0; 174535c4bbdfSmrg rightFace->k = leftFace->k; 174635c4bbdfSmrg y = y1; 174735c4bbdfSmrg if (projectLeft) 174835c4bbdfSmrg y -= lw >> 1; 174935c4bbdfSmrg x = x1 - (lw >> 1); 175035c4bbdfSmrg dy = y2 - y; 175135c4bbdfSmrg if (projectRight) 175235c4bbdfSmrg dy += ((lw + 1) >> 1); 175335c4bbdfSmrg dx = lw; 175435c4bbdfSmrg miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy); 175535c4bbdfSmrg } 175635c4bbdfSmrg else { 175735c4bbdfSmrg l = ((double) lw) / 2.0; 175835c4bbdfSmrg L = hypot((double) dx, (double) dy); 175935c4bbdfSmrg 176035c4bbdfSmrg if (dx < 0) { 176135c4bbdfSmrg right = &rights[1]; 176235c4bbdfSmrg left = &lefts[0]; 176335c4bbdfSmrg top = &rights[0]; 176435c4bbdfSmrg bottom = &lefts[1]; 176535c4bbdfSmrg } 176635c4bbdfSmrg else { 176735c4bbdfSmrg right = &rights[0]; 176835c4bbdfSmrg left = &lefts[1]; 176935c4bbdfSmrg top = &lefts[0]; 177035c4bbdfSmrg bottom = &rights[1]; 177135c4bbdfSmrg } 177235c4bbdfSmrg r = l / L; 177335c4bbdfSmrg 177435c4bbdfSmrg /* coord of upper bound at integral y */ 177535c4bbdfSmrg ya = -r * dx; 177635c4bbdfSmrg xa = r * dy; 177735c4bbdfSmrg 177835c4bbdfSmrg if (projectLeft | projectRight) { 177935c4bbdfSmrg projectXoff = -ya; 178035c4bbdfSmrg projectYoff = xa; 178135c4bbdfSmrg } 178235c4bbdfSmrg 178335c4bbdfSmrg /* xa * dy - ya * dx */ 178435c4bbdfSmrg k = l * L; 178535c4bbdfSmrg 178635c4bbdfSmrg leftFace->xa = xa; 178735c4bbdfSmrg leftFace->ya = ya; 178835c4bbdfSmrg leftFace->k = k; 178935c4bbdfSmrg rightFace->xa = -xa; 179035c4bbdfSmrg rightFace->ya = -ya; 179135c4bbdfSmrg rightFace->k = k; 179235c4bbdfSmrg 179335c4bbdfSmrg if (projectLeft) 179435c4bbdfSmrg righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff, 179535c4bbdfSmrg k, dx, dy, x1, y1, 0, right); 179635c4bbdfSmrg else 179735c4bbdfSmrg righty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 0, right); 179835c4bbdfSmrg 179935c4bbdfSmrg /* coord of lower bound at integral y */ 180035c4bbdfSmrg ya = -ya; 180135c4bbdfSmrg xa = -xa; 180235c4bbdfSmrg 180335c4bbdfSmrg /* xa * dy - ya * dx */ 180435c4bbdfSmrg k = -k; 180535c4bbdfSmrg 180635c4bbdfSmrg if (projectLeft) 180735c4bbdfSmrg lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff, 180835c4bbdfSmrg k, dx, dy, x1, y1, 1, left); 180935c4bbdfSmrg else 181035c4bbdfSmrg lefty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 1, left); 181135c4bbdfSmrg 181235c4bbdfSmrg /* coord of top face at integral y */ 181335c4bbdfSmrg 181435c4bbdfSmrg if (signdx > 0) { 181535c4bbdfSmrg ya = -ya; 181635c4bbdfSmrg xa = -xa; 181735c4bbdfSmrg } 181835c4bbdfSmrg 181935c4bbdfSmrg if (projectLeft) { 182035c4bbdfSmrg double xap = xa - projectXoff; 182135c4bbdfSmrg double yap = ya - projectYoff; 182235c4bbdfSmrg 182335c4bbdfSmrg topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy, 182435c4bbdfSmrg -dy, dx, x1, y1, dx > 0, top); 182535c4bbdfSmrg } 182635c4bbdfSmrg else 182735c4bbdfSmrg topy = miPolyBuildEdge(xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top); 182835c4bbdfSmrg 182935c4bbdfSmrg /* coord of bottom face at integral y */ 183035c4bbdfSmrg 183135c4bbdfSmrg if (projectRight) { 183235c4bbdfSmrg double xap = xa + projectXoff; 183335c4bbdfSmrg double yap = ya + projectYoff; 183435c4bbdfSmrg 183535c4bbdfSmrg bottomy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy, 183635c4bbdfSmrg -dy, dx, x2, y2, dx < 0, bottom); 183735c4bbdfSmrg maxy = -ya + projectYoff; 183835c4bbdfSmrg } 183935c4bbdfSmrg else { 184035c4bbdfSmrg bottomy = miPolyBuildEdge(xa, ya, 184135c4bbdfSmrg 0.0, -dy, dx, x2, y2, dx < 0, bottom); 184235c4bbdfSmrg maxy = -ya; 184335c4bbdfSmrg } 184435c4bbdfSmrg 184535c4bbdfSmrg finaly = ICEIL(maxy) + y2; 184635c4bbdfSmrg 184735c4bbdfSmrg if (dx < 0) { 184835c4bbdfSmrg left->height = bottomy - lefty; 184935c4bbdfSmrg right->height = finaly - righty; 185035c4bbdfSmrg top->height = righty - topy; 185135c4bbdfSmrg } 185235c4bbdfSmrg else { 185335c4bbdfSmrg right->height = bottomy - righty; 185435c4bbdfSmrg left->height = finaly - lefty; 185535c4bbdfSmrg top->height = lefty - topy; 185635c4bbdfSmrg } 185735c4bbdfSmrg bottom->height = finaly - bottomy; 185835c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, 185935c4bbdfSmrg bottom->height + bottomy - topy, lefts, rights, 2, 2); 186005b261ecSmrg } 186105b261ecSmrg} 186205b261ecSmrg 186305b261ecSmrgstatic SpanDataPtr 186435c4bbdfSmrgmiSetupSpanData(GCPtr pGC, SpanDataPtr spanData, int npt) 186505b261ecSmrg{ 186605b261ecSmrg if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu)) 186735c4bbdfSmrg return (SpanDataPtr) NULL; 186805b261ecSmrg if (pGC->lineStyle == LineDoubleDash) 186935c4bbdfSmrg miInitSpanGroup(&spanData->bgGroup); 187035c4bbdfSmrg miInitSpanGroup(&spanData->fgGroup); 187105b261ecSmrg return spanData; 187205b261ecSmrg} 187305b261ecSmrg 187405b261ecSmrgstatic void 187535c4bbdfSmrgmiCleanupSpanData(DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData) 187605b261ecSmrg{ 187735c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash) { 187835c4bbdfSmrg ChangeGCVal oldPixel, pixel; 187935c4bbdfSmrg 188035c4bbdfSmrg pixel.val = pGC->bgPixel; 188135c4bbdfSmrg oldPixel.val = pGC->fgPixel; 188235c4bbdfSmrg if (pixel.val != oldPixel.val) { 188335c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &pixel); 188435c4bbdfSmrg ValidateGC(pDrawable, pGC); 188535c4bbdfSmrg } 188635c4bbdfSmrg miFillUniqueSpanGroup(pDrawable, pGC, &spanData->bgGroup); 188735c4bbdfSmrg miFreeSpanGroup(&spanData->bgGroup); 188835c4bbdfSmrg if (pixel.val != oldPixel.val) { 188935c4bbdfSmrg ChangeGC(NullClient, pGC, GCForeground, &oldPixel); 189035c4bbdfSmrg ValidateGC(pDrawable, pGC); 189135c4bbdfSmrg } 189235c4bbdfSmrg } 189335c4bbdfSmrg miFillUniqueSpanGroup(pDrawable, pGC, &spanData->fgGroup); 189435c4bbdfSmrg miFreeSpanGroup(&spanData->fgGroup); 189505b261ecSmrg} 189605b261ecSmrg 18976747b715Smrgvoid 189835c4bbdfSmrgmiWideLine(DrawablePtr pDrawable, GCPtr pGC, 189935c4bbdfSmrg int mode, int npt, DDXPointPtr pPts) 190005b261ecSmrg{ 190135c4bbdfSmrg int x1, y1, x2, y2; 190235c4bbdfSmrg SpanDataRec spanDataRec; 190335c4bbdfSmrg SpanDataPtr spanData; 190435c4bbdfSmrg long pixel; 190535c4bbdfSmrg Bool projectLeft, projectRight; 190635c4bbdfSmrg LineFaceRec leftFace, rightFace, prevRightFace; 190735c4bbdfSmrg LineFaceRec firstFace; 190835c4bbdfSmrg int first; 190935c4bbdfSmrg Bool somethingDrawn = FALSE; 191035c4bbdfSmrg Bool selfJoin; 191135c4bbdfSmrg 191235c4bbdfSmrg spanData = miSetupSpanData(pGC, &spanDataRec, npt); 191305b261ecSmrg pixel = pGC->fgPixel; 191405b261ecSmrg x2 = pPts->x; 191505b261ecSmrg y2 = pPts->y; 191605b261ecSmrg first = TRUE; 191705b261ecSmrg selfJoin = FALSE; 191835c4bbdfSmrg if (npt > 1) { 191935c4bbdfSmrg if (mode == CoordModePrevious) { 192035c4bbdfSmrg int nptTmp; 192135c4bbdfSmrg DDXPointPtr pPtsTmp; 192235c4bbdfSmrg 192335c4bbdfSmrg x1 = x2; 192435c4bbdfSmrg y1 = y2; 192535c4bbdfSmrg nptTmp = npt; 192635c4bbdfSmrg pPtsTmp = pPts + 1; 192735c4bbdfSmrg while (--nptTmp) { 192835c4bbdfSmrg x1 += pPtsTmp->x; 192935c4bbdfSmrg y1 += pPtsTmp->y; 193035c4bbdfSmrg ++pPtsTmp; 193135c4bbdfSmrg } 193235c4bbdfSmrg if (x2 == x1 && y2 == y1) 193335c4bbdfSmrg selfJoin = TRUE; 193435c4bbdfSmrg } 193535c4bbdfSmrg else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) { 193635c4bbdfSmrg selfJoin = TRUE; 193735c4bbdfSmrg } 193805b261ecSmrg } 193905b261ecSmrg projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 194005b261ecSmrg projectRight = FALSE; 194135c4bbdfSmrg while (--npt) { 194235c4bbdfSmrg x1 = x2; 194335c4bbdfSmrg y1 = y2; 194435c4bbdfSmrg ++pPts; 194535c4bbdfSmrg x2 = pPts->x; 194635c4bbdfSmrg y2 = pPts->y; 194735c4bbdfSmrg if (mode == CoordModePrevious) { 194835c4bbdfSmrg x2 += x1; 194935c4bbdfSmrg y2 += y1; 195035c4bbdfSmrg } 195135c4bbdfSmrg if (x1 != x2 || y1 != y2) { 195235c4bbdfSmrg somethingDrawn = TRUE; 195335c4bbdfSmrg if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin) 195435c4bbdfSmrg projectRight = TRUE; 195535c4bbdfSmrg miWideSegment(pDrawable, pGC, pixel, spanData, x1, y1, x2, y2, 195635c4bbdfSmrg projectLeft, projectRight, &leftFace, &rightFace); 195735c4bbdfSmrg if (first) { 195835c4bbdfSmrg if (selfJoin) 195935c4bbdfSmrg firstFace = leftFace; 196035c4bbdfSmrg else if (pGC->capStyle == CapRound) { 196135c4bbdfSmrg if (pGC->lineWidth == 1 && !spanData) 196235c4bbdfSmrg miLineOnePoint(pDrawable, pGC, pixel, spanData, x1, y1); 196335c4bbdfSmrg else 196435c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 196535c4bbdfSmrg &leftFace, (LineFacePtr) NULL, 196635c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 196735c4bbdfSmrg } 196835c4bbdfSmrg } 196935c4bbdfSmrg else { 197035c4bbdfSmrg miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace, 197135c4bbdfSmrg &prevRightFace); 197235c4bbdfSmrg } 197335c4bbdfSmrg prevRightFace = rightFace; 197435c4bbdfSmrg first = FALSE; 197535c4bbdfSmrg projectLeft = FALSE; 197635c4bbdfSmrg } 197735c4bbdfSmrg if (npt == 1 && somethingDrawn) { 197835c4bbdfSmrg if (selfJoin) 197935c4bbdfSmrg miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace, 198035c4bbdfSmrg &rightFace); 198135c4bbdfSmrg else if (pGC->capStyle == CapRound) { 198235c4bbdfSmrg if (pGC->lineWidth == 1 && !spanData) 198335c4bbdfSmrg miLineOnePoint(pDrawable, pGC, pixel, spanData, x2, y2); 198435c4bbdfSmrg else 198535c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 198635c4bbdfSmrg (LineFacePtr) NULL, &rightFace, 198735c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 198835c4bbdfSmrg } 198935c4bbdfSmrg } 199005b261ecSmrg } 199105b261ecSmrg /* handle crock where all points are coincedent */ 199235c4bbdfSmrg if (!somethingDrawn) { 199335c4bbdfSmrg projectLeft = pGC->capStyle == CapProjecting; 199435c4bbdfSmrg miWideSegment(pDrawable, pGC, pixel, spanData, 199535c4bbdfSmrg x2, y2, x2, y2, projectLeft, projectLeft, 199635c4bbdfSmrg &leftFace, &rightFace); 199735c4bbdfSmrg if (pGC->capStyle == CapRound) { 199835c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 199935c4bbdfSmrg &leftFace, (LineFacePtr) NULL, 200035c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 200135c4bbdfSmrg rightFace.dx = -1; /* sleezy hack to make it work */ 200235c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 200335c4bbdfSmrg (LineFacePtr) NULL, &rightFace, 200435c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 200535c4bbdfSmrg } 200605b261ecSmrg } 200705b261ecSmrg if (spanData) 200835c4bbdfSmrg miCleanupSpanData(pDrawable, pGC, spanData); 200905b261ecSmrg} 201005b261ecSmrg 201105b261ecSmrg#define V_TOP 0 201205b261ecSmrg#define V_RIGHT 1 201305b261ecSmrg#define V_BOTTOM 2 201405b261ecSmrg#define V_LEFT 3 201505b261ecSmrg 201605b261ecSmrgstatic void 201735c4bbdfSmrgmiWideDashSegment(DrawablePtr pDrawable, 201835c4bbdfSmrg GCPtr pGC, 201935c4bbdfSmrg SpanDataPtr spanData, 202035c4bbdfSmrg int *pDashOffset, 202135c4bbdfSmrg int *pDashIndex, 202235c4bbdfSmrg int x1, 202335c4bbdfSmrg int y1, 202435c4bbdfSmrg int x2, 202535c4bbdfSmrg int y2, 202635c4bbdfSmrg Bool projectLeft, 202735c4bbdfSmrg Bool projectRight, 202835c4bbdfSmrg LineFacePtr leftFace, LineFacePtr rightFace) 202905b261ecSmrg{ 203035c4bbdfSmrg int dashIndex, dashRemain; 203135c4bbdfSmrg unsigned char *pDash; 203235c4bbdfSmrg double L, l; 203335c4bbdfSmrg double k; 203435c4bbdfSmrg PolyVertexRec vertices[4]; 203535c4bbdfSmrg PolyVertexRec saveRight, saveBottom; 203635c4bbdfSmrg PolySlopeRec slopes[4]; 203735c4bbdfSmrg PolyEdgeRec left[4], right[4]; 203835c4bbdfSmrg LineFaceRec lcapFace, rcapFace; 203935c4bbdfSmrg int nleft, nright; 204035c4bbdfSmrg int h; 204135c4bbdfSmrg int y; 204235c4bbdfSmrg int dy, dx; 204335c4bbdfSmrg unsigned long pixel; 204435c4bbdfSmrg double LRemain; 204535c4bbdfSmrg double r; 204635c4bbdfSmrg double rdx, rdy; 204735c4bbdfSmrg double dashDx, dashDy; 204835c4bbdfSmrg double saveK = 0.0; 204935c4bbdfSmrg Bool first = TRUE; 205035c4bbdfSmrg double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0; 205135c4bbdfSmrg unsigned long fgPixel, bgPixel; 205235c4bbdfSmrg 205305b261ecSmrg dx = x2 - x1; 205405b261ecSmrg dy = y2 - y1; 205505b261ecSmrg dashIndex = *pDashIndex; 205605b261ecSmrg pDash = pGC->dash; 205705b261ecSmrg dashRemain = pDash[dashIndex] - *pDashOffset; 205805b261ecSmrg fgPixel = pGC->fgPixel; 205905b261ecSmrg bgPixel = pGC->bgPixel; 206035c4bbdfSmrg if (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled) { 206135c4bbdfSmrg bgPixel = fgPixel; 206205b261ecSmrg } 206305b261ecSmrg 206405b261ecSmrg l = ((double) pGC->lineWidth) / 2.0; 206535c4bbdfSmrg if (dx == 0) { 206635c4bbdfSmrg L = dy; 206735c4bbdfSmrg rdx = 0; 206835c4bbdfSmrg rdy = l; 206935c4bbdfSmrg if (dy < 0) { 207035c4bbdfSmrg L = -dy; 207135c4bbdfSmrg rdy = -l; 207235c4bbdfSmrg } 207335c4bbdfSmrg } 207435c4bbdfSmrg else if (dy == 0) { 207535c4bbdfSmrg L = dx; 207635c4bbdfSmrg rdx = l; 207735c4bbdfSmrg rdy = 0; 207835c4bbdfSmrg if (dx < 0) { 207935c4bbdfSmrg L = -dx; 208035c4bbdfSmrg rdx = -l; 208135c4bbdfSmrg } 208235c4bbdfSmrg } 208335c4bbdfSmrg else { 208435c4bbdfSmrg L = hypot((double) dx, (double) dy); 208535c4bbdfSmrg r = l / L; 208635c4bbdfSmrg 208735c4bbdfSmrg rdx = r * dx; 208835c4bbdfSmrg rdy = r * dy; 208905b261ecSmrg } 209005b261ecSmrg k = l * L; 209105b261ecSmrg LRemain = L; 209205b261ecSmrg /* All position comments are relative to a line with dx and dy > 0, 209305b261ecSmrg * but the code does not depend on this */ 209405b261ecSmrg /* top */ 209505b261ecSmrg slopes[V_TOP].dx = dx; 209605b261ecSmrg slopes[V_TOP].dy = dy; 209705b261ecSmrg slopes[V_TOP].k = k; 209805b261ecSmrg /* right */ 209905b261ecSmrg slopes[V_RIGHT].dx = -dy; 210005b261ecSmrg slopes[V_RIGHT].dy = dx; 210105b261ecSmrg slopes[V_RIGHT].k = 0; 210205b261ecSmrg /* bottom */ 210305b261ecSmrg slopes[V_BOTTOM].dx = -dx; 210405b261ecSmrg slopes[V_BOTTOM].dy = -dy; 210505b261ecSmrg slopes[V_BOTTOM].k = k; 210605b261ecSmrg /* left */ 210705b261ecSmrg slopes[V_LEFT].dx = dy; 210805b261ecSmrg slopes[V_LEFT].dy = -dx; 210905b261ecSmrg slopes[V_LEFT].k = 0; 211005b261ecSmrg 211105b261ecSmrg /* preload the start coordinates */ 211205b261ecSmrg vertices[V_RIGHT].x = vertices[V_TOP].x = rdy; 211305b261ecSmrg vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx; 211405b261ecSmrg 211505b261ecSmrg vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy; 211605b261ecSmrg vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx; 211705b261ecSmrg 211835c4bbdfSmrg if (projectLeft) { 211935c4bbdfSmrg vertices[V_TOP].x -= rdx; 212035c4bbdfSmrg vertices[V_TOP].y -= rdy; 212105b261ecSmrg 212235c4bbdfSmrg vertices[V_LEFT].x -= rdx; 212335c4bbdfSmrg vertices[V_LEFT].y -= rdy; 212405b261ecSmrg 212535c4bbdfSmrg slopes[V_LEFT].k = rdx * dx + rdy * dy; 212605b261ecSmrg } 212705b261ecSmrg 212805b261ecSmrg lcenterx = x1; 212905b261ecSmrg lcentery = y1; 213005b261ecSmrg 213135c4bbdfSmrg if (pGC->capStyle == CapRound) { 213235c4bbdfSmrg lcapFace.dx = dx; 213335c4bbdfSmrg lcapFace.dy = dy; 213435c4bbdfSmrg lcapFace.x = x1; 213535c4bbdfSmrg lcapFace.y = y1; 213635c4bbdfSmrg 213735c4bbdfSmrg rcapFace.dx = -dx; 213835c4bbdfSmrg rcapFace.dy = -dy; 213935c4bbdfSmrg rcapFace.x = x1; 214035c4bbdfSmrg rcapFace.y = y1; 214135c4bbdfSmrg } 214235c4bbdfSmrg while (LRemain > dashRemain) { 214335c4bbdfSmrg dashDx = (dashRemain * dx) / L; 214435c4bbdfSmrg dashDy = (dashRemain * dy) / L; 214535c4bbdfSmrg 214635c4bbdfSmrg rcenterx = lcenterx + dashDx; 214735c4bbdfSmrg rcentery = lcentery + dashDy; 214835c4bbdfSmrg 214935c4bbdfSmrg vertices[V_RIGHT].x += dashDx; 215035c4bbdfSmrg vertices[V_RIGHT].y += dashDy; 215135c4bbdfSmrg 215235c4bbdfSmrg vertices[V_BOTTOM].x += dashDx; 215335c4bbdfSmrg vertices[V_BOTTOM].y += dashDy; 215435c4bbdfSmrg 215535c4bbdfSmrg slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy; 215635c4bbdfSmrg 215735c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) { 215835c4bbdfSmrg if (pGC->lineStyle == LineOnOffDash && 215935c4bbdfSmrg pGC->capStyle == CapProjecting) { 216035c4bbdfSmrg saveRight = vertices[V_RIGHT]; 216135c4bbdfSmrg saveBottom = vertices[V_BOTTOM]; 216235c4bbdfSmrg saveK = slopes[V_RIGHT].k; 216335c4bbdfSmrg 216435c4bbdfSmrg if (!first) { 216535c4bbdfSmrg vertices[V_TOP].x -= rdx; 216635c4bbdfSmrg vertices[V_TOP].y -= rdy; 216735c4bbdfSmrg 216835c4bbdfSmrg vertices[V_LEFT].x -= rdx; 216935c4bbdfSmrg vertices[V_LEFT].y -= rdy; 217035c4bbdfSmrg 217135c4bbdfSmrg slopes[V_LEFT].k = vertices[V_LEFT].x * 217235c4bbdfSmrg slopes[V_LEFT].dy - 217335c4bbdfSmrg vertices[V_LEFT].y * slopes[V_LEFT].dx; 217435c4bbdfSmrg } 217535c4bbdfSmrg 217635c4bbdfSmrg vertices[V_RIGHT].x += rdx; 217735c4bbdfSmrg vertices[V_RIGHT].y += rdy; 217835c4bbdfSmrg 217935c4bbdfSmrg vertices[V_BOTTOM].x += rdx; 218035c4bbdfSmrg vertices[V_BOTTOM].y += rdy; 218135c4bbdfSmrg 218235c4bbdfSmrg slopes[V_RIGHT].k = vertices[V_RIGHT].x * 218335c4bbdfSmrg slopes[V_RIGHT].dy - 218435c4bbdfSmrg vertices[V_RIGHT].y * slopes[V_RIGHT].dx; 218535c4bbdfSmrg } 218635c4bbdfSmrg y = miPolyBuildPoly(vertices, slopes, 4, x1, y1, 218735c4bbdfSmrg left, right, &nleft, &nright, &h); 218835c4bbdfSmrg pixel = (dashIndex & 1) ? bgPixel : fgPixel; 218935c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right, 219035c4bbdfSmrg nleft, nright); 219135c4bbdfSmrg 219235c4bbdfSmrg if (pGC->lineStyle == LineOnOffDash) { 219335c4bbdfSmrg switch (pGC->capStyle) { 219435c4bbdfSmrg case CapProjecting: 219535c4bbdfSmrg vertices[V_BOTTOM] = saveBottom; 219635c4bbdfSmrg vertices[V_RIGHT] = saveRight; 219735c4bbdfSmrg slopes[V_RIGHT].k = saveK; 219835c4bbdfSmrg break; 219935c4bbdfSmrg case CapRound: 220035c4bbdfSmrg if (!first) { 220135c4bbdfSmrg if (dx < 0) { 220235c4bbdfSmrg lcapFace.xa = -vertices[V_LEFT].x; 220335c4bbdfSmrg lcapFace.ya = -vertices[V_LEFT].y; 220435c4bbdfSmrg lcapFace.k = slopes[V_LEFT].k; 220535c4bbdfSmrg } 220635c4bbdfSmrg else { 220735c4bbdfSmrg lcapFace.xa = vertices[V_TOP].x; 220835c4bbdfSmrg lcapFace.ya = vertices[V_TOP].y; 220935c4bbdfSmrg lcapFace.k = -slopes[V_LEFT].k; 221035c4bbdfSmrg } 221135c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 221235c4bbdfSmrg &lcapFace, (LineFacePtr) NULL, 221335c4bbdfSmrg lcenterx, lcentery, FALSE); 221435c4bbdfSmrg } 221535c4bbdfSmrg if (dx < 0) { 221635c4bbdfSmrg rcapFace.xa = vertices[V_BOTTOM].x; 221735c4bbdfSmrg rcapFace.ya = vertices[V_BOTTOM].y; 221835c4bbdfSmrg rcapFace.k = slopes[V_RIGHT].k; 221935c4bbdfSmrg } 222035c4bbdfSmrg else { 222135c4bbdfSmrg rcapFace.xa = -vertices[V_RIGHT].x; 222235c4bbdfSmrg rcapFace.ya = -vertices[V_RIGHT].y; 222335c4bbdfSmrg rcapFace.k = -slopes[V_RIGHT].k; 222435c4bbdfSmrg } 222535c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 222635c4bbdfSmrg (LineFacePtr) NULL, &rcapFace, 222735c4bbdfSmrg rcenterx, rcentery, FALSE); 222835c4bbdfSmrg break; 222935c4bbdfSmrg } 223035c4bbdfSmrg } 223135c4bbdfSmrg } 223235c4bbdfSmrg LRemain -= dashRemain; 223335c4bbdfSmrg ++dashIndex; 223435c4bbdfSmrg if (dashIndex == pGC->numInDashList) 223535c4bbdfSmrg dashIndex = 0; 223635c4bbdfSmrg dashRemain = pDash[dashIndex]; 223735c4bbdfSmrg 223835c4bbdfSmrg lcenterx = rcenterx; 223935c4bbdfSmrg lcentery = rcentery; 224035c4bbdfSmrg 224135c4bbdfSmrg vertices[V_TOP] = vertices[V_RIGHT]; 224235c4bbdfSmrg vertices[V_LEFT] = vertices[V_BOTTOM]; 224335c4bbdfSmrg slopes[V_LEFT].k = -slopes[V_RIGHT].k; 224435c4bbdfSmrg first = FALSE; 224535c4bbdfSmrg } 224635c4bbdfSmrg 224735c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) { 224835c4bbdfSmrg vertices[V_TOP].x -= dx; 224935c4bbdfSmrg vertices[V_TOP].y -= dy; 225035c4bbdfSmrg 225135c4bbdfSmrg vertices[V_LEFT].x -= dx; 225235c4bbdfSmrg vertices[V_LEFT].y -= dy; 225335c4bbdfSmrg 225435c4bbdfSmrg vertices[V_RIGHT].x = rdy; 225535c4bbdfSmrg vertices[V_RIGHT].y = -rdx; 225635c4bbdfSmrg 225735c4bbdfSmrg vertices[V_BOTTOM].x = -rdy; 225835c4bbdfSmrg vertices[V_BOTTOM].y = rdx; 225935c4bbdfSmrg 226035c4bbdfSmrg if (projectRight) { 226135c4bbdfSmrg vertices[V_RIGHT].x += rdx; 226235c4bbdfSmrg vertices[V_RIGHT].y += rdy; 226335c4bbdfSmrg 226435c4bbdfSmrg vertices[V_BOTTOM].x += rdx; 226535c4bbdfSmrg vertices[V_BOTTOM].y += rdy; 226635c4bbdfSmrg slopes[V_RIGHT].k = vertices[V_RIGHT].x * 226735c4bbdfSmrg slopes[V_RIGHT].dy - vertices[V_RIGHT].y * slopes[V_RIGHT].dx; 226835c4bbdfSmrg } 226935c4bbdfSmrg else 227035c4bbdfSmrg slopes[V_RIGHT].k = 0; 227135c4bbdfSmrg 227235c4bbdfSmrg if (!first && pGC->lineStyle == LineOnOffDash && 227335c4bbdfSmrg pGC->capStyle == CapProjecting) { 227435c4bbdfSmrg vertices[V_TOP].x -= rdx; 227535c4bbdfSmrg vertices[V_TOP].y -= rdy; 227635c4bbdfSmrg 227735c4bbdfSmrg vertices[V_LEFT].x -= rdx; 227835c4bbdfSmrg vertices[V_LEFT].y -= rdy; 227935c4bbdfSmrg slopes[V_LEFT].k = vertices[V_LEFT].x * 228035c4bbdfSmrg slopes[V_LEFT].dy - vertices[V_LEFT].y * slopes[V_LEFT].dx; 228135c4bbdfSmrg } 228235c4bbdfSmrg else 228335c4bbdfSmrg slopes[V_LEFT].k += dx * dx + dy * dy; 228435c4bbdfSmrg 228535c4bbdfSmrg y = miPolyBuildPoly(vertices, slopes, 4, x2, y2, 228635c4bbdfSmrg left, right, &nleft, &nright, &h); 228735c4bbdfSmrg 228835c4bbdfSmrg pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 228935c4bbdfSmrg miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right, 229035c4bbdfSmrg nleft, nright); 229135c4bbdfSmrg if (!first && pGC->lineStyle == LineOnOffDash && 229235c4bbdfSmrg pGC->capStyle == CapRound) { 229335c4bbdfSmrg lcapFace.x = x2; 229435c4bbdfSmrg lcapFace.y = y2; 229535c4bbdfSmrg if (dx < 0) { 229635c4bbdfSmrg lcapFace.xa = -vertices[V_LEFT].x; 229735c4bbdfSmrg lcapFace.ya = -vertices[V_LEFT].y; 229835c4bbdfSmrg lcapFace.k = slopes[V_LEFT].k; 229935c4bbdfSmrg } 230035c4bbdfSmrg else { 230135c4bbdfSmrg lcapFace.xa = vertices[V_TOP].x; 230235c4bbdfSmrg lcapFace.ya = vertices[V_TOP].y; 230335c4bbdfSmrg lcapFace.k = -slopes[V_LEFT].k; 230435c4bbdfSmrg } 230535c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 230635c4bbdfSmrg &lcapFace, (LineFacePtr) NULL, rcenterx, rcentery, FALSE); 230735c4bbdfSmrg } 230805b261ecSmrg } 230905b261ecSmrg dashRemain = ((double) dashRemain) - LRemain; 231035c4bbdfSmrg if (dashRemain == 0) { 231135c4bbdfSmrg dashIndex++; 231235c4bbdfSmrg if (dashIndex == pGC->numInDashList) 231335c4bbdfSmrg dashIndex = 0; 231435c4bbdfSmrg dashRemain = pDash[dashIndex]; 231505b261ecSmrg } 231605b261ecSmrg 231705b261ecSmrg leftFace->x = x1; 231805b261ecSmrg leftFace->y = y1; 231905b261ecSmrg leftFace->dx = dx; 232005b261ecSmrg leftFace->dy = dy; 232105b261ecSmrg leftFace->xa = rdy; 232205b261ecSmrg leftFace->ya = -rdx; 232305b261ecSmrg leftFace->k = k; 232405b261ecSmrg 232505b261ecSmrg rightFace->x = x2; 232605b261ecSmrg rightFace->y = y2; 232705b261ecSmrg rightFace->dx = -dx; 232805b261ecSmrg rightFace->dy = -dy; 232905b261ecSmrg rightFace->xa = -rdy; 233005b261ecSmrg rightFace->ya = rdx; 233105b261ecSmrg rightFace->k = k; 233205b261ecSmrg 233305b261ecSmrg *pDashIndex = dashIndex; 233405b261ecSmrg *pDashOffset = pDash[dashIndex] - dashRemain; 233505b261ecSmrg} 233605b261ecSmrg 23376747b715Smrgvoid 233835c4bbdfSmrgmiWideDash(DrawablePtr pDrawable, GCPtr pGC, 233935c4bbdfSmrg int mode, int npt, DDXPointPtr pPts) 234005b261ecSmrg{ 234135c4bbdfSmrg int x1, y1, x2, y2; 234235c4bbdfSmrg unsigned long pixel; 234335c4bbdfSmrg Bool projectLeft, projectRight; 234435c4bbdfSmrg LineFaceRec leftFace, rightFace, prevRightFace; 234535c4bbdfSmrg LineFaceRec firstFace; 234635c4bbdfSmrg int first; 234735c4bbdfSmrg int dashIndex, dashOffset; 234835c4bbdfSmrg int prevDashIndex; 234935c4bbdfSmrg SpanDataRec spanDataRec; 235035c4bbdfSmrg SpanDataPtr spanData; 235135c4bbdfSmrg Bool somethingDrawn = FALSE; 235235c4bbdfSmrg Bool selfJoin; 235335c4bbdfSmrg Bool endIsFg = FALSE, startIsFg = FALSE; 235435c4bbdfSmrg Bool firstIsFg = FALSE, prevIsFg = FALSE; 235505b261ecSmrg 235605b261ecSmrg#if 0 235705b261ecSmrg /* XXX backward compatibility */ 235835c4bbdfSmrg if (pGC->lineWidth == 0) { 235935c4bbdfSmrg miZeroDashLine(pDrawable, pGC, mode, npt, pPts); 236035c4bbdfSmrg return; 236105b261ecSmrg } 236205b261ecSmrg#endif 236335c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash && 236435c4bbdfSmrg (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) { 236535c4bbdfSmrg miWideLine(pDrawable, pGC, mode, npt, pPts); 236635c4bbdfSmrg return; 236705b261ecSmrg } 236805b261ecSmrg if (npt == 0) 236935c4bbdfSmrg return; 237035c4bbdfSmrg spanData = miSetupSpanData(pGC, &spanDataRec, npt); 237105b261ecSmrg x2 = pPts->x; 237205b261ecSmrg y2 = pPts->y; 237305b261ecSmrg first = TRUE; 237405b261ecSmrg selfJoin = FALSE; 237535c4bbdfSmrg if (mode == CoordModePrevious) { 237635c4bbdfSmrg int nptTmp; 237735c4bbdfSmrg DDXPointPtr pPtsTmp; 237835c4bbdfSmrg 237935c4bbdfSmrg x1 = x2; 238035c4bbdfSmrg y1 = y2; 238135c4bbdfSmrg nptTmp = npt; 238235c4bbdfSmrg pPtsTmp = pPts + 1; 238335c4bbdfSmrg while (--nptTmp) { 238435c4bbdfSmrg x1 += pPtsTmp->x; 238535c4bbdfSmrg y1 += pPtsTmp->y; 238635c4bbdfSmrg ++pPtsTmp; 238735c4bbdfSmrg } 238835c4bbdfSmrg if (x2 == x1 && y2 == y1) 238935c4bbdfSmrg selfJoin = TRUE; 239035c4bbdfSmrg } 239135c4bbdfSmrg else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) { 239235c4bbdfSmrg selfJoin = TRUE; 239305b261ecSmrg } 239405b261ecSmrg projectLeft = pGC->capStyle == CapProjecting && !selfJoin; 239505b261ecSmrg projectRight = FALSE; 239605b261ecSmrg dashIndex = 0; 239705b261ecSmrg dashOffset = 0; 239835c4bbdfSmrg miStepDash((int) pGC->dashOffset, &dashIndex, 239935c4bbdfSmrg pGC->dash, (int) pGC->numInDashList, &dashOffset); 240035c4bbdfSmrg while (--npt) { 240135c4bbdfSmrg x1 = x2; 240235c4bbdfSmrg y1 = y2; 240335c4bbdfSmrg ++pPts; 240435c4bbdfSmrg x2 = pPts->x; 240535c4bbdfSmrg y2 = pPts->y; 240635c4bbdfSmrg if (mode == CoordModePrevious) { 240735c4bbdfSmrg x2 += x1; 240835c4bbdfSmrg y2 += y1; 240935c4bbdfSmrg } 241035c4bbdfSmrg if (x1 != x2 || y1 != y2) { 241135c4bbdfSmrg somethingDrawn = TRUE; 241235c4bbdfSmrg if (npt == 1 && pGC->capStyle == CapProjecting && 241335c4bbdfSmrg (!selfJoin || !firstIsFg)) 241435c4bbdfSmrg projectRight = TRUE; 241535c4bbdfSmrg prevDashIndex = dashIndex; 241635c4bbdfSmrg miWideDashSegment(pDrawable, pGC, spanData, &dashOffset, &dashIndex, 241735c4bbdfSmrg x1, y1, x2, y2, 241835c4bbdfSmrg projectLeft, projectRight, &leftFace, &rightFace); 241935c4bbdfSmrg startIsFg = !(prevDashIndex & 1); 242035c4bbdfSmrg endIsFg = (dashIndex & 1) ^ (dashOffset != 0); 242135c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash || startIsFg) { 242235c4bbdfSmrg pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel; 242335c4bbdfSmrg if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) { 242435c4bbdfSmrg if (first && selfJoin) { 242535c4bbdfSmrg firstFace = leftFace; 242635c4bbdfSmrg firstIsFg = startIsFg; 242735c4bbdfSmrg } 242835c4bbdfSmrg else if (pGC->capStyle == CapRound) 242935c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 243035c4bbdfSmrg &leftFace, (LineFacePtr) NULL, 243135c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 243235c4bbdfSmrg } 243335c4bbdfSmrg else { 243435c4bbdfSmrg miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace, 243535c4bbdfSmrg &prevRightFace); 243635c4bbdfSmrg } 243735c4bbdfSmrg } 243835c4bbdfSmrg prevRightFace = rightFace; 243935c4bbdfSmrg prevIsFg = endIsFg; 244035c4bbdfSmrg first = FALSE; 244135c4bbdfSmrg projectLeft = FALSE; 244235c4bbdfSmrg } 244335c4bbdfSmrg if (npt == 1 && somethingDrawn) { 244435c4bbdfSmrg if (pGC->lineStyle == LineDoubleDash || endIsFg) { 244535c4bbdfSmrg pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel; 244635c4bbdfSmrg if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) { 244735c4bbdfSmrg miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace, 244835c4bbdfSmrg &rightFace); 244935c4bbdfSmrg } 245035c4bbdfSmrg else { 245135c4bbdfSmrg if (pGC->capStyle == CapRound) 245235c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 245335c4bbdfSmrg (LineFacePtr) NULL, &rightFace, 245435c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 245535c4bbdfSmrg } 245635c4bbdfSmrg } 245735c4bbdfSmrg else { 245835c4bbdfSmrg /* glue a cap to the start of the line if 245935c4bbdfSmrg * we're OnOffDash and ended on odd dash 246035c4bbdfSmrg */ 246135c4bbdfSmrg if (selfJoin && firstIsFg) { 246235c4bbdfSmrg pixel = pGC->fgPixel; 246335c4bbdfSmrg if (pGC->capStyle == CapProjecting) 246435c4bbdfSmrg miLineProjectingCap(pDrawable, pGC, pixel, spanData, 246535c4bbdfSmrg &firstFace, TRUE, 246635c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 246735c4bbdfSmrg else if (pGC->capStyle == CapRound) 246835c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 246935c4bbdfSmrg &firstFace, (LineFacePtr) NULL, 247035c4bbdfSmrg (double) 0.0, (double) 0.0, TRUE); 247135c4bbdfSmrg } 247235c4bbdfSmrg } 247335c4bbdfSmrg } 247405b261ecSmrg } 247505b261ecSmrg /* handle crock where all points are coincident */ 247635c4bbdfSmrg if (!somethingDrawn && 247735c4bbdfSmrg (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) { 247835c4bbdfSmrg /* not the same as endIsFg computation above */ 247935c4bbdfSmrg pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel; 248035c4bbdfSmrg switch (pGC->capStyle) { 248135c4bbdfSmrg case CapRound: 248235c4bbdfSmrg miLineArc(pDrawable, pGC, pixel, spanData, 248335c4bbdfSmrg (LineFacePtr) NULL, (LineFacePtr) NULL, 248435c4bbdfSmrg (double) x2, (double) y2, FALSE); 248535c4bbdfSmrg break; 248635c4bbdfSmrg case CapProjecting: 248735c4bbdfSmrg x1 = pGC->lineWidth; 248835c4bbdfSmrg miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, 248935c4bbdfSmrg x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1); 249035c4bbdfSmrg break; 249135c4bbdfSmrg } 249205b261ecSmrg } 249305b261ecSmrg if (spanData) 249435c4bbdfSmrg miCleanupSpanData(pDrawable, pGC, spanData); 249535c4bbdfSmrg} 249635c4bbdfSmrg 249735c4bbdfSmrgvoid 249835c4bbdfSmrgmiPolylines(DrawablePtr drawable, 249935c4bbdfSmrg GCPtr gc, 250035c4bbdfSmrg int mode, 250135c4bbdfSmrg int n, 250235c4bbdfSmrg DDXPointPtr points) 250335c4bbdfSmrg{ 250435c4bbdfSmrg if (gc->lineWidth == 0) { 250535c4bbdfSmrg if (gc->lineStyle == LineSolid) 250635c4bbdfSmrg miZeroLine(drawable, gc, mode, n, points); 250735c4bbdfSmrg else 250835c4bbdfSmrg miZeroDashLine(drawable, gc, mode, n, points); 250935c4bbdfSmrg } else { 251035c4bbdfSmrg if (gc->lineStyle == LineSolid) 251135c4bbdfSmrg miWideLine(drawable, gc, mode, n, points); 251235c4bbdfSmrg else 251335c4bbdfSmrg miWideDash(drawable, gc, mode, n, points); 251435c4bbdfSmrg } 251505b261ecSmrg} 2516