1
/* $TOG: miwideline.c /main/60 1998/03/07 17:40:23 kaleb $ */
4
Copyright 1988, 1998 The Open Group
8
The above copyright notice and this permission notice shall be included
9
in all copies or substantial portions of the Software.
11
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
14
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
15
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
16
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
17
OTHER DEALINGS IN THE SOFTWARE.
19
Except as contained in this notice, the name of The Open Group shall
20
not be used in advertising or otherwise to promote the sale, use or
21
other dealings in this Software without prior written authorization
25
/* $XFree86: xc/programs/Xserver/mi/miwideline.c,v 1.7 1999/10/13 22:33:13 dawes Exp $ */
27
/* Author: Keith Packard, MIT X Consortium */
30
* Mostly integer wideline code. Uses a technique similar to
31
* bresenham zero-width lines, except walks an X edge
39
#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
45
#include "miwideline.h"
52
miLineArc (GdkDrawable *pDraw, GdkGC *pGC, GdkColor *pixel, SpanDataPtr spanData,
53
LineFacePtr leftFace, LineFacePtr rightFace, double xorg, double yorg, gboolean isInt);
56
* spans-based polygon filler
60
miFillPolyHelper (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel,
61
SpanDataPtr spanData, int y, int overall_height,
62
PolyEdgePtr left, PolyEdgePtr right, int left_count,
65
register int left_x = 0, left_e = 0;
68
int left_dy = 0, left_dx = 0;
70
register int right_x = 0, right_e = 0;
73
int right_dy = 0, right_dx = 0;
76
int left_height = 0, right_height = 0;
78
register GdkSpan* ppt;
79
GdkSpan* pptInit = NULL;
89
pptInit = (GdkSpan*) ALLOCATE_LOCAL (overall_height * sizeof(*ppt));
93
oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
94
if (pixel->pixel != oldPixel.pixel)
96
gdk_gc_set_foreground(pGC, pixel);
101
spanRec.points = (GdkSpan*) g_malloc (overall_height * sizeof (*ppt));
104
ppt = spanRec.points;
108
while ((left_count || left_height) &&
109
(right_count || right_height))
114
height = left_height;
115
if (height > right_height)
116
height = right_height;
118
left_height -= height;
119
right_height -= height;
121
while (--height >= 0)
123
if (right_x >= left_x)
126
ppt->x = left_x + xorg;
127
ppt->width = right_x - left_x + 1;
139
gdk_fb_fill_spans(pDrawable, pGC, pptInit, ppt - pptInit, TRUE);
140
DEALLOCATE_LOCAL (pptInit);
141
if (pixel->pixel != oldPixel.pixel)
143
gdk_gc_set_foreground(pGC, &oldPixel);
148
spanRec.count = ppt - spanRec.points;
149
AppendSpanGroup (pGC, pixel, &spanRec, spanData)
154
miFillRectPolyHelper (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel,
155
SpanDataPtr spanData, int x, int y, int w, int h)
157
register GdkSpan* ppt;
163
oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
164
if (pixel->pixel != oldPixel.pixel)
166
gdk_gc_set_foreground(pGC, pixel);
168
gdk_fb_draw_rectangle(pDrawable, pGC, TRUE, x, y, w, h);
169
if (pixel->pixel != oldPixel.pixel)
171
gdk_gc_set_foreground(pGC, &oldPixel);
176
spanRec.points = (GdkSpan*) g_malloc (h * sizeof (*ppt));
179
ppt = spanRec.points;
189
spanRec.count = ppt - spanRec.points;
190
AppendSpanGroup (pGC, pixel, &spanRec, spanData)
195
miPolyBuildEdge (double x0, double y0, double k, register int dx,
196
register int dy, int xi, int yi, int left,
197
register PolyEdgePtr edge)
211
double realk, kerror;
212
realk = x0 * dy - y0 * dx;
213
kerror = Fabs (realk - k);
215
printf ("realk: %g k: %g\n", realk, k);
219
xady = ICEIL (k) + y * dx;
222
x = - (-xady / dy) - 1;
231
edge->stepx = dx / dy;
237
edge->stepx = - (-dx / dy);
242
edge->x = x + left + xi;
243
edge->e = e - dy; /* bias to compare against 0 instead of dy */
247
#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
250
miPolyBuildPoly (register PolyVertexPtr vertices, register PolySlopePtr slopes,
251
int count, int xi, int yi, PolyEdgePtr left, PolyEdgePtr right,
252
int *pnleft, int *pnright, int *h)
261
register int nright, nleft;
262
int y, lasty = 0, bottomy, topy = 0;
264
/* find the top of the polygon */
265
maxy = miny = vertices[0].y;
267
for (i = 1; i < count; i++)
269
if (vertices[i].y < miny)
272
miny = vertices[i].y;
274
if (vertices[i].y >= maxy)
277
maxy = vertices[i].y;
284
j = StepAround (top, -1, count);
286
if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
292
bottomy = ICEIL (maxy) + yi;
296
s = StepAround (top, slopeoff, count);
300
if (slopes[s].dy != 0)
302
y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
304
slopes[s].dx, slopes[s].dy,
308
right[nright-1].height = y - lasty;
315
i = StepAround (i, clockwise, count);
316
s = StepAround (s, clockwise, count);
319
right[nright-1].height = bottomy - lasty;
327
s = StepAround (top, slopeoff, count);
331
if (slopes[s].dy != 0)
333
y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
335
slopes[s].dx, slopes[s].dy, xi, yi, 1,
339
left[nleft-1].height = y - lasty;
343
i = StepAround (i, -clockwise, count);
344
s = StepAround (s, -clockwise, count);
347
left[nleft-1].height = bottomy - lasty;
355
miLineOnePoint (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel,
356
SpanDataPtr spanData, int x, int y)
361
MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
366
gdk_fb_fill_spans(pDrawable, pGC, &span, 1, TRUE);
367
MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
371
miLineJoin (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel,
372
SpanDataPtr spanData, LineFacePtr pLeft, LineFacePtr pRight)
376
PolyVertexRec vertices[4];
377
PolySlopeRec slopes[4];
379
PolyEdgeRec left[4], right[4];
383
int joinStyle = GDK_GC_FBDATA(pGC)->values.join_style;
384
int lw = GDK_GC_FBDATA(pGC)->values.line_width;
386
if (lw == 1 && !spanData) {
387
/* Lines going in the same direction have no join */
388
if (pLeft->dx >= 0 == pRight->dx <= 0)
390
if (joinStyle != GDK_JOIN_ROUND) {
391
denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
393
return; /* no join to draw */
395
if (joinStyle != GDK_JOIN_MITER) {
396
miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
400
if (joinStyle == GDK_JOIN_ROUND)
402
miLineArc(pDrawable, pGC, pixel, spanData,
404
(double)0.0, (double)0.0, TRUE);
407
denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
409
return; /* no join to draw */
415
pLeft->xa = -pLeft->xa;
416
pLeft->ya = -pLeft->ya;
417
pLeft->dx = -pLeft->dx;
418
pLeft->dy = -pLeft->dy;
423
pRight->xa = -pRight->xa;
424
pRight->ya = -pRight->ya;
425
pRight->dx = -pRight->dx;
426
pRight->dy = -pRight->dy;
429
vertices[0].x = pRight->xa;
430
vertices[0].y = pRight->ya;
431
slopes[0].dx = -pRight->dy;
432
slopes[0].dy = pRight->dx;
437
slopes[1].dx = pLeft->dy;
438
slopes[1].dy = -pLeft->dx;
441
vertices[2].x = pLeft->xa;
442
vertices[2].y = pLeft->ya;
444
if (joinStyle == GDK_JOIN_MITER)
446
my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
447
pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx )) /
451
mx = pLeft->xa + (my - pLeft->ya) *
452
(double) pLeft->dx / (double) pLeft->dy;
456
mx = pRight->xa + (my - pRight->ya) *
457
(double) pRight->dx / (double) pRight->dy;
459
/* check miter limit */
460
if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
461
joinStyle = GDK_JOIN_BEVEL;
464
if (joinStyle == GDK_JOIN_MITER)
466
slopes[2].dx = pLeft->dx;
467
slopes[2].dy = pLeft->dy;
468
slopes[2].k = pLeft->k;
471
slopes[2].dx = -slopes[2].dx;
472
slopes[2].dy = -slopes[2].dy;
473
slopes[2].k = -slopes[2].k;
477
slopes[3].dx = pRight->dx;
478
slopes[3].dy = pRight->dy;
479
slopes[3].k = pRight->k;
482
slopes[3].dx = -slopes[3].dx;
483
slopes[3].dy = -slopes[3].dy;
484
slopes[3].k = -slopes[3].k;
490
double scale, dx, dy, adx, ady;
492
adx = dx = pRight->xa - pLeft->xa;
493
ady = dy = pRight->ya - pLeft->ya;
501
slopes[2].dx = (dx * 65536) / scale;
502
slopes[2].dy = (dy * 65536) / scale;
503
slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
504
(pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
508
y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
509
left, right, &nleft, &nright, &height);
510
miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
514
miLineArcI (GdkDrawable *pDraw, GdkGC *pGC, int xorg, int yorg, GdkSpan *points)
516
register GdkSpan* tpts, *bpts;
517
register int x, y, e, ex, slw;
520
slw = GDK_GC_FBDATA(pGC)->values.line_width;
531
e = - ((y << 2) + 3);
542
e += (ex = -((x << 3) + 4));
546
if ((e == ex) && (slw > 1))
552
if ((y != 0) && ((slw > 1) || (e != ex)))
560
return (GDK_GC_FBDATA(pGC)->values.line_width);
563
#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
564
if (ybase == edgey) \
577
edge->x += edge->stepx; \
578
edge->e += edge->dx; \
581
edge->x += edge->signdx; \
582
edge->e -= edge->dy; \
587
miLineArcD (GdkDrawable *pDraw, GdkGC *pGC, double xorg, double yorg, GdkSpan *points,
588
PolyEdgePtr edge1, int edgey1, gboolean edgeleft1,
589
PolyEdgePtr edge2, int edgey2, gboolean edgeleft2)
591
register GdkSpan* pts;
592
double radius, x0, y0, el, er, yk, xlk, xrk, k;
593
int xbase, ybase, y, boty, xl, xr, xcl, xcr;
595
gboolean edge1IsMin, edge2IsMin;
601
ybase = ICEIL (yorg);
606
radius = ((double)GDK_GC_FBDATA(pGC)->values.line_width) / 2.0;
607
y = floor(radius - y0 + 1.0);
625
if ((edge1->signdx < 0) == edgeleft1)
643
if ((edge2->signdx < 0) == edgeleft2)
650
if (edge2IsMin && ymin1 > ymin2)
652
} else if (edge2IsMin)
654
el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
663
boty = (y0 < -0.5) ? 1 : 0;
664
if (ybase + y - boty > ymax)
665
boty = ymax - ybase - y;
673
er += xrk - (xr << 1);
679
el += (xl << 1) - xlk;
687
CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
688
CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
693
pts->width = xcr - xcl + 1;
697
er = xrk - (xr << 1) - er;
698
el = (xl << 1) - xlk - el;
699
boty = floor(-y0 - radius + 1.0);
700
if (ybase + y - boty > ymax)
701
boty = ymax - ybase - y;
706
while ((er >= 0.0) && (xr >= 0))
709
er += xrk - (xr << 1);
712
while ((el > 0.0) && (xl <= 0))
715
el += (xl << 1) - xlk;
723
CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
724
CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
729
pts->width = xcr - xcl + 1;
733
return (pts - points);
737
miRoundJoinFace (register LineFacePtr face, register PolyEdgePtr edge,
755
if (dy < 0 || (dy == 0 && dx > 0))
761
if (dx == 0 && dy == 0)
765
y = ICEIL (face->ya) + face->y;
776
y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
777
edge->height = 32767;
784
miRoundJoinClip (register LineFacePtr pLeft, register LineFacePtr pRight,
785
PolyEdgePtr edge1, PolyEdgePtr edge2, int *y1, int *y2,
786
gboolean *left1, gboolean *left2)
790
denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
794
pLeft->xa = -pLeft->xa;
795
pLeft->ya = -pLeft->ya;
799
pRight->xa = -pRight->xa;
800
pRight->ya = -pRight->ya;
802
*y1 = miRoundJoinFace (pLeft, edge1, left1);
803
*y2 = miRoundJoinFace (pRight, edge2, left2);
807
miRoundCapClip (register LineFacePtr face, gboolean isInt,
808
register PolyEdgePtr edge, gboolean *leftEdge)
823
if (dy < 0 || (dy == 0 && dx > 0))
831
if (dx == 0 && dy == 0)
835
y = ICEIL (face->ya) + face->y;
846
y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
847
edge->height = 32767;
854
miLineArc (GdkDrawable *pDraw, GdkGC *pGC, GdkColor *pixel,
855
SpanDataPtr spanData, register LineFacePtr leftFace,
856
register LineFacePtr rightFace, double xorg, double yorg,
860
int xorgi = 0, yorgi = 0;
864
PolyEdgeRec edge1, edge2;
866
gboolean edgeleft1, edgeleft2;
870
xorgi = leftFace ? leftFace->x : rightFace->x;
871
yorgi = leftFace ? leftFace->y : rightFace->y;
875
edge1.x = 0; /* not used, keep memory checkers happy */
877
edge2.x = 0; /* not used, keep memory checkers happy */
881
if (((GDK_GC_FBDATA(pGC)->values.line_style != GDK_LINE_SOLID || GDK_GC_FBDATA(pGC)->values.line_width > 2) &&
882
(GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND && GDK_GC_FBDATA(pGC)->values.join_style != GDK_JOIN_ROUND)) ||
883
(GDK_GC_FBDATA(pGC)->values.join_style == GDK_JOIN_ROUND && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_BUTT))
887
xorg = (double) xorgi;
888
yorg = (double) yorgi;
890
if (leftFace && rightFace)
892
miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
893
&edgey1, &edgey2, &edgeleft1, &edgeleft2);
897
edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
901
edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
907
points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * GDK_GC_FBDATA(pGC)->values.line_width);
910
oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
911
if (pixel->pixel != oldPixel.pixel)
913
gdk_gc_set_foreground(pGC, pixel);
918
points = (GdkSpan*) g_malloc (GDK_GC_FBDATA(pGC)->values.line_width * sizeof (GdkSpan));
921
spanRec.points = points;
924
n = miLineArcI(pDraw, pGC, xorgi, yorgi, points);
926
n = miLineArcD(pDraw, pGC, xorg, yorg, points,
927
&edge1, edgey1, edgeleft1,
928
&edge2, edgey2, edgeleft2);
932
gdk_fb_fill_spans(pDraw, pGC, points, n, TRUE);
933
DEALLOCATE_LOCAL(points);
934
if (pixel->pixel != oldPixel.pixel)
936
gdk_gc_set_foreground(pGC, &oldPixel);
942
AppendSpanGroup (pGC, pixel, &spanRec, spanData)
947
miLineProjectingCap (GdkDrawable *pDrawable, register GdkGC *pGC, GdkColor *pixel,
948
SpanDataPtr spanData, register LineFacePtr face,
949
gboolean isLeft, double xorg, double yorg, gboolean isInt)
951
int xorgi = 0, yorgi = 0;
953
PolyEdgeRec lefts[2], rights[2];
954
int lefty, righty, topy, bottomy;
955
PolyEdgePtr left, right;
956
PolyEdgePtr top, bottom;
961
double projectXoff, projectYoff;
970
lw = GDK_GC_FBDATA(pGC)->values.line_width;
976
lefts[0].height = lw;
979
lefts[0].x -= (lw >> 1);
985
rights[0].height = lw;
988
rights[0].x += ((lw + 1) >> 1);
990
rights[0].signdx = 1;
994
miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
995
lefts, rights, 1, 1);
1000
bottomy = yorgi + dy;
1004
bottomy += (lw >> 1);
1005
lefts[0].height = bottomy - topy;
1006
lefts[0].x = xorgi - (lw >> 1);
1008
lefts[0].signdx = 1;
1013
rights[0].height = bottomy - topy;
1014
rights[0].x = lefts[0].x + (lw-1);
1015
rights[0].stepx = 0;
1016
rights[0].signdx = 1;
1020
miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
1040
bottom = &rights[1];
1044
righty = miPolyBuildEdge (xa, ya,
1045
k, dx, dy, xorgi, yorgi, 0, right);
1050
lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1051
k, dx, dy, xorgi, yorgi, 1, left);
1057
xap = xa - projectXoff;
1058
yap = ya - projectYoff;
1059
topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1060
-dy, dx, xorgi, yorgi, dx > 0, top);
1061
bottomy = miPolyBuildEdge (xa, ya,
1062
0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
1067
righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1068
k, dx, dy, xorgi, yorgi, 0, right);
1073
lefty = miPolyBuildEdge (xa, ya,
1074
k, dx, dy, xorgi, yorgi, 1, left);
1080
xap = xa - projectXoff;
1081
yap = ya - projectYoff;
1082
topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
1083
bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1084
-dy, dx, xorgi, xorgi, dx < 0, bottom);
1085
maxy = -ya + projectYoff;
1087
finaly = ICEIL(maxy) + yorgi;
1090
left->height = bottomy - lefty;
1091
right->height = finaly - righty;
1092
top->height = righty - topy;
1096
right->height = bottomy - righty;
1097
left->height = finaly - lefty;
1098
top->height = lefty - topy;
1100
bottom->height = finaly - bottomy;
1101
miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1102
bottom->height + bottomy - topy, lefts, rights, 2, 2);
1107
miWideSegment (GdkDrawable *pDrawable, GdkGC *pGC, GdkColor *pixel, SpanDataPtr spanData,
1108
int x1, int y1, int x2, int y2, gboolean projectLeft, gboolean projectRight, LineFacePtr leftFace, LineFacePtr rightFace)
1112
double projectXoff = 0.0, projectYoff = 0.0;
1118
PolyEdgePtr left, right;
1119
PolyEdgePtr top, bottom;
1120
int lefty, righty, topy, bottomy;
1122
PolyEdgeRec lefts[2], rights[2];
1124
int lw = GDK_GC_FBDATA(pGC)->values.line_width;
1127
/* draw top-to-bottom always */
1128
if (y2 < y1 || (y2 == y1 && x2 < x1))
1139
projectLeft = projectRight;
1143
leftFace = rightFace;
1161
rightFace->dx = -dx;
1162
rightFace->dy = -dy;
1167
rightFace->ya = (double) lw / 2.0;
1168
rightFace->k = -(double) (lw * dx) / 2.0;
1170
leftFace->ya = -rightFace->ya;
1171
leftFace->k = rightFace->k;
1178
dx += ((lw + 1) >> 1);
1180
miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1185
leftFace->xa = (double) lw / 2.0;
1187
leftFace->k = (double) (lw * dy) / 2.0;
1188
rightFace->xa = -leftFace->xa;
1190
rightFace->k = leftFace->k;
1197
dy += ((lw + 1) >> 1);
1199
miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1204
l = ((double) lw) / 2.0;
1205
L = hypot ((double) dx, (double) dy);
1219
bottom = &rights[1];
1223
/* coord of upper bound at integral y */
1227
if (projectLeft | projectRight)
1233
/* xa * dy - ya * dx */
1239
rightFace->xa = -xa;
1240
rightFace->ya = -ya;
1244
righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1245
k, dx, dy, x1, y1, 0, right);
1247
righty = miPolyBuildEdge (xa, ya,
1248
k, dx, dy, x1, y1, 0, right);
1250
/* coord of lower bound at integral y */
1254
/* xa * dy - ya * dx */
1258
lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1259
k, dx, dy, x1, y1, 1, left);
1261
lefty = miPolyBuildEdge (xa, ya,
1262
k, dx, dy, x1, y1, 1, left);
1264
/* coord of top face at integral y */
1274
double xap = xa - projectXoff;
1275
double yap = ya - projectYoff;
1276
topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1277
-dy, dx, x1, y1, dx > 0, top);
1280
topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
1282
/* coord of bottom face at integral y */
1286
double xap = xa + projectXoff;
1287
double yap = ya + projectYoff;
1288
bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1289
-dy, dx, x2, y2, dx < 0, bottom);
1290
maxy = -ya + projectYoff;
1294
bottomy = miPolyBuildEdge (xa, ya,
1295
0.0, -dy, dx, x2, y2, dx < 0, bottom);
1299
finaly = ICEIL (maxy) + y2;
1303
left->height = bottomy - lefty;
1304
right->height = finaly - righty;
1305
top->height = righty - topy;
1309
right->height = bottomy - righty;
1310
left->height = finaly - lefty;
1311
top->height = lefty - topy;
1313
bottom->height = finaly - bottomy;
1314
miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1315
bottom->height + bottomy - topy, lefts, rights, 2, 2);
1320
miSetupSpanData (register GdkGC *pGC, SpanDataPtr spanData, int npt)
1322
if ((npt < 3 && GDK_GC_FBDATA(pGC)->values.cap_style != GDK_CAP_ROUND) || miSpansEasyRop(GDK_GC_FBDATA(pGC)->alu))
1323
return (SpanDataPtr) NULL;
1324
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH)
1325
miInitSpanGroup (&spanData->bgGroup);
1326
miInitSpanGroup (&spanData->fgGroup);
1331
miCleanupSpanData (GdkDrawable *pDrawable, GdkGC *pGC, SpanDataPtr spanData)
1333
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH)
1335
GdkColor oldPixel, pixel;
1337
pixel = GDK_GC_FBDATA(pGC)->values.background;
1338
oldPixel = GDK_GC_FBDATA(pGC)->values.foreground;
1339
if (pixel.pixel != oldPixel.pixel)
1340
gdk_gc_set_foreground(pGC, &pixel);
1341
miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
1342
miFreeSpanGroup (&spanData->bgGroup);
1343
if (pixel.pixel != oldPixel.pixel)
1344
gdk_gc_set_foreground(pGC, &oldPixel);
1346
miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
1347
miFreeSpanGroup (&spanData->fgGroup);
1351
miWideLine (GdkDrawable *pDrawable, GdkGC *pGC, int mode,
1352
register int npt, register GdkPoint *pPts)
1355
SpanDataRec spanDataRec;
1356
SpanDataPtr spanData;
1358
gboolean projectLeft, projectRight;
1359
LineFaceRec leftFace, rightFace, prevRightFace;
1360
LineFaceRec firstFace;
1362
gboolean somethingDrawn = FALSE;
1365
spanData = miSetupSpanData (pGC, &spanDataRec, npt);
1366
pixel = GDK_GC_FBDATA(pGC)->values.foreground;
1373
if (0 /* mode == CoordModePrevious*/)
1388
if (x2 == x1 && y2 == y1)
1391
else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
1396
projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin;
1397
projectRight = FALSE;
1405
if (0 /* mode == CoordModePrevious */)
1410
if (x1 != x2 || y1 != y2)
1412
somethingDrawn = TRUE;
1413
if (npt == 1 && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin)
1414
projectRight = TRUE;
1415
miWideSegment (pDrawable, pGC, &pixel, spanData, x1, y1, x2, y2,
1416
projectLeft, projectRight, &leftFace, &rightFace);
1420
firstFace = leftFace;
1421
else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1423
if (GDK_GC_FBDATA(pGC)->values.line_width == 1 && !spanData)
1424
miLineOnePoint (pDrawable, pGC, &pixel, spanData, x1, y1);
1426
miLineArc (pDrawable, pGC, &pixel, spanData,
1427
&leftFace, (LineFacePtr) NULL,
1428
(double)0.0, (double)0.0,
1434
miLineJoin (pDrawable, pGC, &pixel, spanData, &leftFace,
1437
prevRightFace = rightFace;
1439
projectLeft = FALSE;
1441
if (npt == 1 && somethingDrawn)
1444
miLineJoin (pDrawable, pGC, &pixel, spanData, &firstFace,
1446
else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1448
if (GDK_GC_FBDATA(pGC)->values.line_width == 1 && !spanData)
1449
miLineOnePoint (pDrawable, pGC, &pixel, spanData, x2, y2);
1451
miLineArc (pDrawable, pGC, &pixel, spanData,
1452
(LineFacePtr) NULL, &rightFace,
1453
(double)0.0, (double)0.0,
1458
/* handle crock where all points are coincedent */
1459
if (!somethingDrawn)
1461
projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING;
1462
miWideSegment (pDrawable, pGC, &pixel, spanData,
1463
x2, y2, x2, y2, projectLeft, projectLeft,
1464
&leftFace, &rightFace);
1465
if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1467
miLineArc (pDrawable, pGC, &pixel, spanData,
1468
&leftFace, (LineFacePtr) NULL,
1469
(double)0.0, (double)0.0,
1471
rightFace.dx = -1; /* sleezy hack to make it work */
1472
miLineArc (pDrawable, pGC, &pixel, spanData,
1473
(LineFacePtr) NULL, &rightFace,
1474
(double)0.0, (double)0.0,
1479
miCleanupSpanData (pDrawable, pGC, spanData);
1488
miWideDashSegment (GdkDrawable *pDrawable, register GdkGC *pGC,
1489
SpanDataPtr spanData, int *pDashOffset, int *pDashIndex,
1490
int x1, int y1, int x2, int y2, gboolean projectLeft,
1491
gboolean projectRight, LineFacePtr leftFace,
1492
LineFacePtr rightFace)
1494
int dashIndex, dashRemain;
1495
unsigned char *pDash;
1498
PolyVertexRec vertices[4];
1499
PolyVertexRec saveRight, saveBottom;
1500
PolySlopeRec slopes[4];
1501
PolyEdgeRec left[2], right[2];
1502
LineFaceRec lcapFace, rcapFace;
1511
double dashDx, dashDy;
1513
gboolean first = TRUE;
1514
double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
1515
GdkColor fgPixel, bgPixel;
1519
dashIndex = *pDashIndex;
1520
pDash = GDK_GC_FBDATA(pGC)->dash_list;
1521
dashRemain = pDash[dashIndex] - *pDashOffset;
1522
fgPixel = GDK_GC_FBDATA(pGC)->values.foreground;
1523
bgPixel = GDK_GC_FBDATA(pGC)->values.background;
1524
if (GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED ||
1525
GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED)
1530
l = ((double) GDK_GC_FBDATA(pGC)->values.line_width) / 2.0;
1555
L = hypot ((double) dx, (double) dy);
1563
/* All position comments are relative to a line with dx and dy > 0,
1564
* but the code does not depend on this */
1566
slopes[V_TOP].dx = dx;
1567
slopes[V_TOP].dy = dy;
1568
slopes[V_TOP].k = k;
1570
slopes[V_RIGHT].dx = -dy;
1571
slopes[V_RIGHT].dy = dx;
1572
slopes[V_RIGHT].k = 0;
1574
slopes[V_BOTTOM].dx = -dx;
1575
slopes[V_BOTTOM].dy = -dy;
1576
slopes[V_BOTTOM].k = k;
1578
slopes[V_LEFT].dx = dy;
1579
slopes[V_LEFT].dy = -dx;
1580
slopes[V_LEFT].k = 0;
1582
/* preload the start coordinates */
1583
vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
1584
vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
1586
vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
1587
vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
1591
vertices[V_TOP].x -= rdx;
1592
vertices[V_TOP].y -= rdy;
1594
vertices[V_LEFT].x -= rdx;
1595
vertices[V_LEFT].y -= rdy;
1597
slopes[V_LEFT].k = rdx * dx + rdy * dy;
1603
if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1615
while (LRemain > dashRemain)
1617
dashDx = (dashRemain * dx) / L;
1618
dashDy = (dashRemain * dy) / L;
1620
rcenterx = lcenterx + dashDx;
1621
rcentery = lcentery + dashDy;
1623
vertices[V_RIGHT].x += dashDx;
1624
vertices[V_RIGHT].y += dashDy;
1626
vertices[V_BOTTOM].x += dashDx;
1627
vertices[V_BOTTOM].y += dashDy;
1629
slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
1631
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1))
1633
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
1634
GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
1636
saveRight = vertices[V_RIGHT];
1637
saveBottom = vertices[V_BOTTOM];
1638
saveK = slopes[V_RIGHT].k;
1642
vertices[V_TOP].x -= rdx;
1643
vertices[V_TOP].y -= rdy;
1645
vertices[V_LEFT].x -= rdx;
1646
vertices[V_LEFT].y -= rdy;
1648
slopes[V_LEFT].k = vertices[V_LEFT].x *
1650
vertices[V_LEFT].y *
1654
vertices[V_RIGHT].x += rdx;
1655
vertices[V_RIGHT].y += rdy;
1657
vertices[V_BOTTOM].x += rdx;
1658
vertices[V_BOTTOM].y += rdy;
1660
slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1661
slopes[V_RIGHT].dy -
1662
vertices[V_RIGHT].y *
1665
y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
1666
left, right, &nleft, &nright, &h);
1667
pixel = (dashIndex & 1) ? bgPixel : fgPixel;
1668
miFillPolyHelper (pDrawable, pGC, &pixel, spanData, y, h, left, right, nleft, nright);
1670
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH)
1672
switch (GDK_GC_FBDATA(pGC)->values.cap_style)
1674
case GDK_CAP_PROJECTING:
1675
vertices[V_BOTTOM] = saveBottom;
1676
vertices[V_RIGHT] = saveRight;
1677
slopes[V_RIGHT].k = saveK;
1684
lcapFace.xa = -vertices[V_LEFT].x;
1685
lcapFace.ya = -vertices[V_LEFT].y;
1686
lcapFace.k = slopes[V_LEFT].k;
1690
lcapFace.xa = vertices[V_TOP].x;
1691
lcapFace.ya = vertices[V_TOP].y;
1692
lcapFace.k = -slopes[V_LEFT].k;
1694
miLineArc (pDrawable, pGC, &pixel, spanData,
1695
&lcapFace, (LineFacePtr) NULL,
1696
lcenterx, lcentery, FALSE);
1700
rcapFace.xa = vertices[V_BOTTOM].x;
1701
rcapFace.ya = vertices[V_BOTTOM].y;
1702
rcapFace.k = slopes[V_RIGHT].k;
1706
rcapFace.xa = -vertices[V_RIGHT].x;
1707
rcapFace.ya = -vertices[V_RIGHT].y;
1708
rcapFace.k = -slopes[V_RIGHT].k;
1710
miLineArc (pDrawable, pGC, &pixel, spanData,
1711
(LineFacePtr) NULL, &rcapFace,
1712
rcenterx, rcentery, FALSE);
1719
LRemain -= dashRemain;
1721
if (dashIndex == GDK_GC_FBDATA(pGC)->dash_list_len)
1723
dashRemain = pDash[dashIndex];
1725
lcenterx = rcenterx;
1726
lcentery = rcentery;
1728
vertices[V_TOP] = vertices[V_RIGHT];
1729
vertices[V_LEFT] = vertices[V_BOTTOM];
1730
slopes[V_LEFT].k = -slopes[V_RIGHT].k;
1734
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1))
1736
vertices[V_TOP].x -= dx;
1737
vertices[V_TOP].y -= dy;
1739
vertices[V_LEFT].x -= dx;
1740
vertices[V_LEFT].y -= dy;
1742
vertices[V_RIGHT].x = rdy;
1743
vertices[V_RIGHT].y = -rdx;
1745
vertices[V_BOTTOM].x = -rdy;
1746
vertices[V_BOTTOM].y = rdx;
1751
vertices[V_RIGHT].x += rdx;
1752
vertices[V_RIGHT].y += rdy;
1754
vertices[V_BOTTOM].x += rdx;
1755
vertices[V_BOTTOM].y += rdy;
1756
slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1757
slopes[V_RIGHT].dy -
1758
vertices[V_RIGHT].y *
1762
slopes[V_RIGHT].k = 0;
1764
if (!first && GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
1765
GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
1767
vertices[V_TOP].x -= rdx;
1768
vertices[V_TOP].y -= rdy;
1770
vertices[V_LEFT].x -= rdx;
1771
vertices[V_LEFT].y -= rdy;
1772
slopes[V_LEFT].k = vertices[V_LEFT].x *
1774
vertices[V_LEFT].y *
1778
slopes[V_LEFT].k += dx * dx + dy * dy;
1781
y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
1782
left, right, &nleft, &nright, &h);
1784
pixel = (dashIndex & 1) ? GDK_GC_FBDATA(pGC)->values.background : GDK_GC_FBDATA(pGC)->values.foreground;
1785
miFillPolyHelper (pDrawable, pGC, &pixel, spanData, y, h, left, right, nleft, nright);
1786
if (!first && GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH &&
1787
GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1793
lcapFace.xa = -vertices[V_LEFT].x;
1794
lcapFace.ya = -vertices[V_LEFT].y;
1795
lcapFace.k = slopes[V_LEFT].k;
1799
lcapFace.xa = vertices[V_TOP].x;
1800
lcapFace.ya = vertices[V_TOP].y;
1801
lcapFace.k = -slopes[V_LEFT].k;
1803
miLineArc (pDrawable, pGC, &pixel, spanData,
1804
&lcapFace, (LineFacePtr) NULL,
1805
rcenterx, rcentery, FALSE);
1808
dashRemain = ((double) dashRemain) - LRemain;
1809
if (dashRemain == 0)
1812
if (dashIndex == GDK_GC_FBDATA(pGC)->dash_list_len)
1814
dashRemain = pDash[dashIndex];
1822
leftFace->ya = -rdx;
1827
rightFace->dx = -dx;
1828
rightFace->dy = -dy;
1829
rightFace->xa = -rdy;
1830
rightFace->ya = rdx;
1833
*pDashIndex = dashIndex;
1834
*pDashOffset = pDash[dashIndex] - dashRemain;
1838
miWideDash (GdkDrawable *pDrawable, register GdkGC *pGC, int mode,
1839
register int npt, register GdkPoint *pPts)
1843
gboolean projectLeft, projectRight;
1844
LineFaceRec leftFace, rightFace, prevRightFace;
1845
LineFaceRec firstFace;
1847
int dashIndex, dashOffset;
1848
register int prevDashIndex;
1849
SpanDataRec spanDataRec;
1850
SpanDataPtr spanData;
1851
gboolean somethingDrawn = FALSE;
1853
gboolean endIsFg = FALSE, startIsFg = FALSE;
1854
gboolean firstIsFg = FALSE, prevIsFg = FALSE;
1856
#ifndef XFree86Server
1857
/* XXX backward compatibility */
1858
if (GDK_GC_FBDATA(pGC)->values.line_width == 0)
1860
miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
1864
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH &&
1865
(GDK_GC_FBDATA(pGC)->values.fill == GDK_OPAQUE_STIPPLED || GDK_GC_FBDATA(pGC)->values.fill == GDK_TILED))
1867
miWideLine (pDrawable, pGC, mode, npt, pPts);
1872
spanData = miSetupSpanData (pGC, &spanDataRec, npt);
1877
if (0 /* mode == CoordModePrevious */)
1892
if (x2 == x1 && y2 == y1)
1895
else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
1899
projectLeft = GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING && !selfJoin;
1900
projectRight = FALSE;
1903
miStepDash (GDK_GC_FBDATA(pGC)->dash_offset, &dashIndex,
1904
GDK_GC_FBDATA(pGC)->dash_list, (int)GDK_GC_FBDATA(pGC)->dash_list_len, &dashOffset);
1912
if (0 /* mode == CoordModePrevious */)
1917
if (x1 != x2 || y1 != y2)
1919
somethingDrawn = TRUE;
1920
if (npt == 1 && GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING &&
1921
(!selfJoin || !firstIsFg))
1922
projectRight = TRUE;
1923
prevDashIndex = dashIndex;
1924
miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
1926
projectLeft, projectRight, &leftFace, &rightFace);
1927
startIsFg = !(prevDashIndex & 1);
1928
endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
1929
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || startIsFg)
1931
pixel = startIsFg ? GDK_GC_FBDATA(pGC)->values.foreground : GDK_GC_FBDATA(pGC)->values.background;
1932
if (first || (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_ON_OFF_DASH && !prevIsFg))
1934
if (first && selfJoin)
1936
firstFace = leftFace;
1937
firstIsFg = startIsFg;
1939
else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1940
miLineArc (pDrawable, pGC, &pixel, spanData,
1941
&leftFace, (LineFacePtr) NULL,
1942
(double)0.0, (double)0.0, TRUE);
1946
miLineJoin (pDrawable, pGC, &pixel, spanData, &leftFace,
1950
prevRightFace = rightFace;
1953
projectLeft = FALSE;
1955
if (npt == 1 && somethingDrawn)
1957
if (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || endIsFg)
1959
pixel = endIsFg ? GDK_GC_FBDATA(pGC)->values.foreground : GDK_GC_FBDATA(pGC)->values.background;
1960
if (selfJoin && (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || firstIsFg))
1962
miLineJoin (pDrawable, pGC, &pixel, spanData, &firstFace,
1967
if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1968
miLineArc (pDrawable, pGC, &pixel, spanData,
1969
(LineFacePtr) NULL, &rightFace,
1970
(double)0.0, (double)0.0, TRUE);
1975
/* glue a cap to the start of the line if
1976
* we're OnOffDash and ended on odd dash
1978
if (selfJoin && firstIsFg)
1980
pixel = GDK_GC_FBDATA(pGC)->values.foreground;
1981
if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_PROJECTING)
1982
miLineProjectingCap (pDrawable, pGC, &pixel, spanData,
1984
(double)0.0, (double)0.0, TRUE);
1985
else if (GDK_GC_FBDATA(pGC)->values.cap_style == GDK_CAP_ROUND)
1986
miLineArc (pDrawable, pGC, &pixel, spanData,
1987
&firstFace, (LineFacePtr) NULL,
1988
(double)0.0, (double)0.0, TRUE);
1993
/* handle crock where all points are coincident */
1994
if (!somethingDrawn && (GDK_GC_FBDATA(pGC)->values.line_style == GDK_LINE_DOUBLE_DASH || !(dashIndex & 1)))
1996
/* not the same as endIsFg computation above */
1997
pixel = (dashIndex & 1) ? GDK_GC_FBDATA(pGC)->values.background : GDK_GC_FBDATA(pGC)->values.foreground;
1998
switch (GDK_GC_FBDATA(pGC)->values.cap_style) {
2000
miLineArc (pDrawable, pGC, &pixel, spanData,
2001
(LineFacePtr) NULL, (LineFacePtr) NULL,
2002
(double)x2, (double)y2,
2005
case GDK_CAP_PROJECTING:
2006
x1 = GDK_GC_FBDATA(pGC)->values.line_width;
2007
miFillRectPolyHelper (pDrawable, pGC, &pixel, spanData,
2008
x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
2015
miCleanupSpanData (pDrawable, pGC, spanData);
2018
/* these are stubs to allow old ddx miValidateGCs to work without change */