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