1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "android/skin/region.h" 13 #include <limits.h> 14 #include <string.h> 15 #include <stdlib.h> /* malloc/free */ 16 17 /************************************************************************* 18 ************************************************************************* 19 **** 20 **** ASSERTION SUPPORT 21 **** 22 **** 23 ****/ 24 25 #ifdef UNIT_TEST 26 #include <stdlib.h> 27 #include <stdio.h> 28 static void 29 _rpanic(void) 30 { 31 *((char*)(void*)0) = 1; /* should SEGFAULT */ 32 /* put a breakpoint here */ 33 exit(1); 34 } 35 36 #define RASSERT(cond) \ 37 ({ if (!(cond)) { fprintf(stderr, "%s:%d:%s: assertion failed: %s", \ 38 __FILE__, __LINE__, __FUNCTION__, #cond ); _rpanic(); } }) 39 40 #else 41 #define RASSERT(cond) ((void)0) 42 #endif 43 44 45 /************************************************************************* 46 ************************************************************************* 47 **** 48 **** IMPLEMENTATION DETAILS 49 **** 50 **** 51 ****/ 52 53 /* this implementation of regions encodes the the region's spans with the 54 following format: 55 56 region ::= yband+ YSENTINEL 57 yband ::= YTOP YBOTTOM scanline 58 scanline ::= span+ XSENTINEL 59 span ::= XLEFT XRIGHT 60 61 XSENTINEL ::= 0x7fff 62 YSENTINEL := 0x7fff 63 64 all values are sorted in increasing order, which means that: 65 66 - YTOP1 < YBOTTOM1 <= YTOP2 < YBOTTOM2 <= .... < YSENTINEL 67 - XLEFT1 < XRIGHT1 < XLEFT2 < XRIGHT2 < .... < XSENTINEL 68 (in a given scanline) 69 */ 70 71 /* convenience shortbuts */ 72 typedef SkinRegionRun Run; 73 typedef SkinRegion Region; 74 75 #define RUNS_RECT_COUNT 6 /* YTOP YBOT XLEFT XRIGHT XSENTINEL YSENTINEL */ 76 77 #define XSENTINEL SKIN_REGION_SENTINEL 78 #define YSENTINEL SKIN_REGION_SENTINEL 79 80 #define RUNS_EMPTY ((Run*)(void*)(-1)) 81 #define RUNS_RECT ((Run*)(void*)(0)) 82 83 static __inline__ int 84 region_isEmpty( Region* r ) 85 { 86 return r->runs == RUNS_EMPTY; 87 } 88 89 static __inline__ int 90 region_isRect( Region* r ) 91 { 92 return r->runs == RUNS_RECT; 93 } 94 95 static __inline__ int 96 region_isComplex( Region* r ) 97 { 98 return r->runs != RUNS_EMPTY && r->runs != RUNS_RECT; 99 } 100 101 /** RunStore: ref-counted storage for runs 102 **/ 103 104 typedef struct { 105 int refcount; 106 int count; 107 } RunStore; 108 109 static void 110 runstore_free( RunStore* s ) 111 { 112 free(s); 113 } 114 115 static RunStore* 116 runstore_alloc( int count ) 117 { 118 RunStore* s = malloc( sizeof(*s) + sizeof(Run)*count ); 119 RASSERT(s != NULL); 120 s->count = count; 121 s->refcount = 1; 122 return s; 123 } 124 125 static RunStore* 126 runstore_edit( RunStore* s ) 127 { 128 RunStore* s2; 129 130 if (s->refcount == 1) 131 return s; 132 133 s2 = runstore_alloc( s->count ); 134 if (s2) { 135 memcpy( s2, s, sizeof(*s) + s->count*sizeof(Run) ); 136 s->refcount -= 1; 137 s2->refcount = 1; 138 } 139 return s2; 140 } 141 142 static void 143 runstore_unrefp( RunStore* *ps ) 144 { 145 RunStore* s = *ps; 146 if (s != NULL) { 147 if (s->refcount <= 0) 148 runstore_free(s); 149 *ps = NULL; 150 } 151 } 152 153 static RunStore* 154 runstore_ref( RunStore* s ) 155 { 156 if (s) s->refcount += 1; 157 return s; 158 } 159 160 static __inline__ RunStore* 161 runstore_from_runs( Run* runs ) 162 { 163 RASSERT(runs != RUNS_EMPTY); 164 RASSERT(runs != RUNS_RECT); 165 return (RunStore*)runs - 1; 166 } 167 168 static __inline__ Run* 169 runstore_to_runs( RunStore* s ) 170 { 171 RASSERT(s != NULL); 172 return (Run*)(s + 1); 173 } 174 175 static Run* 176 region_edit( Region* r ) 177 { 178 RunStore* s; 179 180 RASSERT(region_isComplex(r)); 181 182 s = runstore_from_runs(r->runs); 183 s = runstore_edit(s); 184 r->runs = runstore_to_runs(s); 185 return r->runs; 186 } 187 188 /** Run parsing 189 **/ 190 191 static Run* 192 runs_next_scanline( Run* runs ) 193 { 194 RASSERT(runs[0] != YSENTINEL && runs[1] != YSENTINEL ); 195 runs += 2; 196 do { runs += 1; } while (runs[-1] != XSENTINEL); 197 return runs; 198 } 199 200 static Run* 201 runs_find_y( Run* runs, int y ) 202 { 203 do { 204 int ybot, ytop = runs[0]; 205 206 if (y < ytop) 207 return NULL; 208 209 ybot = runs[1]; 210 if (y < ybot) 211 return runs; 212 213 runs = runs_next_scanline( runs ); 214 } while (runs[0] != YSENTINEL); 215 216 return NULL; 217 } 218 219 static void 220 runs_set_rect( Run* runs, SkinRect* rect ) 221 { 222 runs[0] = rect->pos.y; 223 runs[1] = rect->pos.y + rect->size.h; 224 runs[2] = rect->pos.x; 225 runs[3] = rect->pos.x + rect->size.w; 226 runs[4] = XSENTINEL; 227 runs[5] = YSENTINEL; 228 } 229 230 static Run* 231 runs_copy_scanline( Run* dst, Run* src ) 232 { 233 RASSERT(src[0] != YSENTINEL); 234 RASSERT(src[1] != YSENTINEL); 235 dst[0] = src[0]; 236 dst[1] = src[1]; 237 src += 2; 238 dst += 2; 239 do { *dst++ = *src++; } while (src[-1] != XSENTINEL); 240 return dst; 241 } 242 243 static Run* 244 runs_copy_scanline_adj( Run* dst, Run* src, int ytop, int ybot ) 245 { 246 Run* runs2 = runs_copy_scanline( dst, src ); 247 dst[0] = (Run) ytop; 248 dst[1] = (Run) ybot; 249 return runs2; 250 } 251 252 static __inline__ Run* 253 runs_add_span( Run* dst, int left, int right ) 254 { 255 dst[0] = (Run) left; 256 dst[1] = (Run) right; 257 return dst + 2; 258 } 259 260 static __inline__ int 261 runs_get_count( Run* runs ) 262 { 263 RunStore* s = runstore_from_runs(runs); 264 return s->count; 265 } 266 267 268 static void 269 runs_coalesce_band( Run* *psrc_spans, Run* *pdst_spans, SkinBox* minmax ) 270 { 271 Run* sspan = *psrc_spans; 272 Run* dspan = *pdst_spans; 273 int pleft = sspan[0]; 274 int pright = sspan[1]; 275 int xleft, xright; 276 277 RASSERT(pleft != XSENTINEL); 278 RASSERT(pright != XSENTINEL); 279 RASSERT(pleft < pright); 280 281 if (pleft < minmax->x1) minmax->x1 = pleft; 282 283 sspan += 2; 284 xleft = sspan[0]; 285 286 while (xleft != XSENTINEL) 287 { 288 xright = sspan[1]; 289 RASSERT(xright != XSENTINEL); 290 RASSERT(xleft < xright); 291 292 if (xleft == pright) { 293 pright = xright; 294 } else { 295 dspan[0] = (Run) pleft; 296 dspan[1] = (Run) pright; 297 dspan += 2; 298 } 299 sspan += 2; 300 xleft = sspan[0]; 301 } 302 dspan[0] = (Run) pleft; 303 dspan[1] = (Run) pright; 304 dspan[2] = XSENTINEL; 305 dspan += 3; 306 sspan += 1; /* skip XSENTINEL */ 307 308 if (pright > minmax->x2) minmax->x2 = pright; 309 310 *psrc_spans = sspan; 311 *pdst_spans = dspan; 312 } 313 314 315 static int 316 runs_coalesce( Run* dst, Run* src, SkinBox* minmax ) 317 { 318 Run* prev = NULL; 319 Run* dst0 = dst; 320 int ytop = src[0]; 321 int ybot; 322 323 while (ytop != YSENTINEL) 324 { 325 Run* sspan = src + 2; 326 Run* dspan = dst + 2; 327 328 ybot = src[1]; 329 RASSERT( ytop < ybot ); 330 RASSERT( ybot != YSENTINEL ); 331 RASSERT( src[2] != XSENTINEL ); 332 333 if (ytop < minmax->y1) minmax->y1 = ytop; 334 if (ybot > minmax->y2) minmax->y2 = ybot; 335 336 dst[0] = (Run) ytop; 337 dst[1] = (Run) ybot; 338 339 runs_coalesce_band( &sspan, &dspan, minmax ); 340 341 if (prev && prev[1] == dst[0] && (dst-prev) == (dspan-dst) && 342 !memcmp(prev+2, dst+2, (dspan-dst-2)*sizeof(Run))) 343 { 344 /* coalesce two identical bands */ 345 prev[1] = dst[1]; 346 } 347 else 348 { 349 prev = dst; 350 dst = dspan; 351 } 352 src = sspan; 353 ytop = src[0]; 354 } 355 dst[0] = YSENTINEL; 356 return (dst + 1 - dst0); 357 } 358 359 /************************************************************************* 360 ************************************************************************* 361 **** 362 **** PUBLIC API 363 **** 364 ****/ 365 366 void 367 skin_region_init_empty( SkinRegion* r ) 368 { 369 /* empty region */ 370 r->bounds.pos.x = r->bounds.pos.y = 0; 371 r->bounds.size.w = r->bounds.size.h = 0; 372 r->runs = RUNS_EMPTY; 373 } 374 375 void 376 skin_region_init( SkinRegion* r, int x1, int y1, int x2, int y2 ) 377 { 378 if (x1 >= x2 || y1 >= y2) { 379 skin_region_init_empty(r); 380 return; 381 } 382 r->bounds.pos.x = x1; 383 r->bounds.pos.y = y1; 384 r->bounds.size.w = x2 - x1; 385 r->bounds.size.h = y2 - y1; 386 r->runs = RUNS_RECT; 387 } 388 389 void 390 skin_region_init_rect( SkinRegion* r, SkinRect* rect ) 391 { 392 if (rect == NULL || rect->size.w <= 0 || rect->size.h <= 0) { 393 skin_region_init_empty(r); 394 return; 395 } 396 r->bounds = rect[0]; 397 r->runs = RUNS_RECT; 398 } 399 400 void 401 skin_region_init_box( SkinRegion* r, SkinBox* box ) 402 { 403 if (box == NULL || box->x1 >= box->x2 || box->y1 >= box->y2) { 404 skin_region_init_empty(r); 405 return; 406 } 407 r->bounds.pos.x = box->x1; 408 r->bounds.pos.y = box->y1; 409 r->bounds.size.w = box->x2 - box->x1; 410 r->bounds.size.h = box->y2 - box->y1; 411 r->runs = RUNS_RECT; 412 } 413 414 void 415 skin_region_init_copy( SkinRegion* r, SkinRegion* src ) 416 { 417 if (src == NULL || region_isEmpty(src)) 418 skin_region_init_empty(r); 419 else { 420 r[0] = src[0]; 421 if (region_isComplex(src)) { 422 RunStore* s = runstore_from_runs(r->runs); 423 runstore_ref(s); 424 } 425 } 426 } 427 428 429 void 430 skin_region_reset( SkinRegion* r ) 431 { 432 if (r != NULL) { 433 if (region_isComplex(r)) { 434 RunStore* s = runstore_from_runs(r->runs); 435 runstore_unrefp( &s ); 436 } 437 skin_region_init_empty(r); 438 } 439 } 440 441 442 443 void 444 skin_region_copy( SkinRegion* r, SkinRegion* src ) 445 { 446 skin_region_reset(r); 447 skin_region_init_copy(r, src); 448 } 449 450 451 int 452 skin_region_equals( SkinRegion* r1, SkinRegion* r2 ) 453 { 454 Run *runs1, *runs2; 455 RunStore *store1, *store2; 456 457 if (r1 == r2) 458 return 1; 459 460 if (!skin_rect_equals( &r1->bounds, &r2->bounds )) 461 return 0; 462 463 runs1 = r1->runs; 464 runs2 = r2->runs; 465 466 if (runs1 == runs2) /* empties and rects */ 467 return 1; 468 469 if ( !region_isComplex(r1) || !region_isComplex(r2) ) 470 return 0; 471 472 store1 = runstore_from_runs(runs1); 473 store2 = runstore_from_runs(runs2); 474 475 if (store1->count == store2->count && 476 !memcmp( (char*)runs1, (char*)runs2, store1->count*sizeof(Run) ) ) 477 return 1; 478 479 return 0; 480 } 481 482 void 483 skin_region_translate( SkinRegion* r, int dx, int dy ) 484 { 485 Run* runs; 486 487 if (region_isEmpty(r)) 488 return; 489 490 skin_rect_translate( &r->bounds, dx, dy ); 491 if (region_isRect(r)) 492 return; 493 494 runs = region_edit(r); 495 while (runs[0] != YSENTINEL) { 496 int ytop = runs[0]; 497 int ybot = runs[1]; 498 499 RASSERT(ybot != YSENTINEL); 500 runs[0] = (Run)(ytop + dy); 501 runs[1] = (Run)(ybot + dy); 502 runs += 2; 503 while (runs[0] != XSENTINEL) { 504 int xleft = runs[0]; 505 int xright = runs[1]; 506 RASSERT(xright != YSENTINEL); 507 runs[0] = (Run)(xleft + dx); 508 runs[1] = (Run)(xright + dx); 509 runs += 2; 510 } 511 runs += 1; 512 } 513 } 514 515 void 516 skin_region_get_bounds( SkinRegion* r, SkinRect* bounds ) 517 { 518 if (r != NULL) { 519 bounds[0] = r->bounds; 520 } else { 521 bounds->pos.x = bounds->pos.y = 0; 522 bounds->size.w = bounds->size.h = 0; 523 } 524 } 525 526 int 527 skin_region_is_empty( SkinRegion* r ) 528 { 529 return region_isEmpty(r); 530 } 531 532 int 533 skin_region_is_rect( SkinRegion* r ) 534 { 535 return region_isRect(r); 536 } 537 538 int 539 skin_region_is_complex( SkinRegion* r ) 540 { 541 return region_isComplex(r); 542 } 543 544 void 545 skin_region_swap( SkinRegion* r, SkinRegion* r2 ) 546 { 547 SkinRegion tmp; 548 tmp = r[0]; 549 r[0] = r2[0]; 550 r2[0] = tmp; 551 } 552 553 554 SkinOverlap 555 skin_region_contains( SkinRegion* r, int x, int y ) 556 { 557 if (region_isEmpty(r)) 558 return SKIN_OUTSIDE; 559 if (region_isRect(r)) { 560 return skin_rect_contains(&r->bounds,x,y); 561 } else { 562 Run* runs = runs_find_y( r->runs, y ); 563 if (runs != NULL) { 564 runs += 2; 565 do { 566 int xright, xleft = runs[0]; 567 568 if (x < xleft) // also x < xleft == XSENTINEL 569 break; 570 xright = runs[1]; 571 if (xright == XSENTINEL) 572 break; 573 if (x < xright) 574 return SKIN_INSIDE; 575 runs += 2; 576 } while (runs[0] != XSENTINEL); 577 } 578 return SKIN_OUTSIDE; 579 } 580 } 581 582 583 SkinOverlap 584 skin_region_contains_rect( SkinRegion* r, SkinRect* rect ) 585 { 586 SkinRegion r2[1]; 587 skin_region_init_rect( r2, rect ); 588 return skin_region_test_intersect( r, r2 ); 589 } 590 591 592 SkinOverlap 593 skin_region_contains_box( SkinRegion* r, SkinBox* b ) 594 { 595 SkinRegion r2[1]; 596 597 skin_region_init_box( r2, b ); 598 return skin_region_test_intersect( r, r2 ); 599 } 600 601 602 603 #define FLAG_REGION_1 (1 << 0) 604 #define FLAG_REGION_2 (1 << 1) 605 #define FLAG_REGION_BOTH (1 << 2) 606 607 SkinOverlap 608 skin_region_test_intersect( SkinRegion* r1, 609 SkinRegion* r2 ) 610 { 611 Run *runs1, *runs2; 612 Run run2_tmp[ RUNS_RECT_COUNT ]; 613 SkinRect r; 614 615 if (region_isEmpty(r1) || region_isEmpty(r2)) 616 return SKIN_OUTSIDE; 617 618 if ( !skin_rect_intersect( &r, &r1->bounds, &r2->bounds) ) 619 return SKIN_OUTSIDE; 620 621 if (region_isRect(r1)) { 622 if (region_isRect(r2)) { 623 return skin_rect_contains_rect(&r1->bounds, &r2->bounds); 624 } else { 625 SkinRegion* tmp = r1; 626 r1 = r2; 627 r2 = tmp; 628 } 629 } 630 /* here r1 is guaranteed to be complex, r2 is either rect of complex */ 631 runs1 = r1->runs; 632 if (region_isRect(r2)) { 633 runs2 = run2_tmp; 634 runs_set_rect(runs2, &r2->bounds); 635 } 636 else { 637 runs2 = r2->runs; 638 } 639 640 { 641 int flags = 0; 642 643 while (runs1[0] != YSENTINEL && runs2[0] != YSENTINEL) 644 { 645 int ytop1 = runs1[0]; 646 int ybot1 = runs1[1]; 647 int ytop2 = runs2[0]; 648 int ybot2 = runs2[1]; 649 650 if (ybot1 <= ytop2) 651 { 652 /* band1 over band2 */ 653 flags |= FLAG_REGION_1; 654 runs1 = runs_next_scanline( runs1 ); 655 } 656 else if (ybot2 <= ytop1) 657 { 658 /* band2 over band1 */ 659 flags |= FLAG_REGION_2; 660 runs2 = runs_next_scanline( runs2 ); 661 } 662 else /* band1 and band2 overlap */ 663 { 664 Run* span1; 665 Run* span2; 666 int ybot; 667 668 if (ytop1 < ytop2) { 669 flags |= FLAG_REGION_1; 670 ytop1 = ytop2; 671 } else if (ytop2 < ytop1) { 672 flags |= FLAG_REGION_2; 673 ytop2 = ytop1; 674 } 675 676 ybot = (ybot1 < ybot2) ? ybot1 : ybot2; 677 678 span1 = runs1 + 2; 679 span2 = runs2 + 2; 680 681 while (span1[0] != XSENTINEL && span2[0] != XSENTINEL) 682 { 683 int xleft1 = span1[0]; 684 int xright1 = span1[1]; 685 int xleft2 = span2[0]; 686 int xright2 = span2[1]; 687 688 RASSERT(xright1 != XSENTINEL); 689 RASSERT(xright2 != XSENTINEL); 690 691 if (xright1 <= xleft2) { 692 flags |= FLAG_REGION_1; 693 span1 += 2; 694 } 695 else if (xright2 <= xleft1) { 696 flags |= FLAG_REGION_2; 697 span2 += 2; 698 } 699 else { 700 int xright; 701 702 if (xleft1 < xleft2) { 703 flags |= FLAG_REGION_1; 704 xleft1 = xleft2; 705 } else if (xleft2 < xleft1) { 706 flags |= FLAG_REGION_2; 707 xleft2 = xleft1; 708 } 709 710 xright = (xright1 < xright2) ? xright1 : xright2; 711 712 flags |= FLAG_REGION_BOTH; 713 714 if (xright == xright1) 715 span1 += 2; 716 if (xright == xright2) 717 span2 += 2; 718 } 719 } 720 721 if (span1[0] != XSENTINEL) { 722 flags |= FLAG_REGION_1; 723 } 724 725 if (span2[0] != XSENTINEL) { 726 flags |= FLAG_REGION_2; 727 } 728 729 if (ybot == ybot1) 730 runs1 = runs_next_scanline( runs1 ); 731 732 if (ybot == ybot2) 733 runs2 = runs_next_scanline( runs2 ); 734 } 735 } 736 737 if (runs1[0] != YSENTINEL) { 738 flags |= FLAG_REGION_1; 739 } 740 741 if (runs2[0] != YSENTINEL) { 742 flags |= FLAG_REGION_2; 743 } 744 745 if ( !(flags & FLAG_REGION_BOTH) ) { 746 /* no intersection at all */ 747 return SKIN_OUTSIDE; 748 } 749 750 if ( (flags & FLAG_REGION_2) != 0 ) { 751 /* intersection + overlap */ 752 return SKIN_OVERLAP; 753 } 754 755 return SKIN_INSIDE; 756 } 757 } 758 759 typedef struct { 760 Run* runs1; 761 Run* runs2; 762 Run* runs_base; 763 Run* runs; 764 RunStore* store; 765 Region result[1]; 766 Run runs1_rect[ RUNS_RECT_COUNT ]; 767 Run runs2_rect[ RUNS_RECT_COUNT ]; 768 } RegionOperator; 769 770 771 static void 772 region_operator_init( RegionOperator* o, 773 Region* r1, 774 Region* r2 ) 775 { 776 int run1_count, run2_count; 777 int maxruns; 778 779 RASSERT( !region_isEmpty(r1) ); 780 RASSERT( !region_isEmpty(r2) ); 781 782 if (region_isRect(r1)) { 783 run1_count = RUNS_RECT_COUNT; 784 o->runs1 = o->runs1_rect; 785 runs_set_rect( o->runs1, &r1->bounds ); 786 } else { 787 o->runs1 = r1->runs; 788 run1_count = runs_get_count(r1->runs); 789 } 790 791 if (region_isRect(r2)) { 792 run2_count = RUNS_RECT_COUNT; 793 o->runs2 = o->runs2_rect; 794 runs_set_rect( o->runs2, &r2->bounds ); 795 } else { 796 o->runs2 = r2->runs; 797 run2_count = runs_get_count(r2->runs); 798 } 799 800 maxruns = run1_count < run2_count ? run2_count : run1_count; 801 o->store = runstore_alloc( 3*maxruns ); 802 o->runs_base = runstore_to_runs(o->store); 803 } 804 805 806 static void 807 region_operator_do( RegionOperator* o, int wanted ) 808 { 809 Run* runs1 = o->runs1; 810 Run* runs2 = o->runs2; 811 Run* runs = o->runs_base; 812 int ytop1 = runs1[0]; 813 int ytop2 = runs2[0]; 814 815 if (ytop1 != YSENTINEL && ytop2 != YSENTINEL) 816 { 817 int ybot1, ybot2; 818 819 while (ytop1 != YSENTINEL && ytop2 != YSENTINEL) 820 { 821 int ybot; 822 823 ybot1 = runs1[1]; 824 ybot2 = runs2[1]; 825 826 RASSERT(ybot1 != YSENTINEL); 827 RASSERT(ybot2 != YSENTINEL); 828 829 if (ybot1 <= ytop2) { 830 if (wanted & FLAG_REGION_1) 831 runs = runs_copy_scanline_adj( runs, runs1, ytop1, ybot1 ); 832 runs1 = runs_next_scanline( runs1 ); 833 ytop1 = runs1[0]; 834 continue; 835 } 836 837 if (ybot2 <= ytop1) { 838 if (wanted & FLAG_REGION_2) 839 runs = runs_copy_scanline_adj( runs, runs2, ytop2, ybot2 ); 840 runs2 = runs_next_scanline(runs2); 841 ytop2 = runs2[0]; 842 continue; 843 } 844 845 if (ytop1 < ytop2) { 846 if (wanted & FLAG_REGION_1) 847 runs = runs_copy_scanline_adj( runs, runs1, ytop1, ytop2 ); 848 ytop1 = ytop2; 849 } 850 else if (ytop2 < ytop1) { 851 if (wanted & FLAG_REGION_2) 852 runs = runs_copy_scanline_adj( runs, runs2, ytop2, ytop1 ); 853 ytop2 = ytop1; 854 } 855 856 ybot = (ybot1 <= ybot2) ? ybot1 : ybot2; 857 858 runs[0] = (Run) ytop1; 859 runs[1] = (Run) ybot; 860 861 /* do the common band */ 862 { 863 Run* span1 = runs1 + 2; 864 Run* span2 = runs2 + 2; 865 Run* span = runs + 2; 866 int xleft1 = span1[0]; 867 int xleft2 = span2[0]; 868 int xright1, xright2; 869 870 while (xleft1 != XSENTINEL && xleft2 != XSENTINEL) 871 { 872 int xright; 873 874 xright1 = span1[1]; 875 xright2 = span2[1]; 876 877 RASSERT(xright1 != XSENTINEL); 878 RASSERT(xright2 != XSENTINEL); 879 880 if (xright1 <= xleft2) { 881 if (wanted & FLAG_REGION_1) 882 span = runs_add_span( span, xleft1, xright1 ); 883 span1 += 2; 884 xleft1 = span1[0]; 885 continue; 886 } 887 888 if (xright2 <= xleft1) { 889 if (wanted & FLAG_REGION_2) 890 span = runs_add_span( span, xleft2, xright2 ); 891 span2 += 2; 892 xleft2 = span2[0]; 893 continue; 894 } 895 896 if (xleft1 < xleft2) { 897 if (wanted & FLAG_REGION_1) 898 span = runs_add_span( span, xleft1, xleft2 ); 899 xleft1 = xleft2; 900 } 901 902 else if (xleft2 < xleft1) { 903 if (wanted & FLAG_REGION_2) 904 span = runs_add_span( span, xleft2, xleft1 ); 905 xleft2 = xleft1; 906 } 907 908 xright = (xright1 <= xright2) ? xright1 : xright2; 909 910 if (wanted & FLAG_REGION_BOTH) 911 span = runs_add_span( span, xleft1, xright ); 912 913 xleft1 = xleft2 = xright; 914 915 if (xright == xright1) { 916 span1 += 2; 917 xleft1 = span1[0]; 918 } 919 if (xright == xright2) { 920 span2 += 2; 921 xleft2 = span2[0]; 922 } 923 } 924 925 if (wanted & FLAG_REGION_1) { 926 while (xleft1 != XSENTINEL) { 927 RASSERT(span1[1] != XSENTINEL); 928 span[0] = (Run) xleft1; 929 span[1] = span1[1]; 930 span += 2; 931 span1 += 2; 932 xleft1 = span1[0]; 933 } 934 } 935 936 if (wanted & FLAG_REGION_2) { 937 while (xleft2 != XSENTINEL) { 938 RASSERT(span2[1] != XSENTINEL); 939 span[0] = (Run) xleft2; 940 span[1] = span2[1]; 941 span += 2; 942 span2 += 2; 943 xleft2 = span2[0]; 944 } 945 } 946 947 if (span > runs + 2) { 948 span[0] = XSENTINEL; 949 runs = span + 1; 950 } 951 } 952 953 ytop1 = ytop2 = ybot; 954 955 if (ybot == ybot1) { 956 runs1 = runs_next_scanline( runs1 ); 957 ytop1 = runs1[0]; 958 } 959 if (ybot == ybot2) { 960 runs2 = runs_next_scanline( runs2 ); 961 ytop2 = runs2[0]; 962 } 963 } 964 } 965 966 if ((wanted & FLAG_REGION_1) != 0) { 967 while (ytop1 != YSENTINEL) { 968 runs = runs_copy_scanline_adj( runs, runs1, ytop1, runs1[1] ); 969 runs1 = runs_next_scanline(runs1); 970 ytop1 = runs1[0]; 971 } 972 } 973 974 if ((wanted & FLAG_REGION_2) != 0) { 975 while (ytop2 != YSENTINEL) { 976 runs = runs_copy_scanline_adj( runs, runs2, ytop2, runs2[1] ); 977 runs2 = runs_next_scanline(runs2); 978 ytop2 = runs2[0]; 979 } 980 } 981 982 runs[0] = YSENTINEL; 983 o->runs = runs + 1; 984 } 985 986 /* returns 1 if the result is not empty */ 987 static int 988 region_operator_done( RegionOperator* o ) 989 { 990 Run* src = o->runs; 991 int count; 992 SkinBox minmax; 993 RunStore* store; 994 995 if (src <= o->runs_base + 1) { 996 /* result is empty */ 997 skin_region_init_empty( o->result ); 998 return 0; 999 } 1000 1001 /* coalesce the temp runs in-place and compute the corresponding bounds */ 1002 minmax.x1 = minmax.y1 = INT_MAX; 1003 minmax.x2 = minmax.y2 = INT_MIN; 1004 1005 count = runs_coalesce( o->runs_base, o->runs_base, &minmax ); 1006 if (count == 1) { 1007 /* result is empty */ 1008 skin_region_init_empty( o->result ); 1009 } 1010 else 1011 { 1012 skin_box_to_rect( &minmax, &o->result->bounds ); 1013 if (count == RUNS_RECT_COUNT) { 1014 o->result->runs = RUNS_RECT; 1015 } 1016 else 1017 { 1018 /* result is complex */ 1019 store = runstore_alloc( count ); 1020 o->result->runs = runstore_to_runs(store); 1021 memcpy( o->result->runs, o->runs_base, count*sizeof(Run) ); 1022 } 1023 } 1024 1025 /* release temporary runstore */ 1026 runstore_unrefp( &o->store ); 1027 1028 return region_isEmpty(o->result); 1029 } 1030 1031 1032 1033 int 1034 skin_region_intersect( SkinRegion* r, SkinRegion* r2 ) 1035 { 1036 RegionOperator oper[1]; 1037 1038 if (region_isEmpty(r)) 1039 return 0; 1040 1041 if (region_isEmpty(r2)) 1042 return 1; 1043 1044 if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) { 1045 skin_region_init_empty(r); 1046 return 0; 1047 } 1048 1049 region_operator_init( oper, r, r2 ); 1050 region_operator_do( oper, FLAG_REGION_BOTH ); 1051 region_operator_done( oper ); 1052 1053 skin_region_swap( r, oper->result ); 1054 skin_region_reset( oper->result ); 1055 1056 return region_isEmpty( r ); 1057 } 1058 1059 1060 /* performs r = (intersect r (region+_from_rect rect)), returns true iff 1061 the resulting region is not empty */ 1062 int 1063 skin_region_intersect_rect( SkinRegion* r, SkinRect* rect ) 1064 { 1065 Region r2[1]; 1066 1067 skin_region_init_rect( r2, rect ); 1068 return skin_region_intersect( r, r2 ); 1069 } 1070 1071 /* performs r = (union r r2) */ 1072 void 1073 skin_region_union( SkinRegion* r, SkinRegion* r2 ) 1074 { 1075 RegionOperator oper[1]; 1076 1077 if (region_isEmpty(r)) { 1078 skin_region_copy(r, r2); 1079 return; 1080 } 1081 1082 if (region_isEmpty(r2)) 1083 return; 1084 1085 region_operator_init( oper, r, r2 ); 1086 region_operator_do( oper, FLAG_REGION_1|FLAG_REGION_2|FLAG_REGION_BOTH ); 1087 region_operator_done( oper ); 1088 1089 skin_region_swap( r, oper->result ); 1090 skin_region_reset( oper->result ); 1091 } 1092 1093 void 1094 skin_region_union_rect( SkinRegion* r, SkinRect* rect ) 1095 { 1096 Region r2[1]; 1097 1098 skin_region_init_rect(r2, rect); 1099 return skin_region_union( r, r2 ); 1100 } 1101 1102 /* performs r = (difference r r2) */ 1103 void 1104 skin_region_substract( SkinRegion* r, SkinRegion* r2 ) 1105 { 1106 RegionOperator oper[1]; 1107 1108 if (region_isEmpty(r) || region_isEmpty(r2)) 1109 return; 1110 1111 if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) { 1112 skin_region_init_empty(r); 1113 return; 1114 } 1115 1116 region_operator_init( oper, r, r2 ); 1117 region_operator_do( oper, FLAG_REGION_1 ); 1118 region_operator_done( oper ); 1119 1120 skin_region_swap( r, oper->result ); 1121 skin_region_reset( oper->result ); 1122 } 1123 1124 void 1125 skin_region_substract_rect( SkinRegion* r, SkinRect* rect ) 1126 { 1127 Region r2[1]; 1128 1129 skin_region_init_rect(r2, rect); 1130 return skin_region_substract( r, r2 ); 1131 } 1132 1133 /* performs r = (xor r r2) */ 1134 void 1135 skin_region_xor( SkinRegion* r, SkinRegion* r2 ) 1136 { 1137 RegionOperator oper[1]; 1138 1139 if (region_isEmpty(r)) { 1140 skin_region_copy(r, r2); 1141 return; 1142 } 1143 1144 if (region_isEmpty(r2)) 1145 return; 1146 1147 if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) { 1148 skin_region_init_empty(r); 1149 return; 1150 } 1151 1152 region_operator_init( oper, r, r2 ); 1153 region_operator_do( oper, FLAG_REGION_1 ); 1154 region_operator_done( oper ); 1155 1156 skin_region_swap( r, oper->result ); 1157 skin_region_reset( oper->result ); 1158 } 1159 1160 1161 void 1162 skin_region_iterator_init( SkinRegionIterator* iter, 1163 SkinRegion* region ) 1164 { 1165 iter->region = region; 1166 iter->band = NULL; 1167 iter->span = NULL; 1168 } 1169 1170 int 1171 skin_region_iterator_next( SkinRegionIterator* iter, SkinRect *rect ) 1172 { 1173 static const Run dummy[ 2 ] = { XSENTINEL, YSENTINEL }; 1174 1175 Run* span = iter->span; 1176 Run* band = iter->band; 1177 1178 if (span == NULL) { 1179 Region* r = iter->region; 1180 if (region_isEmpty(r)) 1181 return 0; 1182 if (region_isRect(r)) { 1183 rect[0] = r->bounds; 1184 iter->span = (Run*) dummy; 1185 return 1; 1186 } 1187 iter->band = band = r->runs; 1188 iter->span = span = r->runs + 2; 1189 } 1190 else if (band == NULL) 1191 return 0; 1192 1193 while (span[0] == XSENTINEL) { 1194 band = span + 1; 1195 if (band[0] == YSENTINEL || band[1] == YSENTINEL) 1196 return 0; 1197 1198 iter->band = band; 1199 iter->span = span = band + 2; 1200 } 1201 1202 if (span[1] == XSENTINEL) 1203 return 0; 1204 1205 rect->pos.y = band[0]; 1206 rect->pos.x = span[0]; 1207 rect->size.h = band[1] - band[0]; 1208 rect->size.w = span[1] - span[0]; 1209 1210 iter->span = span + 2; 1211 return 1; 1212 } 1213 1214 int 1215 skin_region_iterator_next_box( SkinRegionIterator* iter, SkinBox *box ) 1216 { 1217 SkinRect rect; 1218 int result = skin_region_iterator_next( iter, &rect ); 1219 1220 if (result) 1221 skin_box_from_rect( box, &rect ); 1222 1223 return result; 1224 } 1225 1226 #ifdef UNIT_TEST 1227 1228 #include <stdio.h> 1229 #include <stdlib.h> 1230 #include "skin_rect.c" 1231 1232 static void 1233 panic(void) 1234 { 1235 *((char*)0) = 1; 1236 exit(0); 1237 } 1238 1239 static void 1240 _expectCompare( Region* r, const SkinBox* boxes, int count ) 1241 { 1242 if (count == 0) { 1243 if ( !skin_region_is_empty(r) ) { 1244 printf( " result is not empty\n" ); 1245 panic(); 1246 } 1247 } 1248 else if (count == 1) { 1249 SkinRect rect1, rect2; 1250 if ( !skin_region_is_rect(r) ) { 1251 printf( " result is not a rectangle\n" ); 1252 panic(); 1253 } 1254 skin_region_get_bounds( r, &rect1 ); 1255 skin_box_to_rect( (SkinBox*)boxes, &rect2 ); 1256 if ( !skin_rect_equals( &rect1, &rect2 ) ) { 1257 printf( " result is (%d,%d,%d,%d), expected (%d,%d,%d,%d)\n", 1258 rect1.pos.x, rect1.pos.y, 1259 rect1.pos.x + rect1.size.w, rect1.pos.y + rect1.size.h, 1260 rect2.pos.x, rect2.pos.y, 1261 rect2.pos.x + rect2.size.w, rect2.pos.y + rect2.size.h ); 1262 panic(); 1263 } 1264 } 1265 else { 1266 SkinRegionIterator iter; 1267 SkinBox b; 1268 int n; 1269 1270 skin_region_iterator_init( &iter, r ); 1271 n = 0; 1272 while (n < count) { 1273 if ( !skin_region_iterator_next_box( &iter, &b ) ) { 1274 printf( "missing region box (%d, %d, %d, %d)\n", 1275 boxes->x1, boxes->y1, boxes->x2, boxes->y2 ); 1276 panic(); 1277 } 1278 1279 if (b.x1 != boxes->x1 || b.x2 != boxes->x2|| 1280 b.y1 != boxes->y1 || b.y2 != boxes->y2) 1281 { 1282 printf( "invalid region box (%d,%d,%d,%d) expecting (%d,%d,%d,%d)\n", 1283 b.x1, b.y1, b.x2, b.y2, 1284 boxes->x1, boxes->y1, boxes->x2, boxes->y2 ); 1285 panic(); 1286 } 1287 boxes += 1; 1288 n += 1; 1289 } 1290 1291 if ( skin_region_iterator_next_box( &iter, &b ) ) { 1292 printf( "excess region box (%d,%d,%d,%d)\n", 1293 b.x1, b.y1, b.x2, b.y2 ); 1294 panic(); 1295 } 1296 } 1297 } 1298 1299 1300 static void 1301 expectEmptyRegion( Region* r ) 1302 { 1303 printf( "expectEmptyRegion: " ); 1304 if (!skin_region_is_empty(r)) { 1305 printf( "region not empty !!\n" ); 1306 panic(); 1307 } 1308 printf( "ok\n" ); 1309 } 1310 1311 static void 1312 expectTestIntersect( Region* r1, Region* r2, SkinOverlap overlap ) 1313 { 1314 SkinOverlap result; 1315 printf( "expectTestIntersect(%d): ", overlap ); 1316 result = skin_region_test_intersect(r1, r2); 1317 if (result != overlap) { 1318 printf( "bad result %d, expected %d\n", result, overlap ); 1319 panic(); 1320 } 1321 printf( "ok\n" ); 1322 } 1323 1324 static void 1325 expectRectRegion( Region* r, int x1, int y1, int x2, int y2 ) 1326 { 1327 SkinRect rect; 1328 SkinBox b; 1329 1330 printf( "expectRectRegion(%d,%d,%d,%d): ",x1,y1,x2,y2 ); 1331 if (!skin_region_is_rect(r)) { 1332 printf( "region not rect !!\n" ); 1333 panic(); 1334 } 1335 1336 skin_region_get_bounds( r, &rect ); 1337 skin_box_from_rect( &b, &rect ); 1338 1339 if (b.x1 != x1 || b.x2 != x2 || b.y1 != y1 || b.y2 != y2) { 1340 printf( "rect region bounds are (%d,%d,%d,%d), expecting (%d,%d,%d,%d)\n", 1341 b.x1, b.y1, b.x2, b.y2, x1, y1, x2, y2 ); 1342 panic(); 1343 } 1344 printf( "ok\n" ); 1345 } 1346 1347 static void 1348 expectComplexRegion( Region* r, const SkinBox* boxes, int count ) 1349 { 1350 SkinRegionIterator iter; 1351 SkinBox b; 1352 int n; 1353 1354 printf( "expectComplexRegion(): " ); 1355 if (!skin_region_is_complex(r)) { 1356 printf( "region is not complex !!\n" ); 1357 panic(); 1358 } 1359 _expectCompare( r, boxes, count ); 1360 printf( "ok\n" ); 1361 } 1362 1363 static void 1364 expectIntersect( Region* r1, Region* r2, const SkinBox* boxes, int count ) 1365 { 1366 SkinRegion r[1]; 1367 1368 printf( "expectIntersect(%d): ", count ); 1369 skin_region_init_copy( r, r1 ); 1370 skin_region_intersect( r, r2 ); 1371 _expectCompare( r, boxes, count ); 1372 printf( "ok\n" ); 1373 } 1374 1375 static void 1376 expectUnion( Region* r1, Region* r2, const SkinBox* boxes, int count ) 1377 { 1378 SkinRegion r[1]; 1379 1380 printf( "expectUnion(%d): ", count ); 1381 skin_region_init_copy( r, r1 ); 1382 skin_region_union( r, r2 ); 1383 _expectCompare( r, boxes, count ); 1384 printf( "ok\n" ); 1385 } 1386 1387 1388 static void 1389 expectSubstract( Region* r1, Region* r2, const SkinBox* boxes, int count ) 1390 { 1391 SkinRegion r[1]; 1392 1393 printf( "expectSubstract(%d): ", count ); 1394 skin_region_init_copy( r, r1 ); 1395 skin_region_substract( r, r2 ); 1396 _expectCompare( r, boxes, count ); 1397 printf( "ok\n" ); 1398 } 1399 1400 1401 int main( void ) 1402 { 1403 SkinRegion r[1], r2[1]; 1404 1405 skin_region_init_empty( r ); 1406 expectEmptyRegion( r ); 1407 1408 skin_region_init( r, 10, 20, 110, 120 ); 1409 expectRectRegion( r, 10, 20, 110, 120 ); 1410 1411 skin_region_translate( r, 50, 80 ); 1412 expectRectRegion( r, 60, 100, 160, 200 ); 1413 1414 skin_region_init( r, 10, 10, 40, 40 ); 1415 skin_region_init( r2, 20, 20, 50, 50 ); 1416 expectTestIntersect( r, r2, SKIN_OVERLAP ); 1417 1418 skin_region_translate(r2, +20, + 20 ); 1419 expectTestIntersect( r, r2, SKIN_OUTSIDE ); 1420 1421 skin_region_translate(r2, -30, -30 ); 1422 expectTestIntersect( r, r2, SKIN_INSIDE ); 1423 1424 { 1425 static const SkinBox result1[1] = { 1426 { 20, 20, 40, 40 } 1427 }; 1428 static const SkinBox result2[3] = { 1429 { 10, 10, 40, 20 }, 1430 { 10, 20, 50, 40 }, 1431 { 20, 40, 50, 50 }, 1432 }; 1433 static const SkinBox result3[2] = { 1434 { 10, 10, 40, 20 }, 1435 { 10, 20, 20, 40 }, 1436 }; 1437 1438 skin_region_init( r, 10, 10, 40, 40 ); 1439 skin_region_init( r2, 20, 20, 50, 50 ); 1440 expectIntersect( r, r2, result1, 1 ); 1441 expectUnion( r, r2, result2, 3 ); 1442 expectSubstract( r, r2, result3, 2 ); 1443 } 1444 1445 return 0; 1446 } 1447 1448 #endif /* UNIT_TEST */ 1449