|
1 /* |
|
2 * Copyright 1987, 1988, 1989, 1998 The Open Group |
|
3 * |
|
4 * Permission to use, copy, modify, distribute, and sell this software and its |
|
5 * documentation for any purpose is hereby granted without fee, provided that |
|
6 * the above copyright notice appear in all copies and that both that |
|
7 * copyright notice and this permission notice appear in supporting |
|
8 * documentation. |
|
9 * |
|
10 * The above copyright notice and this permission notice shall be included in |
|
11 * all copies or substantial portions of the Software. |
|
12 * |
|
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
16 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
17 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
19 * |
|
20 * Except as contained in this notice, the name of The Open Group shall not be |
|
21 * used in advertising or otherwise to promote the sale, use or other dealings |
|
22 * in this Software without prior written authorization from The Open Group. |
|
23 * |
|
24 * Copyright 1987, 1988, 1989 by |
|
25 * Digital Equipment Corporation, Maynard, Massachusetts. |
|
26 * |
|
27 * All Rights Reserved |
|
28 * |
|
29 * Permission to use, copy, modify, and distribute this software and its |
|
30 * documentation for any purpose and without fee is hereby granted, |
|
31 * provided that the above copyright notice appear in all copies and that |
|
32 * both that copyright notice and this permission notice appear in |
|
33 * supporting documentation, and that the name of Digital not be |
|
34 * used in advertising or publicity pertaining to distribution of the |
|
35 * software without specific, written prior permission. |
|
36 * |
|
37 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
38 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
39 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
40 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
41 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
42 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
43 * SOFTWARE. |
|
44 * |
|
45 * Copyright © 1998 Keith Packard |
|
46 * |
|
47 * Permission to use, copy, modify, distribute, and sell this software and its |
|
48 * documentation for any purpose is hereby granted without fee, provided that |
|
49 * the above copyright notice appear in all copies and that both that |
|
50 * copyright notice and this permission notice appear in supporting |
|
51 * documentation, and that the name of Keith Packard not be used in |
|
52 * advertising or publicity pertaining to distribution of the software without |
|
53 * specific, written prior permission. Keith Packard makes no |
|
54 * representations about the suitability of this software for any purpose. It |
|
55 * is provided "as is" without express or implied warranty. |
|
56 * |
|
57 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
|
58 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
|
59 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
|
60 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
|
61 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
|
62 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
63 * PERFORMANCE OF THIS SOFTWARE. |
|
64 */ |
|
65 |
|
66 #include <stdlib.h> |
|
67 #include <limits.h> |
|
68 #include <string.h> |
|
69 #include <stdio.h> |
|
70 #include "pixman-private.h" |
|
71 |
|
72 #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects) |
|
73 /* not a region */ |
|
74 #define PIXREGION_NAR(reg) ((reg)->data == pixman_broken_data) |
|
75 #define PIXREGION_NUMRECTS(reg) ((reg)->data ? (reg)->data->numRects : 1) |
|
76 #define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0) |
|
77 #define PIXREGION_RECTS(reg) \ |
|
78 ((reg)->data ? (box_type_t *)((reg)->data + 1) \ |
|
79 : &(reg)->extents) |
|
80 #define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1)) |
|
81 #define PIXREGION_BOX(reg, i) (&PIXREGION_BOXPTR (reg)[i]) |
|
82 #define PIXREGION_TOP(reg) PIXREGION_BOX (reg, (reg)->data->numRects) |
|
83 #define PIXREGION_END(reg) PIXREGION_BOX (reg, (reg)->data->numRects - 1) |
|
84 |
|
85 #define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2) |
|
86 #define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2) |
|
87 |
|
88 #ifdef DEBUG |
|
89 |
|
90 #define GOOD(reg) \ |
|
91 do \ |
|
92 { \ |
|
93 if (!PREFIX (_selfcheck (reg))) \ |
|
94 _pixman_log_error (FUNC, "Malformed region " # reg); \ |
|
95 } while (0) |
|
96 |
|
97 #else |
|
98 |
|
99 #define GOOD(reg) |
|
100 |
|
101 #endif |
|
102 |
|
103 static const box_type_t PREFIX (_empty_box_) = { 0, 0, 0, 0 }; |
|
104 static const region_data_type_t PREFIX (_empty_data_) = { 0, 0 }; |
|
105 #if defined (__llvm__) && !defined (__clang__) |
|
106 static const volatile region_data_type_t PREFIX (_broken_data_) = { 0, 0 }; |
|
107 #else |
|
108 static const region_data_type_t PREFIX (_broken_data_) = { 0, 0 }; |
|
109 #endif |
|
110 |
|
111 static box_type_t *pixman_region_empty_box = |
|
112 (box_type_t *)&PREFIX (_empty_box_); |
|
113 static region_data_type_t *pixman_region_empty_data = |
|
114 (region_data_type_t *)&PREFIX (_empty_data_); |
|
115 static region_data_type_t *pixman_broken_data = |
|
116 (region_data_type_t *)&PREFIX (_broken_data_); |
|
117 |
|
118 static pixman_bool_t |
|
119 pixman_break (region_type_t *region); |
|
120 |
|
121 /* |
|
122 * The functions in this file implement the Region abstraction used extensively |
|
123 * throughout the X11 sample server. A Region is simply a set of disjoint |
|
124 * (non-overlapping) rectangles, plus an "extent" rectangle which is the |
|
125 * smallest single rectangle that contains all the non-overlapping rectangles. |
|
126 * |
|
127 * A Region is implemented as a "y-x-banded" array of rectangles. This array |
|
128 * imposes two degrees of order. First, all rectangles are sorted by top side |
|
129 * y coordinate first (y1), and then by left side x coordinate (x1). |
|
130 * |
|
131 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a |
|
132 * band has the same top y coordinate (y1), and each has the same bottom y |
|
133 * coordinate (y2). Thus all rectangles in a band differ only in their left |
|
134 * and right side (x1 and x2). Bands are implicit in the array of rectangles: |
|
135 * there is no separate list of band start pointers. |
|
136 * |
|
137 * The y-x band representation does not minimize rectangles. In particular, |
|
138 * if a rectangle vertically crosses a band (the rectangle has scanlines in |
|
139 * the y1 to y2 area spanned by the band), then the rectangle may be broken |
|
140 * down into two or more smaller rectangles stacked one atop the other. |
|
141 * |
|
142 * ----------- ----------- |
|
143 * | | | | band 0 |
|
144 * | | -------- ----------- -------- |
|
145 * | | | | in y-x banded | | | | band 1 |
|
146 * | | | | form is | | | | |
|
147 * ----------- | | ----------- -------- |
|
148 * | | | | band 2 |
|
149 * -------- -------- |
|
150 * |
|
151 * An added constraint on the rectangles is that they must cover as much |
|
152 * horizontal area as possible: no two rectangles within a band are allowed |
|
153 * to touch. |
|
154 * |
|
155 * Whenever possible, bands will be merged together to cover a greater vertical |
|
156 * distance (and thus reduce the number of rectangles). Two bands can be merged |
|
157 * only if the bottom of one touches the top of the other and they have |
|
158 * rectangles in the same places (of the same width, of course). |
|
159 * |
|
160 * Adam de Boor wrote most of the original region code. Joel McCormack |
|
161 * substantially modified or rewrote most of the core arithmetic routines, and |
|
162 * added pixman_region_validate in order to support several speed improvements |
|
163 * to pixman_region_validate_tree. Bob Scheifler changed the representation |
|
164 * to be more compact when empty or a single rectangle, and did a bunch of |
|
165 * gratuitous reformatting. Carl Worth did further gratuitous reformatting |
|
166 * while re-merging the server and client region code into libpixregion. |
|
167 * Soren Sandmann did even more gratuitous reformatting. |
|
168 */ |
|
169 |
|
170 /* true iff two Boxes overlap */ |
|
171 #define EXTENTCHECK(r1, r2) \ |
|
172 (!( ((r1)->x2 <= (r2)->x1) || \ |
|
173 ((r1)->x1 >= (r2)->x2) || \ |
|
174 ((r1)->y2 <= (r2)->y1) || \ |
|
175 ((r1)->y1 >= (r2)->y2) ) ) |
|
176 |
|
177 /* true iff (x,y) is in Box */ |
|
178 #define INBOX(r, x, y) \ |
|
179 ( ((r)->x2 > x) && \ |
|
180 ((r)->x1 <= x) && \ |
|
181 ((r)->y2 > y) && \ |
|
182 ((r)->y1 <= y) ) |
|
183 |
|
184 /* true iff Box r1 contains Box r2 */ |
|
185 #define SUBSUMES(r1, r2) \ |
|
186 ( ((r1)->x1 <= (r2)->x1) && \ |
|
187 ((r1)->x2 >= (r2)->x2) && \ |
|
188 ((r1)->y1 <= (r2)->y1) && \ |
|
189 ((r1)->y2 >= (r2)->y2) ) |
|
190 |
|
191 static size_t |
|
192 PIXREGION_SZOF (size_t n) |
|
193 { |
|
194 size_t size = n * sizeof(box_type_t); |
|
195 |
|
196 if (n > UINT32_MAX / sizeof(box_type_t)) |
|
197 return 0; |
|
198 |
|
199 if (sizeof(region_data_type_t) > UINT32_MAX - size) |
|
200 return 0; |
|
201 |
|
202 return size + sizeof(region_data_type_t); |
|
203 } |
|
204 |
|
205 static region_data_type_t * |
|
206 alloc_data (size_t n) |
|
207 { |
|
208 size_t sz = PIXREGION_SZOF (n); |
|
209 |
|
210 if (!sz) |
|
211 return NULL; |
|
212 |
|
213 return malloc (sz); |
|
214 } |
|
215 |
|
216 #define FREE_DATA(reg) if ((reg)->data && (reg)->data->size) free ((reg)->data) |
|
217 |
|
218 #define RECTALLOC_BAIL(region, n, bail) \ |
|
219 do \ |
|
220 { \ |
|
221 if (!(region)->data || \ |
|
222 (((region)->data->numRects + (n)) > (region)->data->size)) \ |
|
223 { \ |
|
224 if (!pixman_rect_alloc (region, n)) \ |
|
225 goto bail; \ |
|
226 } \ |
|
227 } while (0) |
|
228 |
|
229 #define RECTALLOC(region, n) \ |
|
230 do \ |
|
231 { \ |
|
232 if (!(region)->data || \ |
|
233 (((region)->data->numRects + (n)) > (region)->data->size)) \ |
|
234 { \ |
|
235 if (!pixman_rect_alloc (region, n)) { \ |
|
236 return FALSE; \ |
|
237 } \ |
|
238 } \ |
|
239 } while (0) |
|
240 |
|
241 #define ADDRECT(next_rect, nx1, ny1, nx2, ny2) \ |
|
242 do \ |
|
243 { \ |
|
244 next_rect->x1 = nx1; \ |
|
245 next_rect->y1 = ny1; \ |
|
246 next_rect->x2 = nx2; \ |
|
247 next_rect->y2 = ny2; \ |
|
248 next_rect++; \ |
|
249 } \ |
|
250 while (0) |
|
251 |
|
252 #define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2) \ |
|
253 do \ |
|
254 { \ |
|
255 if (!(region)->data || \ |
|
256 ((region)->data->numRects == (region)->data->size)) \ |
|
257 { \ |
|
258 if (!pixman_rect_alloc (region, 1)) \ |
|
259 return FALSE; \ |
|
260 next_rect = PIXREGION_TOP (region); \ |
|
261 } \ |
|
262 ADDRECT (next_rect, nx1, ny1, nx2, ny2); \ |
|
263 region->data->numRects++; \ |
|
264 critical_if_fail (region->data->numRects <= region->data->size); \ |
|
265 } while (0) |
|
266 |
|
267 #define DOWNSIZE(reg, numRects) \ |
|
268 do \ |
|
269 { \ |
|
270 if (((numRects) < ((reg)->data->size >> 1)) && \ |
|
271 ((reg)->data->size > 50)) \ |
|
272 { \ |
|
273 region_data_type_t * new_data; \ |
|
274 size_t data_size = PIXREGION_SZOF (numRects); \ |
|
275 \ |
|
276 if (!data_size) \ |
|
277 { \ |
|
278 new_data = NULL; \ |
|
279 } \ |
|
280 else \ |
|
281 { \ |
|
282 new_data = (region_data_type_t *) \ |
|
283 realloc ((reg)->data, data_size); \ |
|
284 } \ |
|
285 \ |
|
286 if (new_data) \ |
|
287 { \ |
|
288 new_data->size = (numRects); \ |
|
289 (reg)->data = new_data; \ |
|
290 } \ |
|
291 } \ |
|
292 } while (0) |
|
293 |
|
294 PIXMAN_EXPORT pixman_bool_t |
|
295 PREFIX (_equal) (region_type_t *reg1, region_type_t *reg2) |
|
296 { |
|
297 int i; |
|
298 box_type_t *rects1; |
|
299 box_type_t *rects2; |
|
300 |
|
301 if (reg1->extents.x1 != reg2->extents.x1) |
|
302 return FALSE; |
|
303 |
|
304 if (reg1->extents.x2 != reg2->extents.x2) |
|
305 return FALSE; |
|
306 |
|
307 if (reg1->extents.y1 != reg2->extents.y1) |
|
308 return FALSE; |
|
309 |
|
310 if (reg1->extents.y2 != reg2->extents.y2) |
|
311 return FALSE; |
|
312 |
|
313 if (PIXREGION_NUMRECTS (reg1) != PIXREGION_NUMRECTS (reg2)) |
|
314 return FALSE; |
|
315 |
|
316 rects1 = PIXREGION_RECTS (reg1); |
|
317 rects2 = PIXREGION_RECTS (reg2); |
|
318 |
|
319 for (i = 0; i != PIXREGION_NUMRECTS (reg1); i++) |
|
320 { |
|
321 if (rects1[i].x1 != rects2[i].x1) |
|
322 return FALSE; |
|
323 |
|
324 if (rects1[i].x2 != rects2[i].x2) |
|
325 return FALSE; |
|
326 |
|
327 if (rects1[i].y1 != rects2[i].y1) |
|
328 return FALSE; |
|
329 |
|
330 if (rects1[i].y2 != rects2[i].y2) |
|
331 return FALSE; |
|
332 } |
|
333 |
|
334 return TRUE; |
|
335 } |
|
336 |
|
337 int |
|
338 PREFIX (_print) (region_type_t *rgn) |
|
339 { |
|
340 int num, size; |
|
341 int i; |
|
342 box_type_t * rects; |
|
343 |
|
344 num = PIXREGION_NUMRECTS (rgn); |
|
345 size = PIXREGION_SIZE (rgn); |
|
346 rects = PIXREGION_RECTS (rgn); |
|
347 |
|
348 fprintf (stderr, "num: %d size: %d\n", num, size); |
|
349 fprintf (stderr, "extents: %d %d %d %d\n", |
|
350 rgn->extents.x1, |
|
351 rgn->extents.y1, |
|
352 rgn->extents.x2, |
|
353 rgn->extents.y2); |
|
354 |
|
355 for (i = 0; i < num; i++) |
|
356 { |
|
357 fprintf (stderr, "%d %d %d %d \n", |
|
358 rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); |
|
359 } |
|
360 |
|
361 fprintf (stderr, "\n"); |
|
362 |
|
363 return(num); |
|
364 } |
|
365 |
|
366 |
|
367 PIXMAN_EXPORT void |
|
368 PREFIX (_init) (region_type_t *region) |
|
369 { |
|
370 region->extents = *pixman_region_empty_box; |
|
371 region->data = pixman_region_empty_data; |
|
372 } |
|
373 |
|
374 PIXMAN_EXPORT void |
|
375 PREFIX (_init_rect) (region_type_t * region, |
|
376 int x, |
|
377 int y, |
|
378 unsigned int width, |
|
379 unsigned int height) |
|
380 { |
|
381 region->extents.x1 = x; |
|
382 region->extents.y1 = y; |
|
383 region->extents.x2 = x + width; |
|
384 region->extents.y2 = y + height; |
|
385 |
|
386 if (!GOOD_RECT (®ion->extents)) |
|
387 { |
|
388 if (BAD_RECT (®ion->extents)) |
|
389 _pixman_log_error (FUNC, "Invalid rectangle passed"); |
|
390 PREFIX (_init) (region); |
|
391 return; |
|
392 } |
|
393 |
|
394 region->data = NULL; |
|
395 } |
|
396 |
|
397 PIXMAN_EXPORT void |
|
398 PREFIX (_init_with_extents) (region_type_t *region, box_type_t *extents) |
|
399 { |
|
400 if (!GOOD_RECT (extents)) |
|
401 { |
|
402 if (BAD_RECT (extents)) |
|
403 _pixman_log_error (FUNC, "Invalid rectangle passed"); |
|
404 PREFIX (_init) (region); |
|
405 return; |
|
406 } |
|
407 region->extents = *extents; |
|
408 |
|
409 region->data = NULL; |
|
410 } |
|
411 |
|
412 PIXMAN_EXPORT void |
|
413 PREFIX (_fini) (region_type_t *region) |
|
414 { |
|
415 GOOD (region); |
|
416 FREE_DATA (region); |
|
417 } |
|
418 |
|
419 PIXMAN_EXPORT int |
|
420 PREFIX (_n_rects) (region_type_t *region) |
|
421 { |
|
422 return PIXREGION_NUMRECTS (region); |
|
423 } |
|
424 |
|
425 PIXMAN_EXPORT box_type_t * |
|
426 PREFIX (_rectangles) (region_type_t *region, |
|
427 int *n_rects) |
|
428 { |
|
429 if (n_rects) |
|
430 *n_rects = PIXREGION_NUMRECTS (region); |
|
431 |
|
432 return PIXREGION_RECTS (region); |
|
433 } |
|
434 |
|
435 static pixman_bool_t |
|
436 pixman_break (region_type_t *region) |
|
437 { |
|
438 FREE_DATA (region); |
|
439 |
|
440 region->extents = *pixman_region_empty_box; |
|
441 region->data = pixman_broken_data; |
|
442 |
|
443 return FALSE; |
|
444 } |
|
445 |
|
446 static pixman_bool_t |
|
447 pixman_rect_alloc (region_type_t * region, |
|
448 int n) |
|
449 { |
|
450 region_data_type_t *data; |
|
451 |
|
452 if (!region->data) |
|
453 { |
|
454 n++; |
|
455 region->data = alloc_data (n); |
|
456 |
|
457 if (!region->data) |
|
458 return pixman_break (region); |
|
459 |
|
460 region->data->numRects = 1; |
|
461 *PIXREGION_BOXPTR (region) = region->extents; |
|
462 } |
|
463 else if (!region->data->size) |
|
464 { |
|
465 region->data = alloc_data (n); |
|
466 |
|
467 if (!region->data) |
|
468 return pixman_break (region); |
|
469 |
|
470 region->data->numRects = 0; |
|
471 } |
|
472 else |
|
473 { |
|
474 size_t data_size; |
|
475 |
|
476 if (n == 1) |
|
477 { |
|
478 n = region->data->numRects; |
|
479 if (n > 500) /* XXX pick numbers out of a hat */ |
|
480 n = 250; |
|
481 } |
|
482 |
|
483 n += region->data->numRects; |
|
484 data_size = PIXREGION_SZOF (n); |
|
485 |
|
486 if (!data_size) |
|
487 { |
|
488 data = NULL; |
|
489 } |
|
490 else |
|
491 { |
|
492 data = (region_data_type_t *) |
|
493 realloc (region->data, PIXREGION_SZOF (n)); |
|
494 } |
|
495 |
|
496 if (!data) |
|
497 return pixman_break (region); |
|
498 |
|
499 region->data = data; |
|
500 } |
|
501 |
|
502 region->data->size = n; |
|
503 |
|
504 return TRUE; |
|
505 } |
|
506 |
|
507 PIXMAN_EXPORT pixman_bool_t |
|
508 PREFIX (_copy) (region_type_t *dst, region_type_t *src) |
|
509 { |
|
510 GOOD (dst); |
|
511 GOOD (src); |
|
512 |
|
513 if (dst == src) |
|
514 return TRUE; |
|
515 |
|
516 dst->extents = src->extents; |
|
517 |
|
518 if (!src->data || !src->data->size) |
|
519 { |
|
520 FREE_DATA (dst); |
|
521 dst->data = src->data; |
|
522 return TRUE; |
|
523 } |
|
524 |
|
525 if (!dst->data || (dst->data->size < src->data->numRects)) |
|
526 { |
|
527 FREE_DATA (dst); |
|
528 |
|
529 dst->data = alloc_data (src->data->numRects); |
|
530 |
|
531 if (!dst->data) |
|
532 return pixman_break (dst); |
|
533 |
|
534 dst->data->size = src->data->numRects; |
|
535 } |
|
536 |
|
537 dst->data->numRects = src->data->numRects; |
|
538 |
|
539 memmove ((char *)PIXREGION_BOXPTR (dst), (char *)PIXREGION_BOXPTR (src), |
|
540 dst->data->numRects * sizeof(box_type_t)); |
|
541 |
|
542 return TRUE; |
|
543 } |
|
544 |
|
545 /*====================================================================== |
|
546 * Generic Region Operator |
|
547 *====================================================================*/ |
|
548 |
|
549 /*- |
|
550 *----------------------------------------------------------------------- |
|
551 * pixman_coalesce -- |
|
552 * Attempt to merge the boxes in the current band with those in the |
|
553 * previous one. We are guaranteed that the current band extends to |
|
554 * the end of the rects array. Used only by pixman_op. |
|
555 * |
|
556 * Results: |
|
557 * The new index for the previous band. |
|
558 * |
|
559 * Side Effects: |
|
560 * If coalescing takes place: |
|
561 * - rectangles in the previous band will have their y2 fields |
|
562 * altered. |
|
563 * - region->data->numRects will be decreased. |
|
564 * |
|
565 *----------------------------------------------------------------------- |
|
566 */ |
|
567 static inline int |
|
568 pixman_coalesce (region_type_t * region, /* Region to coalesce */ |
|
569 int prev_start, /* Index of start of previous band */ |
|
570 int cur_start) /* Index of start of current band */ |
|
571 { |
|
572 box_type_t *prev_box; /* Current box in previous band */ |
|
573 box_type_t *cur_box; /* Current box in current band */ |
|
574 int numRects; /* Number rectangles in both bands */ |
|
575 int y2; /* Bottom of current band */ |
|
576 |
|
577 /* |
|
578 * Figure out how many rectangles are in the band. |
|
579 */ |
|
580 numRects = cur_start - prev_start; |
|
581 critical_if_fail (numRects == region->data->numRects - cur_start); |
|
582 |
|
583 if (!numRects) return cur_start; |
|
584 |
|
585 /* |
|
586 * The bands may only be coalesced if the bottom of the previous |
|
587 * matches the top scanline of the current. |
|
588 */ |
|
589 prev_box = PIXREGION_BOX (region, prev_start); |
|
590 cur_box = PIXREGION_BOX (region, cur_start); |
|
591 if (prev_box->y2 != cur_box->y1) return cur_start; |
|
592 |
|
593 /* |
|
594 * Make sure the bands have boxes in the same places. This |
|
595 * assumes that boxes have been added in such a way that they |
|
596 * cover the most area possible. I.e. two boxes in a band must |
|
597 * have some horizontal space between them. |
|
598 */ |
|
599 y2 = cur_box->y2; |
|
600 |
|
601 do |
|
602 { |
|
603 if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2)) |
|
604 return (cur_start); |
|
605 |
|
606 prev_box++; |
|
607 cur_box++; |
|
608 numRects--; |
|
609 } |
|
610 while (numRects); |
|
611 |
|
612 /* |
|
613 * The bands may be merged, so set the bottom y of each box |
|
614 * in the previous band to the bottom y of the current band. |
|
615 */ |
|
616 numRects = cur_start - prev_start; |
|
617 region->data->numRects -= numRects; |
|
618 |
|
619 do |
|
620 { |
|
621 prev_box--; |
|
622 prev_box->y2 = y2; |
|
623 numRects--; |
|
624 } |
|
625 while (numRects); |
|
626 |
|
627 return prev_start; |
|
628 } |
|
629 |
|
630 /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */ |
|
631 |
|
632 #define COALESCE(new_reg, prev_band, cur_band) \ |
|
633 do \ |
|
634 { \ |
|
635 if (cur_band - prev_band == new_reg->data->numRects - cur_band) \ |
|
636 prev_band = pixman_coalesce (new_reg, prev_band, cur_band); \ |
|
637 else \ |
|
638 prev_band = cur_band; \ |
|
639 } while (0) |
|
640 |
|
641 /*- |
|
642 *----------------------------------------------------------------------- |
|
643 * pixman_region_append_non_o -- |
|
644 * Handle a non-overlapping band for the union and subtract operations. |
|
645 * Just adds the (top/bottom-clipped) rectangles into the region. |
|
646 * Doesn't have to check for subsumption or anything. |
|
647 * |
|
648 * Results: |
|
649 * None. |
|
650 * |
|
651 * Side Effects: |
|
652 * region->data->numRects is incremented and the rectangles overwritten |
|
653 * with the rectangles we're passed. |
|
654 * |
|
655 *----------------------------------------------------------------------- |
|
656 */ |
|
657 static inline pixman_bool_t |
|
658 pixman_region_append_non_o (region_type_t * region, |
|
659 box_type_t * r, |
|
660 box_type_t * r_end, |
|
661 int y1, |
|
662 int y2) |
|
663 { |
|
664 box_type_t *next_rect; |
|
665 int new_rects; |
|
666 |
|
667 new_rects = r_end - r; |
|
668 |
|
669 critical_if_fail (y1 < y2); |
|
670 critical_if_fail (new_rects != 0); |
|
671 |
|
672 /* Make sure we have enough space for all rectangles to be added */ |
|
673 RECTALLOC (region, new_rects); |
|
674 next_rect = PIXREGION_TOP (region); |
|
675 region->data->numRects += new_rects; |
|
676 |
|
677 do |
|
678 { |
|
679 critical_if_fail (r->x1 < r->x2); |
|
680 ADDRECT (next_rect, r->x1, y1, r->x2, y2); |
|
681 r++; |
|
682 } |
|
683 while (r != r_end); |
|
684 |
|
685 return TRUE; |
|
686 } |
|
687 |
|
688 #define FIND_BAND(r, r_band_end, r_end, ry1) \ |
|
689 do \ |
|
690 { \ |
|
691 ry1 = r->y1; \ |
|
692 r_band_end = r + 1; \ |
|
693 while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \ |
|
694 r_band_end++; \ |
|
695 } \ |
|
696 } while (0) |
|
697 |
|
698 #define APPEND_REGIONS(new_reg, r, r_end) \ |
|
699 do \ |
|
700 { \ |
|
701 int new_rects; \ |
|
702 if ((new_rects = r_end - r)) { \ |
|
703 RECTALLOC_BAIL (new_reg, new_rects, bail); \ |
|
704 memmove ((char *)PIXREGION_TOP (new_reg), (char *)r, \ |
|
705 new_rects * sizeof(box_type_t)); \ |
|
706 new_reg->data->numRects += new_rects; \ |
|
707 } \ |
|
708 } while (0) |
|
709 |
|
710 /*- |
|
711 *----------------------------------------------------------------------- |
|
712 * pixman_op -- |
|
713 * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse, |
|
714 * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one |
|
715 * rectangle, and cannot be the same object. |
|
716 * |
|
717 * Results: |
|
718 * TRUE if successful. |
|
719 * |
|
720 * Side Effects: |
|
721 * The new region is overwritten. |
|
722 * overlap set to TRUE if overlap_func ever returns TRUE. |
|
723 * |
|
724 * Notes: |
|
725 * The idea behind this function is to view the two regions as sets. |
|
726 * Together they cover a rectangle of area that this function divides |
|
727 * into horizontal bands where points are covered only by one region |
|
728 * or by both. For the first case, the non_overlap_func is called with |
|
729 * each the band and the band's upper and lower extents. For the |
|
730 * second, the overlap_func is called to process the entire band. It |
|
731 * is responsible for clipping the rectangles in the band, though |
|
732 * this function provides the boundaries. |
|
733 * At the end of each band, the new region is coalesced, if possible, |
|
734 * to reduce the number of rectangles in the region. |
|
735 * |
|
736 *----------------------------------------------------------------------- |
|
737 */ |
|
738 |
|
739 typedef pixman_bool_t (*overlap_proc_ptr) (region_type_t *region, |
|
740 box_type_t * r1, |
|
741 box_type_t * r1_end, |
|
742 box_type_t * r2, |
|
743 box_type_t * r2_end, |
|
744 int y1, |
|
745 int y2); |
|
746 |
|
747 static pixman_bool_t |
|
748 pixman_op (region_type_t * new_reg, /* Place to store result */ |
|
749 region_type_t * reg1, /* First region in operation */ |
|
750 region_type_t * reg2, /* 2d region in operation */ |
|
751 overlap_proc_ptr overlap_func, /* Function to call for over- |
|
752 * lapping bands */ |
|
753 int append_non1, /* Append non-overlapping bands |
|
754 * in region 1 ? |
|
755 */ |
|
756 int append_non2 /* Append non-overlapping bands |
|
757 * in region 2 ? |
|
758 */ |
|
759 ) |
|
760 { |
|
761 box_type_t *r1; /* Pointer into first region */ |
|
762 box_type_t *r2; /* Pointer into 2d region */ |
|
763 box_type_t *r1_end; /* End of 1st region */ |
|
764 box_type_t *r2_end; /* End of 2d region */ |
|
765 int ybot; /* Bottom of intersection */ |
|
766 int ytop; /* Top of intersection */ |
|
767 region_data_type_t *old_data; /* Old data for new_reg */ |
|
768 int prev_band; /* Index of start of |
|
769 * previous band in new_reg */ |
|
770 int cur_band; /* Index of start of current |
|
771 * band in new_reg */ |
|
772 box_type_t * r1_band_end; /* End of current band in r1 */ |
|
773 box_type_t * r2_band_end; /* End of current band in r2 */ |
|
774 int top; /* Top of non-overlapping band */ |
|
775 int bot; /* Bottom of non-overlapping band*/ |
|
776 int r1y1; /* Temps for r1->y1 and r2->y1 */ |
|
777 int r2y1; |
|
778 int new_size; |
|
779 int numRects; |
|
780 |
|
781 /* |
|
782 * Break any region computed from a broken region |
|
783 */ |
|
784 if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2)) |
|
785 return pixman_break (new_reg); |
|
786 |
|
787 /* |
|
788 * Initialization: |
|
789 * set r1, r2, r1_end and r2_end appropriately, save the rectangles |
|
790 * of the destination region until the end in case it's one of |
|
791 * the two source regions, then mark the "new" region empty, allocating |
|
792 * another array of rectangles for it to use. |
|
793 */ |
|
794 |
|
795 r1 = PIXREGION_RECTS (reg1); |
|
796 new_size = PIXREGION_NUMRECTS (reg1); |
|
797 r1_end = r1 + new_size; |
|
798 |
|
799 numRects = PIXREGION_NUMRECTS (reg2); |
|
800 r2 = PIXREGION_RECTS (reg2); |
|
801 r2_end = r2 + numRects; |
|
802 |
|
803 critical_if_fail (r1 != r1_end); |
|
804 critical_if_fail (r2 != r2_end); |
|
805 |
|
806 old_data = (region_data_type_t *)NULL; |
|
807 |
|
808 if (((new_reg == reg1) && (new_size > 1)) || |
|
809 ((new_reg == reg2) && (numRects > 1))) |
|
810 { |
|
811 old_data = new_reg->data; |
|
812 new_reg->data = pixman_region_empty_data; |
|
813 } |
|
814 |
|
815 /* guess at new size */ |
|
816 if (numRects > new_size) |
|
817 new_size = numRects; |
|
818 |
|
819 new_size <<= 1; |
|
820 |
|
821 if (!new_reg->data) |
|
822 new_reg->data = pixman_region_empty_data; |
|
823 else if (new_reg->data->size) |
|
824 new_reg->data->numRects = 0; |
|
825 |
|
826 if (new_size > new_reg->data->size) |
|
827 { |
|
828 if (!pixman_rect_alloc (new_reg, new_size)) |
|
829 { |
|
830 free (old_data); |
|
831 return FALSE; |
|
832 } |
|
833 } |
|
834 |
|
835 /* |
|
836 * Initialize ybot. |
|
837 * In the upcoming loop, ybot and ytop serve different functions depending |
|
838 * on whether the band being handled is an overlapping or non-overlapping |
|
839 * band. |
|
840 * In the case of a non-overlapping band (only one of the regions |
|
841 * has points in the band), ybot is the bottom of the most recent |
|
842 * intersection and thus clips the top of the rectangles in that band. |
|
843 * ytop is the top of the next intersection between the two regions and |
|
844 * serves to clip the bottom of the rectangles in the current band. |
|
845 * For an overlapping band (where the two regions intersect), ytop clips |
|
846 * the top of the rectangles of both regions and ybot clips the bottoms. |
|
847 */ |
|
848 |
|
849 ybot = MIN (r1->y1, r2->y1); |
|
850 |
|
851 /* |
|
852 * prev_band serves to mark the start of the previous band so rectangles |
|
853 * can be coalesced into larger rectangles. qv. pixman_coalesce, above. |
|
854 * In the beginning, there is no previous band, so prev_band == cur_band |
|
855 * (cur_band is set later on, of course, but the first band will always |
|
856 * start at index 0). prev_band and cur_band must be indices because of |
|
857 * the possible expansion, and resultant moving, of the new region's |
|
858 * array of rectangles. |
|
859 */ |
|
860 prev_band = 0; |
|
861 |
|
862 do |
|
863 { |
|
864 /* |
|
865 * This algorithm proceeds one source-band (as opposed to a |
|
866 * destination band, which is determined by where the two regions |
|
867 * intersect) at a time. r1_band_end and r2_band_end serve to mark the |
|
868 * rectangle after the last one in the current band for their |
|
869 * respective regions. |
|
870 */ |
|
871 critical_if_fail (r1 != r1_end); |
|
872 critical_if_fail (r2 != r2_end); |
|
873 |
|
874 FIND_BAND (r1, r1_band_end, r1_end, r1y1); |
|
875 FIND_BAND (r2, r2_band_end, r2_end, r2y1); |
|
876 |
|
877 /* |
|
878 * First handle the band that doesn't intersect, if any. |
|
879 * |
|
880 * Note that attention is restricted to one band in the |
|
881 * non-intersecting region at once, so if a region has n |
|
882 * bands between the current position and the next place it overlaps |
|
883 * the other, this entire loop will be passed through n times. |
|
884 */ |
|
885 if (r1y1 < r2y1) |
|
886 { |
|
887 if (append_non1) |
|
888 { |
|
889 top = MAX (r1y1, ybot); |
|
890 bot = MIN (r1->y2, r2y1); |
|
891 if (top != bot) |
|
892 { |
|
893 cur_band = new_reg->data->numRects; |
|
894 if (!pixman_region_append_non_o (new_reg, r1, r1_band_end, top, bot)) |
|
895 goto bail; |
|
896 COALESCE (new_reg, prev_band, cur_band); |
|
897 } |
|
898 } |
|
899 ytop = r2y1; |
|
900 } |
|
901 else if (r2y1 < r1y1) |
|
902 { |
|
903 if (append_non2) |
|
904 { |
|
905 top = MAX (r2y1, ybot); |
|
906 bot = MIN (r2->y2, r1y1); |
|
907 |
|
908 if (top != bot) |
|
909 { |
|
910 cur_band = new_reg->data->numRects; |
|
911 |
|
912 if (!pixman_region_append_non_o (new_reg, r2, r2_band_end, top, bot)) |
|
913 goto bail; |
|
914 |
|
915 COALESCE (new_reg, prev_band, cur_band); |
|
916 } |
|
917 } |
|
918 ytop = r1y1; |
|
919 } |
|
920 else |
|
921 { |
|
922 ytop = r1y1; |
|
923 } |
|
924 |
|
925 /* |
|
926 * Now see if we've hit an intersecting band. The two bands only |
|
927 * intersect if ybot > ytop |
|
928 */ |
|
929 ybot = MIN (r1->y2, r2->y2); |
|
930 if (ybot > ytop) |
|
931 { |
|
932 cur_band = new_reg->data->numRects; |
|
933 |
|
934 if (!(*overlap_func)(new_reg, |
|
935 r1, r1_band_end, |
|
936 r2, r2_band_end, |
|
937 ytop, ybot)) |
|
938 { |
|
939 goto bail; |
|
940 } |
|
941 |
|
942 COALESCE (new_reg, prev_band, cur_band); |
|
943 } |
|
944 |
|
945 /* |
|
946 * If we've finished with a band (y2 == ybot) we skip forward |
|
947 * in the region to the next band. |
|
948 */ |
|
949 if (r1->y2 == ybot) |
|
950 r1 = r1_band_end; |
|
951 |
|
952 if (r2->y2 == ybot) |
|
953 r2 = r2_band_end; |
|
954 |
|
955 } |
|
956 while (r1 != r1_end && r2 != r2_end); |
|
957 |
|
958 /* |
|
959 * Deal with whichever region (if any) still has rectangles left. |
|
960 * |
|
961 * We only need to worry about banding and coalescing for the very first |
|
962 * band left. After that, we can just group all remaining boxes, |
|
963 * regardless of how many bands, into one final append to the list. |
|
964 */ |
|
965 |
|
966 if ((r1 != r1_end) && append_non1) |
|
967 { |
|
968 /* Do first non_overlap1Func call, which may be able to coalesce */ |
|
969 FIND_BAND (r1, r1_band_end, r1_end, r1y1); |
|
970 |
|
971 cur_band = new_reg->data->numRects; |
|
972 |
|
973 if (!pixman_region_append_non_o (new_reg, |
|
974 r1, r1_band_end, |
|
975 MAX (r1y1, ybot), r1->y2)) |
|
976 { |
|
977 goto bail; |
|
978 } |
|
979 |
|
980 COALESCE (new_reg, prev_band, cur_band); |
|
981 |
|
982 /* Just append the rest of the boxes */ |
|
983 APPEND_REGIONS (new_reg, r1_band_end, r1_end); |
|
984 } |
|
985 else if ((r2 != r2_end) && append_non2) |
|
986 { |
|
987 /* Do first non_overlap2Func call, which may be able to coalesce */ |
|
988 FIND_BAND (r2, r2_band_end, r2_end, r2y1); |
|
989 |
|
990 cur_band = new_reg->data->numRects; |
|
991 |
|
992 if (!pixman_region_append_non_o (new_reg, |
|
993 r2, r2_band_end, |
|
994 MAX (r2y1, ybot), r2->y2)) |
|
995 { |
|
996 goto bail; |
|
997 } |
|
998 |
|
999 COALESCE (new_reg, prev_band, cur_band); |
|
1000 |
|
1001 /* Append rest of boxes */ |
|
1002 APPEND_REGIONS (new_reg, r2_band_end, r2_end); |
|
1003 } |
|
1004 |
|
1005 free (old_data); |
|
1006 |
|
1007 if (!(numRects = new_reg->data->numRects)) |
|
1008 { |
|
1009 FREE_DATA (new_reg); |
|
1010 new_reg->data = pixman_region_empty_data; |
|
1011 } |
|
1012 else if (numRects == 1) |
|
1013 { |
|
1014 new_reg->extents = *PIXREGION_BOXPTR (new_reg); |
|
1015 FREE_DATA (new_reg); |
|
1016 new_reg->data = (region_data_type_t *)NULL; |
|
1017 } |
|
1018 else |
|
1019 { |
|
1020 DOWNSIZE (new_reg, numRects); |
|
1021 } |
|
1022 |
|
1023 return TRUE; |
|
1024 |
|
1025 bail: |
|
1026 free (old_data); |
|
1027 |
|
1028 return pixman_break (new_reg); |
|
1029 } |
|
1030 |
|
1031 /*- |
|
1032 *----------------------------------------------------------------------- |
|
1033 * pixman_set_extents -- |
|
1034 * Reset the extents of a region to what they should be. Called by |
|
1035 * pixman_region_subtract and pixman_region_intersect as they can't |
|
1036 * figure it out along the way or do so easily, as pixman_region_union can. |
|
1037 * |
|
1038 * Results: |
|
1039 * None. |
|
1040 * |
|
1041 * Side Effects: |
|
1042 * The region's 'extents' structure is overwritten. |
|
1043 * |
|
1044 *----------------------------------------------------------------------- |
|
1045 */ |
|
1046 static void |
|
1047 pixman_set_extents (region_type_t *region) |
|
1048 { |
|
1049 box_type_t *box, *box_end; |
|
1050 |
|
1051 if (!region->data) |
|
1052 return; |
|
1053 |
|
1054 if (!region->data->size) |
|
1055 { |
|
1056 region->extents.x2 = region->extents.x1; |
|
1057 region->extents.y2 = region->extents.y1; |
|
1058 return; |
|
1059 } |
|
1060 |
|
1061 box = PIXREGION_BOXPTR (region); |
|
1062 box_end = PIXREGION_END (region); |
|
1063 |
|
1064 /* |
|
1065 * Since box is the first rectangle in the region, it must have the |
|
1066 * smallest y1 and since box_end is the last rectangle in the region, |
|
1067 * it must have the largest y2, because of banding. Initialize x1 and |
|
1068 * x2 from box and box_end, resp., as good things to initialize them |
|
1069 * to... |
|
1070 */ |
|
1071 region->extents.x1 = box->x1; |
|
1072 region->extents.y1 = box->y1; |
|
1073 region->extents.x2 = box_end->x2; |
|
1074 region->extents.y2 = box_end->y2; |
|
1075 |
|
1076 critical_if_fail (region->extents.y1 < region->extents.y2); |
|
1077 |
|
1078 while (box <= box_end) |
|
1079 { |
|
1080 if (box->x1 < region->extents.x1) |
|
1081 region->extents.x1 = box->x1; |
|
1082 if (box->x2 > region->extents.x2) |
|
1083 region->extents.x2 = box->x2; |
|
1084 box++; |
|
1085 } |
|
1086 |
|
1087 critical_if_fail (region->extents.x1 < region->extents.x2); |
|
1088 } |
|
1089 |
|
1090 /*====================================================================== |
|
1091 * Region Intersection |
|
1092 *====================================================================*/ |
|
1093 /*- |
|
1094 *----------------------------------------------------------------------- |
|
1095 * pixman_region_intersect_o -- |
|
1096 * Handle an overlapping band for pixman_region_intersect. |
|
1097 * |
|
1098 * Results: |
|
1099 * TRUE if successful. |
|
1100 * |
|
1101 * Side Effects: |
|
1102 * Rectangles may be added to the region. |
|
1103 * |
|
1104 *----------------------------------------------------------------------- |
|
1105 */ |
|
1106 /*ARGSUSED*/ |
|
1107 static pixman_bool_t |
|
1108 pixman_region_intersect_o (region_type_t *region, |
|
1109 box_type_t * r1, |
|
1110 box_type_t * r1_end, |
|
1111 box_type_t * r2, |
|
1112 box_type_t * r2_end, |
|
1113 int y1, |
|
1114 int y2) |
|
1115 { |
|
1116 int x1; |
|
1117 int x2; |
|
1118 box_type_t * next_rect; |
|
1119 |
|
1120 next_rect = PIXREGION_TOP (region); |
|
1121 |
|
1122 critical_if_fail (y1 < y2); |
|
1123 critical_if_fail (r1 != r1_end && r2 != r2_end); |
|
1124 |
|
1125 do |
|
1126 { |
|
1127 x1 = MAX (r1->x1, r2->x1); |
|
1128 x2 = MIN (r1->x2, r2->x2); |
|
1129 |
|
1130 /* |
|
1131 * If there's any overlap between the two rectangles, add that |
|
1132 * overlap to the new region. |
|
1133 */ |
|
1134 if (x1 < x2) |
|
1135 NEWRECT (region, next_rect, x1, y1, x2, y2); |
|
1136 |
|
1137 /* |
|
1138 * Advance the pointer(s) with the leftmost right side, since the next |
|
1139 * rectangle on that list may still overlap the other region's |
|
1140 * current rectangle. |
|
1141 */ |
|
1142 if (r1->x2 == x2) |
|
1143 { |
|
1144 r1++; |
|
1145 } |
|
1146 if (r2->x2 == x2) |
|
1147 { |
|
1148 r2++; |
|
1149 } |
|
1150 } |
|
1151 while ((r1 != r1_end) && (r2 != r2_end)); |
|
1152 |
|
1153 return TRUE; |
|
1154 } |
|
1155 |
|
1156 PIXMAN_EXPORT pixman_bool_t |
|
1157 PREFIX (_intersect) (region_type_t * new_reg, |
|
1158 region_type_t * reg1, |
|
1159 region_type_t * reg2) |
|
1160 { |
|
1161 GOOD (reg1); |
|
1162 GOOD (reg2); |
|
1163 GOOD (new_reg); |
|
1164 |
|
1165 /* check for trivial reject */ |
|
1166 if (PIXREGION_NIL (reg1) || PIXREGION_NIL (reg2) || |
|
1167 !EXTENTCHECK (®1->extents, ®2->extents)) |
|
1168 { |
|
1169 /* Covers about 20% of all cases */ |
|
1170 FREE_DATA (new_reg); |
|
1171 new_reg->extents.x2 = new_reg->extents.x1; |
|
1172 new_reg->extents.y2 = new_reg->extents.y1; |
|
1173 if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2)) |
|
1174 { |
|
1175 new_reg->data = pixman_broken_data; |
|
1176 return FALSE; |
|
1177 } |
|
1178 else |
|
1179 { |
|
1180 new_reg->data = pixman_region_empty_data; |
|
1181 } |
|
1182 } |
|
1183 else if (!reg1->data && !reg2->data) |
|
1184 { |
|
1185 /* Covers about 80% of cases that aren't trivially rejected */ |
|
1186 new_reg->extents.x1 = MAX (reg1->extents.x1, reg2->extents.x1); |
|
1187 new_reg->extents.y1 = MAX (reg1->extents.y1, reg2->extents.y1); |
|
1188 new_reg->extents.x2 = MIN (reg1->extents.x2, reg2->extents.x2); |
|
1189 new_reg->extents.y2 = MIN (reg1->extents.y2, reg2->extents.y2); |
|
1190 |
|
1191 FREE_DATA (new_reg); |
|
1192 |
|
1193 new_reg->data = (region_data_type_t *)NULL; |
|
1194 } |
|
1195 else if (!reg2->data && SUBSUMES (®2->extents, ®1->extents)) |
|
1196 { |
|
1197 return PREFIX (_copy) (new_reg, reg1); |
|
1198 } |
|
1199 else if (!reg1->data && SUBSUMES (®1->extents, ®2->extents)) |
|
1200 { |
|
1201 return PREFIX (_copy) (new_reg, reg2); |
|
1202 } |
|
1203 else if (reg1 == reg2) |
|
1204 { |
|
1205 return PREFIX (_copy) (new_reg, reg1); |
|
1206 } |
|
1207 else |
|
1208 { |
|
1209 /* General purpose intersection */ |
|
1210 |
|
1211 if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE)) |
|
1212 return FALSE; |
|
1213 |
|
1214 pixman_set_extents (new_reg); |
|
1215 } |
|
1216 |
|
1217 GOOD (new_reg); |
|
1218 return(TRUE); |
|
1219 } |
|
1220 |
|
1221 #define MERGERECT(r) \ |
|
1222 do \ |
|
1223 { \ |
|
1224 if (r->x1 <= x2) \ |
|
1225 { \ |
|
1226 /* Merge with current rectangle */ \ |
|
1227 if (x2 < r->x2) \ |
|
1228 x2 = r->x2; \ |
|
1229 } \ |
|
1230 else \ |
|
1231 { \ |
|
1232 /* Add current rectangle, start new one */ \ |
|
1233 NEWRECT (region, next_rect, x1, y1, x2, y2); \ |
|
1234 x1 = r->x1; \ |
|
1235 x2 = r->x2; \ |
|
1236 } \ |
|
1237 r++; \ |
|
1238 } while (0) |
|
1239 |
|
1240 /*====================================================================== |
|
1241 * Region Union |
|
1242 *====================================================================*/ |
|
1243 |
|
1244 /*- |
|
1245 *----------------------------------------------------------------------- |
|
1246 * pixman_region_union_o -- |
|
1247 * Handle an overlapping band for the union operation. Picks the |
|
1248 * left-most rectangle each time and merges it into the region. |
|
1249 * |
|
1250 * Results: |
|
1251 * TRUE if successful. |
|
1252 * |
|
1253 * Side Effects: |
|
1254 * region is overwritten. |
|
1255 * overlap is set to TRUE if any boxes overlap. |
|
1256 * |
|
1257 *----------------------------------------------------------------------- |
|
1258 */ |
|
1259 static pixman_bool_t |
|
1260 pixman_region_union_o (region_type_t *region, |
|
1261 box_type_t * r1, |
|
1262 box_type_t * r1_end, |
|
1263 box_type_t * r2, |
|
1264 box_type_t * r2_end, |
|
1265 int y1, |
|
1266 int y2) |
|
1267 { |
|
1268 box_type_t *next_rect; |
|
1269 int x1; /* left and right side of current union */ |
|
1270 int x2; |
|
1271 |
|
1272 critical_if_fail (y1 < y2); |
|
1273 critical_if_fail (r1 != r1_end && r2 != r2_end); |
|
1274 |
|
1275 next_rect = PIXREGION_TOP (region); |
|
1276 |
|
1277 /* Start off current rectangle */ |
|
1278 if (r1->x1 < r2->x1) |
|
1279 { |
|
1280 x1 = r1->x1; |
|
1281 x2 = r1->x2; |
|
1282 r1++; |
|
1283 } |
|
1284 else |
|
1285 { |
|
1286 x1 = r2->x1; |
|
1287 x2 = r2->x2; |
|
1288 r2++; |
|
1289 } |
|
1290 while (r1 != r1_end && r2 != r2_end) |
|
1291 { |
|
1292 if (r1->x1 < r2->x1) |
|
1293 MERGERECT (r1); |
|
1294 else |
|
1295 MERGERECT (r2); |
|
1296 } |
|
1297 |
|
1298 /* Finish off whoever (if any) is left */ |
|
1299 if (r1 != r1_end) |
|
1300 { |
|
1301 do |
|
1302 { |
|
1303 MERGERECT (r1); |
|
1304 } |
|
1305 while (r1 != r1_end); |
|
1306 } |
|
1307 else if (r2 != r2_end) |
|
1308 { |
|
1309 do |
|
1310 { |
|
1311 MERGERECT (r2); |
|
1312 } |
|
1313 while (r2 != r2_end); |
|
1314 } |
|
1315 |
|
1316 /* Add current rectangle */ |
|
1317 NEWRECT (region, next_rect, x1, y1, x2, y2); |
|
1318 |
|
1319 return TRUE; |
|
1320 } |
|
1321 |
|
1322 PIXMAN_EXPORT pixman_bool_t |
|
1323 PREFIX(_intersect_rect) (region_type_t *dest, |
|
1324 region_type_t *source, |
|
1325 int x, int y, |
|
1326 unsigned int width, |
|
1327 unsigned int height) |
|
1328 { |
|
1329 region_type_t region; |
|
1330 |
|
1331 region.data = NULL; |
|
1332 region.extents.x1 = x; |
|
1333 region.extents.y1 = y; |
|
1334 region.extents.x2 = x + width; |
|
1335 region.extents.y2 = y + height; |
|
1336 |
|
1337 return PREFIX(_intersect) (dest, source, ®ion); |
|
1338 } |
|
1339 |
|
1340 /* Convenience function for performing union of region with a |
|
1341 * single rectangle |
|
1342 */ |
|
1343 PIXMAN_EXPORT pixman_bool_t |
|
1344 PREFIX (_union_rect) (region_type_t *dest, |
|
1345 region_type_t *source, |
|
1346 int x, |
|
1347 int y, |
|
1348 unsigned int width, |
|
1349 unsigned int height) |
|
1350 { |
|
1351 region_type_t region; |
|
1352 |
|
1353 region.extents.x1 = x; |
|
1354 region.extents.y1 = y; |
|
1355 region.extents.x2 = x + width; |
|
1356 region.extents.y2 = y + height; |
|
1357 |
|
1358 if (!GOOD_RECT (®ion.extents)) |
|
1359 { |
|
1360 if (BAD_RECT (®ion.extents)) |
|
1361 _pixman_log_error (FUNC, "Invalid rectangle passed"); |
|
1362 return PREFIX (_copy) (dest, source); |
|
1363 } |
|
1364 |
|
1365 region.data = NULL; |
|
1366 |
|
1367 return PREFIX (_union) (dest, source, ®ion); |
|
1368 } |
|
1369 |
|
1370 PIXMAN_EXPORT pixman_bool_t |
|
1371 PREFIX (_union) (region_type_t *new_reg, |
|
1372 region_type_t *reg1, |
|
1373 region_type_t *reg2) |
|
1374 { |
|
1375 /* Return TRUE if some overlap |
|
1376 * between reg1, reg2 |
|
1377 */ |
|
1378 GOOD (reg1); |
|
1379 GOOD (reg2); |
|
1380 GOOD (new_reg); |
|
1381 |
|
1382 /* checks all the simple cases */ |
|
1383 |
|
1384 /* |
|
1385 * Region 1 and 2 are the same |
|
1386 */ |
|
1387 if (reg1 == reg2) |
|
1388 return PREFIX (_copy) (new_reg, reg1); |
|
1389 |
|
1390 /* |
|
1391 * Region 1 is empty |
|
1392 */ |
|
1393 if (PIXREGION_NIL (reg1)) |
|
1394 { |
|
1395 if (PIXREGION_NAR (reg1)) |
|
1396 return pixman_break (new_reg); |
|
1397 |
|
1398 if (new_reg != reg2) |
|
1399 return PREFIX (_copy) (new_reg, reg2); |
|
1400 |
|
1401 return TRUE; |
|
1402 } |
|
1403 |
|
1404 /* |
|
1405 * Region 2 is empty |
|
1406 */ |
|
1407 if (PIXREGION_NIL (reg2)) |
|
1408 { |
|
1409 if (PIXREGION_NAR (reg2)) |
|
1410 return pixman_break (new_reg); |
|
1411 |
|
1412 if (new_reg != reg1) |
|
1413 return PREFIX (_copy) (new_reg, reg1); |
|
1414 |
|
1415 return TRUE; |
|
1416 } |
|
1417 |
|
1418 /* |
|
1419 * Region 1 completely subsumes region 2 |
|
1420 */ |
|
1421 if (!reg1->data && SUBSUMES (®1->extents, ®2->extents)) |
|
1422 { |
|
1423 if (new_reg != reg1) |
|
1424 return PREFIX (_copy) (new_reg, reg1); |
|
1425 |
|
1426 return TRUE; |
|
1427 } |
|
1428 |
|
1429 /* |
|
1430 * Region 2 completely subsumes region 1 |
|
1431 */ |
|
1432 if (!reg2->data && SUBSUMES (®2->extents, ®1->extents)) |
|
1433 { |
|
1434 if (new_reg != reg2) |
|
1435 return PREFIX (_copy) (new_reg, reg2); |
|
1436 |
|
1437 return TRUE; |
|
1438 } |
|
1439 |
|
1440 if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE)) |
|
1441 return FALSE; |
|
1442 |
|
1443 new_reg->extents.x1 = MIN (reg1->extents.x1, reg2->extents.x1); |
|
1444 new_reg->extents.y1 = MIN (reg1->extents.y1, reg2->extents.y1); |
|
1445 new_reg->extents.x2 = MAX (reg1->extents.x2, reg2->extents.x2); |
|
1446 new_reg->extents.y2 = MAX (reg1->extents.y2, reg2->extents.y2); |
|
1447 |
|
1448 GOOD (new_reg); |
|
1449 |
|
1450 return TRUE; |
|
1451 } |
|
1452 |
|
1453 /*====================================================================== |
|
1454 * Batch Rectangle Union |
|
1455 *====================================================================*/ |
|
1456 |
|
1457 #define EXCHANGE_RECTS(a, b) \ |
|
1458 { \ |
|
1459 box_type_t t; \ |
|
1460 t = rects[a]; \ |
|
1461 rects[a] = rects[b]; \ |
|
1462 rects[b] = t; \ |
|
1463 } |
|
1464 |
|
1465 static void |
|
1466 quick_sort_rects ( |
|
1467 box_type_t rects[], |
|
1468 int numRects) |
|
1469 { |
|
1470 int y1; |
|
1471 int x1; |
|
1472 int i, j; |
|
1473 box_type_t *r; |
|
1474 |
|
1475 /* Always called with numRects > 1 */ |
|
1476 |
|
1477 do |
|
1478 { |
|
1479 if (numRects == 2) |
|
1480 { |
|
1481 if (rects[0].y1 > rects[1].y1 || |
|
1482 (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) |
|
1483 { |
|
1484 EXCHANGE_RECTS (0, 1); |
|
1485 } |
|
1486 |
|
1487 return; |
|
1488 } |
|
1489 |
|
1490 /* Choose partition element, stick in location 0 */ |
|
1491 EXCHANGE_RECTS (0, numRects >> 1); |
|
1492 y1 = rects[0].y1; |
|
1493 x1 = rects[0].x1; |
|
1494 |
|
1495 /* Partition array */ |
|
1496 i = 0; |
|
1497 j = numRects; |
|
1498 |
|
1499 do |
|
1500 { |
|
1501 r = &(rects[i]); |
|
1502 do |
|
1503 { |
|
1504 r++; |
|
1505 i++; |
|
1506 } |
|
1507 while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); |
|
1508 |
|
1509 r = &(rects[j]); |
|
1510 do |
|
1511 { |
|
1512 r--; |
|
1513 j--; |
|
1514 } |
|
1515 while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); |
|
1516 |
|
1517 if (i < j) |
|
1518 EXCHANGE_RECTS (i, j); |
|
1519 } |
|
1520 while (i < j); |
|
1521 |
|
1522 /* Move partition element back to middle */ |
|
1523 EXCHANGE_RECTS (0, j); |
|
1524 |
|
1525 /* Recurse */ |
|
1526 if (numRects - j - 1 > 1) |
|
1527 quick_sort_rects (&rects[j + 1], numRects - j - 1); |
|
1528 |
|
1529 numRects = j; |
|
1530 } |
|
1531 while (numRects > 1); |
|
1532 } |
|
1533 |
|
1534 /*- |
|
1535 *----------------------------------------------------------------------- |
|
1536 * pixman_region_validate -- |
|
1537 * |
|
1538 * Take a ``region'' which is a non-y-x-banded random collection of |
|
1539 * rectangles, and compute a nice region which is the union of all the |
|
1540 * rectangles. |
|
1541 * |
|
1542 * Results: |
|
1543 * TRUE if successful. |
|
1544 * |
|
1545 * Side Effects: |
|
1546 * The passed-in ``region'' may be modified. |
|
1547 * overlap set to TRUE if any retangles overlapped, |
|
1548 * else FALSE; |
|
1549 * |
|
1550 * Strategy: |
|
1551 * Step 1. Sort the rectangles into ascending order with primary key y1 |
|
1552 * and secondary key x1. |
|
1553 * |
|
1554 * Step 2. Split the rectangles into the minimum number of proper y-x |
|
1555 * banded regions. This may require horizontally merging |
|
1556 * rectangles, and vertically coalescing bands. With any luck, |
|
1557 * this step in an identity transformation (ala the Box widget), |
|
1558 * or a coalescing into 1 box (ala Menus). |
|
1559 * |
|
1560 * Step 3. Merge the separate regions down to a single region by calling |
|
1561 * pixman_region_union. Maximize the work each pixman_region_union call does by using |
|
1562 * a binary merge. |
|
1563 * |
|
1564 *----------------------------------------------------------------------- |
|
1565 */ |
|
1566 |
|
1567 static pixman_bool_t |
|
1568 validate (region_type_t * badreg) |
|
1569 { |
|
1570 /* Descriptor for regions under construction in Step 2. */ |
|
1571 typedef struct |
|
1572 { |
|
1573 region_type_t reg; |
|
1574 int prev_band; |
|
1575 int cur_band; |
|
1576 } region_info_t; |
|
1577 |
|
1578 region_info_t stack_regions[64]; |
|
1579 |
|
1580 int numRects; /* Original numRects for badreg */ |
|
1581 region_info_t *ri; /* Array of current regions */ |
|
1582 int num_ri; /* Number of entries used in ri */ |
|
1583 int size_ri; /* Number of entries available in ri */ |
|
1584 int i; /* Index into rects */ |
|
1585 int j; /* Index into ri */ |
|
1586 region_info_t *rit; /* &ri[j] */ |
|
1587 region_type_t *reg; /* ri[j].reg */ |
|
1588 box_type_t *box; /* Current box in rects */ |
|
1589 box_type_t *ri_box; /* Last box in ri[j].reg */ |
|
1590 region_type_t *hreg; /* ri[j_half].reg */ |
|
1591 pixman_bool_t ret = TRUE; |
|
1592 |
|
1593 if (!badreg->data) |
|
1594 { |
|
1595 GOOD (badreg); |
|
1596 return TRUE; |
|
1597 } |
|
1598 |
|
1599 numRects = badreg->data->numRects; |
|
1600 if (!numRects) |
|
1601 { |
|
1602 if (PIXREGION_NAR (badreg)) |
|
1603 return FALSE; |
|
1604 GOOD (badreg); |
|
1605 return TRUE; |
|
1606 } |
|
1607 |
|
1608 if (badreg->extents.x1 < badreg->extents.x2) |
|
1609 { |
|
1610 if ((numRects) == 1) |
|
1611 { |
|
1612 FREE_DATA (badreg); |
|
1613 badreg->data = (region_data_type_t *) NULL; |
|
1614 } |
|
1615 else |
|
1616 { |
|
1617 DOWNSIZE (badreg, numRects); |
|
1618 } |
|
1619 |
|
1620 GOOD (badreg); |
|
1621 |
|
1622 return TRUE; |
|
1623 } |
|
1624 |
|
1625 /* Step 1: Sort the rects array into ascending (y1, x1) order */ |
|
1626 quick_sort_rects (PIXREGION_BOXPTR (badreg), numRects); |
|
1627 |
|
1628 /* Step 2: Scatter the sorted array into the minimum number of regions */ |
|
1629 |
|
1630 /* Set up the first region to be the first rectangle in badreg */ |
|
1631 /* Note that step 2 code will never overflow the ri[0].reg rects array */ |
|
1632 ri = stack_regions; |
|
1633 size_ri = sizeof (stack_regions) / sizeof (stack_regions[0]); |
|
1634 num_ri = 1; |
|
1635 ri[0].prev_band = 0; |
|
1636 ri[0].cur_band = 0; |
|
1637 ri[0].reg = *badreg; |
|
1638 box = PIXREGION_BOXPTR (&ri[0].reg); |
|
1639 ri[0].reg.extents = *box; |
|
1640 ri[0].reg.data->numRects = 1; |
|
1641 badreg->extents = *pixman_region_empty_box; |
|
1642 badreg->data = pixman_region_empty_data; |
|
1643 |
|
1644 /* Now scatter rectangles into the minimum set of valid regions. If the |
|
1645 * next rectangle to be added to a region would force an existing rectangle |
|
1646 * in the region to be split up in order to maintain y-x banding, just |
|
1647 * forget it. Try the next region. If it doesn't fit cleanly into any |
|
1648 * region, make a new one. |
|
1649 */ |
|
1650 |
|
1651 for (i = numRects; --i > 0;) |
|
1652 { |
|
1653 box++; |
|
1654 /* Look for a region to append box to */ |
|
1655 for (j = num_ri, rit = ri; --j >= 0; rit++) |
|
1656 { |
|
1657 reg = &rit->reg; |
|
1658 ri_box = PIXREGION_END (reg); |
|
1659 |
|
1660 if (box->y1 == ri_box->y1 && box->y2 == ri_box->y2) |
|
1661 { |
|
1662 /* box is in same band as ri_box. Merge or append it */ |
|
1663 if (box->x1 <= ri_box->x2) |
|
1664 { |
|
1665 /* Merge it with ri_box */ |
|
1666 if (box->x2 > ri_box->x2) |
|
1667 ri_box->x2 = box->x2; |
|
1668 } |
|
1669 else |
|
1670 { |
|
1671 RECTALLOC_BAIL (reg, 1, bail); |
|
1672 *PIXREGION_TOP (reg) = *box; |
|
1673 reg->data->numRects++; |
|
1674 } |
|
1675 |
|
1676 goto next_rect; /* So sue me */ |
|
1677 } |
|
1678 else if (box->y1 >= ri_box->y2) |
|
1679 { |
|
1680 /* Put box into new band */ |
|
1681 if (reg->extents.x2 < ri_box->x2) |
|
1682 reg->extents.x2 = ri_box->x2; |
|
1683 |
|
1684 if (reg->extents.x1 > box->x1) |
|
1685 reg->extents.x1 = box->x1; |
|
1686 |
|
1687 COALESCE (reg, rit->prev_band, rit->cur_band); |
|
1688 rit->cur_band = reg->data->numRects; |
|
1689 RECTALLOC_BAIL (reg, 1, bail); |
|
1690 *PIXREGION_TOP (reg) = *box; |
|
1691 reg->data->numRects++; |
|
1692 |
|
1693 goto next_rect; |
|
1694 } |
|
1695 /* Well, this region was inappropriate. Try the next one. */ |
|
1696 } /* for j */ |
|
1697 |
|
1698 /* Uh-oh. No regions were appropriate. Create a new one. */ |
|
1699 if (size_ri == num_ri) |
|
1700 { |
|
1701 size_t data_size; |
|
1702 |
|
1703 /* Oops, allocate space for new region information */ |
|
1704 size_ri <<= 1; |
|
1705 |
|
1706 data_size = size_ri * sizeof(region_info_t); |
|
1707 if (data_size / size_ri != sizeof(region_info_t)) |
|
1708 goto bail; |
|
1709 |
|
1710 if (ri == stack_regions) |
|
1711 { |
|
1712 rit = malloc (data_size); |
|
1713 if (!rit) |
|
1714 goto bail; |
|
1715 memcpy (rit, ri, num_ri * sizeof (region_info_t)); |
|
1716 } |
|
1717 else |
|
1718 { |
|
1719 rit = (region_info_t *) realloc (ri, data_size); |
|
1720 if (!rit) |
|
1721 goto bail; |
|
1722 } |
|
1723 ri = rit; |
|
1724 rit = &ri[num_ri]; |
|
1725 } |
|
1726 num_ri++; |
|
1727 rit->prev_band = 0; |
|
1728 rit->cur_band = 0; |
|
1729 rit->reg.extents = *box; |
|
1730 rit->reg.data = (region_data_type_t *)NULL; |
|
1731 |
|
1732 /* MUST force allocation */ |
|
1733 if (!pixman_rect_alloc (&rit->reg, (i + num_ri) / num_ri)) |
|
1734 goto bail; |
|
1735 |
|
1736 next_rect: ; |
|
1737 } /* for i */ |
|
1738 |
|
1739 /* Make a final pass over each region in order to COALESCE and set |
|
1740 * extents.x2 and extents.y2 |
|
1741 */ |
|
1742 for (j = num_ri, rit = ri; --j >= 0; rit++) |
|
1743 { |
|
1744 reg = &rit->reg; |
|
1745 ri_box = PIXREGION_END (reg); |
|
1746 reg->extents.y2 = ri_box->y2; |
|
1747 |
|
1748 if (reg->extents.x2 < ri_box->x2) |
|
1749 reg->extents.x2 = ri_box->x2; |
|
1750 |
|
1751 COALESCE (reg, rit->prev_band, rit->cur_band); |
|
1752 |
|
1753 if (reg->data->numRects == 1) /* keep unions happy below */ |
|
1754 { |
|
1755 FREE_DATA (reg); |
|
1756 reg->data = (region_data_type_t *)NULL; |
|
1757 } |
|
1758 } |
|
1759 |
|
1760 /* Step 3: Union all regions into a single region */ |
|
1761 while (num_ri > 1) |
|
1762 { |
|
1763 int half = num_ri / 2; |
|
1764 for (j = num_ri & 1; j < (half + (num_ri & 1)); j++) |
|
1765 { |
|
1766 reg = &ri[j].reg; |
|
1767 hreg = &ri[j + half].reg; |
|
1768 |
|
1769 if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE)) |
|
1770 ret = FALSE; |
|
1771 |
|
1772 if (hreg->extents.x1 < reg->extents.x1) |
|
1773 reg->extents.x1 = hreg->extents.x1; |
|
1774 |
|
1775 if (hreg->extents.y1 < reg->extents.y1) |
|
1776 reg->extents.y1 = hreg->extents.y1; |
|
1777 |
|
1778 if (hreg->extents.x2 > reg->extents.x2) |
|
1779 reg->extents.x2 = hreg->extents.x2; |
|
1780 |
|
1781 if (hreg->extents.y2 > reg->extents.y2) |
|
1782 reg->extents.y2 = hreg->extents.y2; |
|
1783 |
|
1784 FREE_DATA (hreg); |
|
1785 } |
|
1786 |
|
1787 num_ri -= half; |
|
1788 |
|
1789 if (!ret) |
|
1790 goto bail; |
|
1791 } |
|
1792 |
|
1793 *badreg = ri[0].reg; |
|
1794 |
|
1795 if (ri != stack_regions) |
|
1796 free (ri); |
|
1797 |
|
1798 GOOD (badreg); |
|
1799 return ret; |
|
1800 |
|
1801 bail: |
|
1802 for (i = 0; i < num_ri; i++) |
|
1803 FREE_DATA (&ri[i].reg); |
|
1804 |
|
1805 if (ri != stack_regions) |
|
1806 free (ri); |
|
1807 |
|
1808 return pixman_break (badreg); |
|
1809 } |
|
1810 |
|
1811 /*====================================================================== |
|
1812 * Region Subtraction |
|
1813 *====================================================================*/ |
|
1814 |
|
1815 /*- |
|
1816 *----------------------------------------------------------------------- |
|
1817 * pixman_region_subtract_o -- |
|
1818 * Overlapping band subtraction. x1 is the left-most point not yet |
|
1819 * checked. |
|
1820 * |
|
1821 * Results: |
|
1822 * TRUE if successful. |
|
1823 * |
|
1824 * Side Effects: |
|
1825 * region may have rectangles added to it. |
|
1826 * |
|
1827 *----------------------------------------------------------------------- |
|
1828 */ |
|
1829 /*ARGSUSED*/ |
|
1830 static pixman_bool_t |
|
1831 pixman_region_subtract_o (region_type_t * region, |
|
1832 box_type_t * r1, |
|
1833 box_type_t * r1_end, |
|
1834 box_type_t * r2, |
|
1835 box_type_t * r2_end, |
|
1836 int y1, |
|
1837 int y2) |
|
1838 { |
|
1839 box_type_t * next_rect; |
|
1840 int x1; |
|
1841 |
|
1842 x1 = r1->x1; |
|
1843 |
|
1844 critical_if_fail (y1 < y2); |
|
1845 critical_if_fail (r1 != r1_end && r2 != r2_end); |
|
1846 |
|
1847 next_rect = PIXREGION_TOP (region); |
|
1848 |
|
1849 do |
|
1850 { |
|
1851 if (r2->x2 <= x1) |
|
1852 { |
|
1853 /* |
|
1854 * Subtrahend entirely to left of minuend: go to next subtrahend. |
|
1855 */ |
|
1856 r2++; |
|
1857 } |
|
1858 else if (r2->x1 <= x1) |
|
1859 { |
|
1860 /* |
|
1861 * Subtrahend preceeds minuend: nuke left edge of minuend. |
|
1862 */ |
|
1863 x1 = r2->x2; |
|
1864 if (x1 >= r1->x2) |
|
1865 { |
|
1866 /* |
|
1867 * Minuend completely covered: advance to next minuend and |
|
1868 * reset left fence to edge of new minuend. |
|
1869 */ |
|
1870 r1++; |
|
1871 if (r1 != r1_end) |
|
1872 x1 = r1->x1; |
|
1873 } |
|
1874 else |
|
1875 { |
|
1876 /* |
|
1877 * Subtrahend now used up since it doesn't extend beyond |
|
1878 * minuend |
|
1879 */ |
|
1880 r2++; |
|
1881 } |
|
1882 } |
|
1883 else if (r2->x1 < r1->x2) |
|
1884 { |
|
1885 /* |
|
1886 * Left part of subtrahend covers part of minuend: add uncovered |
|
1887 * part of minuend to region and skip to next subtrahend. |
|
1888 */ |
|
1889 critical_if_fail (x1 < r2->x1); |
|
1890 NEWRECT (region, next_rect, x1, y1, r2->x1, y2); |
|
1891 |
|
1892 x1 = r2->x2; |
|
1893 if (x1 >= r1->x2) |
|
1894 { |
|
1895 /* |
|
1896 * Minuend used up: advance to new... |
|
1897 */ |
|
1898 r1++; |
|
1899 if (r1 != r1_end) |
|
1900 x1 = r1->x1; |
|
1901 } |
|
1902 else |
|
1903 { |
|
1904 /* |
|
1905 * Subtrahend used up |
|
1906 */ |
|
1907 r2++; |
|
1908 } |
|
1909 } |
|
1910 else |
|
1911 { |
|
1912 /* |
|
1913 * Minuend used up: add any remaining piece before advancing. |
|
1914 */ |
|
1915 if (r1->x2 > x1) |
|
1916 NEWRECT (region, next_rect, x1, y1, r1->x2, y2); |
|
1917 |
|
1918 r1++; |
|
1919 |
|
1920 if (r1 != r1_end) |
|
1921 x1 = r1->x1; |
|
1922 } |
|
1923 } |
|
1924 while ((r1 != r1_end) && (r2 != r2_end)); |
|
1925 |
|
1926 /* |
|
1927 * Add remaining minuend rectangles to region. |
|
1928 */ |
|
1929 while (r1 != r1_end) |
|
1930 { |
|
1931 critical_if_fail (x1 < r1->x2); |
|
1932 |
|
1933 NEWRECT (region, next_rect, x1, y1, r1->x2, y2); |
|
1934 |
|
1935 r1++; |
|
1936 if (r1 != r1_end) |
|
1937 x1 = r1->x1; |
|
1938 } |
|
1939 return TRUE; |
|
1940 } |
|
1941 |
|
1942 /*- |
|
1943 *----------------------------------------------------------------------- |
|
1944 * pixman_region_subtract -- |
|
1945 * Subtract reg_s from reg_m and leave the result in reg_d. |
|
1946 * S stands for subtrahend, M for minuend and D for difference. |
|
1947 * |
|
1948 * Results: |
|
1949 * TRUE if successful. |
|
1950 * |
|
1951 * Side Effects: |
|
1952 * reg_d is overwritten. |
|
1953 * |
|
1954 *----------------------------------------------------------------------- |
|
1955 */ |
|
1956 PIXMAN_EXPORT pixman_bool_t |
|
1957 PREFIX (_subtract) (region_type_t *reg_d, |
|
1958 region_type_t *reg_m, |
|
1959 region_type_t *reg_s) |
|
1960 { |
|
1961 GOOD (reg_m); |
|
1962 GOOD (reg_s); |
|
1963 GOOD (reg_d); |
|
1964 |
|
1965 /* check for trivial rejects */ |
|
1966 if (PIXREGION_NIL (reg_m) || PIXREGION_NIL (reg_s) || |
|
1967 !EXTENTCHECK (®_m->extents, ®_s->extents)) |
|
1968 { |
|
1969 if (PIXREGION_NAR (reg_s)) |
|
1970 return pixman_break (reg_d); |
|
1971 |
|
1972 return PREFIX (_copy) (reg_d, reg_m); |
|
1973 } |
|
1974 else if (reg_m == reg_s) |
|
1975 { |
|
1976 FREE_DATA (reg_d); |
|
1977 reg_d->extents.x2 = reg_d->extents.x1; |
|
1978 reg_d->extents.y2 = reg_d->extents.y1; |
|
1979 reg_d->data = pixman_region_empty_data; |
|
1980 |
|
1981 return TRUE; |
|
1982 } |
|
1983 |
|
1984 /* Add those rectangles in region 1 that aren't in region 2, |
|
1985 do yucky substraction for overlaps, and |
|
1986 just throw away rectangles in region 2 that aren't in region 1 */ |
|
1987 if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE)) |
|
1988 return FALSE; |
|
1989 |
|
1990 /* |
|
1991 * Can't alter reg_d's extents before we call pixman_op because |
|
1992 * it might be one of the source regions and pixman_op depends |
|
1993 * on the extents of those regions being unaltered. Besides, this |
|
1994 * way there's no checking against rectangles that will be nuked |
|
1995 * due to coalescing, so we have to examine fewer rectangles. |
|
1996 */ |
|
1997 pixman_set_extents (reg_d); |
|
1998 GOOD (reg_d); |
|
1999 return TRUE; |
|
2000 } |
|
2001 |
|
2002 /*====================================================================== |
|
2003 * Region Inversion |
|
2004 *====================================================================*/ |
|
2005 |
|
2006 /*- |
|
2007 *----------------------------------------------------------------------- |
|
2008 * pixman_region_inverse -- |
|
2009 * Take a region and a box and return a region that is everything |
|
2010 * in the box but not in the region. The careful reader will note |
|
2011 * that this is the same as subtracting the region from the box... |
|
2012 * |
|
2013 * Results: |
|
2014 * TRUE. |
|
2015 * |
|
2016 * Side Effects: |
|
2017 * new_reg is overwritten. |
|
2018 * |
|
2019 *----------------------------------------------------------------------- |
|
2020 */ |
|
2021 PIXMAN_EXPORT pixman_bool_t |
|
2022 PREFIX (_inverse) (region_type_t *new_reg, /* Destination region */ |
|
2023 region_type_t *reg1, /* Region to invert */ |
|
2024 box_type_t * inv_rect) /* Bounding box for inversion */ |
|
2025 { |
|
2026 region_type_t inv_reg; /* Quick and dirty region made from the |
|
2027 * bounding box */ |
|
2028 GOOD (reg1); |
|
2029 GOOD (new_reg); |
|
2030 |
|
2031 /* check for trivial rejects */ |
|
2032 if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, ®1->extents)) |
|
2033 { |
|
2034 if (PIXREGION_NAR (reg1)) |
|
2035 return pixman_break (new_reg); |
|
2036 |
|
2037 new_reg->extents = *inv_rect; |
|
2038 FREE_DATA (new_reg); |
|
2039 new_reg->data = (region_data_type_t *)NULL; |
|
2040 |
|
2041 return TRUE; |
|
2042 } |
|
2043 |
|
2044 /* Add those rectangles in region 1 that aren't in region 2, |
|
2045 * do yucky substraction for overlaps, and |
|
2046 * just throw away rectangles in region 2 that aren't in region 1 |
|
2047 */ |
|
2048 inv_reg.extents = *inv_rect; |
|
2049 inv_reg.data = (region_data_type_t *)NULL; |
|
2050 if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE)) |
|
2051 return FALSE; |
|
2052 |
|
2053 /* |
|
2054 * Can't alter new_reg's extents before we call pixman_op because |
|
2055 * it might be one of the source regions and pixman_op depends |
|
2056 * on the extents of those regions being unaltered. Besides, this |
|
2057 * way there's no checking against rectangles that will be nuked |
|
2058 * due to coalescing, so we have to examine fewer rectangles. |
|
2059 */ |
|
2060 pixman_set_extents (new_reg); |
|
2061 GOOD (new_reg); |
|
2062 return TRUE; |
|
2063 } |
|
2064 |
|
2065 /* In time O(log n), locate the first box whose y2 is greater than y. |
|
2066 * Return @end if no such box exists. |
|
2067 */ |
|
2068 static box_type_t * |
|
2069 find_box_for_y (box_type_t *begin, box_type_t *end, int y) |
|
2070 { |
|
2071 box_type_t *mid; |
|
2072 |
|
2073 if (end == begin) |
|
2074 return end; |
|
2075 |
|
2076 if (end - begin == 1) |
|
2077 { |
|
2078 if (begin->y2 > y) |
|
2079 return begin; |
|
2080 else |
|
2081 return end; |
|
2082 } |
|
2083 |
|
2084 mid = begin + (end - begin) / 2; |
|
2085 if (mid->y2 > y) |
|
2086 { |
|
2087 /* If no box is found in [begin, mid], the function |
|
2088 * will return @mid, which is then known to be the |
|
2089 * correct answer. |
|
2090 */ |
|
2091 return find_box_for_y (begin, mid, y); |
|
2092 } |
|
2093 else |
|
2094 { |
|
2095 return find_box_for_y (mid, end, y); |
|
2096 } |
|
2097 } |
|
2098 |
|
2099 /* |
|
2100 * rect_in(region, rect) |
|
2101 * This routine takes a pointer to a region and a pointer to a box |
|
2102 * and determines if the box is outside/inside/partly inside the region. |
|
2103 * |
|
2104 * The idea is to travel through the list of rectangles trying to cover the |
|
2105 * passed box with them. Anytime a piece of the rectangle isn't covered |
|
2106 * by a band of rectangles, part_out is set TRUE. Any time a rectangle in |
|
2107 * the region covers part of the box, part_in is set TRUE. The process ends |
|
2108 * when either the box has been completely covered (we reached a band that |
|
2109 * doesn't overlap the box, part_in is TRUE and part_out is false), the |
|
2110 * box has been partially covered (part_in == part_out == TRUE -- because of |
|
2111 * the banding, the first time this is true we know the box is only |
|
2112 * partially in the region) or is outside the region (we reached a band |
|
2113 * that doesn't overlap the box at all and part_in is false) |
|
2114 */ |
|
2115 PIXMAN_EXPORT pixman_region_overlap_t |
|
2116 PREFIX (_contains_rectangle) (region_type_t * region, |
|
2117 box_type_t * prect) |
|
2118 { |
|
2119 box_type_t * pbox; |
|
2120 box_type_t * pbox_end; |
|
2121 int part_in, part_out; |
|
2122 int numRects; |
|
2123 int x, y; |
|
2124 |
|
2125 GOOD (region); |
|
2126 |
|
2127 numRects = PIXREGION_NUMRECTS (region); |
|
2128 |
|
2129 /* useful optimization */ |
|
2130 if (!numRects || !EXTENTCHECK (®ion->extents, prect)) |
|
2131 return(PIXMAN_REGION_OUT); |
|
2132 |
|
2133 if (numRects == 1) |
|
2134 { |
|
2135 /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */ |
|
2136 if (SUBSUMES (®ion->extents, prect)) |
|
2137 return(PIXMAN_REGION_IN); |
|
2138 else |
|
2139 return(PIXMAN_REGION_PART); |
|
2140 } |
|
2141 |
|
2142 part_out = FALSE; |
|
2143 part_in = FALSE; |
|
2144 |
|
2145 /* (x,y) starts at upper left of rect, moving to the right and down */ |
|
2146 x = prect->x1; |
|
2147 y = prect->y1; |
|
2148 |
|
2149 /* can stop when both part_out and part_in are TRUE, or we reach prect->y2 */ |
|
2150 for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects; |
|
2151 pbox != pbox_end; |
|
2152 pbox++) |
|
2153 { |
|
2154 /* getting up to speed or skipping remainder of band */ |
|
2155 if (pbox->y2 <= y) |
|
2156 { |
|
2157 if ((pbox = find_box_for_y (pbox, pbox_end, y)) == pbox_end) |
|
2158 break; |
|
2159 } |
|
2160 |
|
2161 if (pbox->y1 > y) |
|
2162 { |
|
2163 part_out = TRUE; /* missed part of rectangle above */ |
|
2164 if (part_in || (pbox->y1 >= prect->y2)) |
|
2165 break; |
|
2166 y = pbox->y1; /* x guaranteed to be == prect->x1 */ |
|
2167 } |
|
2168 |
|
2169 if (pbox->x2 <= x) |
|
2170 continue; /* not far enough over yet */ |
|
2171 |
|
2172 if (pbox->x1 > x) |
|
2173 { |
|
2174 part_out = TRUE; /* missed part of rectangle to left */ |
|
2175 if (part_in) |
|
2176 break; |
|
2177 } |
|
2178 |
|
2179 if (pbox->x1 < prect->x2) |
|
2180 { |
|
2181 part_in = TRUE; /* definitely overlap */ |
|
2182 if (part_out) |
|
2183 break; |
|
2184 } |
|
2185 |
|
2186 if (pbox->x2 >= prect->x2) |
|
2187 { |
|
2188 y = pbox->y2; /* finished with this band */ |
|
2189 if (y >= prect->y2) |
|
2190 break; |
|
2191 x = prect->x1; /* reset x out to left again */ |
|
2192 } |
|
2193 else |
|
2194 { |
|
2195 /* |
|
2196 * Because boxes in a band are maximal width, if the first box |
|
2197 * to overlap the rectangle doesn't completely cover it in that |
|
2198 * band, the rectangle must be partially out, since some of it |
|
2199 * will be uncovered in that band. part_in will have been set true |
|
2200 * by now... |
|
2201 */ |
|
2202 part_out = TRUE; |
|
2203 break; |
|
2204 } |
|
2205 } |
|
2206 |
|
2207 if (part_in) |
|
2208 { |
|
2209 if (y < prect->y2) |
|
2210 return PIXMAN_REGION_PART; |
|
2211 else |
|
2212 return PIXMAN_REGION_IN; |
|
2213 } |
|
2214 else |
|
2215 { |
|
2216 return PIXMAN_REGION_OUT; |
|
2217 } |
|
2218 } |
|
2219 |
|
2220 /* PREFIX(_translate) (region, x, y) |
|
2221 * translates in place |
|
2222 */ |
|
2223 |
|
2224 PIXMAN_EXPORT void |
|
2225 PREFIX (_translate) (region_type_t *region, int x, int y) |
|
2226 { |
|
2227 overflow_int_t x1, x2, y1, y2; |
|
2228 int nbox; |
|
2229 box_type_t * pbox; |
|
2230 |
|
2231 GOOD (region); |
|
2232 region->extents.x1 = x1 = region->extents.x1 + x; |
|
2233 region->extents.y1 = y1 = region->extents.y1 + y; |
|
2234 region->extents.x2 = x2 = region->extents.x2 + x; |
|
2235 region->extents.y2 = y2 = region->extents.y2 + y; |
|
2236 |
|
2237 if (((x1 - PIXMAN_REGION_MIN) | (y1 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x2) | (PIXMAN_REGION_MAX - y2)) >= 0) |
|
2238 { |
|
2239 if (region->data && (nbox = region->data->numRects)) |
|
2240 { |
|
2241 for (pbox = PIXREGION_BOXPTR (region); nbox--; pbox++) |
|
2242 { |
|
2243 pbox->x1 += x; |
|
2244 pbox->y1 += y; |
|
2245 pbox->x2 += x; |
|
2246 pbox->y2 += y; |
|
2247 } |
|
2248 } |
|
2249 return; |
|
2250 } |
|
2251 |
|
2252 if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) |
|
2253 { |
|
2254 region->extents.x2 = region->extents.x1; |
|
2255 region->extents.y2 = region->extents.y1; |
|
2256 FREE_DATA (region); |
|
2257 region->data = pixman_region_empty_data; |
|
2258 return; |
|
2259 } |
|
2260 |
|
2261 if (x1 < PIXMAN_REGION_MIN) |
|
2262 region->extents.x1 = PIXMAN_REGION_MIN; |
|
2263 else if (x2 > PIXMAN_REGION_MAX) |
|
2264 region->extents.x2 = PIXMAN_REGION_MAX; |
|
2265 |
|
2266 if (y1 < PIXMAN_REGION_MIN) |
|
2267 region->extents.y1 = PIXMAN_REGION_MIN; |
|
2268 else if (y2 > PIXMAN_REGION_MAX) |
|
2269 region->extents.y2 = PIXMAN_REGION_MAX; |
|
2270 |
|
2271 if (region->data && (nbox = region->data->numRects)) |
|
2272 { |
|
2273 box_type_t * pbox_out; |
|
2274 |
|
2275 for (pbox_out = pbox = PIXREGION_BOXPTR (region); nbox--; pbox++) |
|
2276 { |
|
2277 pbox_out->x1 = x1 = pbox->x1 + x; |
|
2278 pbox_out->y1 = y1 = pbox->y1 + y; |
|
2279 pbox_out->x2 = x2 = pbox->x2 + x; |
|
2280 pbox_out->y2 = y2 = pbox->y2 + y; |
|
2281 |
|
2282 if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | |
|
2283 (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) |
|
2284 { |
|
2285 region->data->numRects--; |
|
2286 continue; |
|
2287 } |
|
2288 |
|
2289 if (x1 < PIXMAN_REGION_MIN) |
|
2290 pbox_out->x1 = PIXMAN_REGION_MIN; |
|
2291 else if (x2 > PIXMAN_REGION_MAX) |
|
2292 pbox_out->x2 = PIXMAN_REGION_MAX; |
|
2293 |
|
2294 if (y1 < PIXMAN_REGION_MIN) |
|
2295 pbox_out->y1 = PIXMAN_REGION_MIN; |
|
2296 else if (y2 > PIXMAN_REGION_MAX) |
|
2297 pbox_out->y2 = PIXMAN_REGION_MAX; |
|
2298 |
|
2299 pbox_out++; |
|
2300 } |
|
2301 |
|
2302 if (pbox_out != pbox) |
|
2303 { |
|
2304 if (region->data->numRects == 1) |
|
2305 { |
|
2306 region->extents = *PIXREGION_BOXPTR (region); |
|
2307 FREE_DATA (region); |
|
2308 region->data = (region_data_type_t *)NULL; |
|
2309 } |
|
2310 else |
|
2311 { |
|
2312 pixman_set_extents (region); |
|
2313 } |
|
2314 } |
|
2315 } |
|
2316 |
|
2317 GOOD (region); |
|
2318 } |
|
2319 |
|
2320 PIXMAN_EXPORT void |
|
2321 PREFIX (_reset) (region_type_t *region, box_type_t *box) |
|
2322 { |
|
2323 GOOD (region); |
|
2324 |
|
2325 critical_if_fail (GOOD_RECT (box)); |
|
2326 |
|
2327 region->extents = *box; |
|
2328 |
|
2329 FREE_DATA (region); |
|
2330 |
|
2331 region->data = NULL; |
|
2332 } |
|
2333 |
|
2334 PIXMAN_EXPORT void |
|
2335 PREFIX (_clear) (region_type_t *region) |
|
2336 { |
|
2337 GOOD (region); |
|
2338 FREE_DATA (region); |
|
2339 |
|
2340 region->extents = *pixman_region_empty_box; |
|
2341 region->data = pixman_region_empty_data; |
|
2342 } |
|
2343 |
|
2344 /* box is "return" value */ |
|
2345 PIXMAN_EXPORT int |
|
2346 PREFIX (_contains_point) (region_type_t * region, |
|
2347 int x, int y, |
|
2348 box_type_t * box) |
|
2349 { |
|
2350 box_type_t *pbox, *pbox_end; |
|
2351 int numRects; |
|
2352 |
|
2353 GOOD (region); |
|
2354 numRects = PIXREGION_NUMRECTS (region); |
|
2355 |
|
2356 if (!numRects || !INBOX (®ion->extents, x, y)) |
|
2357 return(FALSE); |
|
2358 |
|
2359 if (numRects == 1) |
|
2360 { |
|
2361 if (box) |
|
2362 *box = region->extents; |
|
2363 |
|
2364 return(TRUE); |
|
2365 } |
|
2366 |
|
2367 pbox = PIXREGION_BOXPTR (region); |
|
2368 pbox_end = pbox + numRects; |
|
2369 |
|
2370 pbox = find_box_for_y (pbox, pbox_end, y); |
|
2371 |
|
2372 for (;pbox != pbox_end; pbox++) |
|
2373 { |
|
2374 if ((y < pbox->y1) || (x < pbox->x1)) |
|
2375 break; /* missed it */ |
|
2376 |
|
2377 if (x >= pbox->x2) |
|
2378 continue; /* not there yet */ |
|
2379 |
|
2380 if (box) |
|
2381 *box = *pbox; |
|
2382 |
|
2383 return(TRUE); |
|
2384 } |
|
2385 |
|
2386 return(FALSE); |
|
2387 } |
|
2388 |
|
2389 PIXMAN_EXPORT int |
|
2390 PREFIX (_not_empty) (region_type_t * region) |
|
2391 { |
|
2392 GOOD (region); |
|
2393 |
|
2394 return(!PIXREGION_NIL (region)); |
|
2395 } |
|
2396 |
|
2397 PIXMAN_EXPORT box_type_t * |
|
2398 PREFIX (_extents) (region_type_t * region) |
|
2399 { |
|
2400 GOOD (region); |
|
2401 |
|
2402 return(®ion->extents); |
|
2403 } |
|
2404 |
|
2405 /* |
|
2406 * Clip a list of scanlines to a region. The caller has allocated the |
|
2407 * space. FSorted is non-zero if the scanline origins are in ascending order. |
|
2408 * |
|
2409 * returns the number of new, clipped scanlines. |
|
2410 */ |
|
2411 |
|
2412 PIXMAN_EXPORT pixman_bool_t |
|
2413 PREFIX (_selfcheck) (region_type_t *reg) |
|
2414 { |
|
2415 int i, numRects; |
|
2416 |
|
2417 if ((reg->extents.x1 > reg->extents.x2) || |
|
2418 (reg->extents.y1 > reg->extents.y2)) |
|
2419 { |
|
2420 return FALSE; |
|
2421 } |
|
2422 |
|
2423 numRects = PIXREGION_NUMRECTS (reg); |
|
2424 if (!numRects) |
|
2425 { |
|
2426 return ((reg->extents.x1 == reg->extents.x2) && |
|
2427 (reg->extents.y1 == reg->extents.y2) && |
|
2428 (reg->data->size || (reg->data == pixman_region_empty_data))); |
|
2429 } |
|
2430 else if (numRects == 1) |
|
2431 { |
|
2432 return (!reg->data); |
|
2433 } |
|
2434 else |
|
2435 { |
|
2436 box_type_t * pbox_p, * pbox_n; |
|
2437 box_type_t box; |
|
2438 |
|
2439 pbox_p = PIXREGION_RECTS (reg); |
|
2440 box = *pbox_p; |
|
2441 box.y2 = pbox_p[numRects - 1].y2; |
|
2442 pbox_n = pbox_p + 1; |
|
2443 |
|
2444 for (i = numRects; --i > 0; pbox_p++, pbox_n++) |
|
2445 { |
|
2446 if ((pbox_n->x1 >= pbox_n->x2) || |
|
2447 (pbox_n->y1 >= pbox_n->y2)) |
|
2448 { |
|
2449 return FALSE; |
|
2450 } |
|
2451 |
|
2452 if (pbox_n->x1 < box.x1) |
|
2453 box.x1 = pbox_n->x1; |
|
2454 |
|
2455 if (pbox_n->x2 > box.x2) |
|
2456 box.x2 = pbox_n->x2; |
|
2457 |
|
2458 if ((pbox_n->y1 < pbox_p->y1) || |
|
2459 ((pbox_n->y1 == pbox_p->y1) && |
|
2460 ((pbox_n->x1 < pbox_p->x2) || (pbox_n->y2 != pbox_p->y2)))) |
|
2461 { |
|
2462 return FALSE; |
|
2463 } |
|
2464 } |
|
2465 |
|
2466 return ((box.x1 == reg->extents.x1) && |
|
2467 (box.x2 == reg->extents.x2) && |
|
2468 (box.y1 == reg->extents.y1) && |
|
2469 (box.y2 == reg->extents.y2)); |
|
2470 } |
|
2471 } |
|
2472 |
|
2473 PIXMAN_EXPORT pixman_bool_t |
|
2474 PREFIX (_init_rects) (region_type_t *region, |
|
2475 const box_type_t *boxes, int count) |
|
2476 { |
|
2477 box_type_t *rects; |
|
2478 int displacement; |
|
2479 int i; |
|
2480 |
|
2481 /* if it's 1, then we just want to set the extents, so call |
|
2482 * the existing method. */ |
|
2483 if (count == 1) |
|
2484 { |
|
2485 PREFIX (_init_rect) (region, |
|
2486 boxes[0].x1, |
|
2487 boxes[0].y1, |
|
2488 boxes[0].x2 - boxes[0].x1, |
|
2489 boxes[0].y2 - boxes[0].y1); |
|
2490 return TRUE; |
|
2491 } |
|
2492 |
|
2493 PREFIX (_init) (region); |
|
2494 |
|
2495 /* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is |
|
2496 * a special case, and causing pixman_rect_alloc would cause |
|
2497 * us to leak memory (because the 0-rect case should be the |
|
2498 * static pixman_region_empty_data data). |
|
2499 */ |
|
2500 if (count == 0) |
|
2501 return TRUE; |
|
2502 |
|
2503 if (!pixman_rect_alloc (region, count)) |
|
2504 return FALSE; |
|
2505 |
|
2506 rects = PIXREGION_RECTS (region); |
|
2507 |
|
2508 /* Copy in the rects */ |
|
2509 memcpy (rects, boxes, sizeof(box_type_t) * count); |
|
2510 region->data->numRects = count; |
|
2511 |
|
2512 /* Eliminate empty and malformed rectangles */ |
|
2513 displacement = 0; |
|
2514 |
|
2515 for (i = 0; i < count; ++i) |
|
2516 { |
|
2517 box_type_t *box = &rects[i]; |
|
2518 |
|
2519 if (box->x1 >= box->x2 || box->y1 >= box->y2) |
|
2520 displacement++; |
|
2521 else if (displacement) |
|
2522 rects[i - displacement] = rects[i]; |
|
2523 } |
|
2524 |
|
2525 region->data->numRects -= displacement; |
|
2526 |
|
2527 /* If eliminating empty rectangles caused there |
|
2528 * to be only 0 or 1 rectangles, deal with that. |
|
2529 */ |
|
2530 if (region->data->numRects == 0) |
|
2531 { |
|
2532 FREE_DATA (region); |
|
2533 PREFIX (_init) (region); |
|
2534 |
|
2535 return TRUE; |
|
2536 } |
|
2537 |
|
2538 if (region->data->numRects == 1) |
|
2539 { |
|
2540 region->extents = rects[0]; |
|
2541 |
|
2542 FREE_DATA (region); |
|
2543 region->data = NULL; |
|
2544 |
|
2545 GOOD (region); |
|
2546 |
|
2547 return TRUE; |
|
2548 } |
|
2549 |
|
2550 /* Validate */ |
|
2551 region->extents.x1 = region->extents.x2 = 0; |
|
2552 |
|
2553 return validate (region); |
|
2554 } |
|
2555 |
|
2556 #define READ(_ptr) (*(_ptr)) |
|
2557 |
|
2558 static inline box_type_t * |
|
2559 bitmap_addrect (region_type_t *reg, |
|
2560 box_type_t *r, |
|
2561 box_type_t **first_rect, |
|
2562 int rx1, int ry1, |
|
2563 int rx2, int ry2) |
|
2564 { |
|
2565 if ((rx1 < rx2) && (ry1 < ry2) && |
|
2566 (!(reg->data->numRects && |
|
2567 ((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) && |
|
2568 ((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2)))) |
|
2569 { |
|
2570 if (reg->data->numRects == reg->data->size) |
|
2571 { |
|
2572 if (!pixman_rect_alloc (reg, 1)) |
|
2573 return NULL; |
|
2574 *first_rect = PIXREGION_BOXPTR(reg); |
|
2575 r = *first_rect + reg->data->numRects; |
|
2576 } |
|
2577 r->x1 = rx1; |
|
2578 r->y1 = ry1; |
|
2579 r->x2 = rx2; |
|
2580 r->y2 = ry2; |
|
2581 reg->data->numRects++; |
|
2582 if (r->x1 < reg->extents.x1) |
|
2583 reg->extents.x1 = r->x1; |
|
2584 if (r->x2 > reg->extents.x2) |
|
2585 reg->extents.x2 = r->x2; |
|
2586 r++; |
|
2587 } |
|
2588 return r; |
|
2589 } |
|
2590 |
|
2591 /* Convert bitmap clip mask into clipping region. |
|
2592 * First, goes through each line and makes boxes by noting the transitions |
|
2593 * from 0 to 1 and 1 to 0. |
|
2594 * Then it coalesces the current line with the previous if they have boxes |
|
2595 * at the same X coordinates. |
|
2596 * Stride is in number of uint32_t per line. |
|
2597 */ |
|
2598 PIXMAN_EXPORT void |
|
2599 PREFIX (_init_from_image) (region_type_t *region, |
|
2600 pixman_image_t *image) |
|
2601 { |
|
2602 uint32_t mask0 = 0xffffffff & ~SCREEN_SHIFT_RIGHT(0xffffffff, 1); |
|
2603 box_type_t *first_rect, *rects, *prect_line_start; |
|
2604 box_type_t *old_rect, *new_rect; |
|
2605 uint32_t *pw, w, *pw_line, *pw_line_end; |
|
2606 int irect_prev_start, irect_line_start; |
|
2607 int h, base, rx1 = 0, crects; |
|
2608 int ib; |
|
2609 pixman_bool_t in_box, same; |
|
2610 int width, height, stride; |
|
2611 |
|
2612 PREFIX(_init) (region); |
|
2613 |
|
2614 critical_if_fail (region->data); |
|
2615 |
|
2616 return_if_fail (image->type == BITS); |
|
2617 return_if_fail (image->bits.format == PIXMAN_a1); |
|
2618 |
|
2619 pw_line = pixman_image_get_data (image); |
|
2620 width = pixman_image_get_width (image); |
|
2621 height = pixman_image_get_height (image); |
|
2622 stride = pixman_image_get_stride (image) / 4; |
|
2623 |
|
2624 first_rect = PIXREGION_BOXPTR(region); |
|
2625 rects = first_rect; |
|
2626 |
|
2627 region->extents.x1 = width - 1; |
|
2628 region->extents.x2 = 0; |
|
2629 irect_prev_start = -1; |
|
2630 for (h = 0; h < height; h++) |
|
2631 { |
|
2632 pw = pw_line; |
|
2633 pw_line += stride; |
|
2634 irect_line_start = rects - first_rect; |
|
2635 |
|
2636 /* If the Screen left most bit of the word is set, we're starting in |
|
2637 * a box */ |
|
2638 if (READ(pw) & mask0) |
|
2639 { |
|
2640 in_box = TRUE; |
|
2641 rx1 = 0; |
|
2642 } |
|
2643 else |
|
2644 { |
|
2645 in_box = FALSE; |
|
2646 } |
|
2647 |
|
2648 /* Process all words which are fully in the pixmap */ |
|
2649 pw_line_end = pw + (width >> 5); |
|
2650 for (base = 0; pw < pw_line_end; base += 32) |
|
2651 { |
|
2652 w = READ(pw++); |
|
2653 if (in_box) |
|
2654 { |
|
2655 if (!~w) |
|
2656 continue; |
|
2657 } |
|
2658 else |
|
2659 { |
|
2660 if (!w) |
|
2661 continue; |
|
2662 } |
|
2663 for (ib = 0; ib < 32; ib++) |
|
2664 { |
|
2665 /* If the Screen left most bit of the word is set, we're |
|
2666 * starting a box */ |
|
2667 if (w & mask0) |
|
2668 { |
|
2669 if (!in_box) |
|
2670 { |
|
2671 rx1 = base + ib; |
|
2672 /* start new box */ |
|
2673 in_box = TRUE; |
|
2674 } |
|
2675 } |
|
2676 else |
|
2677 { |
|
2678 if (in_box) |
|
2679 { |
|
2680 /* end box */ |
|
2681 rects = bitmap_addrect (region, rects, &first_rect, |
|
2682 rx1, h, base + ib, h + 1); |
|
2683 if (rects == NULL) |
|
2684 goto error; |
|
2685 in_box = FALSE; |
|
2686 } |
|
2687 } |
|
2688 /* Shift the word VISUALLY left one. */ |
|
2689 w = SCREEN_SHIFT_LEFT(w, 1); |
|
2690 } |
|
2691 } |
|
2692 |
|
2693 if (width & 31) |
|
2694 { |
|
2695 /* Process final partial word on line */ |
|
2696 w = READ(pw++); |
|
2697 for (ib = 0; ib < (width & 31); ib++) |
|
2698 { |
|
2699 /* If the Screen left most bit of the word is set, we're |
|
2700 * starting a box */ |
|
2701 if (w & mask0) |
|
2702 { |
|
2703 if (!in_box) |
|
2704 { |
|
2705 rx1 = base + ib; |
|
2706 /* start new box */ |
|
2707 in_box = TRUE; |
|
2708 } |
|
2709 } |
|
2710 else |
|
2711 { |
|
2712 if (in_box) |
|
2713 { |
|
2714 /* end box */ |
|
2715 rects = bitmap_addrect(region, rects, &first_rect, |
|
2716 rx1, h, base + ib, h + 1); |
|
2717 if (rects == NULL) |
|
2718 goto error; |
|
2719 in_box = FALSE; |
|
2720 } |
|
2721 } |
|
2722 /* Shift the word VISUALLY left one. */ |
|
2723 w = SCREEN_SHIFT_LEFT(w, 1); |
|
2724 } |
|
2725 } |
|
2726 /* If scanline ended with last bit set, end the box */ |
|
2727 if (in_box) |
|
2728 { |
|
2729 rects = bitmap_addrect(region, rects, &first_rect, |
|
2730 rx1, h, base + (width & 31), h + 1); |
|
2731 if (rects == NULL) |
|
2732 goto error; |
|
2733 } |
|
2734 /* if all rectangles on this line have the same x-coords as |
|
2735 * those on the previous line, then add 1 to all the previous y2s and |
|
2736 * throw away all the rectangles from this line |
|
2737 */ |
|
2738 same = FALSE; |
|
2739 if (irect_prev_start != -1) |
|
2740 { |
|
2741 crects = irect_line_start - irect_prev_start; |
|
2742 if (crects != 0 && |
|
2743 crects == ((rects - first_rect) - irect_line_start)) |
|
2744 { |
|
2745 old_rect = first_rect + irect_prev_start; |
|
2746 new_rect = prect_line_start = first_rect + irect_line_start; |
|
2747 same = TRUE; |
|
2748 while (old_rect < prect_line_start) |
|
2749 { |
|
2750 if ((old_rect->x1 != new_rect->x1) || |
|
2751 (old_rect->x2 != new_rect->x2)) |
|
2752 { |
|
2753 same = FALSE; |
|
2754 break; |
|
2755 } |
|
2756 old_rect++; |
|
2757 new_rect++; |
|
2758 } |
|
2759 if (same) |
|
2760 { |
|
2761 old_rect = first_rect + irect_prev_start; |
|
2762 while (old_rect < prect_line_start) |
|
2763 { |
|
2764 old_rect->y2 += 1; |
|
2765 old_rect++; |
|
2766 } |
|
2767 rects -= crects; |
|
2768 region->data->numRects -= crects; |
|
2769 } |
|
2770 } |
|
2771 } |
|
2772 if(!same) |
|
2773 irect_prev_start = irect_line_start; |
|
2774 } |
|
2775 if (!region->data->numRects) |
|
2776 { |
|
2777 region->extents.x1 = region->extents.x2 = 0; |
|
2778 } |
|
2779 else |
|
2780 { |
|
2781 region->extents.y1 = PIXREGION_BOXPTR(region)->y1; |
|
2782 region->extents.y2 = PIXREGION_END(region)->y2; |
|
2783 if (region->data->numRects == 1) |
|
2784 { |
|
2785 free (region->data); |
|
2786 region->data = NULL; |
|
2787 } |
|
2788 } |
|
2789 |
|
2790 error: |
|
2791 return; |
|
2792 } |