First import
[xorg_rtime.git] / xorg-server-1.4 / mi / mispans.c
blob530d9dff20e6fc4448dcc71e3970d2c6eaa5cd8c
1 /***********************************************************
3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
28 All Rights Reserved
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
46 ******************************************************************/
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
51 #endif
53 #include "misc.h"
54 #include "pixmapstr.h"
55 #include "gcstruct.h"
56 #include "mispans.h"
60 These routines maintain lists of Spans, in order to implement the
61 ``touch-each-pixel-once'' rules of wide lines and arcs.
63 Written by Joel McCormack, Summer 1989.
68 void miInitSpanGroup(spanGroup)
69 SpanGroup *spanGroup;
71 spanGroup->size = 0;
72 spanGroup->count = 0;
73 spanGroup->group = NULL;
74 spanGroup->ymin = MAXSHORT;
75 spanGroup->ymax = MINSHORT;
76 } /* InitSpanGroup */
78 #define YMIN(spans) (spans->points[0].y)
79 #define YMAX(spans) (spans->points[spans->count-1].y)
81 static void miSubtractSpans (SpanGroup *spanGroup, Spans *sub)
83 int i, subCount, spansCount;
84 int ymin, ymax, xmin, xmax;
85 Spans *spans;
86 DDXPointPtr subPt, spansPt;
87 int *subWid, *spansWid;
88 int extra;
90 ymin = YMIN(sub);
91 ymax = YMAX(sub);
92 spans = spanGroup->group;
93 for (i = spanGroup->count; i; i--, spans++) {
94 if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) {
95 subCount = sub->count;
96 subPt = sub->points;
97 subWid = sub->widths;
98 spansCount = spans->count;
99 spansPt = spans->points;
100 spansWid = spans->widths;
101 extra = 0;
102 for (;;)
104 while (spansCount && spansPt->y < subPt->y)
106 spansPt++; spansWid++; spansCount--;
108 if (!spansCount)
109 break;
110 while (subCount && subPt->y < spansPt->y)
112 subPt++; subWid++; subCount--;
114 if (!subCount)
115 break;
116 if (subPt->y == spansPt->y)
118 xmin = subPt->x;
119 xmax = xmin + *subWid;
120 if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax)
124 else if (xmin <= spansPt->x)
126 if (xmax >= spansPt->x + *spansWid)
128 memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1));
129 memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1));
130 spansPt--;
131 spansWid--;
132 spans->count--;
133 extra++;
135 else
137 *spansWid = *spansWid - (xmax - spansPt->x);
138 spansPt->x = xmax;
141 else
143 if (xmax >= spansPt->x + *spansWid)
145 *spansWid = xmin - spansPt->x;
147 else
149 if (!extra) {
150 DDXPointPtr newPt;
151 int *newwid;
153 #define EXTRA 8
154 newPt = (DDXPointPtr) xrealloc (spans->points, (spans->count + EXTRA) * sizeof (DDXPointRec));
155 if (!newPt)
156 break;
157 spansPt = newPt + (spansPt - spans->points);
158 spans->points = newPt;
159 newwid = (int *) xrealloc (spans->widths, (spans->count + EXTRA) * sizeof (int));
160 if (!newwid)
161 break;
162 spansWid = newwid + (spansWid - spans->widths);
163 spans->widths = newwid;
164 extra = EXTRA;
166 memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount));
167 memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount));
168 spans->count++;
169 extra--;
170 *spansWid = xmin - spansPt->x;
171 spansWid++;
172 spansPt++;
173 *spansWid = *spansWid - (xmax - spansPt->x);
174 spansPt->x = xmax;
178 spansPt++; spansWid++; spansCount--;
184 void miAppendSpans(spanGroup, otherGroup, spans)
185 SpanGroup *spanGroup;
186 SpanGroup *otherGroup;
187 Spans *spans;
189 int ymin, ymax;
190 int spansCount;
192 spansCount = spans->count;
193 if (spansCount > 0) {
194 if (spanGroup->size == spanGroup->count) {
195 spanGroup->size = (spanGroup->size + 8) * 2;
196 spanGroup->group = (Spans *)
197 xrealloc(spanGroup->group, sizeof(Spans) * spanGroup->size);
200 spanGroup->group[spanGroup->count] = *spans;
201 (spanGroup->count)++;
202 ymin = spans->points[0].y;
203 if (ymin < spanGroup->ymin) spanGroup->ymin = ymin;
204 ymax = spans->points[spansCount - 1].y;
205 if (ymax > spanGroup->ymax) spanGroup->ymax = ymax;
206 if (otherGroup &&
207 otherGroup->ymin < ymax &&
208 ymin < otherGroup->ymax)
210 miSubtractSpans (otherGroup, spans);
213 else
215 xfree (spans->points);
216 xfree (spans->widths);
218 } /* AppendSpans */
220 void miFreeSpanGroup(spanGroup)
221 SpanGroup *spanGroup;
223 if (spanGroup->group != NULL) xfree(spanGroup->group);
226 static void QuickSortSpansX(
227 DDXPointRec points[],
228 int widths[],
229 int numSpans )
231 int x;
232 int i, j, m;
233 DDXPointPtr r;
235 /* Always called with numSpans > 1 */
236 /* Sorts only by x, as all y should be the same */
238 #define ExchangeSpans(a, b) \
240 DDXPointRec tpt; \
241 int tw; \
243 tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
244 tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
247 do {
248 if (numSpans < 9) {
249 /* Do insertion sort */
250 int xprev;
252 xprev = points[0].x;
253 i = 1;
254 do { /* while i != numSpans */
255 x = points[i].x;
256 if (xprev > x) {
257 /* points[i] is out of order. Move into proper location. */
258 DDXPointRec tpt;
259 int tw, k;
261 for (j = 0; x >= points[j].x; j++) {}
262 tpt = points[i];
263 tw = widths[i];
264 for (k = i; k != j; k--) {
265 points[k] = points[k-1];
266 widths[k] = widths[k-1];
268 points[j] = tpt;
269 widths[j] = tw;
270 x = points[i].x;
271 } /* if out of order */
272 xprev = x;
273 i++;
274 } while (i != numSpans);
275 return;
278 /* Choose partition element, stick in location 0 */
279 m = numSpans / 2;
280 if (points[m].x > points[0].x) ExchangeSpans(m, 0);
281 if (points[m].x > points[numSpans-1].x) ExchangeSpans(m, numSpans-1);
282 if (points[m].x > points[0].x) ExchangeSpans(m, 0);
283 x = points[0].x;
285 /* Partition array */
286 i = 0;
287 j = numSpans;
288 do {
289 r = &(points[i]);
290 do {
291 r++;
292 i++;
293 } while (i != numSpans && r->x < x);
294 r = &(points[j]);
295 do {
296 r--;
297 j--;
298 } while (x < r->x);
299 if (i < j) ExchangeSpans(i, j);
300 } while (i < j);
302 /* Move partition element back to middle */
303 ExchangeSpans(0, j);
305 /* Recurse */
306 if (numSpans-j-1 > 1)
307 QuickSortSpansX(&points[j+1], &widths[j+1], numSpans-j-1);
308 numSpans = j;
309 } while (numSpans > 1);
310 } /* QuickSortSpans */
313 static int UniquifySpansX(
314 Spans *spans,
315 DDXPointRec *newPoints,
316 int *newWidths )
318 int newx1, newx2, oldpt, i, y;
319 DDXPointRec *oldPoints;
320 int *oldWidths;
321 int *startNewWidths;
323 /* Always called with numSpans > 1 */
324 /* Uniquify the spans, and stash them into newPoints and newWidths. Return the
325 number of unique spans. */
328 startNewWidths = newWidths;
330 oldPoints = spans->points;
331 oldWidths = spans->widths;
333 y = oldPoints->y;
334 newx1 = oldPoints->x;
335 newx2 = newx1 + *oldWidths;
337 for (i = spans->count-1; i != 0; i--) {
338 oldPoints++;
339 oldWidths++;
340 oldpt = oldPoints->x;
341 if (oldpt > newx2) {
342 /* Write current span, start a new one */
343 newPoints->x = newx1;
344 newPoints->y = y;
345 *newWidths = newx2 - newx1;
346 newPoints++;
347 newWidths++;
348 newx1 = oldpt;
349 newx2 = oldpt + *oldWidths;
350 } else {
351 /* extend current span, if old extends beyond new */
352 oldpt = oldpt + *oldWidths;
353 if (oldpt > newx2) newx2 = oldpt;
355 } /* for */
357 /* Write final span */
358 newPoints->x = newx1;
359 *newWidths = newx2 - newx1;
360 newPoints->y = y;
362 return (newWidths - startNewWidths) + 1;
363 } /* UniquifySpansX */
365 static void
366 miDisposeSpanGroup (SpanGroup *spanGroup)
368 int i;
369 Spans *spans;
371 for (i = 0; i < spanGroup->count; i++)
373 spans = spanGroup->group + i;
374 xfree (spans->points);
375 xfree (spans->widths);
379 void miFillUniqueSpanGroup(pDraw, pGC, spanGroup)
380 DrawablePtr pDraw;
381 GCPtr pGC;
382 SpanGroup *spanGroup;
384 int i;
385 Spans *spans;
386 Spans *yspans;
387 int *ysizes;
388 int ymin, ylength;
390 /* Outgoing spans for one big call to FillSpans */
391 DDXPointPtr points;
392 int *widths;
393 int count;
395 if (spanGroup->count == 0) return;
397 if (spanGroup->count == 1) {
398 /* Already should be sorted, unique */
399 spans = spanGroup->group;
400 (*pGC->ops->FillSpans)
401 (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE);
402 xfree(spans->points);
403 xfree(spans->widths);
405 else
407 /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
408 /* This seems to be the fastest thing to do. I've tried sorting on
409 both x and y at the same time rather than creating into all those
410 y buckets, but it was somewhat slower. */
412 ymin = spanGroup->ymin;
413 ylength = spanGroup->ymax - ymin + 1;
415 /* Allocate Spans for y buckets */
416 yspans = (Spans *) xalloc(ylength * sizeof(Spans));
417 ysizes = (int *) xalloc(ylength * sizeof (int));
419 if (!yspans || !ysizes)
421 if (yspans)
422 xfree (yspans);
423 if (ysizes)
424 xfree (ysizes);
425 miDisposeSpanGroup (spanGroup);
426 return;
429 for (i = 0; i != ylength; i++) {
430 ysizes[i] = 0;
431 yspans[i].count = 0;
432 yspans[i].points = NULL;
433 yspans[i].widths = NULL;
436 /* Go through every single span and put it into the correct bucket */
437 count = 0;
438 for (i = 0, spans = spanGroup->group;
439 i != spanGroup->count;
440 i++, spans++) {
441 int index;
442 int j;
444 for (j = 0, points = spans->points, widths = spans->widths;
445 j != spans->count;
446 j++, points++, widths++) {
447 index = points->y - ymin;
448 if (index >= 0 && index < ylength) {
449 Spans *newspans = &(yspans[index]);
450 if (newspans->count == ysizes[index]) {
451 DDXPointPtr newpoints;
452 int *newwidths;
453 ysizes[index] = (ysizes[index] + 8) * 2;
454 newpoints = (DDXPointPtr) xrealloc(
455 newspans->points,
456 ysizes[index] * sizeof(DDXPointRec));
457 newwidths = (int *) xrealloc(
458 newspans->widths,
459 ysizes[index] * sizeof(int));
460 if (!newpoints || !newwidths)
462 int i;
464 for (i = 0; i < ylength; i++)
466 xfree (yspans[i].points);
467 xfree (yspans[i].widths);
469 xfree (yspans);
470 xfree (ysizes);
471 miDisposeSpanGroup (spanGroup);
472 return;
474 newspans->points = newpoints;
475 newspans->widths = newwidths;
477 newspans->points[newspans->count] = *points;
478 newspans->widths[newspans->count] = *widths;
479 (newspans->count)++;
480 } /* if y value of span in range */
481 } /* for j through spans */
482 count += spans->count;
483 xfree(spans->points);
484 spans->points = NULL;
485 xfree(spans->widths);
486 spans->widths = NULL;
487 } /* for i thorough Spans */
489 /* Now sort by x and uniquify each bucket into the final array */
490 points = (DDXPointPtr) xalloc(count * sizeof(DDXPointRec));
491 widths = (int *) xalloc(count * sizeof(int));
492 if (!points || !widths)
494 int i;
496 for (i = 0; i < ylength; i++)
498 xfree (yspans[i].points);
499 xfree (yspans[i].widths);
501 xfree (yspans);
502 xfree (ysizes);
503 if (points)
504 xfree (points);
505 if (widths)
506 xfree (widths);
507 return;
509 count = 0;
510 for (i = 0; i != ylength; i++) {
511 int ycount = yspans[i].count;
512 if (ycount > 0) {
513 if (ycount > 1) {
514 QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount);
515 count += UniquifySpansX
516 (&(yspans[i]), &(points[count]), &(widths[count]));
517 } else {
518 points[count] = yspans[i].points[0];
519 widths[count] = yspans[i].widths[0];
520 count++;
522 xfree(yspans[i].points);
523 xfree(yspans[i].widths);
527 (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE);
528 xfree(points);
529 xfree(widths);
530 xfree(yspans);
531 xfree(ysizes); /* use (DE)ALLOCATE_LOCAL for these? */
534 spanGroup->count = 0;
535 spanGroup->ymin = MAXSHORT;
536 spanGroup->ymax = MINSHORT;