Bug Summary

File:mi/miwideline.c
Location:line 489, column 41
Description:The left operand of '==' is a garbage value

Annotated Source Code

1/*
2
3Copyright 1988, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
28
29 All Rights Reserved
30
31Permission to use, copy, modify, and distribute this software and its
32documentation for any purpose and without fee is hereby granted,
33provided that the above copyright notice appear in all copies and that
34both that copyright notice and this permission notice appear in
35supporting documentation, and that the name of Digital not be
36used in advertising or publicity pertaining to distribution of the
37software without specific, written prior permission.
38
39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45SOFTWARE.
46*/
47
48/* Author: Keith Packard, MIT X Consortium */
49
50/*
51 * Mostly integer wideline code. Uses a technique similar to
52 * bresenham zero-width lines, except walks an X edge
53 */
54
55#ifdef HAVE_DIX_CONFIG_H1
56#include <dix-config.h>
57#endif
58
59#include <stdio.h>
60#ifdef _XOPEN_SOURCE
61#include <math.h>
62#else
63#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
64#include <math.h>
65#undef _XOPEN_SOURCE
66#endif
67#include <X11/X.h>
68#include "windowstr.h"
69#include "gcstruct.h"
70#include "regionstr.h"
71#include "miwideline.h"
72#include "mi.h"
73
74#if 0
75#ifdef HAVE_DIX_CONFIG_H1
76#include <dix-config.h>
77#endif
78
79#include "misc.h"
80#include "pixmapstr.h"
81#include "gcstruct.h"
82#endif
83
84typedef struct {
85 int count; /* number of spans */
86 DDXPointPtr points; /* pointer to list of start points */
87 int *widths; /* pointer to list of widths */
88} Spans;
89
90typedef struct {
91 int size; /* Total number of *Spans allocated */
92 int count; /* Number of *Spans actually in group */
93 Spans *group; /* List of Spans */
94 int ymin, ymax; /* Min, max y values encountered */
95} SpanGroup;
96
97/* Rops which must use span groups */
98#define miSpansCarefulRop(rop)(((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
99#define miSpansEasyRop(rop)(!(((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)) (!miSpansCarefulRop(rop)(((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2))
100
101/*
102
103These routines maintain lists of Spans, in order to implement the
104``touch-each-pixel-once'' rules of wide lines and arcs.
105
106Written by Joel McCormack, Summer 1989.
107
108*/
109
110static void
111miInitSpanGroup(SpanGroup * spanGroup)
112{
113 spanGroup->size = 0;
114 spanGroup->count = 0;
115 spanGroup->group = NULL((void*)0);
116 spanGroup->ymin = MAXSHORT32767;
117 spanGroup->ymax = MINSHORT(-32767 -1);
118} /* InitSpanGroup */
119
120#define YMIN(spans)(spans->points[0].y) (spans->points[0].y)
121#define YMAX(spans)(spans->points[spans->count-1].y) (spans->points[spans->count-1].y)
122
123static void
124miSubtractSpans(SpanGroup * spanGroup, Spans * sub)
125{
126 int i, subCount, spansCount;
127 int ymin, ymax, xmin, xmax;
128 Spans *spans;
129 DDXPointPtr subPt, spansPt;
130 int *subWid, *spansWid;
131 int extra;
132
133 ymin = YMIN(sub)(sub->points[0].y);
134 ymax = YMAX(sub)(sub->points[sub->count-1].y);
135 spans = spanGroup->group;
136 for (i = spanGroup->count; i; i--, spans++) {
137 if (YMIN(spans)(spans->points[0].y) <= ymax && ymin <= YMAX(spans)(spans->points[spans->count-1].y)) {
138 subCount = sub->count;
139 subPt = sub->points;
140 subWid = sub->widths;
141 spansCount = spans->count;
142 spansPt = spans->points;
143 spansWid = spans->widths;
144 extra = 0;
145 for (;;) {
146 while (spansCount && spansPt->y < subPt->y) {
147 spansPt++;
148 spansWid++;
149 spansCount--;
150 }
151 if (!spansCount)
152 break;
153 while (subCount && subPt->y < spansPt->y) {
154 subPt++;
155 subWid++;
156 subCount--;
157 }
158 if (!subCount)
159 break;
160 if (subPt->y == spansPt->y) {
161 xmin = subPt->x;
162 xmax = xmin + *subWid;
163 if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) {
164 ;
165 }
166 else if (xmin <= spansPt->x) {
167 if (xmax >= spansPt->x + *spansWid) {
168 memmove(spansPt, spansPt + 1,__builtin___memmove_chk (spansPt, spansPt + 1, sizeof *spansPt
* (spansCount - 1), __builtin_object_size (spansPt, 0))
169 sizeof *spansPt * (spansCount - 1))__builtin___memmove_chk (spansPt, spansPt + 1, sizeof *spansPt
* (spansCount - 1), __builtin_object_size (spansPt, 0))
;
170 memmove(spansWid, spansWid + 1,__builtin___memmove_chk (spansWid, spansWid + 1, sizeof *spansWid
* (spansCount - 1), __builtin_object_size (spansWid, 0))
171 sizeof *spansWid * (spansCount - 1))__builtin___memmove_chk (spansWid, spansWid + 1, sizeof *spansWid
* (spansCount - 1), __builtin_object_size (spansWid, 0))
;
172 spansPt--;
173 spansWid--;
174 spans->count--;
175 extra++;
176 }
177 else {
178 *spansWid = *spansWid - (xmax - spansPt->x);
179 spansPt->x = xmax;
180 }
181 }
182 else {
183 if (xmax >= spansPt->x + *spansWid) {
184 *spansWid = xmin - spansPt->x;
185 }
186 else {
187 if (!extra) {
188 DDXPointPtr newPt;
189 int *newwid;
190
191#define EXTRA8 8
192 newPt =
193 (DDXPointPtr) realloc(spans->points,
194 (spans->count +
195 EXTRA8) *
196 sizeof(DDXPointRec));
197 if (!newPt)
198 break;
199 spansPt = newPt + (spansPt - spans->points);
200 spans->points = newPt;
201 newwid =
202 (int *) realloc(spans->widths,
203 (spans->count +
204 EXTRA8) * sizeof(int));
205 if (!newwid)
206 break;
207 spansWid = newwid + (spansWid - spans->widths);
208 spans->widths = newwid;
209 extra = EXTRA8;
210 }
211 memmove(spansPt + 1, spansPt,__builtin___memmove_chk (spansPt + 1, spansPt, sizeof *spansPt
* (spansCount), __builtin_object_size (spansPt + 1, 0))
212 sizeof *spansPt * (spansCount))__builtin___memmove_chk (spansPt + 1, spansPt, sizeof *spansPt
* (spansCount), __builtin_object_size (spansPt + 1, 0))
;
213 memmove(spansWid + 1, spansWid,__builtin___memmove_chk (spansWid + 1, spansWid, sizeof *spansWid
* (spansCount), __builtin_object_size (spansWid + 1, 0))
214 sizeof *spansWid * (spansCount))__builtin___memmove_chk (spansWid + 1, spansWid, sizeof *spansWid
* (spansCount), __builtin_object_size (spansWid + 1, 0))
;
215 spans->count++;
216 extra--;
217 *spansWid = xmin - spansPt->x;
218 spansWid++;
219 spansPt++;
220 *spansWid = *spansWid - (xmax - spansPt->x);
221 spansPt->x = xmax;
222 }
223 }
224 }
225 spansPt++;
226 spansWid++;
227 spansCount--;
228 }
229 }
230 }
231}
232
233static void
234miAppendSpans(SpanGroup * spanGroup, SpanGroup * otherGroup, Spans * spans)
235{
236 int ymin, ymax;
237 int spansCount;
238
239 spansCount = spans->count;
240 if (spansCount > 0) {
241 if (spanGroup->size == spanGroup->count) {
242 spanGroup->size = (spanGroup->size + 8) * 2;
243 spanGroup->group = (Spans *)
244 realloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
245 }
246
247 spanGroup->group[spanGroup->count] = *spans;
248 (spanGroup->count)++;
249 ymin = spans->points[0].y;
250 if (ymin < spanGroup->ymin)
251 spanGroup->ymin = ymin;
252 ymax = spans->points[spansCount - 1].y;
253 if (ymax > spanGroup->ymax)
254 spanGroup->ymax = ymax;
255 if (otherGroup && otherGroup->ymin < ymax && ymin < otherGroup->ymax) {
256 miSubtractSpans(otherGroup, spans);
257 }
258 }
259 else {
260 free(spans->points);
261 free(spans->widths);
262 }
263} /* AppendSpans */
264
265static void
266miFreeSpanGroup(SpanGroup * spanGroup)
267{
268 free(spanGroup->group);
269}
270
271static void
272QuickSortSpansX(DDXPointRec points[], int widths[], int numSpans)
273{
274 int x;
275 int i, j, m;
276 DDXPointPtr r;
277
278/* Always called with numSpans > 1 */
279/* Sorts only by x, as all y should be the same */
280
281#define ExchangeSpans(a, b){ DDXPointRec tpt; int tw; tpt = points[a]; points[a] = points
[b]; points[b] = tpt; tw = widths[a]; widths[a] = widths[b]; widths
[b] = tw; }
\
282{ \
283 DDXPointRec tpt; \
284 int tw; \
285 \
286 tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
287 tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
288}
289
290 do {
291 if (numSpans < 9) {
292 /* Do insertion sort */
293 int xprev;
294
295 xprev = points[0].x;
296 i = 1;
297 do { /* while i != numSpans */
298 x = points[i].x;
299 if (xprev > x) {
300 /* points[i] is out of order. Move into proper location. */
301 DDXPointRec tpt;
302 int tw, k;
303
304 for (j = 0; x >= points[j].x; j++) {
305 }
306 tpt = points[i];
307 tw = widths[i];
308 for (k = i; k != j; k--) {
309 points[k] = points[k - 1];
310 widths[k] = widths[k - 1];
311 }
312 points[j] = tpt;
313 widths[j] = tw;
314 x = points[i].x;
315 } /* if out of order */
316 xprev = x;
317 i++;
318 } while (i != numSpans);
319 return;
320 }
321
322 /* Choose partition element, stick in location 0 */
323 m = numSpans / 2;
324 if (points[m].x > points[0].x)
325 ExchangeSpans(m, 0){ DDXPointRec tpt; int tw; tpt = points[m]; points[m] = points
[0]; points[0] = tpt; tw = widths[m]; widths[m] = widths[0]; widths
[0] = tw; }
;
326 if (points[m].x > points[numSpans - 1].x)
327 ExchangeSpans(m, numSpans - 1){ DDXPointRec tpt; int tw; tpt = points[m]; points[m] = points
[numSpans - 1]; points[numSpans - 1] = tpt; tw = widths[m]; widths
[m] = widths[numSpans - 1]; widths[numSpans - 1] = tw; }
;
328 if (points[m].x > points[0].x)
329 ExchangeSpans(m, 0){ DDXPointRec tpt; int tw; tpt = points[m]; points[m] = points
[0]; points[0] = tpt; tw = widths[m]; widths[m] = widths[0]; widths
[0] = tw; }
;
330 x = points[0].x;
331
332 /* Partition array */
333 i = 0;
334 j = numSpans;
335 do {
336 r = &(points[i]);
337 do {
338 r++;
339 i++;
340 } while (i != numSpans && r->x < x);
341 r = &(points[j]);
342 do {
343 r--;
344 j--;
345 } while (x < r->x);
346 if (i < j)
347 ExchangeSpans(i, j){ DDXPointRec tpt; int tw; tpt = points[i]; points[i] = points
[j]; points[j] = tpt; tw = widths[i]; widths[i] = widths[j]; widths
[j] = tw; }
;
348 } while (i < j);
349
350 /* Move partition element back to middle */
351 ExchangeSpans(0, j){ DDXPointRec tpt; int tw; tpt = points[0]; points[0] = points
[j]; points[j] = tpt; tw = widths[0]; widths[0] = widths[j]; widths
[j] = tw; }
;
352
353 /* Recurse */
354 if (numSpans - j - 1 > 1)
355 QuickSortSpansX(&points[j + 1], &widths[j + 1], numSpans - j - 1);
356 numSpans = j;
357 } while (numSpans > 1);
358} /* QuickSortSpans */
359
360static int
361UniquifySpansX(Spans * spans, DDXPointRec * newPoints, int *newWidths)
362{
363 int newx1, newx2, oldpt, i, y;
364 DDXPointRec *oldPoints;
365 int *oldWidths;
366 int *startNewWidths;
367
368/* Always called with numSpans > 1 */
369/* Uniquify the spans, and stash them into newPoints and newWidths. Return the
370 number of unique spans. */
371
372 startNewWidths = newWidths;
373
374 oldPoints = spans->points;
375 oldWidths = spans->widths;
376
377 y = oldPoints->y;
378 newx1 = oldPoints->x;
379 newx2 = newx1 + *oldWidths;
380
381 for (i = spans->count - 1; i != 0; i--) {
382 oldPoints++;
383 oldWidths++;
384 oldpt = oldPoints->x;
385 if (oldpt > newx2) {
386 /* Write current span, start a new one */
387 newPoints->x = newx1;
388 newPoints->y = y;
389 *newWidths = newx2 - newx1;
390 newPoints++;
391 newWidths++;
392 newx1 = oldpt;
393 newx2 = oldpt + *oldWidths;
394 }
395 else {
396 /* extend current span, if old extends beyond new */
397 oldpt = oldpt + *oldWidths;
398 if (oldpt > newx2)
399 newx2 = oldpt;
400 }
401 } /* for */
402
403 /* Write final span */
404 newPoints->x = newx1;
405 *newWidths = newx2 - newx1;
406 newPoints->y = y;
407
408 return (newWidths - startNewWidths) + 1;
409} /* UniquifySpansX */
410
411static void
412miDisposeSpanGroup(SpanGroup * spanGroup)
413{
414 int i;
415 Spans *spans;
416
417 for (i = 0; i < spanGroup->count; i++) {
418 spans = spanGroup->group + i;
419 free(spans->points);
420 free(spans->widths);
421 }
422}
423
424static void
425miFillUniqueSpanGroup(DrawablePtr pDraw, GCPtr pGC, SpanGroup * spanGroup)
426{
427 int i;
428 Spans *spans;
429 Spans *yspans;
430 int *ysizes;
431 int ymin, ylength;
432
433 /* Outgoing spans for one big call to FillSpans */
434 DDXPointPtr points;
435 int *widths;
436 int count;
437
438 if (spanGroup->count == 0)
3
Taking false branch
439 return;
440
441 if (spanGroup->count == 1) {
4
Taking false branch
442 /* Already should be sorted, unique */
443 spans = spanGroup->group;
444 (*pGC->ops->FillSpans)
445 (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE1);
446 free(spans->points);
447 free(spans->widths);
448 }
449 else {
450 /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
451 /* This seems to be the fastest thing to do. I've tried sorting on
452 both x and y at the same time rather than creating into all those
453 y buckets, but it was somewhat slower. */
454
455 ymin = spanGroup->ymin;
456 ylength = spanGroup->ymax - ymin + 1;
457
458 /* Allocate Spans for y buckets */
459 yspans = malloc(ylength * sizeof(Spans));
5
Uninitialized value stored to field 'count'
460 ysizes = malloc(ylength * sizeof(int));
461
462 if (!yspans || !ysizes) {
6
Assuming 'yspans' is non-null
7
Assuming 'ysizes' is non-null
8
Taking false branch
463 free(yspans);
464 free(ysizes);
465 miDisposeSpanGroup(spanGroup);
466 return;
467 }
468
469 for (i = 0; i != ylength; i++) {
9
Assuming 'i' is not equal to 'ylength'
10
Loop condition is true. Entering loop body
11
Assuming 'i' is not equal to 'ylength'
12
Loop condition is true. Entering loop body
13
Assuming 'i' is equal to 'ylength'
14
Loop condition is false. Execution continues on line 477
470 ysizes[i] = 0;
471 yspans[i].count = 0;
472 yspans[i].points = NULL((void*)0);
473 yspans[i].widths = NULL((void*)0);
474 }
475
476 /* Go through every single span and put it into the correct bucket */
477 count = 0;
478 for (i = 0, spans = spanGroup->group;
15
Loop condition is true. Entering loop body
479 i != spanGroup->count; i++, spans++) {
480 int index;
481 int j;
482
483 for (j = 0, points = spans->points, widths = spans->widths;
16
Loop condition is true. Entering loop body
484 j != spans->count; j++, points++, widths++) {
485 index = points->y - ymin;
486 if (index >= 0 && index < ylength) {
17
Assuming 'index' is >= 0
18
Assuming 'index' is < 'ylength'
19
Taking true branch
487 Spans *newspans = &(yspans[index]);
488
489 if (newspans->count == ysizes[index]) {
20
The left operand of '==' is a garbage value
490 DDXPointPtr newpoints;
491 int *newwidths;
492
493 ysizes[index] = (ysizes[index] + 8) * 2;
494 newpoints = (DDXPointPtr) realloc(newspans->points,
495 ysizes[index] *
496 sizeof(DDXPointRec));
497 newwidths =
498 (int *) realloc(newspans->widths,
499 ysizes[index] * sizeof(int));
500 if (!newpoints || !newwidths) {
501 for (i = 0; i < ylength; i++) {
502 free(yspans[i].points);
503 free(yspans[i].widths);
504 }
505 free(yspans);
506 free(ysizes);
507 free(newpoints);
508 free(newwidths);
509 miDisposeSpanGroup(spanGroup);
510 return;
511 }
512 newspans->points = newpoints;
513 newspans->widths = newwidths;
514 }
515 newspans->points[newspans->count] = *points;
516 newspans->widths[newspans->count] = *widths;
517 (newspans->count)++;
518 } /* if y value of span in range */
519 } /* for j through spans */
520 count += spans->count;
521 free(spans->points);
522 spans->points = NULL((void*)0);
523 free(spans->widths);
524 spans->widths = NULL((void*)0);
525 } /* for i thorough Spans */
526
527 /* Now sort by x and uniquify each bucket into the final array */
528 points = malloc(count * sizeof(DDXPointRec));
529 widths = malloc(count * sizeof(int));
530 if (!points || !widths) {
531 for (i = 0; i < ylength; i++) {
532 free(yspans[i].points);
533 free(yspans[i].widths);
534 }
535 free(yspans);
536 free(ysizes);
537 free(points);
538 free(widths);
539 return;
540 }
541 count = 0;
542 for (i = 0; i != ylength; i++) {
543 int ycount = yspans[i].count;
544
545 if (ycount > 0) {
546 if (ycount > 1) {
547 QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount);
548 count += UniquifySpansX
549 (&(yspans[i]), &(points[count]), &(widths[count]));
550 }
551 else {
552 points[count] = yspans[i].points[0];
553 widths[count] = yspans[i].widths[0];
554 count++;
555 }
556 free(yspans[i].points);
557 free(yspans[i].widths);
558 }
559 }
560
561 (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE1);
562 free(points);
563 free(widths);
564 free(yspans);
565 free(ysizes); /* use (DE)xalloc for these? */
566 }
567
568 spanGroup->count = 0;
569 spanGroup->ymin = MAXSHORT32767;
570 spanGroup->ymax = MINSHORT(-32767 -1);
571}
572
573static Bool
574InitSpans(Spans * spans, size_t nspans)
575{
576 spans->points = malloc(nspans * sizeof(*spans->points));
577 if (!spans->points)
578 return FALSE0;
579 spans->widths = malloc(nspans * sizeof(*spans->widths));
580 if (!spans->widths) {
581 free(spans->points);
582 return FALSE0;
583 }
584 return TRUE1;
585}
586
587/*
588 * interface data to span-merging polygon filler
589 */
590
591typedef struct _SpanData {
592 SpanGroup fgGroup, bgGroup;
593} SpanDataRec, *SpanDataPtr;
594
595static void
596AppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans * spanPtr,
597 SpanDataPtr spanData)
598{
599 SpanGroup *group, *othergroup = NULL((void*)0);
600
601 if (pixel == pGC->fgPixel) {
602 group = &spanData->fgGroup;
603 if (pGC->lineStyle == LineDoubleDash2)
604 othergroup = &spanData->bgGroup;
605 }
606 else {
607 group = &spanData->bgGroup;
608 othergroup = &spanData->fgGroup;
609 }
610 miAppendSpans(group, othergroup, spanPtr);
611}
612
613static void miLineArc(DrawablePtr pDraw, GCPtr pGC,
614 unsigned long pixel, SpanDataPtr spanData,
615 LineFacePtr leftFace,
616 LineFacePtr rightFace,
617 double xorg, double yorg, Bool isInt);
618
619/*
620 * spans-based polygon filler
621 */
622
623static void
624fillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans * spans,
625 SpanDataPtr spanData)
626{
627 if (!spanData) {
628 ChangeGCVal oldPixel, tmpPixel;
629
630 oldPixel.val = pGC->fgPixel;
631 if (pixel != oldPixel.val) {
632 tmpPixel.val = (XID) pixel;
633 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &tmpPixel);
634 ValidateGC(pDrawable, pGC);
635 }
636 (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points,
637 spans->widths, TRUE1);
638 free(spans->widths);
639 free(spans->points);
640 if (pixel != oldPixel.val) {
641 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &oldPixel);
642 ValidateGC(pDrawable, pGC);
643 }
644 }
645 else
646 AppendSpanGroup(pGC, pixel, spans, spanData);
647}
648
649static void
650miFillPolyHelper(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
651 SpanDataPtr spanData, int y, int overall_height,
652 PolyEdgePtr left, PolyEdgePtr right,
653 int left_count, int right_count)
654{
655 int left_x = 0, left_e = 0;
656 int left_stepx = 0;
657 int left_signdx = 0;
658 int left_dy = 0, left_dx = 0;
659
660 int right_x = 0, right_e = 0;
661 int right_stepx = 0;
662 int right_signdx = 0;
663 int right_dy = 0, right_dx = 0;
664
665 int height = 0;
666 int left_height = 0, right_height = 0;
667
668 DDXPointPtr ppt;
669 int *pwidth;
670 int xorg;
671 Spans spanRec;
672
673 if (!InitSpans(&spanRec, overall_height))
674 return;
675 ppt = spanRec.points;
676 pwidth = spanRec.widths;
677
678 xorg = 0;
679 if (pGC->miTranslate) {
680 y += pDrawable->y;
681 xorg = pDrawable->x;
682 }
683 while ((left_count || left_height) && (right_count || right_height)) {
684 if (!left_height && left_count) {
685 left_height = left->height;
686 left_x = left->x;
687 left_stepx = left->stepx;
688 left_signdx = left->signdx;
689 left_e = left->e;
690 left_dy = left->dy;
691 left_dx = left->dx;
692 --left_count;
693 ++left;
694 }
695
696 if (!right_height && right_count) {
697 right_height = right->height;
698 right_x = right->x;
699 right_stepx = right->stepx;
700 right_signdx = right->signdx;
701 right_e = right->e;
702 right_dy = right->dy;
703 right_dx = right->dx;
704 --right_count;
705 ++right;
706 }
707
708 height = left_height;
709 if (height > right_height)
710 height = right_height;
711
712 left_height -= height;
713 right_height -= height;
714
715 while (--height >= 0) {
716 if (right_x >= left_x) {
717 ppt->y = y;
718 ppt->x = left_x + xorg;
719 ppt++;
720 *pwidth++ = right_x - left_x + 1;
721 }
722 y++;
723
724 left_x += left_stepx;
725 left_e += left_dx;
726 if (left_e > 0) {
727 left_x += left_signdx;
728 left_e -= left_dy;
729 }
730
731 right_x += right_stepx;
732 right_e += right_dx;
733 if (right_e > 0) {
734 right_x += right_signdx;
735 right_e -= right_dy;
736 }
737 }
738 }
739 spanRec.count = ppt - spanRec.points;
740 fillSpans(pDrawable, pGC, pixel, &spanRec, spanData);
741}
742
743static void
744miFillRectPolyHelper(DrawablePtr pDrawable,
745 GCPtr pGC,
746 unsigned long pixel,
747 SpanDataPtr spanData, int x, int y, int w, int h)
748{
749 DDXPointPtr ppt;
750 int *pwidth;
751 ChangeGCVal oldPixel, tmpPixel;
752 Spans spanRec;
753 xRectangle rect;
754
755 if (!spanData) {
756 rect.x = x;
757 rect.y = y;
758 rect.width = w;
759 rect.height = h;
760 oldPixel.val = pGC->fgPixel;
761 if (pixel != oldPixel.val) {
762 tmpPixel.val = (XID) pixel;
763 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &tmpPixel);
764 ValidateGC(pDrawable, pGC);
765 }
766 (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
767 if (pixel != oldPixel.val) {
768 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &oldPixel);
769 ValidateGC(pDrawable, pGC);
770 }
771 }
772 else {
773 if (!InitSpans(&spanRec, h))
774 return;
775 ppt = spanRec.points;
776 pwidth = spanRec.widths;
777
778 if (pGC->miTranslate) {
779 y += pDrawable->y;
780 x += pDrawable->x;
781 }
782 while (h--) {
783 ppt->x = x;
784 ppt->y = y;
785 ppt++;
786 *pwidth++ = w;
787 y++;
788 }
789 spanRec.count = ppt - spanRec.points;
790 AppendSpanGroup(pGC, pixel, &spanRec, spanData);
791 }
792}
793
794static int
795miPolyBuildEdge(double x0, double y0, double k, /* x0 * dy - y0 * dx */
796 int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
797{
798 int x, y, e;
799 int xady;
800
801 if (dy < 0) {
802 dy = -dy;
803 dx = -dx;
804 k = -k;
805 }
806
807#ifdef NOTDEF
808 {
809 double realk, kerror;
810
811 realk = x0 * dy - y0 * dx;
812 kerror = fabs(realk - k);
813 if (kerror > .1)
814 printf("realk: %g k: %g\n", realk, k);
815 }
816#endif
817 y = ICEIL(y0);
818 xady = ICEIL(k) + y * dx;
819
820 if (xady <= 0)
821 x = -(-xady / dy) - 1;
822 else
823 x = (xady - 1) / dy;
824
825 e = xady - x * dy;
826
827 if (dx >= 0) {
828 edge->signdx = 1;
829 edge->stepx = dx / dy;
830 edge->dx = dx % dy;
831 }
832 else {
833 edge->signdx = -1;
834 edge->stepx = -(-dx / dy);
835 edge->dx = -dx % dy;
836 e = dy - e + 1;
837 }
838 edge->dy = dy;
839 edge->x = x + left + xi;
840 edge->e = e - dy; /* bias to compare against 0 instead of dy */
841 return y + yi;
842}
843
844#define StepAround(v, incr, max)(((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0
: ((v) + (incr)))
(((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
845
846static int
847miPolyBuildPoly(PolyVertexPtr vertices,
848 PolySlopePtr slopes,
849 int count,
850 int xi,
851 int yi,
852 PolyEdgePtr left,
853 PolyEdgePtr right, int *pnleft, int *pnright, int *h)
854{
855 int top, bottom;
856 double miny, maxy;
857 int i;
858 int j;
859 int clockwise;
860 int slopeoff;
861 int s;
862 int nright, nleft;
863 int y, lasty = 0, bottomy, topy = 0;
864
865 /* find the top of the polygon */
866 maxy = miny = vertices[0].y;
867 bottom = top = 0;
868 for (i = 1; i < count; i++) {
869 if (vertices[i].y < miny) {
870 top = i;
871 miny = vertices[i].y;
872 }
873 if (vertices[i].y >= maxy) {
874 bottom = i;
875 maxy = vertices[i].y;
876 }
877 }
878 clockwise = 1;
879 slopeoff = 0;
880
881 i = top;
882 j = StepAround(top, -1, count)(((top) + (-1) < 0) ? (count - 1) : ((top) + (-1) == count
) ? 0 : ((top) + (-1)))
;
883
884 if ((int64_t) slopes[j].dy * slopes[i].dx >
885 (int64_t) slopes[i].dy * slopes[j].dx) {
886 clockwise = -1;
887 slopeoff = -1;
888 }
889
890 bottomy = ICEIL(maxy) + yi;
891
892 nright = 0;
893
894 s = StepAround(top, slopeoff, count)(((top) + (slopeoff) < 0) ? (count - 1) : ((top) + (slopeoff
) == count) ? 0 : ((top) + (slopeoff)))
;
895 i = top;
896 while (i != bottom) {
897 if (slopes[s].dy != 0) {
898 y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
899 slopes[s].k,
900 slopes[s].dx, slopes[s].dy,
901 xi, yi, 0, &right[nright]);
902 if (nright != 0)
903 right[nright - 1].height = y - lasty;
904 else
905 topy = y;
906 nright++;
907 lasty = y;
908 }
909
910 i = StepAround(i, clockwise, count)(((i) + (clockwise) < 0) ? (count - 1) : ((i) + (clockwise
) == count) ? 0 : ((i) + (clockwise)))
;
911 s = StepAround(s, clockwise, count)(((s) + (clockwise) < 0) ? (count - 1) : ((s) + (clockwise
) == count) ? 0 : ((s) + (clockwise)))
;
912 }
913 if (nright != 0)
914 right[nright - 1].height = bottomy - lasty;
915
916 if (slopeoff == 0)
917 slopeoff = -1;
918 else
919 slopeoff = 0;
920
921 nleft = 0;
922 s = StepAround(top, slopeoff, count)(((top) + (slopeoff) < 0) ? (count - 1) : ((top) + (slopeoff
) == count) ? 0 : ((top) + (slopeoff)))
;
923 i = top;
924 while (i != bottom) {
925 if (slopes[s].dy != 0) {
926 y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
927 slopes[s].k,
928 slopes[s].dx, slopes[s].dy, xi, yi, 1,
929 &left[nleft]);
930
931 if (nleft != 0)
932 left[nleft - 1].height = y - lasty;
933 nleft++;
934 lasty = y;
935 }
936 i = StepAround(i, -clockwise, count)(((i) + (-clockwise) < 0) ? (count - 1) : ((i) + (-clockwise
) == count) ? 0 : ((i) + (-clockwise)))
;
937 s = StepAround(s, -clockwise, count)(((s) + (-clockwise) < 0) ? (count - 1) : ((s) + (-clockwise
) == count) ? 0 : ((s) + (-clockwise)))
;
938 }
939 if (nleft != 0)
940 left[nleft - 1].height = bottomy - lasty;
941 *pnleft = nleft;
942 *pnright = nright;
943 *h = bottomy - topy;
944 return topy;
945}
946
947static void
948miLineOnePoint(DrawablePtr pDrawable,
949 GCPtr pGC,
950 unsigned long pixel, SpanDataPtr spanData, int x, int y)
951{
952 DDXPointRec pt;
953 int wid;
954 unsigned long oldPixel;
955
956 MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel){ oldPixel = pGC->fgPixel; if (pixel != oldPixel) { ChangeGCVal
gcval; gcval.val = pixel; ChangeGC (((ClientPtr) 0), pGC, (1L
<<2), &gcval); ValidateGC (pDrawable, pGC); } }
;
957 if (pGC->fillStyle == FillSolid0) {
958 pt.x = x;
959 pt.y = y;
960 (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin0, 1, &pt);
961 }
962 else {
963 wid = 1;
964 if (pGC->miTranslate) {
965 x += pDrawable->x;
966 y += pDrawable->y;
967 }
968 pt.x = x;
969 pt.y = y;
970 (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE1);
971 }
972 MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel){ if (pixel != oldPixel) { ChangeGCVal gcval; gcval.val = oldPixel
; ChangeGC (((ClientPtr) 0), pGC, (1L<<2), &gcval);
ValidateGC (pDrawable, pGC); } }
;
973}
974
975static void
976miLineJoin(DrawablePtr pDrawable,
977 GCPtr pGC,
978 unsigned long pixel,
979 SpanDataPtr spanData, LineFacePtr pLeft, LineFacePtr pRight)
980{
981 double mx = 0, my = 0;
982 double denom = 0.0;
983 PolyVertexRec vertices[4];
984 PolySlopeRec slopes[4];
985 int edgecount;
986 PolyEdgeRec left[4], right[4];
987 int nleft, nright;
988 int y, height;
989 int swapslopes;
990 int joinStyle = pGC->joinStyle;
991 int lw = pGC->lineWidth;
992
993 if (lw == 1 && !spanData) {
994 /* See if one of the lines will draw the joining pixel */
995 if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
996 return;
997 if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
998 return;
999 if (joinStyle != JoinRound1) {
1000 denom =
1001 -pLeft->dx * (double) pRight->dy +
1002 pRight->dx * (double) pLeft->dy;
1003 if (denom == 0)
1004 return; /* no join to draw */
1005 }
1006 if (joinStyle != JoinMiter0) {
1007 miLineOnePoint(pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
1008 return;
1009 }
1010 }
1011 else {
1012 if (joinStyle == JoinRound1) {
1013 miLineArc(pDrawable, pGC, pixel, spanData,
1014 pLeft, pRight, (double) 0.0, (double) 0.0, TRUE1);
1015 return;
1016 }
1017 denom =
1018 -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
1019 if (denom == 0.0)
1020 return; /* no join to draw */
1021 }
1022
1023 swapslopes = 0;
1024 if (denom > 0) {
1025 pLeft->xa = -pLeft->xa;
1026 pLeft->ya = -pLeft->ya;
1027 pLeft->dx = -pLeft->dx;
1028 pLeft->dy = -pLeft->dy;
1029 }
1030 else {
1031 swapslopes = 1;
1032 pRight->xa = -pRight->xa;
1033 pRight->ya = -pRight->ya;
1034 pRight->dx = -pRight->dx;
1035 pRight->dy = -pRight->dy;
1036 }
1037
1038 vertices[0].x = pRight->xa;
1039 vertices[0].y = pRight->ya;
1040 slopes[0].dx = -pRight->dy;
1041 slopes[0].dy = pRight->dx;
1042 slopes[0].k = 0;
1043
1044 vertices[1].x = 0;
1045 vertices[1].y = 0;
1046 slopes[1].dx = pLeft->dy;
1047 slopes[1].dy = -pLeft->dx;
1048 slopes[1].k = 0;
1049
1050 vertices[2].x = pLeft->xa;
1051 vertices[2].y = pLeft->ya;
1052
1053 if (joinStyle == JoinMiter0) {
1054 my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
1055 pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx)) /
1056 denom;
1057 if (pLeft->dy != 0) {
1058 mx = pLeft->xa + (my - pLeft->ya) *
1059 (double) pLeft->dx / (double) pLeft->dy;
1060 }
1061 else {
1062 mx = pRight->xa + (my - pRight->ya) *
1063 (double) pRight->dx / (double) pRight->dy;
1064 }
1065 /* check miter limit */
1066 if ((mx * mx + my * my) * 4 > SQSECANT108.856472512142 * lw * lw)
1067 joinStyle = JoinBevel2;
1068 }
1069
1070 if (joinStyle == JoinMiter0) {
1071 slopes[2].dx = pLeft->dx;
1072 slopes[2].dy = pLeft->dy;
1073 slopes[2].k = pLeft->k;
1074 if (swapslopes) {
1075 slopes[2].dx = -slopes[2].dx;
1076 slopes[2].dy = -slopes[2].dy;
1077 slopes[2].k = -slopes[2].k;
1078 }
1079 vertices[3].x = mx;
1080 vertices[3].y = my;
1081 slopes[3].dx = pRight->dx;
1082 slopes[3].dy = pRight->dy;
1083 slopes[3].k = pRight->k;
1084 if (swapslopes) {
1085 slopes[3].dx = -slopes[3].dx;
1086 slopes[3].dy = -slopes[3].dy;
1087 slopes[3].k = -slopes[3].k;
1088 }
1089 edgecount = 4;
1090 }
1091 else {
1092 double scale, dx, dy, adx, ady;
1093
1094 adx = dx = pRight->xa - pLeft->xa;
1095 ady = dy = pRight->ya - pLeft->ya;
1096 if (adx < 0)
1097 adx = -adx;
1098 if (ady < 0)
1099 ady = -ady;
1100 scale = ady;
1101 if (adx > ady)
1102 scale = adx;
1103 slopes[2].dx = (dx * 65536) / scale;
1104 slopes[2].dy = (dy * 65536) / scale;
1105 slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
1106 (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
1107 edgecount = 3;
1108 }
1109
1110 y = miPolyBuildPoly(vertices, slopes, edgecount, pLeft->x, pLeft->y,
1111 left, right, &nleft, &nright, &height);
1112 miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, height, left, right,
1113 nleft, nright);
1114}
1115
1116static int
1117miLineArcI(DrawablePtr pDraw,
1118 GCPtr pGC, int xorg, int yorg, DDXPointPtr points, int *widths)
1119{
1120 DDXPointPtr tpts, bpts;
1121 int *twids, *bwids;
1122 int x, y, e, ex, slw;
1123
1124 tpts = points;
1125 twids = widths;
1126 if (pGC->miTranslate) {
1127 xorg += pDraw->x;
1128 yorg += pDraw->y;
1129 }
1130 slw = pGC->lineWidth;
1131 if (slw == 1) {
1132 tpts->x = xorg;
1133 tpts->y = yorg;
1134 *twids = 1;
1135 return 1;
1136 }
1137 bpts = tpts + slw;
1138 bwids = twids + slw;
1139 y = (slw >> 1) + 1;
1140 if (slw & 1)
1141 e = -((y << 2) + 3);
1142 else
1143 e = -(y << 3);
1144 ex = -4;
1145 x = 0;
1146 while (y) {
1147 e += (y << 3) - 4;
1148 while (e >= 0) {
1149 x++;
1150 e += (ex = -((x << 3) + 4));
1151 }
1152 y--;
1153 slw = (x << 1) + 1;
1154 if ((e == ex) && (slw > 1))
1155 slw--;
1156 tpts->x = xorg - x;
1157 tpts->y = yorg - y;
1158 tpts++;
1159 *twids++ = slw;
1160 if ((y != 0) && ((slw > 1) || (e != ex))) {
1161 bpts--;
1162 bpts->x = xorg - x;
1163 bpts->y = yorg + y;
1164 *--bwids = slw;
1165 }
1166 }
1167 return pGC->lineWidth;
1168}
1169
1170#define CLIPSTEPEDGE(edgey,edge,edgeleft)if (ybase == edgey) { if (edgeleft) { if (edge->x > xcl
) xcl = edge->x; } else { if (edge->x < xcr) xcr = edge
->x; } edgey++; edge->x += edge->stepx; edge->e +=
edge->dx; if (edge->e > 0) { edge->x += edge->
signdx; edge->e -= edge->dy; } }
\
1171 if (ybase == edgey) \
1172 { \
1173 if (edgeleft) \
1174 { \
1175 if (edge->x > xcl) \
1176 xcl = edge->x; \
1177 } \
1178 else \
1179 { \
1180 if (edge->x < xcr) \
1181 xcr = edge->x; \
1182 } \
1183 edgey++; \
1184 edge->x += edge->stepx; \
1185 edge->e += edge->dx; \
1186 if (edge->e > 0) \
1187 { \
1188 edge->x += edge->signdx; \
1189 edge->e -= edge->dy; \
1190 } \
1191 }
1192
1193static int
1194miLineArcD(DrawablePtr pDraw,
1195 GCPtr pGC,
1196 double xorg,
1197 double yorg,
1198 DDXPointPtr points,
1199 int *widths,
1200 PolyEdgePtr edge1,
1201 int edgey1,
1202 Bool edgeleft1, PolyEdgePtr edge2, int edgey2, Bool edgeleft2)
1203{
1204 DDXPointPtr pts;
1205 int *wids;
1206 double radius, x0, y0, el, er, yk, xlk, xrk, k;
1207 int xbase, ybase, y, boty, xl, xr, xcl, xcr;
1208 int ymin, ymax;
1209 Bool edge1IsMin, edge2IsMin;
1210 int ymin1, ymin2;
1211
1212 pts = points;
1213 wids = widths;
1214 xbase = floor(xorg);
1215 x0 = xorg - xbase;
1216 ybase = ICEIL(yorg);
1217 y0 = yorg - ybase;
1218 if (pGC->miTranslate) {
1219 xbase += pDraw->x;
1220 ybase += pDraw->y;
1221 edge1->x += pDraw->x;
1222 edge2->x += pDraw->x;
1223 edgey1 += pDraw->y;
1224 edgey2 += pDraw->y;
1225 }
1226 xlk = x0 + x0 + 1.0;
1227 xrk = x0 + x0 - 1.0;
1228 yk = y0 + y0 - 1.0;
1229 radius = ((double) pGC->lineWidth) / 2.0;
1230 y = floor(radius - y0 + 1.0);
1231 ybase -= y;
1232 ymin = ybase;
1233 ymax = 65536;
1234 edge1IsMin = FALSE0;
1235 ymin1 = edgey1;
1236 if (edge1->dy >= 0) {
1237 if (!edge1->dy) {
1238 if (edgeleft1)
1239 edge1IsMin = TRUE1;
1240 else
1241 ymax = edgey1;
1242 edgey1 = 65536;
1243 }
1244 else {
1245 if ((edge1->signdx < 0) == edgeleft1)
1246 edge1IsMin = TRUE1;
1247 }
1248 }
1249 edge2IsMin = FALSE0;
1250 ymin2 = edgey2;
1251 if (edge2->dy >= 0) {
1252 if (!edge2->dy) {
1253 if (edgeleft2)
1254 edge2IsMin = TRUE1;
1255 else
1256 ymax = edgey2;
1257 edgey2 = 65536;
1258 }
1259 else {
1260 if ((edge2->signdx < 0) == edgeleft2)
1261 edge2IsMin = TRUE1;
1262 }
1263 }
1264 if (edge1IsMin) {
1265 ymin = ymin1;
1266 if (edge2IsMin && ymin1 > ymin2)
1267 ymin = ymin2;
1268 }
1269 else if (edge2IsMin)
1270 ymin = ymin2;
1271 el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
1272 er = el + xrk;
1273 xl = 1;
1274 xr = 0;
1275 if (x0 < 0.5) {
1276 xl = 0;
1277 el -= xlk;
1278 }
1279 boty = (y0 < -0.5) ? 1 : 0;
1280 if (ybase + y - boty > ymax)
1281 boty = ymax - ybase - y;
1282 while (y > boty) {
1283 k = (y << 1) + yk;
1284 er += k;
1285 while (er > 0.0) {
1286 xr++;
1287 er += xrk - (xr << 1);
1288 }
1289 el += k;
1290 while (el >= 0.0) {
1291 xl--;
1292 el += (xl << 1) - xlk;
1293 }
1294 y--;
1295 ybase++;
1296 if (ybase < ymin)
1297 continue;
1298 xcl = xl + xbase;
1299 xcr = xr + xbase;
1300 CLIPSTEPEDGE(edgey1, edge1, edgeleft1)if (ybase == edgey1) { if (edgeleft1) { if (edge1->x > xcl
) xcl = edge1->x; } else { if (edge1->x < xcr) xcr =
edge1->x; } edgey1++; edge1->x += edge1->stepx; edge1
->e += edge1->dx; if (edge1->e > 0) { edge1->x
+= edge1->signdx; edge1->e -= edge1->dy; } }
;
1301 CLIPSTEPEDGE(edgey2, edge2, edgeleft2)if (ybase == edgey2) { if (edgeleft2) { if (edge2->x > xcl
) xcl = edge2->x; } else { if (edge2->x < xcr) xcr =
edge2->x; } edgey2++; edge2->x += edge2->stepx; edge2
->e += edge2->dx; if (edge2->e > 0) { edge2->x
+= edge2->signdx; edge2->e -= edge2->dy; } }
;
1302 if (xcr >= xcl) {
1303 pts->x = xcl;
1304 pts->y = ybase;
1305 pts++;
1306 *wids++ = xcr - xcl + 1;
1307 }
1308 }
1309 er = xrk - (xr << 1) - er;
1310 el = (xl << 1) - xlk - el;
1311 boty = floor(-y0 - radius + 1.0);
1312 if (ybase + y - boty > ymax)
1313 boty = ymax - ybase - y;
1314 while (y > boty) {
1315 k = (y << 1) + yk;
1316 er -= k;
1317 while ((er >= 0.0) && (xr >= 0)) {
1318 xr--;
1319 er += xrk - (xr << 1);
1320 }
1321 el -= k;
1322 while ((el > 0.0) && (xl <= 0)) {
1323 xl++;
1324 el += (xl << 1) - xlk;
1325 }
1326 y--;
1327 ybase++;
1328 if (ybase < ymin)
1329 continue;
1330 xcl = xl + xbase;
1331 xcr = xr + xbase;
1332 CLIPSTEPEDGE(edgey1, edge1, edgeleft1)if (ybase == edgey1) { if (edgeleft1) { if (edge1->x > xcl
) xcl = edge1->x; } else { if (edge1->x < xcr) xcr =
edge1->x; } edgey1++; edge1->x += edge1->stepx; edge1
->e += edge1->dx; if (edge1->e > 0) { edge1->x
+= edge1->signdx; edge1->e -= edge1->dy; } }
;
1333 CLIPSTEPEDGE(edgey2, edge2, edgeleft2)if (ybase == edgey2) { if (edgeleft2) { if (edge2->x > xcl
) xcl = edge2->x; } else { if (edge2->x < xcr) xcr =
edge2->x; } edgey2++; edge2->x += edge2->stepx; edge2
->e += edge2->dx; if (edge2->e > 0) { edge2->x
+= edge2->signdx; edge2->e -= edge2->dy; } }
;
1334 if (xcr >= xcl) {
1335 pts->x = xcl;
1336 pts->y = ybase;
1337 pts++;
1338 *wids++ = xcr - xcl + 1;
1339 }
1340 }
1341 return pts - points;
1342}
1343
1344static int
1345miRoundJoinFace(LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
1346{
1347 int y;
1348 int dx, dy;
1349 double xa, ya;
1350 Bool left;
1351
1352 dx = -face->dy;
1353 dy = face->dx;
1354 xa = face->xa;
1355 ya = face->ya;
1356 left = 1;
1357 if (ya > 0) {
1358 ya = 0.0;
1359 xa = 0.0;
1360 }
1361 if (dy < 0 || (dy == 0 && dx > 0)) {
1362 dx = -dx;
1363 dy = -dy;
1364 left = !left;
1365 }
1366 if (dx == 0 && dy == 0)
1367 dy = 1;
1368 if (dy == 0) {
1369 y = ICEIL(face->ya) + face->y;
1370 edge->x = -32767;
1371 edge->stepx = 0;
1372 edge->signdx = 0;
1373 edge->e = -1;
1374 edge->dy = 0;
1375 edge->dx = 0;
1376 edge->height = 0;
1377 }
1378 else {
1379 y = miPolyBuildEdge(xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
1380 edge->height = 32767;
1381 }
1382 *leftEdge = !left;
1383 return y;
1384}
1385
1386static void
1387miRoundJoinClip(LineFacePtr pLeft, LineFacePtr pRight,
1388 PolyEdgePtr edge1, PolyEdgePtr edge2,
1389 int *y1, int *y2, Bool *left1, Bool *left2)
1390{
1391 double denom;
1392
1393 denom = -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
1394
1395 if (denom >= 0) {
1396 pLeft->xa = -pLeft->xa;
1397 pLeft->ya = -pLeft->ya;
1398 }
1399 else {
1400 pRight->xa = -pRight->xa;
1401 pRight->ya = -pRight->ya;
1402 }
1403 *y1 = miRoundJoinFace(pLeft, edge1, left1);
1404 *y2 = miRoundJoinFace(pRight, edge2, left2);
1405}
1406
1407static int
1408miRoundCapClip(LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
1409{
1410 int y;
1411 int dx, dy;
1412 double xa, ya, k;
1413 Bool left;
1414
1415 dx = -face->dy;
1416 dy = face->dx;
1417 xa = face->xa;
1418 ya = face->ya;
1419 k = 0.0;
1420 if (!isInt)
1421 k = face->k;
1422 left = 1;
1423 if (dy < 0 || (dy == 0 && dx > 0)) {
1424 dx = -dx;
1425 dy = -dy;
1426 xa = -xa;
1427 ya = -ya;
1428 left = !left;
1429 }
1430 if (dx == 0 && dy == 0)
1431 dy = 1;
1432 if (dy == 0) {
1433 y = ICEIL(face->ya) + face->y;
1434 edge->x = -32767;
1435 edge->stepx = 0;
1436 edge->signdx = 0;
1437 edge->e = -1;
1438 edge->dy = 0;
1439 edge->dx = 0;
1440 edge->height = 0;
1441 }
1442 else {
1443 y = miPolyBuildEdge(xa, ya, k, dx, dy, face->x, face->y, !left, edge);
1444 edge->height = 32767;
1445 }
1446 *leftEdge = !left;
1447 return y;
1448}
1449
1450static void
1451miLineArc(DrawablePtr pDraw,
1452 GCPtr pGC,
1453 unsigned long pixel,
1454 SpanDataPtr spanData,
1455 LineFacePtr leftFace,
1456 LineFacePtr rightFace, double xorg, double yorg, Bool isInt)
1457{
1458 int xorgi = 0, yorgi = 0;
1459 Spans spanRec;
1460 int n;
1461 PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
1462 int edgey1, edgey2;
1463 Bool edgeleft1, edgeleft2;
1464
1465 if (isInt) {
1466 xorgi = leftFace ? leftFace->x : rightFace->x;
1467 yorgi = leftFace ? leftFace->y : rightFace->y;
1468 }
1469 edgey1 = 65536;
1470 edgey2 = 65536;
1471 edge1.x = 0; /* not used, keep memory checkers happy */
1472 edge1.dy = -1;
1473 edge2.x = 0; /* not used, keep memory checkers happy */
1474 edge2.dy = -1;
1475 edgeleft1 = FALSE0;
1476 edgeleft2 = FALSE0;
1477 if ((pGC->lineStyle != LineSolid0 || pGC->lineWidth > 2) &&
1478 ((pGC->capStyle == CapRound2 && pGC->joinStyle != JoinRound1) ||
1479 (pGC->joinStyle == JoinRound1 && pGC->capStyle == CapButt1))) {
1480 if (isInt) {
1481 xorg = (double) xorgi;
1482 yorg = (double) yorgi;
1483 }
1484 if (leftFace && rightFace) {
1485 miRoundJoinClip(leftFace, rightFace, &edge1, &edge2,
1486 &edgey1, &edgey2, &edgeleft1, &edgeleft2);
1487 }
1488 else if (leftFace) {
1489 edgey1 = miRoundCapClip(leftFace, isInt, &edge1, &edgeleft1);
1490 }
1491 else if (rightFace) {
1492 edgey2 = miRoundCapClip(rightFace, isInt, &edge2, &edgeleft2);
1493 }
1494 isInt = FALSE0;
1495 }
1496 if (!InitSpans(&spanRec, pGC->lineWidth))
1497 return;
1498 if (isInt)
1499 n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points,
1500 spanRec.widths);
1501 else
1502 n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths,
1503 &edge1, edgey1, edgeleft1, &edge2, edgey2, edgeleft2);
1504 spanRec.count = n;
1505 fillSpans(pDraw, pGC, pixel, &spanRec, spanData);
1506}
1507
1508static void
1509miLineProjectingCap(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
1510 SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
1511 double xorg, double yorg, Bool isInt)
1512{
1513 int xorgi = 0, yorgi = 0;
1514 int lw;
1515 PolyEdgeRec lefts[4], rights[4];
1516 int lefty, righty, topy, bottomy;
1517 PolyEdgePtr left, right;
1518 PolyEdgePtr top, bottom;
1519 double xa, ya;
1520 double k;
1521 double xap, yap;
1522 int dx, dy;
1523 double projectXoff, projectYoff;
1524 double maxy;
1525 int finaly;
1526
1527 if (isInt) {
1528 xorgi = face->x;
1529 yorgi = face->y;
1530 }
1531 lw = pGC->lineWidth;
1532 dx = face->dx;
1533 dy = face->dy;
1534 k = face->k;
1535 if (dy == 0) {
1536 lefts[0].height = lw;
1537 lefts[0].x = xorgi;
1538 if (isLeft)
1539 lefts[0].x -= (lw >> 1);
1540 lefts[0].stepx = 0;
1541 lefts[0].signdx = 1;
1542 lefts[0].e = -lw;
1543 lefts[0].dx = 0;
1544 lefts[0].dy = lw;
1545 rights[0].height = lw;
1546 rights[0].x = xorgi;
1547 if (!isLeft)
1548 rights[0].x += ((lw + 1) >> 1);
1549 rights[0].stepx = 0;
1550 rights[0].signdx = 1;
1551 rights[0].e = -lw;
1552 rights[0].dx = 0;
1553 rights[0].dy = lw;
1554 miFillPolyHelper(pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
1555 lefts, rights, 1, 1);
1556 }
1557 else if (dx == 0) {
1558 if (dy < 0) {
1559 dy = -dy;
1560 isLeft = !isLeft;
1561 }
1562 topy = yorgi;
1563 bottomy = yorgi + dy;
1564 if (isLeft)
1565 topy -= (lw >> 1);
1566 else
1567 bottomy += (lw >> 1);
1568 lefts[0].height = bottomy - topy;
1569 lefts[0].x = xorgi - (lw >> 1);
1570 lefts[0].stepx = 0;
1571 lefts[0].signdx = 1;
1572 lefts[0].e = -dy;
1573 lefts[0].dx = dx;
1574 lefts[0].dy = dy;
1575
1576 rights[0].height = bottomy - topy;
1577 rights[0].x = lefts[0].x + (lw - 1);
1578 rights[0].stepx = 0;
1579 rights[0].signdx = 1;
1580 rights[0].e = -dy;
1581 rights[0].dx = dx;
1582 rights[0].dy = dy;
1583 miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, bottomy - topy,
1584 lefts, rights, 1, 1);
1585 }
1586 else {
1587 xa = face->xa;
1588 ya = face->ya;
1589 projectXoff = -ya;
1590 projectYoff = xa;
1591 if (dx < 0) {
1592 right = &rights[1];
1593 left = &lefts[0];
1594 top = &rights[0];
1595 bottom = &lefts[1];
1596 }
1597 else {
1598 right = &rights[0];
1599 left = &lefts[1];
1600 top = &lefts[0];
1601 bottom = &rights[1];
1602 }
1603 if (isLeft) {
1604 righty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 0, right);
1605
1606 xa = -xa;
1607 ya = -ya;
1608 k = -k;
1609 lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
1610 k, dx, dy, xorgi, yorgi, 1, left);
1611 if (dx > 0) {
1612 ya = -ya;
1613 xa = -xa;
1614 }
1615 xap = xa - projectXoff;
1616 yap = ya - projectYoff;
1617 topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
1618 -dy, dx, xorgi, yorgi, dx > 0, top);
1619 bottomy = miPolyBuildEdge(xa, ya,
1620 0.0, -dy, dx, xorgi, yorgi, dx < 0,
1621 bottom);
1622 maxy = -ya;
1623 }
1624 else {
1625 righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
1626 k, dx, dy, xorgi, yorgi, 0, right);
1627
1628 xa = -xa;
1629 ya = -ya;
1630 k = -k;
1631 lefty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 1, left);
1632 if (dx > 0) {
1633 ya = -ya;
1634 xa = -xa;
1635 }
1636 xap = xa - projectXoff;
1637 yap = ya - projectYoff;
1638 topy =
1639 miPolyBuildEdge(xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0,
1640 top);
1641 bottomy =
1642 miPolyBuildEdge(xap, yap, xap * dx + yap * dy, -dy, dx, xorgi,
1643 xorgi, dx < 0, bottom);
1644 maxy = -ya + projectYoff;
1645 }
1646 finaly = ICEIL(maxy) + yorgi;
1647 if (dx < 0) {
1648 left->height = bottomy - lefty;
1649 right->height = finaly - righty;
1650 top->height = righty - topy;
1651 }
1652 else {
1653 right->height = bottomy - righty;
1654 left->height = finaly - lefty;
1655 top->height = lefty - topy;
1656 }
1657 bottom->height = finaly - bottomy;
1658 miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
1659 bottom->height + bottomy - topy, lefts, rights, 2, 2);
1660 }
1661}
1662
1663static void
1664miWideSegment(DrawablePtr pDrawable,
1665 GCPtr pGC,
1666 unsigned long pixel,
1667 SpanDataPtr spanData,
1668 int x1,
1669 int y1,
1670 int x2,
1671 int y2,
1672 Bool projectLeft,
1673 Bool projectRight, LineFacePtr leftFace, LineFacePtr rightFace)
1674{
1675 double l, L, r;
1676 double xa, ya;
1677 double projectXoff = 0.0, projectYoff = 0.0;
1678 double k;
1679 double maxy;
1680 int x, y;
1681 int dx, dy;
1682 int finaly;
1683 PolyEdgePtr left, right;
1684 PolyEdgePtr top, bottom;
1685 int lefty, righty, topy, bottomy;
1686 int signdx;
1687 PolyEdgeRec lefts[4], rights[4];
1688 LineFacePtr tface;
1689 int lw = pGC->lineWidth;
1690
1691 /* draw top-to-bottom always */
1692 if (y2 < y1 || (y2 == y1 && x2 < x1)) {
1693 x = x1;
1694 x1 = x2;
1695 x2 = x;
1696
1697 y = y1;
1698 y1 = y2;
1699 y2 = y;
1700
1701 x = projectLeft;
1702 projectLeft = projectRight;
1703 projectRight = x;
1704
1705 tface = leftFace;
1706 leftFace = rightFace;
1707 rightFace = tface;
1708 }
1709
1710 dy = y2 - y1;
1711 signdx = 1;
1712 dx = x2 - x1;
1713 if (dx < 0)
1714 signdx = -1;
1715
1716 leftFace->x = x1;
1717 leftFace->y = y1;
1718 leftFace->dx = dx;
1719 leftFace->dy = dy;
1720
1721 rightFace->x = x2;
1722 rightFace->y = y2;
1723 rightFace->dx = -dx;
1724 rightFace->dy = -dy;
1725
1726 if (dy == 0) {
1727 rightFace->xa = 0;
1728 rightFace->ya = (double) lw / 2.0;
1729 rightFace->k = -(double) (lw * dx) / 2.0;
1730 leftFace->xa = 0;
1731 leftFace->ya = -rightFace->ya;
1732 leftFace->k = rightFace->k;
1733 x = x1;
1734 if (projectLeft)
1735 x -= (lw >> 1);
1736 y = y1 - (lw >> 1);
1737 dx = x2 - x;
1738 if (projectRight)
1739 dx += ((lw + 1) >> 1);
1740 dy = lw;
1741 miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
1742 }
1743 else if (dx == 0) {
1744 leftFace->xa = (double) lw / 2.0;
1745 leftFace->ya = 0;
1746 leftFace->k = (double) (lw * dy) / 2.0;
1747 rightFace->xa = -leftFace->xa;
1748 rightFace->ya = 0;
1749 rightFace->k = leftFace->k;
1750 y = y1;
1751 if (projectLeft)
1752 y -= lw >> 1;
1753 x = x1 - (lw >> 1);
1754 dy = y2 - y;
1755 if (projectRight)
1756 dy += ((lw + 1) >> 1);
1757 dx = lw;
1758 miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
1759 }
1760 else {
1761 l = ((double) lw) / 2.0;
1762 L = hypot((double) dx, (double) dy);
1763
1764 if (dx < 0) {
1765 right = &rights[1];
1766 left = &lefts[0];
1767 top = &rights[0];
1768 bottom = &lefts[1];
1769 }
1770 else {
1771 right = &rights[0];
1772 left = &lefts[1];
1773 top = &lefts[0];
1774 bottom = &rights[1];
1775 }
1776 r = l / L;
1777
1778 /* coord of upper bound at integral y */
1779 ya = -r * dx;
1780 xa = r * dy;
1781
1782 if (projectLeft | projectRight) {
1783 projectXoff = -ya;
1784 projectYoff = xa;
1785 }
1786
1787 /* xa * dy - ya * dx */
1788 k = l * L;
1789
1790 leftFace->xa = xa;
1791 leftFace->ya = ya;
1792 leftFace->k = k;
1793 rightFace->xa = -xa;
1794 rightFace->ya = -ya;
1795 rightFace->k = k;
1796
1797 if (projectLeft)
1798 righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
1799 k, dx, dy, x1, y1, 0, right);
1800 else
1801 righty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 0, right);
1802
1803 /* coord of lower bound at integral y */
1804 ya = -ya;
1805 xa = -xa;
1806
1807 /* xa * dy - ya * dx */
1808 k = -k;
1809
1810 if (projectLeft)
1811 lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
1812 k, dx, dy, x1, y1, 1, left);
1813 else
1814 lefty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 1, left);
1815
1816 /* coord of top face at integral y */
1817
1818 if (signdx > 0) {
1819 ya = -ya;
1820 xa = -xa;
1821 }
1822
1823 if (projectLeft) {
1824 double xap = xa - projectXoff;
1825 double yap = ya - projectYoff;
1826
1827 topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
1828 -dy, dx, x1, y1, dx > 0, top);
1829 }
1830 else
1831 topy = miPolyBuildEdge(xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
1832
1833 /* coord of bottom face at integral y */
1834
1835 if (projectRight) {
1836 double xap = xa + projectXoff;
1837 double yap = ya + projectYoff;
1838
1839 bottomy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
1840 -dy, dx, x2, y2, dx < 0, bottom);
1841 maxy = -ya + projectYoff;
1842 }
1843 else {
1844 bottomy = miPolyBuildEdge(xa, ya,
1845 0.0, -dy, dx, x2, y2, dx < 0, bottom);
1846 maxy = -ya;
1847 }
1848
1849 finaly = ICEIL(maxy) + y2;
1850
1851 if (dx < 0) {
1852 left->height = bottomy - lefty;
1853 right->height = finaly - righty;
1854 top->height = righty - topy;
1855 }
1856 else {
1857 right->height = bottomy - righty;
1858 left->height = finaly - lefty;
1859 top->height = lefty - topy;
1860 }
1861 bottom->height = finaly - bottomy;
1862 miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
1863 bottom->height + bottomy - topy, lefts, rights, 2, 2);
1864 }
1865}
1866
1867static SpanDataPtr
1868miSetupSpanData(GCPtr pGC, SpanDataPtr spanData, int npt)
1869{
1870 if ((npt < 3 && pGC->capStyle != CapRound2) || miSpansEasyRop(pGC->alu)(!(((pGC->alu) & 0xc) == 0x8 || ((pGC->alu) & 0x3
) == 0x2))
)
1871 return (SpanDataPtr) NULL((void*)0);
1872 if (pGC->lineStyle == LineDoubleDash2)
1873 miInitSpanGroup(&spanData->bgGroup);
1874 miInitSpanGroup(&spanData->fgGroup);
1875 return spanData;
1876}
1877
1878static void
1879miCleanupSpanData(DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
1880{
1881 if (pGC->lineStyle == LineDoubleDash2) {
1
Taking false branch
1882 ChangeGCVal oldPixel, pixel;
1883
1884 pixel.val = pGC->bgPixel;
1885 oldPixel.val = pGC->fgPixel;
1886 if (pixel.val != oldPixel.val) {
1887 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &pixel);
1888 ValidateGC(pDrawable, pGC);
1889 }
1890 miFillUniqueSpanGroup(pDrawable, pGC, &spanData->bgGroup);
1891 miFreeSpanGroup(&spanData->bgGroup);
1892 if (pixel.val != oldPixel.val) {
1893 ChangeGC(NullClient((ClientPtr) 0), pGC, GCForeground(1L<<2), &oldPixel);
1894 ValidateGC(pDrawable, pGC);
1895 }
1896 }
1897 miFillUniqueSpanGroup(pDrawable, pGC, &spanData->fgGroup);
2
Calling 'miFillUniqueSpanGroup'
1898 miFreeSpanGroup(&spanData->fgGroup);
1899}
1900
1901void
1902miWideLine(DrawablePtr pDrawable, GCPtr pGC,
1903 int mode, int npt, DDXPointPtr pPts)
1904{
1905 int x1, y1, x2, y2;
1906 SpanDataRec spanDataRec;
1907 SpanDataPtr spanData;
1908 long pixel;
1909 Bool projectLeft, projectRight;
1910 LineFaceRec leftFace, rightFace, prevRightFace;
1911 LineFaceRec firstFace;
1912 int first;
1913 Bool somethingDrawn = FALSE0;
1914 Bool selfJoin;
1915
1916 spanData = miSetupSpanData(pGC, &spanDataRec, npt);
1917 pixel = pGC->fgPixel;
1918 x2 = pPts->x;
1919 y2 = pPts->y;
1920 first = TRUE1;
1921 selfJoin = FALSE0;
1922 if (npt > 1) {
1923 if (mode == CoordModePrevious1) {
1924 int nptTmp;
1925 DDXPointPtr pPtsTmp;
1926
1927 x1 = x2;
1928 y1 = y2;
1929 nptTmp = npt;
1930 pPtsTmp = pPts + 1;
1931 while (--nptTmp) {
1932 x1 += pPtsTmp->x;
1933 y1 += pPtsTmp->y;
1934 ++pPtsTmp;
1935 }
1936 if (x2 == x1 && y2 == y1)
1937 selfJoin = TRUE1;
1938 }
1939 else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
1940 selfJoin = TRUE1;
1941 }
1942 }
1943 projectLeft = pGC->capStyle == CapProjecting3 && !selfJoin;
1944 projectRight = FALSE0;
1945 while (--npt) {
1946 x1 = x2;
1947 y1 = y2;
1948 ++pPts;
1949 x2 = pPts->x;
1950 y2 = pPts->y;
1951 if (mode == CoordModePrevious1) {
1952 x2 += x1;
1953 y2 += y1;
1954 }
1955 if (x1 != x2 || y1 != y2) {
1956 somethingDrawn = TRUE1;
1957 if (npt == 1 && pGC->capStyle == CapProjecting3 && !selfJoin)
1958 projectRight = TRUE1;
1959 miWideSegment(pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
1960 projectLeft, projectRight, &leftFace, &rightFace);
1961 if (first) {
1962 if (selfJoin)
1963 firstFace = leftFace;
1964 else if (pGC->capStyle == CapRound2) {
1965 if (pGC->lineWidth == 1 && !spanData)
1966 miLineOnePoint(pDrawable, pGC, pixel, spanData, x1, y1);
1967 else
1968 miLineArc(pDrawable, pGC, pixel, spanData,
1969 &leftFace, (LineFacePtr) NULL((void*)0),
1970 (double) 0.0, (double) 0.0, TRUE1);
1971 }
1972 }
1973 else {
1974 miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
1975 &prevRightFace);
1976 }
1977 prevRightFace = rightFace;
1978 first = FALSE0;
1979 projectLeft = FALSE0;
1980 }
1981 if (npt == 1 && somethingDrawn) {
1982 if (selfJoin)
1983 miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
1984 &rightFace);
1985 else if (pGC->capStyle == CapRound2) {
1986 if (pGC->lineWidth == 1 && !spanData)
1987 miLineOnePoint(pDrawable, pGC, pixel, spanData, x2, y2);
1988 else
1989 miLineArc(pDrawable, pGC, pixel, spanData,
1990 (LineFacePtr) NULL((void*)0), &rightFace,
1991 (double) 0.0, (double) 0.0, TRUE1);
1992 }
1993 }
1994 }
1995 /* handle crock where all points are coincedent */
1996 if (!somethingDrawn) {
1997 projectLeft = pGC->capStyle == CapProjecting3;
1998 miWideSegment(pDrawable, pGC, pixel, spanData,
1999 x2, y2, x2, y2, projectLeft, projectLeft,
2000 &leftFace, &rightFace);
2001 if (pGC->capStyle == CapRound2) {
2002 miLineArc(pDrawable, pGC, pixel, spanData,
2003 &leftFace, (LineFacePtr) NULL((void*)0),
2004 (double) 0.0, (double) 0.0, TRUE1);
2005 rightFace.dx = -1; /* sleezy hack to make it work */
2006 miLineArc(pDrawable, pGC, pixel, spanData,
2007 (LineFacePtr) NULL((void*)0), &rightFace,
2008 (double) 0.0, (double) 0.0, TRUE1);
2009 }
2010 }
2011 if (spanData)
2012 miCleanupSpanData(pDrawable, pGC, spanData);
2013}
2014
2015#define V_TOP0 0
2016#define V_RIGHT1 1
2017#define V_BOTTOM2 2
2018#define V_LEFT3 3
2019
2020static void
2021miWideDashSegment(DrawablePtr pDrawable,
2022 GCPtr pGC,
2023 SpanDataPtr spanData,
2024 int *pDashOffset,
2025 int *pDashIndex,
2026 int x1,
2027 int y1,
2028 int x2,
2029 int y2,
2030 Bool projectLeft,
2031 Bool projectRight,
2032 LineFacePtr leftFace, LineFacePtr rightFace)
2033{
2034 int dashIndex, dashRemain;
2035 unsigned char *pDash;
2036 double L, l;
2037 double k;
2038 PolyVertexRec vertices[4];
2039 PolyVertexRec saveRight, saveBottom;
2040 PolySlopeRec slopes[4];
2041 PolyEdgeRec left[4], right[4];
2042 LineFaceRec lcapFace, rcapFace;
2043 int nleft, nright;
2044 int h;
2045 int y;
2046 int dy, dx;
2047 unsigned long pixel;
2048 double LRemain;
2049 double r;
2050 double rdx, rdy;
2051 double dashDx, dashDy;
2052 double saveK = 0.0;
2053 Bool first = TRUE1;
2054 double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
2055 unsigned long fgPixel, bgPixel;
2056
2057 dx = x2 - x1;
2058 dy = y2 - y1;
2059 dashIndex = *pDashIndex;
2060 pDash = pGC->dash;
2061 dashRemain = pDash[dashIndex] - *pDashOffset;
2062 fgPixel = pGC->fgPixel;
2063 bgPixel = pGC->bgPixel;
2064 if (pGC->fillStyle == FillOpaqueStippled3 || pGC->fillStyle == FillTiled1) {
2065 bgPixel = fgPixel;
2066 }
2067
2068 l = ((double) pGC->lineWidth) / 2.0;
2069 if (dx == 0) {
2070 L = dy;
2071 rdx = 0;
2072 rdy = l;
2073 if (dy < 0) {
2074 L = -dy;
2075 rdy = -l;
2076 }
2077 }
2078 else if (dy == 0) {
2079 L = dx;
2080 rdx = l;
2081 rdy = 0;
2082 if (dx < 0) {
2083 L = -dx;
2084 rdx = -l;
2085 }
2086 }
2087 else {
2088 L = hypot((double) dx, (double) dy);
2089 r = l / L;
2090
2091 rdx = r * dx;
2092 rdy = r * dy;
2093 }
2094 k = l * L;
2095 LRemain = L;
2096 /* All position comments are relative to a line with dx and dy > 0,
2097 * but the code does not depend on this */
2098 /* top */
2099 slopes[V_TOP0].dx = dx;
2100 slopes[V_TOP0].dy = dy;
2101 slopes[V_TOP0].k = k;
2102 /* right */
2103 slopes[V_RIGHT1].dx = -dy;
2104 slopes[V_RIGHT1].dy = dx;
2105 slopes[V_RIGHT1].k = 0;
2106 /* bottom */
2107 slopes[V_BOTTOM2].dx = -dx;
2108 slopes[V_BOTTOM2].dy = -dy;
2109 slopes[V_BOTTOM2].k = k;
2110 /* left */
2111 slopes[V_LEFT3].dx = dy;
2112 slopes[V_LEFT3].dy = -dx;
2113 slopes[V_LEFT3].k = 0;
2114
2115 /* preload the start coordinates */
2116 vertices[V_RIGHT1].x = vertices[V_TOP0].x = rdy;
2117 vertices[V_RIGHT1].y = vertices[V_TOP0].y = -rdx;
2118
2119 vertices[V_BOTTOM2].x = vertices[V_LEFT3].x = -rdy;
2120 vertices[V_BOTTOM2].y = vertices[V_LEFT3].y = rdx;
2121
2122 if (projectLeft) {
2123 vertices[V_TOP0].x -= rdx;
2124 vertices[V_TOP0].y -= rdy;
2125
2126 vertices[V_LEFT3].x -= rdx;
2127 vertices[V_LEFT3].y -= rdy;
2128
2129 slopes[V_LEFT3].k = rdx * dx + rdy * dy;
2130 }
2131
2132 lcenterx = x1;
2133 lcentery = y1;
2134
2135 if (pGC->capStyle == CapRound2) {
2136 lcapFace.dx = dx;
2137 lcapFace.dy = dy;
2138 lcapFace.x = x1;
2139 lcapFace.y = y1;
2140
2141 rcapFace.dx = -dx;
2142 rcapFace.dy = -dy;
2143 rcapFace.x = x1;
2144 rcapFace.y = y1;
2145 }
2146 while (LRemain > dashRemain) {
2147 dashDx = (dashRemain * dx) / L;
2148 dashDy = (dashRemain * dy) / L;
2149
2150 rcenterx = lcenterx + dashDx;
2151 rcentery = lcentery + dashDy;
2152
2153 vertices[V_RIGHT1].x += dashDx;
2154 vertices[V_RIGHT1].y += dashDy;
2155
2156 vertices[V_BOTTOM2].x += dashDx;
2157 vertices[V_BOTTOM2].y += dashDy;
2158
2159 slopes[V_RIGHT1].k = vertices[V_RIGHT1].x * dx + vertices[V_RIGHT1].y * dy;
2160
2161 if (pGC->lineStyle == LineDoubleDash2 || !(dashIndex & 1)) {
2162 if (pGC->lineStyle == LineOnOffDash1 &&
2163 pGC->capStyle == CapProjecting3) {
2164 saveRight = vertices[V_RIGHT1];
2165 saveBottom = vertices[V_BOTTOM2];
2166 saveK = slopes[V_RIGHT1].k;
2167
2168 if (!first) {
2169 vertices[V_TOP0].x -= rdx;
2170 vertices[V_TOP0].y -= rdy;
2171
2172 vertices[V_LEFT3].x -= rdx;
2173 vertices[V_LEFT3].y -= rdy;
2174
2175 slopes[V_LEFT3].k = vertices[V_LEFT3].x *
2176 slopes[V_LEFT3].dy -
2177 vertices[V_LEFT3].y * slopes[V_LEFT3].dx;
2178 }
2179
2180 vertices[V_RIGHT1].x += rdx;
2181 vertices[V_RIGHT1].y += rdy;
2182
2183 vertices[V_BOTTOM2].x += rdx;
2184 vertices[V_BOTTOM2].y += rdy;
2185
2186 slopes[V_RIGHT1].k = vertices[V_RIGHT1].x *
2187 slopes[V_RIGHT1].dy -
2188 vertices[V_RIGHT1].y * slopes[V_RIGHT1].dx;
2189 }
2190 y = miPolyBuildPoly(vertices, slopes, 4, x1, y1,
2191 left, right, &nleft, &nright, &h);
2192 pixel = (dashIndex & 1) ? bgPixel : fgPixel;
2193 miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
2194 nleft, nright);
2195
2196 if (pGC->lineStyle == LineOnOffDash1) {
2197 switch (pGC->capStyle) {
2198 case CapProjecting3:
2199 vertices[V_BOTTOM2] = saveBottom;
2200 vertices[V_RIGHT1] = saveRight;
2201 slopes[V_RIGHT1].k = saveK;
2202 break;
2203 case CapRound2:
2204 if (!first) {
2205 if (dx < 0) {
2206 lcapFace.xa = -vertices[V_LEFT3].x;
2207 lcapFace.ya = -vertices[V_LEFT3].y;
2208 lcapFace.k = slopes[V_LEFT3].k;
2209 }
2210 else {
2211 lcapFace.xa = vertices[V_TOP0].x;
2212 lcapFace.ya = vertices[V_TOP0].y;
2213 lcapFace.k = -slopes[V_LEFT3].k;
2214 }
2215 miLineArc(pDrawable, pGC, pixel, spanData,
2216 &lcapFace, (LineFacePtr) NULL((void*)0),
2217 lcenterx, lcentery, FALSE0);
2218 }
2219 if (dx < 0) {
2220 rcapFace.xa = vertices[V_BOTTOM2].x;
2221 rcapFace.ya = vertices[V_BOTTOM2].y;
2222 rcapFace.k = slopes[V_RIGHT1].k;
2223 }
2224 else {
2225 rcapFace.xa = -vertices[V_RIGHT1].x;
2226 rcapFace.ya = -vertices[V_RIGHT1].y;
2227 rcapFace.k = -slopes[V_RIGHT1].k;
2228 }
2229 miLineArc(pDrawable, pGC, pixel, spanData,
2230 (LineFacePtr) NULL((void*)0), &rcapFace,
2231 rcenterx, rcentery, FALSE0);
2232 break;
2233 }
2234 }
2235 }
2236 LRemain -= dashRemain;
2237 ++dashIndex;
2238 if (dashIndex == pGC->numInDashList)
2239 dashIndex = 0;
2240 dashRemain = pDash[dashIndex];
2241
2242 lcenterx = rcenterx;
2243 lcentery = rcentery;
2244
2245 vertices[V_TOP0] = vertices[V_RIGHT1];
2246 vertices[V_LEFT3] = vertices[V_BOTTOM2];
2247 slopes[V_LEFT3].k = -slopes[V_RIGHT1].k;
2248 first = FALSE0;
2249 }
2250
2251 if (pGC->lineStyle == LineDoubleDash2 || !(dashIndex & 1)) {
2252 vertices[V_TOP0].x -= dx;
2253 vertices[V_TOP0].y -= dy;
2254
2255 vertices[V_LEFT3].x -= dx;
2256 vertices[V_LEFT3].y -= dy;
2257
2258 vertices[V_RIGHT1].x = rdy;
2259 vertices[V_RIGHT1].y = -rdx;
2260
2261 vertices[V_BOTTOM2].x = -rdy;
2262 vertices[V_BOTTOM2].y = rdx;
2263
2264 if (projectRight) {
2265 vertices[V_RIGHT1].x += rdx;
2266 vertices[V_RIGHT1].y += rdy;
2267
2268 vertices[V_BOTTOM2].x += rdx;
2269 vertices[V_BOTTOM2].y += rdy;
2270 slopes[V_RIGHT1].k = vertices[V_RIGHT1].x *
2271 slopes[V_RIGHT1].dy - vertices[V_RIGHT1].y * slopes[V_RIGHT1].dx;
2272 }
2273 else
2274 slopes[V_RIGHT1].k = 0;
2275
2276 if (!first && pGC->lineStyle == LineOnOffDash1 &&
2277 pGC->capStyle == CapProjecting3) {
2278 vertices[V_TOP0].x -= rdx;
2279 vertices[V_TOP0].y -= rdy;
2280
2281 vertices[V_LEFT3].x -= rdx;
2282 vertices[V_LEFT3].y -= rdy;
2283 slopes[V_LEFT3].k = vertices[V_LEFT3].x *
2284 slopes[V_LEFT3].dy - vertices[V_LEFT3].y * slopes[V_LEFT3].dx;
2285 }
2286 else
2287 slopes[V_LEFT3].k += dx * dx + dy * dy;
2288
2289 y = miPolyBuildPoly(vertices, slopes, 4, x2, y2,
2290 left, right, &nleft, &nright, &h);
2291
2292 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
2293 miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
2294 nleft, nright);
2295 if (!first && pGC->lineStyle == LineOnOffDash1 &&
2296 pGC->capStyle == CapRound2) {
2297 lcapFace.x = x2;
2298 lcapFace.y = y2;
2299 if (dx < 0) {
2300 lcapFace.xa = -vertices[V_LEFT3].x;
2301 lcapFace.ya = -vertices[V_LEFT3].y;
2302 lcapFace.k = slopes[V_LEFT3].k;
2303 }
2304 else {
2305 lcapFace.xa = vertices[V_TOP0].x;
2306 lcapFace.ya = vertices[V_TOP0].y;
2307 lcapFace.k = -slopes[V_LEFT3].k;
2308 }
2309 miLineArc(pDrawable, pGC, pixel, spanData,
2310 &lcapFace, (LineFacePtr) NULL((void*)0), rcenterx, rcentery, FALSE0);
2311 }
2312 }
2313 dashRemain = ((double) dashRemain) - LRemain;
2314 if (dashRemain == 0) {
2315 dashIndex++;
2316 if (dashIndex == pGC->numInDashList)
2317 dashIndex = 0;
2318 dashRemain = pDash[dashIndex];
2319 }
2320
2321 leftFace->x = x1;
2322 leftFace->y = y1;
2323 leftFace->dx = dx;
2324 leftFace->dy = dy;
2325 leftFace->xa = rdy;
2326 leftFace->ya = -rdx;
2327 leftFace->k = k;
2328
2329 rightFace->x = x2;
2330 rightFace->y = y2;
2331 rightFace->dx = -dx;
2332 rightFace->dy = -dy;
2333 rightFace->xa = -rdy;
2334 rightFace->ya = rdx;
2335 rightFace->k = k;
2336
2337 *pDashIndex = dashIndex;
2338 *pDashOffset = pDash[dashIndex] - dashRemain;
2339}
2340
2341void
2342miWideDash(DrawablePtr pDrawable, GCPtr pGC,
2343 int mode, int npt, DDXPointPtr pPts)
2344{
2345 int x1, y1, x2, y2;
2346 unsigned long pixel;
2347 Bool projectLeft, projectRight;
2348 LineFaceRec leftFace, rightFace, prevRightFace;
2349 LineFaceRec firstFace;
2350 int first;
2351 int dashIndex, dashOffset;
2352 int prevDashIndex;
2353 SpanDataRec spanDataRec;
2354 SpanDataPtr spanData;
2355 Bool somethingDrawn = FALSE0;
2356 Bool selfJoin;
2357 Bool endIsFg = FALSE0, startIsFg = FALSE0;
2358 Bool firstIsFg = FALSE0, prevIsFg = FALSE0;
2359
2360#if 0
2361 /* XXX backward compatibility */
2362 if (pGC->lineWidth == 0) {
2363 miZeroDashLine(pDrawable, pGC, mode, npt, pPts);
2364 return;
2365 }
2366#endif
2367 if (pGC->lineStyle == LineDoubleDash2 &&
2368 (pGC->fillStyle == FillOpaqueStippled3 || pGC->fillStyle == FillTiled1)) {
2369 miWideLine(pDrawable, pGC, mode, npt, pPts);
2370 return;
2371 }
2372 if (npt == 0)
2373 return;
2374 spanData = miSetupSpanData(pGC, &spanDataRec, npt);
2375 x2 = pPts->x;
2376 y2 = pPts->y;
2377 first = TRUE1;
2378 selfJoin = FALSE0;
2379 if (mode == CoordModePrevious1) {
2380 int nptTmp;
2381 DDXPointPtr pPtsTmp;
2382
2383 x1 = x2;
2384 y1 = y2;
2385 nptTmp = npt;
2386 pPtsTmp = pPts + 1;
2387 while (--nptTmp) {
2388 x1 += pPtsTmp->x;
2389 y1 += pPtsTmp->y;
2390 ++pPtsTmp;
2391 }
2392 if (x2 == x1 && y2 == y1)
2393 selfJoin = TRUE1;
2394 }
2395 else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
2396 selfJoin = TRUE1;
2397 }
2398 projectLeft = pGC->capStyle == CapProjecting3 && !selfJoin;
2399 projectRight = FALSE0;
2400 dashIndex = 0;
2401 dashOffset = 0;
2402 miStepDash((int) pGC->dashOffset, &dashIndex,
2403 pGC->dash, (int) pGC->numInDashList, &dashOffset);
2404 while (--npt) {
2405 x1 = x2;
2406 y1 = y2;
2407 ++pPts;
2408 x2 = pPts->x;
2409 y2 = pPts->y;
2410 if (mode == CoordModePrevious1) {
2411 x2 += x1;
2412 y2 += y1;
2413 }
2414 if (x1 != x2 || y1 != y2) {
2415 somethingDrawn = TRUE1;
2416 if (npt == 1 && pGC->capStyle == CapProjecting3 &&
2417 (!selfJoin || !firstIsFg))
2418 projectRight = TRUE1;
2419 prevDashIndex = dashIndex;
2420 miWideDashSegment(pDrawable, pGC, spanData, &dashOffset, &dashIndex,
2421 x1, y1, x2, y2,
2422 projectLeft, projectRight, &leftFace, &rightFace);
2423 startIsFg = !(prevDashIndex & 1);
2424 endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
2425 if (pGC->lineStyle == LineDoubleDash2 || startIsFg) {
2426 pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
2427 if (first || (pGC->lineStyle == LineOnOffDash1 && !prevIsFg)) {
2428 if (first && selfJoin) {
2429 firstFace = leftFace;
2430 firstIsFg = startIsFg;
2431 }
2432 else if (pGC->capStyle == CapRound2)
2433 miLineArc(pDrawable, pGC, pixel, spanData,
2434 &leftFace, (LineFacePtr) NULL((void*)0),
2435 (double) 0.0, (double) 0.0, TRUE1);
2436 }
2437 else {
2438 miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
2439 &prevRightFace);
2440 }
2441 }
2442 prevRightFace = rightFace;
2443 prevIsFg = endIsFg;
2444 first = FALSE0;
2445 projectLeft = FALSE0;
2446 }
2447 if (npt == 1 && somethingDrawn) {
2448 if (pGC->lineStyle == LineDoubleDash2 || endIsFg) {
2449 pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
2450 if (selfJoin && (pGC->lineStyle == LineDoubleDash2 || firstIsFg)) {
2451 miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
2452 &rightFace);
2453 }
2454 else {
2455 if (pGC->capStyle == CapRound2)
2456 miLineArc(pDrawable, pGC, pixel, spanData,
2457 (LineFacePtr) NULL((void*)0), &rightFace,
2458 (double) 0.0, (double) 0.0, TRUE1);
2459 }
2460 }
2461 else {
2462 /* glue a cap to the start of the line if
2463 * we're OnOffDash and ended on odd dash
2464 */
2465 if (selfJoin && firstIsFg) {
2466 pixel = pGC->fgPixel;
2467 if (pGC->capStyle == CapProjecting3)
2468 miLineProjectingCap(pDrawable, pGC, pixel, spanData,
2469 &firstFace, TRUE1,
2470 (double) 0.0, (double) 0.0, TRUE1);
2471 else if (pGC->capStyle == CapRound2)
2472 miLineArc(pDrawable, pGC, pixel, spanData,
2473 &firstFace, (LineFacePtr) NULL((void*)0),
2474 (double) 0.0, (double) 0.0, TRUE1);
2475 }
2476 }
2477 }
2478 }
2479 /* handle crock where all points are coincident */
2480 if (!somethingDrawn &&
2481 (pGC->lineStyle == LineDoubleDash2 || !(dashIndex & 1))) {
2482 /* not the same as endIsFg computation above */
2483 pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
2484 switch (pGC->capStyle) {
2485 case CapRound2:
2486 miLineArc(pDrawable, pGC, pixel, spanData,
2487 (LineFacePtr) NULL((void*)0), (LineFacePtr) NULL((void*)0),
2488 (double) x2, (double) y2, FALSE0);
2489 break;
2490 case CapProjecting3:
2491 x1 = pGC->lineWidth;
2492 miFillRectPolyHelper(pDrawable, pGC, pixel, spanData,
2493 x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
2494 break;
2495 }
2496 }
2497 if (spanData)
2498 miCleanupSpanData(pDrawable, pGC, spanData);
2499}
2500
2501void
2502miPolylines(DrawablePtr drawable,
2503 GCPtr gc,
2504 int mode,
2505 int n,
2506 DDXPointPtr points)
2507{
2508 if (gc->lineWidth == 0) {
2509 if (gc->lineStyle == LineSolid0)
2510 miZeroLine(drawable, gc, mode, n, points);
2511 else
2512 miZeroDashLine(drawable, gc, mode, n, points);
2513 } else {
2514 if (gc->lineStyle == LineSolid0)
2515 miWideLine(drawable, gc, mode, n, points);
2516 else
2517 miWideDash(drawable, gc, mode, n, points);
2518 }
2519}