3 Copyright 1988, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
29 /* Author: Keith Packard, MIT X Consortium */
32 * Mostly integer wideline code. Uses a technique similar to
33 * bresenham zero-width lines, except walks an X edge
36 #ifdef HAVE_DIX_CONFIG_H
37 #include <dix-config.h>
44 #define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
49 #include "windowstr.h"
51 #include "regionstr.h"
52 #include "miwideline.h"
56 InitSpans(Spans
* spans
, size_t nspans
)
58 spans
->points
= malloc(nspans
* sizeof(*spans
->points
));
61 spans
->widths
= malloc(nspans
* sizeof(*spans
->widths
));
70 * interface data to span-merging polygon filler
73 typedef struct _SpanData
{
74 SpanGroup fgGroup
, bgGroup
;
75 } SpanDataRec
, *SpanDataPtr
;
78 AppendSpanGroup(GCPtr pGC
, unsigned long pixel
, Spans
* spanPtr
,
81 SpanGroup
*group
, *othergroup
= NULL
;
83 if (pixel
== pGC
->fgPixel
) {
84 group
= &spanData
->fgGroup
;
85 if (pGC
->lineStyle
== LineDoubleDash
)
86 othergroup
= &spanData
->bgGroup
;
89 group
= &spanData
->bgGroup
;
90 othergroup
= &spanData
->fgGroup
;
92 miAppendSpans(group
, othergroup
, spanPtr
);
95 static void miLineArc(DrawablePtr pDraw
, GCPtr pGC
,
96 unsigned long pixel
, SpanDataPtr spanData
,
98 LineFacePtr rightFace
,
99 double xorg
, double yorg
, Bool isInt
);
102 * spans-based polygon filler
106 fillSpans(DrawablePtr pDrawable
, GCPtr pGC
, unsigned long pixel
, Spans
* spans
,
107 SpanDataPtr spanData
)
110 ChangeGCVal oldPixel
, tmpPixel
;
112 oldPixel
.val
= pGC
->fgPixel
;
113 if (pixel
!= oldPixel
.val
) {
114 tmpPixel
.val
= (XID
) pixel
;
115 ChangeGC(NullClient
, pGC
, GCForeground
, &tmpPixel
);
116 ValidateGC(pDrawable
, pGC
);
118 (*pGC
->ops
->FillSpans
) (pDrawable
, pGC
, spans
->count
, spans
->points
,
119 spans
->widths
, TRUE
);
122 if (pixel
!= oldPixel
.val
) {
123 ChangeGC(NullClient
, pGC
, GCForeground
, &oldPixel
);
124 ValidateGC(pDrawable
, pGC
);
128 AppendSpanGroup(pGC
, pixel
, spans
, spanData
);
132 miFillPolyHelper(DrawablePtr pDrawable
, GCPtr pGC
, unsigned long pixel
,
133 SpanDataPtr spanData
, int y
, int overall_height
,
134 PolyEdgePtr left
, PolyEdgePtr right
,
135 int left_count
, int right_count
)
137 int left_x
= 0, left_e
= 0;
140 int left_dy
= 0, left_dx
= 0;
142 int right_x
= 0, right_e
= 0;
144 int right_signdx
= 0;
145 int right_dy
= 0, right_dx
= 0;
148 int left_height
= 0, right_height
= 0;
155 if (!InitSpans(&spanRec
, overall_height
))
157 ppt
= spanRec
.points
;
158 pwidth
= spanRec
.widths
;
161 if (pGC
->miTranslate
) {
165 while ((left_count
|| left_height
) && (right_count
|| right_height
)) {
166 if (!left_height
&& left_count
) {
167 left_height
= left
->height
;
169 left_stepx
= left
->stepx
;
170 left_signdx
= left
->signdx
;
178 if (!right_height
&& right_count
) {
179 right_height
= right
->height
;
181 right_stepx
= right
->stepx
;
182 right_signdx
= right
->signdx
;
184 right_dy
= right
->dy
;
185 right_dx
= right
->dx
;
190 height
= left_height
;
191 if (height
> right_height
)
192 height
= right_height
;
194 left_height
-= height
;
195 right_height
-= height
;
197 while (--height
>= 0) {
198 if (right_x
>= left_x
) {
200 ppt
->x
= left_x
+ xorg
;
202 *pwidth
++ = right_x
- left_x
+ 1;
206 left_x
+= left_stepx
;
209 left_x
+= left_signdx
;
213 right_x
+= right_stepx
;
216 right_x
+= right_signdx
;
221 spanRec
.count
= ppt
- spanRec
.points
;
222 fillSpans(pDrawable
, pGC
, pixel
, &spanRec
, spanData
);
226 miFillRectPolyHelper(DrawablePtr pDrawable
,
229 SpanDataPtr spanData
, int x
, int y
, int w
, int h
)
233 ChangeGCVal oldPixel
, tmpPixel
;
242 oldPixel
.val
= pGC
->fgPixel
;
243 if (pixel
!= oldPixel
.val
) {
244 tmpPixel
.val
= (XID
) pixel
;
245 ChangeGC(NullClient
, pGC
, GCForeground
, &tmpPixel
);
246 ValidateGC(pDrawable
, pGC
);
248 (*pGC
->ops
->PolyFillRect
) (pDrawable
, pGC
, 1, &rect
);
249 if (pixel
!= oldPixel
.val
) {
250 ChangeGC(NullClient
, pGC
, GCForeground
, &oldPixel
);
251 ValidateGC(pDrawable
, pGC
);
255 if (!InitSpans(&spanRec
, h
))
257 ppt
= spanRec
.points
;
258 pwidth
= spanRec
.widths
;
260 if (pGC
->miTranslate
) {
271 spanRec
.count
= ppt
- spanRec
.points
;
272 AppendSpanGroup(pGC
, pixel
, &spanRec
, spanData
);
277 miPolyBuildEdge(double x0
, double y0
, double k
, /* x0 * dy - y0 * dx */
278 int dx
, int dy
, int xi
, int yi
, int left
, PolyEdgePtr edge
)
291 double realk
, kerror
;
293 realk
= x0
* dy
- y0
* dx
;
294 kerror
= fabs(realk
- k
);
296 printf("realk: %g k: %g\n", realk
, k
);
300 xady
= ICEIL(k
) + y
* dx
;
303 x
= -(-xady
/ dy
) - 1;
311 edge
->stepx
= dx
/ dy
;
316 edge
->stepx
= -(-dx
/ dy
);
321 edge
->x
= x
+ left
+ xi
;
322 edge
->e
= e
- dy
; /* bias to compare against 0 instead of dy */
326 #define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
329 miPolyBuildPoly(PolyVertexPtr vertices
,
335 PolyEdgePtr right
, int *pnleft
, int *pnright
, int *h
)
345 int y
, lasty
= 0, bottomy
, topy
= 0;
347 /* find the top of the polygon */
348 maxy
= miny
= vertices
[0].y
;
350 for (i
= 1; i
< count
; i
++) {
351 if (vertices
[i
].y
< miny
) {
353 miny
= vertices
[i
].y
;
355 if (vertices
[i
].y
>= maxy
) {
357 maxy
= vertices
[i
].y
;
364 j
= StepAround(top
, -1, count
);
366 if ((int64_t) slopes
[j
].dy
* slopes
[i
].dx
>
367 (int64_t) slopes
[i
].dy
* slopes
[j
].dx
) {
372 bottomy
= ICEIL(maxy
) + yi
;
376 s
= StepAround(top
, slopeoff
, count
);
378 while (i
!= bottom
) {
379 if (slopes
[s
].dy
!= 0) {
380 y
= miPolyBuildEdge(vertices
[i
].x
, vertices
[i
].y
,
382 slopes
[s
].dx
, slopes
[s
].dy
,
383 xi
, yi
, 0, &right
[nright
]);
385 right
[nright
- 1].height
= y
- lasty
;
392 i
= StepAround(i
, clockwise
, count
);
393 s
= StepAround(s
, clockwise
, count
);
396 right
[nright
- 1].height
= bottomy
- lasty
;
404 s
= StepAround(top
, slopeoff
, count
);
406 while (i
!= bottom
) {
407 if (slopes
[s
].dy
!= 0) {
408 y
= miPolyBuildEdge(vertices
[i
].x
, vertices
[i
].y
,
410 slopes
[s
].dx
, slopes
[s
].dy
, xi
, yi
, 1,
414 left
[nleft
- 1].height
= y
- lasty
;
418 i
= StepAround(i
, -clockwise
, count
);
419 s
= StepAround(s
, -clockwise
, count
);
422 left
[nleft
- 1].height
= bottomy
- lasty
;
430 miLineOnePoint(DrawablePtr pDrawable
,
432 unsigned long pixel
, SpanDataPtr spanData
, int x
, int y
)
436 unsigned long oldPixel
;
438 MILINESETPIXEL(pDrawable
, pGC
, pixel
, oldPixel
);
439 if (pGC
->fillStyle
== FillSolid
) {
442 (*pGC
->ops
->PolyPoint
) (pDrawable
, pGC
, CoordModeOrigin
, 1, &pt
);
446 if (pGC
->miTranslate
) {
452 (*pGC
->ops
->FillSpans
) (pDrawable
, pGC
, 1, &pt
, &wid
, TRUE
);
454 MILINERESETPIXEL(pDrawable
, pGC
, pixel
, oldPixel
);
458 miLineJoin(DrawablePtr pDrawable
,
461 SpanDataPtr spanData
, LineFacePtr pLeft
, LineFacePtr pRight
)
463 double mx
= 0, my
= 0;
465 PolyVertexRec vertices
[4];
466 PolySlopeRec slopes
[4];
468 PolyEdgeRec left
[4], right
[4];
472 int joinStyle
= pGC
->joinStyle
;
473 int lw
= pGC
->lineWidth
;
475 if (lw
== 1 && !spanData
) {
476 /* See if one of the lines will draw the joining pixel */
477 if (pLeft
->dx
> 0 || (pLeft
->dx
== 0 && pLeft
->dy
> 0))
479 if (pRight
->dx
> 0 || (pRight
->dx
== 0 && pRight
->dy
> 0))
481 if (joinStyle
!= JoinRound
) {
483 -pLeft
->dx
* (double) pRight
->dy
+
484 pRight
->dx
* (double) pLeft
->dy
;
486 return; /* no join to draw */
488 if (joinStyle
!= JoinMiter
) {
489 miLineOnePoint(pDrawable
, pGC
, pixel
, spanData
, pLeft
->x
, pLeft
->y
);
494 if (joinStyle
== JoinRound
) {
495 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
496 pLeft
, pRight
, (double) 0.0, (double) 0.0, TRUE
);
500 -pLeft
->dx
* (double) pRight
->dy
+ pRight
->dx
* (double) pLeft
->dy
;
502 return; /* no join to draw */
507 pLeft
->xa
= -pLeft
->xa
;
508 pLeft
->ya
= -pLeft
->ya
;
509 pLeft
->dx
= -pLeft
->dx
;
510 pLeft
->dy
= -pLeft
->dy
;
514 pRight
->xa
= -pRight
->xa
;
515 pRight
->ya
= -pRight
->ya
;
516 pRight
->dx
= -pRight
->dx
;
517 pRight
->dy
= -pRight
->dy
;
520 vertices
[0].x
= pRight
->xa
;
521 vertices
[0].y
= pRight
->ya
;
522 slopes
[0].dx
= -pRight
->dy
;
523 slopes
[0].dy
= pRight
->dx
;
528 slopes
[1].dx
= pLeft
->dy
;
529 slopes
[1].dy
= -pLeft
->dx
;
532 vertices
[2].x
= pLeft
->xa
;
533 vertices
[2].y
= pLeft
->ya
;
535 if (joinStyle
== JoinMiter
) {
536 my
= (pLeft
->dy
* (pRight
->xa
* pRight
->dy
- pRight
->ya
* pRight
->dx
) -
537 pRight
->dy
* (pLeft
->xa
* pLeft
->dy
- pLeft
->ya
* pLeft
->dx
)) /
539 if (pLeft
->dy
!= 0) {
540 mx
= pLeft
->xa
+ (my
- pLeft
->ya
) *
541 (double) pLeft
->dx
/ (double) pLeft
->dy
;
544 mx
= pRight
->xa
+ (my
- pRight
->ya
) *
545 (double) pRight
->dx
/ (double) pRight
->dy
;
547 /* check miter limit */
548 if ((mx
* mx
+ my
* my
) * 4 > SQSECANT
* lw
* lw
)
549 joinStyle
= JoinBevel
;
552 if (joinStyle
== JoinMiter
) {
553 slopes
[2].dx
= pLeft
->dx
;
554 slopes
[2].dy
= pLeft
->dy
;
555 slopes
[2].k
= pLeft
->k
;
557 slopes
[2].dx
= -slopes
[2].dx
;
558 slopes
[2].dy
= -slopes
[2].dy
;
559 slopes
[2].k
= -slopes
[2].k
;
563 slopes
[3].dx
= pRight
->dx
;
564 slopes
[3].dy
= pRight
->dy
;
565 slopes
[3].k
= pRight
->k
;
567 slopes
[3].dx
= -slopes
[3].dx
;
568 slopes
[3].dy
= -slopes
[3].dy
;
569 slopes
[3].k
= -slopes
[3].k
;
574 double scale
, dx
, dy
, adx
, ady
;
576 adx
= dx
= pRight
->xa
- pLeft
->xa
;
577 ady
= dy
= pRight
->ya
- pLeft
->ya
;
585 slopes
[2].dx
= (dx
* 65536) / scale
;
586 slopes
[2].dy
= (dy
* 65536) / scale
;
587 slopes
[2].k
= ((pLeft
->xa
+ pRight
->xa
) * slopes
[2].dy
-
588 (pLeft
->ya
+ pRight
->ya
) * slopes
[2].dx
) / 2.0;
592 y
= miPolyBuildPoly(vertices
, slopes
, edgecount
, pLeft
->x
, pLeft
->y
,
593 left
, right
, &nleft
, &nright
, &height
);
594 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, y
, height
, left
, right
,
599 miLineArcI(DrawablePtr pDraw
,
600 GCPtr pGC
, int xorg
, int yorg
, DDXPointPtr points
, int *widths
)
602 DDXPointPtr tpts
, bpts
;
604 int x
, y
, e
, ex
, slw
;
608 if (pGC
->miTranslate
) {
612 slw
= pGC
->lineWidth
;
632 e
+= (ex
= -((x
<< 3) + 4));
636 if ((e
== ex
) && (slw
> 1))
642 if ((y
!= 0) && ((slw
> 1) || (e
!= ex
))) {
649 return pGC
->lineWidth
;
652 #define CLIPSTEPEDGE(edgey,edge,edgeleft) \
653 if (ybase == edgey) \
666 edge->x += edge->stepx; \
667 edge->e += edge->dx; \
670 edge->x += edge->signdx; \
671 edge->e -= edge->dy; \
676 miLineArcD(DrawablePtr pDraw
,
684 Bool edgeleft1
, PolyEdgePtr edge2
, int edgey2
, Bool edgeleft2
)
688 double radius
, x0
, y0
, el
, er
, yk
, xlk
, xrk
, k
;
689 int xbase
, ybase
, y
, boty
, xl
, xr
, xcl
, xcr
;
691 Bool edge1IsMin
, edge2IsMin
;
700 if (pGC
->miTranslate
) {
703 edge1
->x
+= pDraw
->x
;
704 edge2
->x
+= pDraw
->x
;
711 radius
= ((double) pGC
->lineWidth
) / 2.0;
712 y
= floor(radius
- y0
+ 1.0);
718 if (edge1
->dy
>= 0) {
727 if ((edge1
->signdx
< 0) == edgeleft1
)
733 if (edge2
->dy
>= 0) {
742 if ((edge2
->signdx
< 0) == edgeleft2
)
748 if (edge2IsMin
&& ymin1
> ymin2
)
753 el
= radius
* radius
- ((y
+ y0
) * (y
+ y0
)) - (x0
* x0
);
761 boty
= (y0
< -0.5) ? 1 : 0;
762 if (ybase
+ y
- boty
> ymax
)
763 boty
= ymax
- ybase
- y
;
769 er
+= xrk
- (xr
<< 1);
774 el
+= (xl
<< 1) - xlk
;
782 CLIPSTEPEDGE(edgey1
, edge1
, edgeleft1
);
783 CLIPSTEPEDGE(edgey2
, edge2
, edgeleft2
);
788 *wids
++ = xcr
- xcl
+ 1;
791 er
= xrk
- (xr
<< 1) - er
;
792 el
= (xl
<< 1) - xlk
- el
;
793 boty
= floor(-y0
- radius
+ 1.0);
794 if (ybase
+ y
- boty
> ymax
)
795 boty
= ymax
- ybase
- y
;
799 while ((er
>= 0.0) && (xr
>= 0)) {
801 er
+= xrk
- (xr
<< 1);
804 while ((el
> 0.0) && (xl
<= 0)) {
806 el
+= (xl
<< 1) - xlk
;
814 CLIPSTEPEDGE(edgey1
, edge1
, edgeleft1
);
815 CLIPSTEPEDGE(edgey2
, edge2
, edgeleft2
);
820 *wids
++ = xcr
- xcl
+ 1;
827 miRoundJoinFace(LineFacePtr face
, PolyEdgePtr edge
, Bool
*leftEdge
)
843 if (dy
< 0 || (dy
== 0 && dx
> 0)) {
848 if (dx
== 0 && dy
== 0)
851 y
= ICEIL(face
->ya
) + face
->y
;
861 y
= miPolyBuildEdge(xa
, ya
, 0.0, dx
, dy
, face
->x
, face
->y
, !left
, edge
);
862 edge
->height
= 32767;
869 miRoundJoinClip(LineFacePtr pLeft
, LineFacePtr pRight
,
870 PolyEdgePtr edge1
, PolyEdgePtr edge2
,
871 int *y1
, int *y2
, Bool
*left1
, Bool
*left2
)
875 denom
= -pLeft
->dx
* (double) pRight
->dy
+ pRight
->dx
* (double) pLeft
->dy
;
878 pLeft
->xa
= -pLeft
->xa
;
879 pLeft
->ya
= -pLeft
->ya
;
882 pRight
->xa
= -pRight
->xa
;
883 pRight
->ya
= -pRight
->ya
;
885 *y1
= miRoundJoinFace(pLeft
, edge1
, left1
);
886 *y2
= miRoundJoinFace(pRight
, edge2
, left2
);
890 miRoundCapClip(LineFacePtr face
, Bool isInt
, PolyEdgePtr edge
, Bool
*leftEdge
)
905 if (dy
< 0 || (dy
== 0 && dx
> 0)) {
912 if (dx
== 0 && dy
== 0)
915 y
= ICEIL(face
->ya
) + face
->y
;
925 y
= miPolyBuildEdge(xa
, ya
, k
, dx
, dy
, face
->x
, face
->y
, !left
, edge
);
926 edge
->height
= 32767;
933 miLineArc(DrawablePtr pDraw
,
936 SpanDataPtr spanData
,
937 LineFacePtr leftFace
,
938 LineFacePtr rightFace
, double xorg
, double yorg
, Bool isInt
)
940 int xorgi
= 0, yorgi
= 0;
943 PolyEdgeRec edge1
, edge2
;
945 Bool edgeleft1
, edgeleft2
;
948 xorgi
= leftFace
? leftFace
->x
: rightFace
->x
;
949 yorgi
= leftFace
? leftFace
->y
: rightFace
->y
;
953 edge1
.x
= 0; /* not used, keep memory checkers happy */
955 edge2
.x
= 0; /* not used, keep memory checkers happy */
959 if ((pGC
->lineStyle
!= LineSolid
|| pGC
->lineWidth
> 2) &&
960 ((pGC
->capStyle
== CapRound
&& pGC
->joinStyle
!= JoinRound
) ||
961 (pGC
->joinStyle
== JoinRound
&& pGC
->capStyle
== CapButt
))) {
963 xorg
= (double) xorgi
;
964 yorg
= (double) yorgi
;
966 if (leftFace
&& rightFace
) {
967 miRoundJoinClip(leftFace
, rightFace
, &edge1
, &edge2
,
968 &edgey1
, &edgey2
, &edgeleft1
, &edgeleft2
);
971 edgey1
= miRoundCapClip(leftFace
, isInt
, &edge1
, &edgeleft1
);
973 else if (rightFace
) {
974 edgey2
= miRoundCapClip(rightFace
, isInt
, &edge2
, &edgeleft2
);
978 if (!InitSpans(&spanRec
, pGC
->lineWidth
))
981 n
= miLineArcI(pDraw
, pGC
, xorgi
, yorgi
, spanRec
.points
,
984 n
= miLineArcD(pDraw
, pGC
, xorg
, yorg
, spanRec
.points
, spanRec
.widths
,
985 &edge1
, edgey1
, edgeleft1
, &edge2
, edgey2
, edgeleft2
);
987 fillSpans(pDraw
, pGC
, pixel
, &spanRec
, spanData
);
991 miLineProjectingCap(DrawablePtr pDrawable
, GCPtr pGC
, unsigned long pixel
,
992 SpanDataPtr spanData
, LineFacePtr face
, Bool isLeft
,
993 double xorg
, double yorg
, Bool isInt
)
995 int xorgi
= 0, yorgi
= 0;
997 PolyEdgeRec lefts
[4], rights
[4];
998 int lefty
, righty
, topy
, bottomy
;
999 PolyEdgePtr left
, right
;
1000 PolyEdgePtr top
, bottom
;
1005 double projectXoff
, projectYoff
;
1013 lw
= pGC
->lineWidth
;
1018 lefts
[0].height
= lw
;
1021 lefts
[0].x
-= (lw
>> 1);
1023 lefts
[0].signdx
= 1;
1027 rights
[0].height
= lw
;
1028 rights
[0].x
= xorgi
;
1030 rights
[0].x
+= ((lw
+ 1) >> 1);
1031 rights
[0].stepx
= 0;
1032 rights
[0].signdx
= 1;
1036 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, yorgi
- (lw
>> 1), lw
,
1037 lefts
, rights
, 1, 1);
1045 bottomy
= yorgi
+ dy
;
1049 bottomy
+= (lw
>> 1);
1050 lefts
[0].height
= bottomy
- topy
;
1051 lefts
[0].x
= xorgi
- (lw
>> 1);
1053 lefts
[0].signdx
= 1;
1058 rights
[0].height
= bottomy
- topy
;
1059 rights
[0].x
= lefts
[0].x
+ (lw
- 1);
1060 rights
[0].stepx
= 0;
1061 rights
[0].signdx
= 1;
1065 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, topy
, bottomy
- topy
,
1066 lefts
, rights
, 1, 1);
1083 bottom
= &rights
[1];
1086 righty
= miPolyBuildEdge(xa
, ya
, k
, dx
, dy
, xorgi
, yorgi
, 0, right
);
1091 lefty
= miPolyBuildEdge(xa
- projectXoff
, ya
- projectYoff
,
1092 k
, dx
, dy
, xorgi
, yorgi
, 1, left
);
1097 xap
= xa
- projectXoff
;
1098 yap
= ya
- projectYoff
;
1099 topy
= miPolyBuildEdge(xap
, yap
, xap
* dx
+ yap
* dy
,
1100 -dy
, dx
, xorgi
, yorgi
, dx
> 0, top
);
1101 bottomy
= miPolyBuildEdge(xa
, ya
,
1102 0.0, -dy
, dx
, xorgi
, yorgi
, dx
< 0,
1107 righty
= miPolyBuildEdge(xa
- projectXoff
, ya
- projectYoff
,
1108 k
, dx
, dy
, xorgi
, yorgi
, 0, right
);
1113 lefty
= miPolyBuildEdge(xa
, ya
, k
, dx
, dy
, xorgi
, yorgi
, 1, left
);
1118 xap
= xa
- projectXoff
;
1119 yap
= ya
- projectYoff
;
1121 miPolyBuildEdge(xa
, ya
, 0.0, -dy
, dx
, xorgi
, xorgi
, dx
> 0,
1124 miPolyBuildEdge(xap
, yap
, xap
* dx
+ yap
* dy
, -dy
, dx
, xorgi
,
1125 xorgi
, dx
< 0, bottom
);
1126 maxy
= -ya
+ projectYoff
;
1128 finaly
= ICEIL(maxy
) + yorgi
;
1130 left
->height
= bottomy
- lefty
;
1131 right
->height
= finaly
- righty
;
1132 top
->height
= righty
- topy
;
1135 right
->height
= bottomy
- righty
;
1136 left
->height
= finaly
- lefty
;
1137 top
->height
= lefty
- topy
;
1139 bottom
->height
= finaly
- bottomy
;
1140 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, topy
,
1141 bottom
->height
+ bottomy
- topy
, lefts
, rights
, 2, 2);
1146 miWideSegment(DrawablePtr pDrawable
,
1148 unsigned long pixel
,
1149 SpanDataPtr spanData
,
1155 Bool projectRight
, LineFacePtr leftFace
, LineFacePtr rightFace
)
1159 double projectXoff
= 0.0, projectYoff
= 0.0;
1165 PolyEdgePtr left
, right
;
1166 PolyEdgePtr top
, bottom
;
1167 int lefty
, righty
, topy
, bottomy
;
1169 PolyEdgeRec lefts
[4], rights
[4];
1171 int lw
= pGC
->lineWidth
;
1173 /* draw top-to-bottom always */
1174 if (y2
< y1
|| (y2
== y1
&& x2
< x1
)) {
1184 projectLeft
= projectRight
;
1188 leftFace
= rightFace
;
1205 rightFace
->dx
= -dx
;
1206 rightFace
->dy
= -dy
;
1210 rightFace
->ya
= (double) lw
/ 2.0;
1211 rightFace
->k
= -(double) (lw
* dx
) / 2.0;
1213 leftFace
->ya
= -rightFace
->ya
;
1214 leftFace
->k
= rightFace
->k
;
1221 dx
+= ((lw
+ 1) >> 1);
1223 miFillRectPolyHelper(pDrawable
, pGC
, pixel
, spanData
, x
, y
, dx
, dy
);
1226 leftFace
->xa
= (double) lw
/ 2.0;
1228 leftFace
->k
= (double) (lw
* dy
) / 2.0;
1229 rightFace
->xa
= -leftFace
->xa
;
1231 rightFace
->k
= leftFace
->k
;
1238 dy
+= ((lw
+ 1) >> 1);
1240 miFillRectPolyHelper(pDrawable
, pGC
, pixel
, spanData
, x
, y
, dx
, dy
);
1243 l
= ((double) lw
) / 2.0;
1244 L
= hypot((double) dx
, (double) dy
);
1256 bottom
= &rights
[1];
1260 /* coord of upper bound at integral y */
1264 if (projectLeft
| projectRight
) {
1269 /* xa * dy - ya * dx */
1275 rightFace
->xa
= -xa
;
1276 rightFace
->ya
= -ya
;
1280 righty
= miPolyBuildEdge(xa
- projectXoff
, ya
- projectYoff
,
1281 k
, dx
, dy
, x1
, y1
, 0, right
);
1283 righty
= miPolyBuildEdge(xa
, ya
, k
, dx
, dy
, x1
, y1
, 0, right
);
1285 /* coord of lower bound at integral y */
1289 /* xa * dy - ya * dx */
1293 lefty
= miPolyBuildEdge(xa
- projectXoff
, ya
- projectYoff
,
1294 k
, dx
, dy
, x1
, y1
, 1, left
);
1296 lefty
= miPolyBuildEdge(xa
, ya
, k
, dx
, dy
, x1
, y1
, 1, left
);
1298 /* coord of top face at integral y */
1306 double xap
= xa
- projectXoff
;
1307 double yap
= ya
- projectYoff
;
1309 topy
= miPolyBuildEdge(xap
, yap
, xap
* dx
+ yap
* dy
,
1310 -dy
, dx
, x1
, y1
, dx
> 0, top
);
1313 topy
= miPolyBuildEdge(xa
, ya
, 0.0, -dy
, dx
, x1
, y1
, dx
> 0, top
);
1315 /* coord of bottom face at integral y */
1318 double xap
= xa
+ projectXoff
;
1319 double yap
= ya
+ projectYoff
;
1321 bottomy
= miPolyBuildEdge(xap
, yap
, xap
* dx
+ yap
* dy
,
1322 -dy
, dx
, x2
, y2
, dx
< 0, bottom
);
1323 maxy
= -ya
+ projectYoff
;
1326 bottomy
= miPolyBuildEdge(xa
, ya
,
1327 0.0, -dy
, dx
, x2
, y2
, dx
< 0, bottom
);
1331 finaly
= ICEIL(maxy
) + y2
;
1334 left
->height
= bottomy
- lefty
;
1335 right
->height
= finaly
- righty
;
1336 top
->height
= righty
- topy
;
1339 right
->height
= bottomy
- righty
;
1340 left
->height
= finaly
- lefty
;
1341 top
->height
= lefty
- topy
;
1343 bottom
->height
= finaly
- bottomy
;
1344 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, topy
,
1345 bottom
->height
+ bottomy
- topy
, lefts
, rights
, 2, 2);
1350 miSetupSpanData(GCPtr pGC
, SpanDataPtr spanData
, int npt
)
1352 if ((npt
< 3 && pGC
->capStyle
!= CapRound
) || miSpansEasyRop(pGC
->alu
))
1353 return (SpanDataPtr
) NULL
;
1354 if (pGC
->lineStyle
== LineDoubleDash
)
1355 miInitSpanGroup(&spanData
->bgGroup
);
1356 miInitSpanGroup(&spanData
->fgGroup
);
1361 miCleanupSpanData(DrawablePtr pDrawable
, GCPtr pGC
, SpanDataPtr spanData
)
1363 if (pGC
->lineStyle
== LineDoubleDash
) {
1364 ChangeGCVal oldPixel
, pixel
;
1366 pixel
.val
= pGC
->bgPixel
;
1367 oldPixel
.val
= pGC
->fgPixel
;
1368 if (pixel
.val
!= oldPixel
.val
) {
1369 ChangeGC(NullClient
, pGC
, GCForeground
, &pixel
);
1370 ValidateGC(pDrawable
, pGC
);
1372 miFillUniqueSpanGroup(pDrawable
, pGC
, &spanData
->bgGroup
);
1373 miFreeSpanGroup(&spanData
->bgGroup
);
1374 if (pixel
.val
!= oldPixel
.val
) {
1375 ChangeGC(NullClient
, pGC
, GCForeground
, &oldPixel
);
1376 ValidateGC(pDrawable
, pGC
);
1379 miFillUniqueSpanGroup(pDrawable
, pGC
, &spanData
->fgGroup
);
1380 miFreeSpanGroup(&spanData
->fgGroup
);
1384 miWideLine(DrawablePtr pDrawable
, GCPtr pGC
,
1385 int mode
, int npt
, DDXPointPtr pPts
)
1388 SpanDataRec spanDataRec
;
1389 SpanDataPtr spanData
;
1391 Bool projectLeft
, projectRight
;
1392 LineFaceRec leftFace
, rightFace
, prevRightFace
;
1393 LineFaceRec firstFace
;
1395 Bool somethingDrawn
= FALSE
;
1398 spanData
= miSetupSpanData(pGC
, &spanDataRec
, npt
);
1399 pixel
= pGC
->fgPixel
;
1405 if (mode
== CoordModePrevious
) {
1407 DDXPointPtr pPtsTmp
;
1418 if (x2
== x1
&& y2
== y1
)
1421 else if (x2
== pPts
[npt
- 1].x
&& y2
== pPts
[npt
- 1].y
) {
1425 projectLeft
= pGC
->capStyle
== CapProjecting
&& !selfJoin
;
1426 projectRight
= FALSE
;
1433 if (mode
== CoordModePrevious
) {
1437 if (x1
!= x2
|| y1
!= y2
) {
1438 somethingDrawn
= TRUE
;
1439 if (npt
== 1 && pGC
->capStyle
== CapProjecting
&& !selfJoin
)
1440 projectRight
= TRUE
;
1441 miWideSegment(pDrawable
, pGC
, pixel
, spanData
, x1
, y1
, x2
, y2
,
1442 projectLeft
, projectRight
, &leftFace
, &rightFace
);
1445 firstFace
= leftFace
;
1446 else if (pGC
->capStyle
== CapRound
) {
1447 if (pGC
->lineWidth
== 1 && !spanData
)
1448 miLineOnePoint(pDrawable
, pGC
, pixel
, spanData
, x1
, y1
);
1450 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1451 &leftFace
, (LineFacePtr
) NULL
,
1452 (double) 0.0, (double) 0.0, TRUE
);
1456 miLineJoin(pDrawable
, pGC
, pixel
, spanData
, &leftFace
,
1459 prevRightFace
= rightFace
;
1461 projectLeft
= FALSE
;
1463 if (npt
== 1 && somethingDrawn
) {
1465 miLineJoin(pDrawable
, pGC
, pixel
, spanData
, &firstFace
,
1467 else if (pGC
->capStyle
== CapRound
) {
1468 if (pGC
->lineWidth
== 1 && !spanData
)
1469 miLineOnePoint(pDrawable
, pGC
, pixel
, spanData
, x2
, y2
);
1471 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1472 (LineFacePtr
) NULL
, &rightFace
,
1473 (double) 0.0, (double) 0.0, TRUE
);
1477 /* handle crock where all points are coincedent */
1478 if (!somethingDrawn
) {
1479 projectLeft
= pGC
->capStyle
== CapProjecting
;
1480 miWideSegment(pDrawable
, pGC
, pixel
, spanData
,
1481 x2
, y2
, x2
, y2
, projectLeft
, projectLeft
,
1482 &leftFace
, &rightFace
);
1483 if (pGC
->capStyle
== CapRound
) {
1484 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1485 &leftFace
, (LineFacePtr
) NULL
,
1486 (double) 0.0, (double) 0.0, TRUE
);
1487 rightFace
.dx
= -1; /* sleezy hack to make it work */
1488 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1489 (LineFacePtr
) NULL
, &rightFace
,
1490 (double) 0.0, (double) 0.0, TRUE
);
1494 miCleanupSpanData(pDrawable
, pGC
, spanData
);
1503 miWideDashSegment(DrawablePtr pDrawable
,
1505 SpanDataPtr spanData
,
1514 LineFacePtr leftFace
, LineFacePtr rightFace
)
1516 int dashIndex
, dashRemain
;
1517 unsigned char *pDash
;
1520 PolyVertexRec vertices
[4];
1521 PolyVertexRec saveRight
, saveBottom
;
1522 PolySlopeRec slopes
[4];
1523 PolyEdgeRec left
[4], right
[4];
1524 LineFaceRec lcapFace
, rcapFace
;
1529 unsigned long pixel
;
1533 double dashDx
, dashDy
;
1536 double lcenterx
, lcentery
, rcenterx
= 0.0, rcentery
= 0.0;
1537 unsigned long fgPixel
, bgPixel
;
1541 dashIndex
= *pDashIndex
;
1543 dashRemain
= pDash
[dashIndex
] - *pDashOffset
;
1544 fgPixel
= pGC
->fgPixel
;
1545 bgPixel
= pGC
->bgPixel
;
1546 if (pGC
->fillStyle
== FillOpaqueStippled
|| pGC
->fillStyle
== FillTiled
) {
1550 l
= ((double) pGC
->lineWidth
) / 2.0;
1570 L
= hypot((double) dx
, (double) dy
);
1578 /* All position comments are relative to a line with dx and dy > 0,
1579 * but the code does not depend on this */
1581 slopes
[V_TOP
].dx
= dx
;
1582 slopes
[V_TOP
].dy
= dy
;
1583 slopes
[V_TOP
].k
= k
;
1585 slopes
[V_RIGHT
].dx
= -dy
;
1586 slopes
[V_RIGHT
].dy
= dx
;
1587 slopes
[V_RIGHT
].k
= 0;
1589 slopes
[V_BOTTOM
].dx
= -dx
;
1590 slopes
[V_BOTTOM
].dy
= -dy
;
1591 slopes
[V_BOTTOM
].k
= k
;
1593 slopes
[V_LEFT
].dx
= dy
;
1594 slopes
[V_LEFT
].dy
= -dx
;
1595 slopes
[V_LEFT
].k
= 0;
1597 /* preload the start coordinates */
1598 vertices
[V_RIGHT
].x
= vertices
[V_TOP
].x
= rdy
;
1599 vertices
[V_RIGHT
].y
= vertices
[V_TOP
].y
= -rdx
;
1601 vertices
[V_BOTTOM
].x
= vertices
[V_LEFT
].x
= -rdy
;
1602 vertices
[V_BOTTOM
].y
= vertices
[V_LEFT
].y
= rdx
;
1605 vertices
[V_TOP
].x
-= rdx
;
1606 vertices
[V_TOP
].y
-= rdy
;
1608 vertices
[V_LEFT
].x
-= rdx
;
1609 vertices
[V_LEFT
].y
-= rdy
;
1611 slopes
[V_LEFT
].k
= rdx
* dx
+ rdy
* dy
;
1617 if (pGC
->capStyle
== CapRound
) {
1628 while (LRemain
> dashRemain
) {
1629 dashDx
= (dashRemain
* dx
) / L
;
1630 dashDy
= (dashRemain
* dy
) / L
;
1632 rcenterx
= lcenterx
+ dashDx
;
1633 rcentery
= lcentery
+ dashDy
;
1635 vertices
[V_RIGHT
].x
+= dashDx
;
1636 vertices
[V_RIGHT
].y
+= dashDy
;
1638 vertices
[V_BOTTOM
].x
+= dashDx
;
1639 vertices
[V_BOTTOM
].y
+= dashDy
;
1641 slopes
[V_RIGHT
].k
= vertices
[V_RIGHT
].x
* dx
+ vertices
[V_RIGHT
].y
* dy
;
1643 if (pGC
->lineStyle
== LineDoubleDash
|| !(dashIndex
& 1)) {
1644 if (pGC
->lineStyle
== LineOnOffDash
&&
1645 pGC
->capStyle
== CapProjecting
) {
1646 saveRight
= vertices
[V_RIGHT
];
1647 saveBottom
= vertices
[V_BOTTOM
];
1648 saveK
= slopes
[V_RIGHT
].k
;
1651 vertices
[V_TOP
].x
-= rdx
;
1652 vertices
[V_TOP
].y
-= rdy
;
1654 vertices
[V_LEFT
].x
-= rdx
;
1655 vertices
[V_LEFT
].y
-= rdy
;
1657 slopes
[V_LEFT
].k
= vertices
[V_LEFT
].x
*
1659 vertices
[V_LEFT
].y
* slopes
[V_LEFT
].dx
;
1662 vertices
[V_RIGHT
].x
+= rdx
;
1663 vertices
[V_RIGHT
].y
+= rdy
;
1665 vertices
[V_BOTTOM
].x
+= rdx
;
1666 vertices
[V_BOTTOM
].y
+= rdy
;
1668 slopes
[V_RIGHT
].k
= vertices
[V_RIGHT
].x
*
1669 slopes
[V_RIGHT
].dy
-
1670 vertices
[V_RIGHT
].y
* slopes
[V_RIGHT
].dx
;
1672 y
= miPolyBuildPoly(vertices
, slopes
, 4, x1
, y1
,
1673 left
, right
, &nleft
, &nright
, &h
);
1674 pixel
= (dashIndex
& 1) ? bgPixel
: fgPixel
;
1675 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, y
, h
, left
, right
,
1678 if (pGC
->lineStyle
== LineOnOffDash
) {
1679 switch (pGC
->capStyle
) {
1681 vertices
[V_BOTTOM
] = saveBottom
;
1682 vertices
[V_RIGHT
] = saveRight
;
1683 slopes
[V_RIGHT
].k
= saveK
;
1688 lcapFace
.xa
= -vertices
[V_LEFT
].x
;
1689 lcapFace
.ya
= -vertices
[V_LEFT
].y
;
1690 lcapFace
.k
= slopes
[V_LEFT
].k
;
1693 lcapFace
.xa
= vertices
[V_TOP
].x
;
1694 lcapFace
.ya
= vertices
[V_TOP
].y
;
1695 lcapFace
.k
= -slopes
[V_LEFT
].k
;
1697 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1698 &lcapFace
, (LineFacePtr
) NULL
,
1699 lcenterx
, lcentery
, FALSE
);
1702 rcapFace
.xa
= vertices
[V_BOTTOM
].x
;
1703 rcapFace
.ya
= vertices
[V_BOTTOM
].y
;
1704 rcapFace
.k
= slopes
[V_RIGHT
].k
;
1707 rcapFace
.xa
= -vertices
[V_RIGHT
].x
;
1708 rcapFace
.ya
= -vertices
[V_RIGHT
].y
;
1709 rcapFace
.k
= -slopes
[V_RIGHT
].k
;
1711 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1712 (LineFacePtr
) NULL
, &rcapFace
,
1713 rcenterx
, rcentery
, FALSE
);
1718 LRemain
-= dashRemain
;
1720 if (dashIndex
== pGC
->numInDashList
)
1722 dashRemain
= pDash
[dashIndex
];
1724 lcenterx
= rcenterx
;
1725 lcentery
= rcentery
;
1727 vertices
[V_TOP
] = vertices
[V_RIGHT
];
1728 vertices
[V_LEFT
] = vertices
[V_BOTTOM
];
1729 slopes
[V_LEFT
].k
= -slopes
[V_RIGHT
].k
;
1733 if (pGC
->lineStyle
== LineDoubleDash
|| !(dashIndex
& 1)) {
1734 vertices
[V_TOP
].x
-= dx
;
1735 vertices
[V_TOP
].y
-= dy
;
1737 vertices
[V_LEFT
].x
-= dx
;
1738 vertices
[V_LEFT
].y
-= dy
;
1740 vertices
[V_RIGHT
].x
= rdy
;
1741 vertices
[V_RIGHT
].y
= -rdx
;
1743 vertices
[V_BOTTOM
].x
= -rdy
;
1744 vertices
[V_BOTTOM
].y
= rdx
;
1747 vertices
[V_RIGHT
].x
+= rdx
;
1748 vertices
[V_RIGHT
].y
+= rdy
;
1750 vertices
[V_BOTTOM
].x
+= rdx
;
1751 vertices
[V_BOTTOM
].y
+= rdy
;
1752 slopes
[V_RIGHT
].k
= vertices
[V_RIGHT
].x
*
1753 slopes
[V_RIGHT
].dy
- vertices
[V_RIGHT
].y
* slopes
[V_RIGHT
].dx
;
1756 slopes
[V_RIGHT
].k
= 0;
1758 if (!first
&& pGC
->lineStyle
== LineOnOffDash
&&
1759 pGC
->capStyle
== CapProjecting
) {
1760 vertices
[V_TOP
].x
-= rdx
;
1761 vertices
[V_TOP
].y
-= rdy
;
1763 vertices
[V_LEFT
].x
-= rdx
;
1764 vertices
[V_LEFT
].y
-= rdy
;
1765 slopes
[V_LEFT
].k
= vertices
[V_LEFT
].x
*
1766 slopes
[V_LEFT
].dy
- vertices
[V_LEFT
].y
* slopes
[V_LEFT
].dx
;
1769 slopes
[V_LEFT
].k
+= dx
* dx
+ dy
* dy
;
1771 y
= miPolyBuildPoly(vertices
, slopes
, 4, x2
, y2
,
1772 left
, right
, &nleft
, &nright
, &h
);
1774 pixel
= (dashIndex
& 1) ? pGC
->bgPixel
: pGC
->fgPixel
;
1775 miFillPolyHelper(pDrawable
, pGC
, pixel
, spanData
, y
, h
, left
, right
,
1777 if (!first
&& pGC
->lineStyle
== LineOnOffDash
&&
1778 pGC
->capStyle
== CapRound
) {
1782 lcapFace
.xa
= -vertices
[V_LEFT
].x
;
1783 lcapFace
.ya
= -vertices
[V_LEFT
].y
;
1784 lcapFace
.k
= slopes
[V_LEFT
].k
;
1787 lcapFace
.xa
= vertices
[V_TOP
].x
;
1788 lcapFace
.ya
= vertices
[V_TOP
].y
;
1789 lcapFace
.k
= -slopes
[V_LEFT
].k
;
1791 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1792 &lcapFace
, (LineFacePtr
) NULL
, rcenterx
, rcentery
, FALSE
);
1795 dashRemain
= ((double) dashRemain
) - LRemain
;
1796 if (dashRemain
== 0) {
1798 if (dashIndex
== pGC
->numInDashList
)
1800 dashRemain
= pDash
[dashIndex
];
1808 leftFace
->ya
= -rdx
;
1813 rightFace
->dx
= -dx
;
1814 rightFace
->dy
= -dy
;
1815 rightFace
->xa
= -rdy
;
1816 rightFace
->ya
= rdx
;
1819 *pDashIndex
= dashIndex
;
1820 *pDashOffset
= pDash
[dashIndex
] - dashRemain
;
1824 miWideDash(DrawablePtr pDrawable
, GCPtr pGC
,
1825 int mode
, int npt
, DDXPointPtr pPts
)
1828 unsigned long pixel
;
1829 Bool projectLeft
, projectRight
;
1830 LineFaceRec leftFace
, rightFace
, prevRightFace
;
1831 LineFaceRec firstFace
;
1833 int dashIndex
, dashOffset
;
1835 SpanDataRec spanDataRec
;
1836 SpanDataPtr spanData
;
1837 Bool somethingDrawn
= FALSE
;
1839 Bool endIsFg
= FALSE
, startIsFg
= FALSE
;
1840 Bool firstIsFg
= FALSE
, prevIsFg
= FALSE
;
1843 /* XXX backward compatibility */
1844 if (pGC
->lineWidth
== 0) {
1845 miZeroDashLine(pDrawable
, pGC
, mode
, npt
, pPts
);
1849 if (pGC
->lineStyle
== LineDoubleDash
&&
1850 (pGC
->fillStyle
== FillOpaqueStippled
|| pGC
->fillStyle
== FillTiled
)) {
1851 miWideLine(pDrawable
, pGC
, mode
, npt
, pPts
);
1856 spanData
= miSetupSpanData(pGC
, &spanDataRec
, npt
);
1861 if (mode
== CoordModePrevious
) {
1863 DDXPointPtr pPtsTmp
;
1874 if (x2
== x1
&& y2
== y1
)
1877 else if (x2
== pPts
[npt
- 1].x
&& y2
== pPts
[npt
- 1].y
) {
1880 projectLeft
= pGC
->capStyle
== CapProjecting
&& !selfJoin
;
1881 projectRight
= FALSE
;
1884 miStepDash((int) pGC
->dashOffset
, &dashIndex
,
1885 pGC
->dash
, (int) pGC
->numInDashList
, &dashOffset
);
1892 if (mode
== CoordModePrevious
) {
1896 if (x1
!= x2
|| y1
!= y2
) {
1897 somethingDrawn
= TRUE
;
1898 if (npt
== 1 && pGC
->capStyle
== CapProjecting
&&
1899 (!selfJoin
|| !firstIsFg
))
1900 projectRight
= TRUE
;
1901 prevDashIndex
= dashIndex
;
1902 miWideDashSegment(pDrawable
, pGC
, spanData
, &dashOffset
, &dashIndex
,
1904 projectLeft
, projectRight
, &leftFace
, &rightFace
);
1905 startIsFg
= !(prevDashIndex
& 1);
1906 endIsFg
= (dashIndex
& 1) ^ (dashOffset
!= 0);
1907 if (pGC
->lineStyle
== LineDoubleDash
|| startIsFg
) {
1908 pixel
= startIsFg
? pGC
->fgPixel
: pGC
->bgPixel
;
1909 if (first
|| (pGC
->lineStyle
== LineOnOffDash
&& !prevIsFg
)) {
1910 if (first
&& selfJoin
) {
1911 firstFace
= leftFace
;
1912 firstIsFg
= startIsFg
;
1914 else if (pGC
->capStyle
== CapRound
)
1915 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1916 &leftFace
, (LineFacePtr
) NULL
,
1917 (double) 0.0, (double) 0.0, TRUE
);
1920 miLineJoin(pDrawable
, pGC
, pixel
, spanData
, &leftFace
,
1924 prevRightFace
= rightFace
;
1927 projectLeft
= FALSE
;
1929 if (npt
== 1 && somethingDrawn
) {
1930 if (pGC
->lineStyle
== LineDoubleDash
|| endIsFg
) {
1931 pixel
= endIsFg
? pGC
->fgPixel
: pGC
->bgPixel
;
1932 if (selfJoin
&& (pGC
->lineStyle
== LineDoubleDash
|| firstIsFg
)) {
1933 miLineJoin(pDrawable
, pGC
, pixel
, spanData
, &firstFace
,
1937 if (pGC
->capStyle
== CapRound
)
1938 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1939 (LineFacePtr
) NULL
, &rightFace
,
1940 (double) 0.0, (double) 0.0, TRUE
);
1944 /* glue a cap to the start of the line if
1945 * we're OnOffDash and ended on odd dash
1947 if (selfJoin
&& firstIsFg
) {
1948 pixel
= pGC
->fgPixel
;
1949 if (pGC
->capStyle
== CapProjecting
)
1950 miLineProjectingCap(pDrawable
, pGC
, pixel
, spanData
,
1952 (double) 0.0, (double) 0.0, TRUE
);
1953 else if (pGC
->capStyle
== CapRound
)
1954 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1955 &firstFace
, (LineFacePtr
) NULL
,
1956 (double) 0.0, (double) 0.0, TRUE
);
1961 /* handle crock where all points are coincident */
1962 if (!somethingDrawn
&&
1963 (pGC
->lineStyle
== LineDoubleDash
|| !(dashIndex
& 1))) {
1964 /* not the same as endIsFg computation above */
1965 pixel
= (dashIndex
& 1) ? pGC
->bgPixel
: pGC
->fgPixel
;
1966 switch (pGC
->capStyle
) {
1968 miLineArc(pDrawable
, pGC
, pixel
, spanData
,
1969 (LineFacePtr
) NULL
, (LineFacePtr
) NULL
,
1970 (double) x2
, (double) y2
, FALSE
);
1973 x1
= pGC
->lineWidth
;
1974 miFillRectPolyHelper(pDrawable
, pGC
, pixel
, spanData
,
1975 x2
- (x1
>> 1), y2
- (x1
>> 1), x1
, x1
);
1980 miCleanupSpanData(pDrawable
, pGC
, spanData
);