File: | mi/miwideline.c |
Location: | line 528, column 18 |
Description: | Call to 'malloc' has an allocation size of 0 bytes |
1 | /* | |||
2 | ||||
3 | Copyright 1988, 1998 The Open Group | |||
4 | ||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||
6 | documentation for any purpose is hereby granted without fee, provided that | |||
7 | the above copyright notice appear in all copies and that both that | |||
8 | copyright notice and this permission notice appear in supporting | |||
9 | documentation. | |||
10 | ||||
11 | The above copyright notice and this permission notice shall be included | |||
12 | in all copies or substantial portions of the Software. | |||
13 | ||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
20 | OTHER DEALINGS IN THE SOFTWARE. | |||
21 | ||||
22 | Except as contained in this notice, the name of The Open Group shall | |||
23 | not be used in advertising or otherwise to promote the sale, use or | |||
24 | other dealings in this Software without prior written authorization | |||
25 | from The Open Group. | |||
26 | ||||
27 | Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts. | |||
28 | ||||
29 | All Rights Reserved | |||
30 | ||||
31 | Permission to use, copy, modify, and distribute this software and its | |||
32 | documentation for any purpose and without fee is hereby granted, | |||
33 | provided that the above copyright notice appear in all copies and that | |||
34 | both that copyright notice and this permission notice appear in | |||
35 | supporting documentation, and that the name of Digital not be | |||
36 | used in advertising or publicity pertaining to distribution of the | |||
37 | software without specific, written prior permission. | |||
38 | ||||
39 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |||
40 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |||
41 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |||
42 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||
43 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |||
44 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |||
45 | SOFTWARE. | |||
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 | ||||
84 | typedef 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 | ||||
90 | typedef 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 | ||||
103 | These routines maintain lists of Spans, in order to implement the | |||
104 | ``touch-each-pixel-once'' rules of wide lines and arcs. | |||
105 | ||||
106 | Written by Joel McCormack, Summer 1989. | |||
107 | ||||
108 | */ | |||
109 | ||||
110 | static void | |||
111 | miInitSpanGroup(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 | ||||
123 | static void | |||
124 | miSubtractSpans(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 | ||||
233 | static void | |||
234 | miAppendSpans(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 | ||||
265 | static void | |||
266 | miFreeSpanGroup(SpanGroup * spanGroup) | |||
267 | { | |||
268 | free(spanGroup->group); | |||
269 | } | |||
270 | ||||
271 | static void | |||
272 | QuickSortSpansX(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 | ||||
360 | static int | |||
361 | UniquifySpansX(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 | ||||
411 | static void | |||
412 | miDisposeSpanGroup(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 | ||||
424 | static void | |||
425 | miFillUniqueSpanGroup(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) | |||
439 | return; | |||
440 | ||||
441 | if (spanGroup->count == 1) { | |||
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)); | |||
460 | ysizes = malloc(ylength * sizeof(int)); | |||
461 | ||||
462 | if (!yspans || !ysizes) { | |||
463 | free(yspans); | |||
464 | free(ysizes); | |||
465 | miDisposeSpanGroup(spanGroup); | |||
466 | return; | |||
467 | } | |||
468 | ||||
469 | for (i = 0; i != ylength; i++) { | |||
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; | |||
479 | i != spanGroup->count; i++, spans++) { | |||
480 | int index; | |||
481 | int j; | |||
482 | ||||
483 | for (j = 0, points = spans->points, widths = spans->widths; | |||
484 | j != spans->count; j++, points++, widths++) { | |||
485 | index = points->y - ymin; | |||
486 | if (index >= 0 && index < ylength) { | |||
487 | Spans *newspans = &(yspans[index]); | |||
488 | ||||
489 | if (newspans->count == ysizes[index]) { | |||
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 | ||||
573 | static Bool | |||
574 | InitSpans(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 | ||||
591 | typedef struct _SpanData { | |||
592 | SpanGroup fgGroup, bgGroup; | |||
593 | } SpanDataRec, *SpanDataPtr; | |||
594 | ||||
595 | static void | |||
596 | AppendSpanGroup(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 | ||||
613 | static 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 | ||||
623 | static void | |||
624 | fillSpans(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 | ||||
649 | static void | |||
650 | miFillPolyHelper(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 | ||||
743 | static void | |||
744 | miFillRectPolyHelper(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 | ||||
794 | static int | |||
795 | miPolyBuildEdge(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 | ||||
846 | static int | |||
847 | miPolyBuildPoly(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 | ||||
947 | static void | |||
948 | miLineOnePoint(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 | ||||
975 | static void | |||
976 | miLineJoin(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 | ||||
1116 | static int | |||
1117 | miLineArcI(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 | ||||
1193 | static int | |||
1194 | miLineArcD(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 | ||||
1344 | static int | |||
1345 | miRoundJoinFace(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 | ||||
1386 | static void | |||
1387 | miRoundJoinClip(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 | ||||
1407 | static int | |||
1408 | miRoundCapClip(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 | ||||
1450 | static void | |||
1451 | miLineArc(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 | ||||
1508 | static void | |||
1509 | miLineProjectingCap(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 | ||||
1663 | static void | |||
1664 | miWideSegment(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 | ||||
1867 | static SpanDataPtr | |||
1868 | miSetupSpanData(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 | ||||
1878 | static void | |||
1879 | miCleanupSpanData(DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData) | |||
1880 | { | |||
1881 | if (pGC->lineStyle == LineDoubleDash2) { | |||
| ||||
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); | |||
1898 | miFreeSpanGroup(&spanData->fgGroup); | |||
1899 | } | |||
1900 | ||||
1901 | void | |||
1902 | miWideLine(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 | ||||
2020 | static void | |||
2021 | miWideDashSegment(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 | ||||
2341 | void | |||
2342 | miWideDash(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 | ||||
2501 | void | |||
2502 | miPolylines(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 | } |