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
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.
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
46 ******************************************************************/
49 #ifdef HAVE_DIX_CONFIG_H
50 #include <dix-config.h>
54 #include "pixmapstr.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
)
73 spanGroup
->group
= NULL
;
74 spanGroup
->ymin
= MAXSHORT
;
75 spanGroup
->ymax
= MINSHORT
;
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
;
86 DDXPointPtr subPt
, spansPt
;
87 int *subWid
, *spansWid
;
92 spans
= spanGroup
->group
;
93 for (i
= spanGroup
->count
; i
; i
--, spans
++) {
94 if (YMIN(spans
) <= ymax
&& ymin
<= YMAX(spans
)) {
95 subCount
= sub
->count
;
98 spansCount
= spans
->count
;
99 spansPt
= spans
->points
;
100 spansWid
= spans
->widths
;
104 while (spansCount
&& spansPt
->y
< subPt
->y
)
106 spansPt
++; spansWid
++; spansCount
--;
110 while (subCount
&& subPt
->y
< spansPt
->y
)
112 subPt
++; subWid
++; subCount
--;
116 if (subPt
->y
== spansPt
->y
)
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));
137 *spansWid
= *spansWid
- (xmax
- spansPt
->x
);
143 if (xmax
>= spansPt
->x
+ *spansWid
)
145 *spansWid
= xmin
- spansPt
->x
;
154 newPt
= (DDXPointPtr
) xrealloc (spans
->points
, (spans
->count
+ EXTRA
) * sizeof (DDXPointRec
));
157 spansPt
= newPt
+ (spansPt
- spans
->points
);
158 spans
->points
= newPt
;
159 newwid
= (int *) xrealloc (spans
->widths
, (spans
->count
+ EXTRA
) * sizeof (int));
162 spansWid
= newwid
+ (spansWid
- spans
->widths
);
163 spans
->widths
= newwid
;
166 memmove (spansPt
+ 1, spansPt
, sizeof *spansPt
* (spansCount
));
167 memmove (spansWid
+ 1, spansWid
, sizeof *spansWid
* (spansCount
));
170 *spansWid
= xmin
- spansPt
->x
;
173 *spansWid
= *spansWid
- (xmax
- spansPt
->x
);
178 spansPt
++; spansWid
++; spansCount
--;
184 void miAppendSpans(spanGroup
, otherGroup
, spans
)
185 SpanGroup
*spanGroup
;
186 SpanGroup
*otherGroup
;
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
;
207 otherGroup
->ymin
< ymax
&&
208 ymin
< otherGroup
->ymax
)
210 miSubtractSpans (otherGroup
, spans
);
215 xfree (spans
->points
);
216 xfree (spans
->widths
);
220 void miFreeSpanGroup(spanGroup
)
221 SpanGroup
*spanGroup
;
223 if (spanGroup
->group
!= NULL
) xfree(spanGroup
->group
);
226 static void QuickSortSpansX(
227 DDXPointRec points
[],
235 /* Always called with numSpans > 1 */
236 /* Sorts only by x, as all y should be the same */
238 #define ExchangeSpans(a, b) \
243 tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
244 tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
249 /* Do insertion sort */
254 do { /* while i != numSpans */
257 /* points[i] is out of order. Move into proper location. */
261 for (j
= 0; x
>= points
[j
].x
; j
++) {}
264 for (k
= i
; k
!= j
; k
--) {
265 points
[k
] = points
[k
-1];
266 widths
[k
] = widths
[k
-1];
271 } /* if out of order */
274 } while (i
!= numSpans
);
278 /* Choose partition element, stick in location 0 */
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);
285 /* Partition array */
293 } while (i
!= numSpans
&& r
->x
< x
);
299 if (i
< j
) ExchangeSpans(i
, j
);
302 /* Move partition element back to middle */
306 if (numSpans
-j
-1 > 1)
307 QuickSortSpansX(&points
[j
+1], &widths
[j
+1], numSpans
-j
-1);
309 } while (numSpans
> 1);
310 } /* QuickSortSpans */
313 static int UniquifySpansX(
315 DDXPointRec
*newPoints
,
318 int newx1
, newx2
, oldpt
, i
, y
;
319 DDXPointRec
*oldPoints
;
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
;
334 newx1
= oldPoints
->x
;
335 newx2
= newx1
+ *oldWidths
;
337 for (i
= spans
->count
-1; i
!= 0; i
--) {
340 oldpt
= oldPoints
->x
;
342 /* Write current span, start a new one */
343 newPoints
->x
= newx1
;
345 *newWidths
= newx2
- newx1
;
349 newx2
= oldpt
+ *oldWidths
;
351 /* extend current span, if old extends beyond new */
352 oldpt
= oldpt
+ *oldWidths
;
353 if (oldpt
> newx2
) newx2
= oldpt
;
357 /* Write final span */
358 newPoints
->x
= newx1
;
359 *newWidths
= newx2
- newx1
;
362 return (newWidths
- startNewWidths
) + 1;
363 } /* UniquifySpansX */
366 miDisposeSpanGroup (SpanGroup
*spanGroup
)
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
)
382 SpanGroup
*spanGroup
;
390 /* Outgoing spans for one big call to FillSpans */
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
);
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
)
425 miDisposeSpanGroup (spanGroup
);
429 for (i
= 0; i
!= ylength
; i
++) {
432 yspans
[i
].points
= NULL
;
433 yspans
[i
].widths
= NULL
;
436 /* Go through every single span and put it into the correct bucket */
438 for (i
= 0, spans
= spanGroup
->group
;
439 i
!= spanGroup
->count
;
444 for (j
= 0, points
= spans
->points
, widths
= spans
->widths
;
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
;
453 ysizes
[index
] = (ysizes
[index
] + 8) * 2;
454 newpoints
= (DDXPointPtr
) xrealloc(
456 ysizes
[index
] * sizeof(DDXPointRec
));
457 newwidths
= (int *) xrealloc(
459 ysizes
[index
] * sizeof(int));
460 if (!newpoints
|| !newwidths
)
464 for (i
= 0; i
< ylength
; i
++)
466 xfree (yspans
[i
].points
);
467 xfree (yspans
[i
].widths
);
471 miDisposeSpanGroup (spanGroup
);
474 newspans
->points
= newpoints
;
475 newspans
->widths
= newwidths
;
477 newspans
->points
[newspans
->count
] = *points
;
478 newspans
->widths
[newspans
->count
] = *widths
;
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
)
496 for (i
= 0; i
< ylength
; i
++)
498 xfree (yspans
[i
].points
);
499 xfree (yspans
[i
].widths
);
510 for (i
= 0; i
!= ylength
; i
++) {
511 int ycount
= yspans
[i
].count
;
514 QuickSortSpansX(yspans
[i
].points
, yspans
[i
].widths
, ycount
);
515 count
+= UniquifySpansX
516 (&(yspans
[i
]), &(points
[count
]), &(widths
[count
]));
518 points
[count
] = yspans
[i
].points
[0];
519 widths
[count
] = yspans
[i
].widths
[0];
522 xfree(yspans
[i
].points
);
523 xfree(yspans
[i
].widths
);
527 (*pGC
->ops
->FillSpans
) (pDraw
, pGC
, count
, points
, widths
, TRUE
);
531 xfree(ysizes
); /* use (DE)ALLOCATE_LOCAL for these? */
534 spanGroup
->count
= 0;
535 spanGroup
->ymin
= MAXSHORT
;
536 spanGroup
->ymax
= MINSHORT
;