|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: misetclip.c,v 1.4 87/09/11 07:20:53 toddb Exp $ */
25: /* Author: Todd Newman */
26:
27: #include "X.h"
28: #include "Xprotostr.h"
29: #include "miscstruct.h"
30: #include "scrnintstr.h"
31: #include "pixmap.h"
32: #include "regionstr.h"
33: #include "gcstruct.h"
34:
35: /* The file name is something of a misnomer. Actually, this just contains
36: * a routine to convert a set of rectangles into a region
37: */
38:
39: typedef struct _ybucket
40: {
41: short y;
42: short count;
43: BoxPtr boxes;
44: short miny2;
45: short fdiff; /* do any have different y2s */
46: struct _ybucket *next;
47: } YBUCKET;
48:
49:
50: /* NEWBUCKET -- a private helper to build a bucket for sorting */
51: static
52: YBUCKET *
53: newbucket(y, miny2)
54: {
55: YBUCKET *pb;
56:
57: pb = (YBUCKET *) Xalloc( sizeof(YBUCKET));
58: pb->count = 0;
59: pb->y = y;
60: pb->miny2 = miny2;
61: pb->fdiff = FALSE;
62: pb->boxes = (BoxPtr)Xalloc(sizeof(BoxRec));
63: pb->next = (YBUCKET *) NULL;
64: return(pb);
65: }
66:
67: /* MIRECTSTOREGION -- helper called by the device private routine called when
68: * the clipmask changes. Converts the set of rectangles to a region.
69: * dix/gc/SetClipRects has already checked that the rectangles are sorted as
70: * advertised.
71: * We just take those rectangles and convert to a YX banded region.
72: * First we sort the rectangles by starting Y values. Then we make sure that
73: * all rectangles that start at a given line all end at the same line. Bits
74: * that hang over fall into the next Y bucket. (Sort of Procrustean, isn't
75: * it?) Next, we sort within each Y bucket by X starting values. Finally,
76: * we take the resulting set of rectangles and stuff it into a region.
77: */
78: RegionPtr
79: miRectsToRegion(pGC, nrects, prect, ordering)
80: GCPtr pGC;
81: int nrects;
82: xRectangle *prect;
83: int ordering;
84: {
85: register YBUCKET *pb;
86: register BoxRec *pbox, *pboxNew;
87: BoxRec tbox;
88: RegionPtr pReg;
89: YBUCKET *pbFirst, *pbNew, *newbucket();
90: int count, miny2;
91: Bool fInserted, fChanged;
92: int xMin, xMax, yMin, yMax;
93: BoxRec b;
94:
95: /* if there's only one rectangle, we don't care about ordering */
96: if (nrects == 1)
97: {
98: b.x1 = prect->x;
99: b.y1 = prect->y;
100: b.x2 = b.x1 + prect->width;
101: b.y2 = b.y1 + prect->height;
102: return ((* pGC->pScreen->RegionCreate)(&b, 1));
103: }
104: /* setting the number of rectangles to zero stops all output */
105: if (nrects == 0)
106: {
107: b.x1 = 0;
108: b.y1 = 0;
109: b.x2 = 0;
110: b.y2 = 0;
111: return ((* pGC->pScreen->RegionCreate)(&b, 1));
112: }
113:
114: xMin = yMin = MAXSHORT;
115: xMax = yMax = -1;
116: if ((nrects < 0) ||
117: ((pReg = (* pGC->pScreen->RegionCreate)(NULL, 1)) == NullRegion))
118: {
119: return NullRegion;
120: }
121:
122: if (ordering == YXBanded)
123: {
124: pReg->rects = (BoxPtr)Xrealloc(pReg->rects, nrects * sizeof(BoxRec));
125: pbox = pReg->rects;
126: while(pbox < pReg->rects + nrects)
127: {
128: pbox->x1 = prect->x;
129: pbox->y1 = prect->y;
130: pbox->x2 = prect->x + prect->width;
131: pbox->y2 = prect->y + prect->height;
132: xMin = min(xMin, pbox->x1);
133: xMax = max(xMax, pbox->x2);
134: yMin = min(yMin, pbox->y1);
135: yMax = max(yMax, pbox->y2);
136: prect++;
137: pbox++;
138: }
139: pReg->numRects = nrects;
140: pReg->size = nrects;
141: pReg->extents.x1 = xMin;
142: pReg->extents.y1 = yMin;
143: pReg->extents.x2 = xMax;
144: pReg->extents.y2 = yMax;
145: return (pReg);
146: }
147:
148: pbFirst = (YBUCKET *) newbucket(prect->y, prect->y + prect->height);
149: pb = pbFirst;
150: count = nrects;
151:
152: /* Sort into Y buckets -- everthing in a bucket has the same starting
153: * scanline. Also note the smallest box in the band and whether any
154: * boxes are of other sizes */
155: while(count--)
156: {
157: if(ordering == Unsorted)
158: {
159: /* We have to search from the top, otherwise we know no
160: * box will be before the current one */
161: pb = pbFirst;
162: }
163:
164: fInserted = FALSE;
165: while(!fInserted)
166: {
167: if(prect->y == pb->y)
168: {
169: /* add rectangle at the end of this bucket */
170: pb->count++;
171: pb->boxes = (BoxPtr)Xrealloc(pb->boxes,
172: pb->count * sizeof(BoxRec));
173: pbox = &pb->boxes[pb->count - 1];
174:
175: pbox->x1 = prect->x;
176: pbox->y1 = prect->y;
177: pbox->x2 = prect->x + prect->width;
178: pbox->y2 = prect->y + prect->height;
179: xMin = min(xMin, pbox->x1);
180: xMax = max(xMax, pbox->x2);
181: yMin = min(yMin, pbox->y1);
182: yMax = max(yMax, pbox->y2);
183:
184: if (pbox->y2 != pb->miny2)
185: pb->fdiff = TRUE;
186: if (pbox->y2 < pb->miny2)
187: pb->miny2 = pbox->y2;
188: fInserted = TRUE;
189: }
190: else if(prect->y < pbFirst->y)
191: {
192: /* Create a new first record in the list */
193: pbNew = newbucket(prect->y, prect->y + prect->height);
194: pbNew->next = pbFirst;
195: pbFirst = pbNew;
196: pb = pbNew;
197: }
198: else if ((pb->next == (YBUCKET *) NULL) ||
199: (pb->next->y > prect->y))
200: {
201: /* create a new ybucket linked between this and the next.
202: * set pb to new bucket */
203: pbNew = newbucket(prect->y, prect->y + prect->height);
204: pbNew->next = pb->next;
205: pb->next = pbNew;
206: pb = pbNew;
207:
208: }
209: else
210: {
211: /* try with next bucket */
212: pb = pb->next;
213: }
214: }
215: prect++;
216: }
217:
218: /* YBand the buckets */
219: pb = pbFirst;
220: while(pb)
221: {
222: if(pb->fdiff)
223: {
224: miny2 = pb->miny2;
225:
226: /* Figure out which ybucket the lopped-off part of these boxes
227: * will go in */
228: if(pb->next ? (miny2 < pb->next->y) : TRUE)
229: {
230: /* create new y bucket */
231: pbNew = newbucket(miny2, MAXSHORT);
232: pbNew->next = pb->next;
233: pb->next = pbNew;
234: }
235: else
236: {
237: pbNew = pb->next;
238: }
239:
240: /* if any rectangle is longer than the shortest in this ybucket,
241: * drop the rest of the rectangle into the next lowest bucket */
242: pbox = pb->boxes;
243: while(pbox < pb->boxes + pb->count)
244: {
245: if(pbox->y2 > miny2)
246: {
247: if(pbNew->count == 0)
248: {
249: pbNew->miny2 = pbox->y2;
250: }
251: pbNew->count++;
252: pbNew->boxes = (BoxPtr)Xrealloc(pbNew->boxes, pbNew->count *
253: sizeof(BoxRec));
254: pboxNew = &pbNew->boxes[pbNew->count - 1];
255: pboxNew->x1 = pbox->x1;
256: pboxNew->y1 = pbNew->y;
257: pboxNew->x2 = pbox->x2;
258: pboxNew->y2 = pbox->y2;
259: if(pboxNew->y2 !=pbNew->miny2)
260: pbNew->fdiff = TRUE;
261: if(pboxNew->y2 < pbNew->miny2)
262: pbNew->miny2 = pboxNew->y2;
263:
264: }
265: pbox++;
266: }
267: }
268: else
269: {
270: pbNew = pb->next;
271: }
272:
273: pb = pbNew;
274: }
275:
276: /* X sort the buckets, and tally total size */
277: pb = pbFirst;
278: count = 0;
279: while(pb)
280: {
281: count += pb->count;
282: /* Yes, it's a bubble sort. I wanted something (a) in place,
283: * (b) with a low startup cost, because I expect to find few
284: * rectangles per yband and don't want to spend more effort setting
285: * up the sort than I do performing it.
286: */
287: fChanged = TRUE;
288: while(fChanged)
289: {
290: fChanged = FALSE;
291: pbox = pb->boxes;
292: while(pbox < pb->boxes + pb->count - 1)
293: {
294: if(pbox->x1 > (pbox+1)->x1)
295: {
296: tbox = *pbox;
297: *pbox = *(pbox + 1);
298: *(pbox + 1) = tbox;
299: fChanged = TRUE;
300: }
301: pbox++;
302: }
303: }
304: pb = pb->next;
305: }
306:
307: /* copy the rectangles into the region and free up the buckets */
308: pReg->rects = (BoxPtr) Xrealloc (pReg->rects, count * sizeof(BoxRec));
309: pReg->numRects = count;
310: pReg->size = count;
311: pboxNew = pReg->rects;
312: pb = pbFirst;
313: while(pb)
314: {
315: for(pbox = pb->boxes; pbox < pb->boxes + pb->count; pbox++)
316: {
317: *pboxNew++ = *pbox;
318: }
319: Xfree((char *)pb->boxes);
320:
321: pb = pb->next;
322: Xfree(pb);
323: }
324: pReg->extents.x1 = xMin;
325: pReg->extents.y1 = yMin;
326: pReg->extents.x2 = xMax;
327: pReg->extents.y2 = yMax;
328: return(pReg);
329:
330: }
331:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.