1/* -=- sraRegion.c 2 * Copyright (c) 2001 James "Wez" Weatherall, Johannes E. Schindelin 3 * 4 * A general purpose region clipping library 5 * Only deals with rectangular regions, though. 6 */ 7 8#include <rfb/rfb.h> 9#include <rfb/rfbregion.h> 10 11/* -=- Internal Span structure */ 12 13struct sraRegion; 14 15typedef struct sraSpan { 16 struct sraSpan *_next; 17 struct sraSpan *_prev; 18 int start; 19 int end; 20 struct sraRegion *subspan; 21} sraSpan; 22 23typedef struct sraRegion { 24 sraSpan front; 25 sraSpan back; 26} sraSpanList; 27 28/* -=- Span routines */ 29 30sraSpanList *sraSpanListDup(const sraSpanList *src); 31void sraSpanListDestroy(sraSpanList *list); 32 33static sraSpan * 34sraSpanCreate(int start, int end, const sraSpanList *subspan) { 35 sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan)); 36 item->_next = item->_prev = NULL; 37 item->start = start; 38 item->end = end; 39 item->subspan = sraSpanListDup(subspan); 40 return item; 41} 42 43static sraSpan * 44sraSpanDup(const sraSpan *src) { 45 sraSpan *span; 46 if (!src) return NULL; 47 span = sraSpanCreate(src->start, src->end, src->subspan); 48 return span; 49} 50 51static void 52sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) { 53 newspan->_next = after->_next; 54 newspan->_prev = after; 55 after->_next->_prev = newspan; 56 after->_next = newspan; 57} 58 59static void 60sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) { 61 newspan->_next = before; 62 newspan->_prev = before->_prev; 63 before->_prev->_next = newspan; 64 before->_prev = newspan; 65} 66 67static void 68sraSpanRemove(sraSpan *span) { 69 span->_prev->_next = span->_next; 70 span->_next->_prev = span->_prev; 71} 72 73static void 74sraSpanDestroy(sraSpan *span) { 75 if (span->subspan) sraSpanListDestroy(span->subspan); 76 free(span); 77} 78 79#ifdef DEBUG 80static void 81sraSpanCheck(const sraSpan *span, const char *text) { 82 /* Check the span is valid! */ 83 if (span->start == span->end) { 84 printf(text); 85 printf(":%d-%d\n", span->start, span->end); 86 } 87} 88#endif 89 90/* -=- SpanList routines */ 91 92static void sraSpanPrint(const sraSpan *s); 93 94static void 95sraSpanListPrint(const sraSpanList *l) { 96 sraSpan *curr; 97 if (!l) { 98 printf("NULL"); 99 return; 100 } 101 curr = l->front._next; 102 printf("["); 103 while (curr != &(l->back)) { 104 sraSpanPrint(curr); 105 curr = curr->_next; 106 } 107 printf("]"); 108} 109 110void 111sraSpanPrint(const sraSpan *s) { 112 printf("(%d-%d)", (s->start), (s->end)); 113 if (s->subspan) 114 sraSpanListPrint(s->subspan); 115} 116 117static sraSpanList * 118sraSpanListCreate(void) { 119 sraSpanList *item = (sraSpanList*)malloc(sizeof(sraSpanList)); 120 item->front._next = &(item->back); 121 item->front._prev = NULL; 122 item->back._prev = &(item->front); 123 item->back._next = NULL; 124 return item; 125} 126 127sraSpanList * 128sraSpanListDup(const sraSpanList *src) { 129 sraSpanList *newlist; 130 sraSpan *newspan, *curr; 131 132 if (!src) return NULL; 133 newlist = sraSpanListCreate(); 134 curr = src->front._next; 135 while (curr != &(src->back)) { 136 newspan = sraSpanDup(curr); 137 sraSpanInsertBefore(newspan, &(newlist->back)); 138 curr = curr->_next; 139 } 140 141 return newlist; 142} 143 144void 145sraSpanListDestroy(sraSpanList *list) { 146 sraSpan *curr, *next; 147 while (list->front._next != &(list->back)) { 148 curr = list->front._next; 149 next = curr->_next; 150 sraSpanRemove(curr); 151 sraSpanDestroy(curr); 152 curr = next; 153 } 154 free(list); 155} 156 157static void 158sraSpanListMakeEmpty(sraSpanList *list) { 159 sraSpan *curr, *next; 160 while (list->front._next != &(list->back)) { 161 curr = list->front._next; 162 next = curr->_next; 163 sraSpanRemove(curr); 164 sraSpanDestroy(curr); 165 curr = next; 166 } 167 list->front._next = &(list->back); 168 list->front._prev = NULL; 169 list->back._prev = &(list->front); 170 list->back._next = NULL; 171} 172 173static rfbBool 174sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) { 175 sraSpan *sp1, *sp2; 176 177 if (!s1) { 178 if (!s2) { 179 return 1; 180 } else { 181 rfbErr("sraSpanListEqual:incompatible spans (only one NULL!)\n"); 182 return FALSE; 183 } 184 } 185 186 sp1 = s1->front._next; 187 sp2 = s2->front._next; 188 while ((sp1 != &(s1->back)) && 189 (sp2 != &(s2->back))) { 190 if ((sp1->start != sp2->start) || 191 (sp1->end != sp2->end) || 192 (!sraSpanListEqual(sp1->subspan, sp2->subspan))) { 193 return 0; 194 } 195 sp1 = sp1->_next; 196 sp2 = sp2->_next; 197 } 198 199 if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) { 200 return 1; 201 } else { 202 return 0; 203 } 204} 205 206static rfbBool 207sraSpanListEmpty(const sraSpanList *list) { 208 return (list->front._next == &(list->back)); 209} 210 211static unsigned long 212sraSpanListCount(const sraSpanList *list) { 213 sraSpan *curr = list->front._next; 214 unsigned long count = 0; 215 while (curr != &(list->back)) { 216 if (curr->subspan) { 217 count += sraSpanListCount(curr->subspan); 218 } else { 219 count += 1; 220 } 221 curr = curr->_next; 222 } 223 return count; 224} 225 226static void 227sraSpanMergePrevious(sraSpan *dest) { 228 sraSpan *prev = dest->_prev; 229 230 while ((prev->_prev) && 231 (prev->end == dest->start) && 232 (sraSpanListEqual(prev->subspan, dest->subspan))) { 233 /* 234 printf("merge_prev:"); 235 sraSpanPrint(prev); 236 printf(" & "); 237 sraSpanPrint(dest); 238 printf("\n"); 239 */ 240 dest->start = prev->start; 241 sraSpanRemove(prev); 242 sraSpanDestroy(prev); 243 prev = dest->_prev; 244 } 245} 246 247static void 248sraSpanMergeNext(sraSpan *dest) { 249 sraSpan *next = dest->_next; 250 while ((next->_next) && 251 (next->start == dest->end) && 252 (sraSpanListEqual(next->subspan, dest->subspan))) { 253/* 254 printf("merge_next:"); 255 sraSpanPrint(dest); 256 printf(" & "); 257 sraSpanPrint(next); 258 printf("\n"); 259 */ 260 dest->end = next->end; 261 sraSpanRemove(next); 262 sraSpanDestroy(next); 263 next = dest->_next; 264 } 265} 266 267static void 268sraSpanListOr(sraSpanList *dest, const sraSpanList *src) { 269 sraSpan *d_curr, *s_curr; 270 int s_start, s_end; 271 272 if (!dest) { 273 if (!src) { 274 return; 275 } else { 276 rfbErr("sraSpanListOr:incompatible spans (only one NULL!)\n"); 277 return; 278 } 279 } 280 281 d_curr = dest->front._next; 282 s_curr = src->front._next; 283 s_start = s_curr->start; 284 s_end = s_curr->end; 285 while (s_curr != &(src->back)) { 286 287 /* - If we are at end of destination list OR 288 If the new span comes before the next destination one */ 289 if ((d_curr == &(dest->back)) || 290 (d_curr->start >= s_end)) { 291 /* - Add the span */ 292 sraSpanInsertBefore(sraSpanCreate(s_start, s_end, 293 s_curr->subspan), 294 d_curr); 295 if (d_curr != &(dest->back)) 296 sraSpanMergePrevious(d_curr); 297 s_curr = s_curr->_next; 298 s_start = s_curr->start; 299 s_end = s_curr->end; 300 } else { 301 302 /* - If the new span overlaps the existing one */ 303 if ((s_start < d_curr->end) && 304 (s_end > d_curr->start)) { 305 306 /* - Insert new span before the existing destination one? */ 307 if (s_start < d_curr->start) { 308 sraSpanInsertBefore(sraSpanCreate(s_start, 309 d_curr->start, 310 s_curr->subspan), 311 d_curr); 312 sraSpanMergePrevious(d_curr); 313 } 314 315 /* Split the existing span if necessary */ 316 if (s_end < d_curr->end) { 317 sraSpanInsertAfter(sraSpanCreate(s_end, 318 d_curr->end, 319 d_curr->subspan), 320 d_curr); 321 d_curr->end = s_end; 322 } 323 if (s_start > d_curr->start) { 324 sraSpanInsertBefore(sraSpanCreate(d_curr->start, 325 s_start, 326 d_curr->subspan), 327 d_curr); 328 d_curr->start = s_start; 329 } 330 331 /* Recursively OR subspans */ 332 sraSpanListOr(d_curr->subspan, s_curr->subspan); 333 334 /* Merge this span with previous or next? */ 335 if (d_curr->_prev != &(dest->front)) 336 sraSpanMergePrevious(d_curr); 337 if (d_curr->_next != &(dest->back)) 338 sraSpanMergeNext(d_curr); 339 340 /* Move onto the next pair to compare */ 341 if (s_end > d_curr->end) { 342 s_start = d_curr->end; 343 d_curr = d_curr->_next; 344 } else { 345 s_curr = s_curr->_next; 346 s_start = s_curr->start; 347 s_end = s_curr->end; 348 } 349 } else { 350 /* - No overlap. Move to the next destination span */ 351 d_curr = d_curr->_next; 352 } 353 } 354 } 355} 356 357static rfbBool 358sraSpanListAnd(sraSpanList *dest, const sraSpanList *src) { 359 sraSpan *d_curr, *s_curr, *d_next; 360 361 if (!dest) { 362 if (!src) { 363 return 1; 364 } else { 365 rfbErr("sraSpanListAnd:incompatible spans (only one NULL!)\n"); 366 return FALSE; 367 } 368 } 369 370 d_curr = dest->front._next; 371 s_curr = src->front._next; 372 while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) { 373 374 /* - If we haven't reached a destination span yet then move on */ 375 if (d_curr->start >= s_curr->end) { 376 s_curr = s_curr->_next; 377 continue; 378 } 379 380 /* - If we are beyond the current destination span then remove it */ 381 if (d_curr->end <= s_curr->start) { 382 sraSpan *next = d_curr->_next; 383 sraSpanRemove(d_curr); 384 sraSpanDestroy(d_curr); 385 d_curr = next; 386 continue; 387 } 388 389 /* - If we partially overlap a span then split it up or remove bits */ 390 if (s_curr->start > d_curr->start) { 391 /* - The top bit of the span does not match */ 392 d_curr->start = s_curr->start; 393 } 394 if (s_curr->end < d_curr->end) { 395 /* - The end of the span does not match */ 396 sraSpanInsertAfter(sraSpanCreate(s_curr->end, 397 d_curr->end, 398 d_curr->subspan), 399 d_curr); 400 d_curr->end = s_curr->end; 401 } 402 403 /* - Now recursively process the affected span */ 404 if (!sraSpanListAnd(d_curr->subspan, s_curr->subspan)) { 405 /* - The destination subspan is now empty, so we should remove it */ 406 sraSpan *next = d_curr->_next; 407 sraSpanRemove(d_curr); 408 sraSpanDestroy(d_curr); 409 d_curr = next; 410 } else { 411 /* Merge this span with previous or next? */ 412 if (d_curr->_prev != &(dest->front)) 413 sraSpanMergePrevious(d_curr); 414 415 /* - Move on to the next span */ 416 d_next = d_curr; 417 if (s_curr->end >= d_curr->end) { 418 d_next = d_curr->_next; 419 } 420 if (s_curr->end <= d_curr->end) { 421 s_curr = s_curr->_next; 422 } 423 d_curr = d_next; 424 } 425 } 426 427 while (d_curr != &(dest->back)) { 428 sraSpan *next = d_curr->_next; 429 sraSpanRemove(d_curr); 430 sraSpanDestroy(d_curr); 431 d_curr=next; 432 } 433 434 return !sraSpanListEmpty(dest); 435} 436 437static rfbBool 438sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) { 439 sraSpan *d_curr, *s_curr; 440 441 if (!dest) { 442 if (!src) { 443 return 1; 444 } else { 445 rfbErr("sraSpanListSubtract:incompatible spans (only one NULL!)\n"); 446 return FALSE; 447 } 448 } 449 450 d_curr = dest->front._next; 451 s_curr = src->front._next; 452 while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) { 453 454 /* - If we haven't reached a destination span yet then move on */ 455 if (d_curr->start >= s_curr->end) { 456 s_curr = s_curr->_next; 457 continue; 458 } 459 460 /* - If we are beyond the current destination span then skip it */ 461 if (d_curr->end <= s_curr->start) { 462 d_curr = d_curr->_next; 463 continue; 464 } 465 466 /* - If we partially overlap the current span then split it up */ 467 if (s_curr->start > d_curr->start) { 468 sraSpanInsertBefore(sraSpanCreate(d_curr->start, 469 s_curr->start, 470 d_curr->subspan), 471 d_curr); 472 d_curr->start = s_curr->start; 473 } 474 if (s_curr->end < d_curr->end) { 475 sraSpanInsertAfter(sraSpanCreate(s_curr->end, 476 d_curr->end, 477 d_curr->subspan), 478 d_curr); 479 d_curr->end = s_curr->end; 480 } 481 482 /* - Now recursively process the affected span */ 483 if ((!d_curr->subspan) || !sraSpanListSubtract(d_curr->subspan, s_curr->subspan)) { 484 /* - The destination subspan is now empty, so we should remove it */ 485 sraSpan *next = d_curr->_next; 486 sraSpanRemove(d_curr); 487 sraSpanDestroy(d_curr); 488 d_curr = next; 489 } else { 490 /* Merge this span with previous or next? */ 491 if (d_curr->_prev != &(dest->front)) 492 sraSpanMergePrevious(d_curr); 493 if (d_curr->_next != &(dest->back)) 494 sraSpanMergeNext(d_curr); 495 496 /* - Move on to the next span */ 497 if (s_curr->end > d_curr->end) { 498 d_curr = d_curr->_next; 499 } else { 500 s_curr = s_curr->_next; 501 } 502 } 503 } 504 505 return !sraSpanListEmpty(dest); 506} 507 508/* -=- Region routines */ 509 510sraRegion * 511sraRgnCreate(void) { 512 return (sraRegion*)sraSpanListCreate(); 513} 514 515sraRegion * 516sraRgnCreateRect(int x1, int y1, int x2, int y2) { 517 sraSpanList *vlist, *hlist; 518 sraSpan *vspan, *hspan; 519 520 /* - Build the horizontal portion of the span */ 521 hlist = sraSpanListCreate(); 522 hspan = sraSpanCreate(x1, x2, NULL); 523 sraSpanInsertAfter(hspan, &(hlist->front)); 524 525 /* - Build the vertical portion of the span */ 526 vlist = sraSpanListCreate(); 527 vspan = sraSpanCreate(y1, y2, hlist); 528 sraSpanInsertAfter(vspan, &(vlist->front)); 529 530 sraSpanListDestroy(hlist); 531 532 return (sraRegion*)vlist; 533} 534 535sraRegion * 536sraRgnCreateRgn(const sraRegion *src) { 537 return (sraRegion*)sraSpanListDup((sraSpanList*)src); 538} 539 540void 541sraRgnDestroy(sraRegion *rgn) { 542 sraSpanListDestroy((sraSpanList*)rgn); 543} 544 545void 546sraRgnMakeEmpty(sraRegion *rgn) { 547 sraSpanListMakeEmpty((sraSpanList*)rgn); 548} 549 550/* -=- Boolean Region ops */ 551 552rfbBool 553sraRgnAnd(sraRegion *dst, const sraRegion *src) { 554 return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src); 555} 556 557void 558sraRgnOr(sraRegion *dst, const sraRegion *src) { 559 sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src); 560} 561 562rfbBool 563sraRgnSubtract(sraRegion *dst, const sraRegion *src) { 564 return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src); 565} 566 567void 568sraRgnOffset(sraRegion *dst, int dx, int dy) { 569 sraSpan *vcurr, *hcurr; 570 571 vcurr = ((sraSpanList*)dst)->front._next; 572 while (vcurr != &(((sraSpanList*)dst)->back)) { 573 vcurr->start += dy; 574 vcurr->end += dy; 575 576 hcurr = vcurr->subspan->front._next; 577 while (hcurr != &(vcurr->subspan->back)) { 578 hcurr->start += dx; 579 hcurr->end += dx; 580 hcurr = hcurr->_next; 581 } 582 583 vcurr = vcurr->_next; 584 } 585} 586 587sraRegion *sraRgnBBox(const sraRegion *src) { 588 int xmin=((unsigned int)(int)-1)>>1,ymin=xmin,xmax=1-xmin,ymax=xmax; 589 sraSpan *vcurr, *hcurr; 590 591 if(!src) 592 return sraRgnCreate(); 593 594 vcurr = ((sraSpanList*)src)->front._next; 595 while (vcurr != &(((sraSpanList*)src)->back)) { 596 if(vcurr->start<ymin) 597 ymin=vcurr->start; 598 if(vcurr->end>ymax) 599 ymax=vcurr->end; 600 601 hcurr = vcurr->subspan->front._next; 602 while (hcurr != &(vcurr->subspan->back)) { 603 if(hcurr->start<xmin) 604 xmin=hcurr->start; 605 if(hcurr->end>xmax) 606 xmax=hcurr->end; 607 hcurr = hcurr->_next; 608 } 609 610 vcurr = vcurr->_next; 611 } 612 613 if(xmax<xmin || ymax<ymin) 614 return sraRgnCreate(); 615 616 return sraRgnCreateRect(xmin,ymin,xmax,ymax); 617} 618 619rfbBool 620sraRgnPopRect(sraRegion *rgn, sraRect *rect, unsigned long flags) { 621 sraSpan *vcurr, *hcurr; 622 sraSpan *vend, *hend; 623 rfbBool right2left = (flags & 2) == 2; 624 rfbBool bottom2top = (flags & 1) == 1; 625 626 /* - Pick correct order */ 627 if (bottom2top) { 628 vcurr = ((sraSpanList*)rgn)->back._prev; 629 vend = &(((sraSpanList*)rgn)->front); 630 } else { 631 vcurr = ((sraSpanList*)rgn)->front._next; 632 vend = &(((sraSpanList*)rgn)->back); 633 } 634 635 if (vcurr != vend) { 636 rect->y1 = vcurr->start; 637 rect->y2 = vcurr->end; 638 639 /* - Pick correct order */ 640 if (right2left) { 641 hcurr = vcurr->subspan->back._prev; 642 hend = &(vcurr->subspan->front); 643 } else { 644 hcurr = vcurr->subspan->front._next; 645 hend = &(vcurr->subspan->back); 646 } 647 648 if (hcurr != hend) { 649 rect->x1 = hcurr->start; 650 rect->x2 = hcurr->end; 651 652 sraSpanRemove(hcurr); 653 sraSpanDestroy(hcurr); 654 655 if (sraSpanListEmpty(vcurr->subspan)) { 656 sraSpanRemove(vcurr); 657 sraSpanDestroy(vcurr); 658 } 659 660#if 0 661 printf("poprect:(%dx%d)-(%dx%d)\n", 662 rect->x1, rect->y1, rect->x2, rect->y2); 663#endif 664 return 1; 665 } 666 } 667 668 return 0; 669} 670 671unsigned long 672sraRgnCountRects(const sraRegion *rgn) { 673 unsigned long count = sraSpanListCount((sraSpanList*)rgn); 674 return count; 675} 676 677rfbBool 678sraRgnEmpty(const sraRegion *rgn) { 679 return sraSpanListEmpty((sraSpanList*)rgn); 680} 681 682/* iterator stuff */ 683sraRectangleIterator *sraRgnGetIterator(sraRegion *s) 684{ 685 /* these values have to be multiples of 4 */ 686#define DEFSIZE 4 687#define DEFSTEP 8 688 sraRectangleIterator *i = 689 (sraRectangleIterator*)malloc(sizeof(sraRectangleIterator)); 690 if(!i) 691 return NULL; 692 693 /* we have to recurse eventually. So, the first sPtr is the pointer to 694 the sraSpan in the first level. the second sPtr is the pointer to 695 the sraRegion.back. The third and fourth sPtr are for the second 696 recursion level and so on. */ 697 i->sPtrs = (sraSpan**)malloc(sizeof(sraSpan*)*DEFSIZE); 698 if(!i->sPtrs) { 699 free(i); 700 return NULL; 701 } 702 i->ptrSize = DEFSIZE; 703 i->sPtrs[0] = &(s->front); 704 i->sPtrs[1] = &(s->back); 705 i->ptrPos = 0; 706 i->reverseX = 0; 707 i->reverseY = 0; 708 return i; 709} 710 711sraRectangleIterator *sraRgnGetReverseIterator(sraRegion *s,rfbBool reverseX,rfbBool reverseY) 712{ 713 sraRectangleIterator *i = sraRgnGetIterator(s); 714 if(reverseY) { 715 i->sPtrs[1] = &(s->front); 716 i->sPtrs[0] = &(s->back); 717 } 718 i->reverseX = reverseX; 719 i->reverseY = reverseY; 720 return(i); 721} 722 723static rfbBool sraReverse(sraRectangleIterator *i) 724{ 725 return( ((i->ptrPos&2) && i->reverseX) || 726 (!(i->ptrPos&2) && i->reverseY)); 727} 728 729static sraSpan* sraNextSpan(sraRectangleIterator *i) 730{ 731 if(sraReverse(i)) 732 return(i->sPtrs[i->ptrPos]->_prev); 733 else 734 return(i->sPtrs[i->ptrPos]->_next); 735} 736 737rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r) 738{ 739 /* is the subspan finished? */ 740 while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) { 741 i->ptrPos -= 2; 742 if(i->ptrPos < 0) /* the end */ 743 return(0); 744 } 745 746 i->sPtrs[i->ptrPos] = sraNextSpan(i); 747 748 /* is this a new subspan? */ 749 while(i->sPtrs[i->ptrPos]->subspan) { 750 if(i->ptrPos+2 > i->ptrSize) { /* array is too small */ 751 i->ptrSize += DEFSTEP; 752 i->sPtrs = (sraSpan**)realloc(i->sPtrs, sizeof(sraSpan*)*i->ptrSize); 753 } 754 i->ptrPos += 2; 755 if(sraReverse(i)) { 756 i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->back._prev; 757 i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->front); 758 } else { 759 i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->front._next; 760 i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->back); 761 } 762 } 763 764 if((i->ptrPos%4)!=2) { 765 rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos); 766 return FALSE; 767 } 768 769 r->y1 = i->sPtrs[i->ptrPos-2]->start; 770 r->y2 = i->sPtrs[i->ptrPos-2]->end; 771 r->x1 = i->sPtrs[i->ptrPos]->start; 772 r->x2 = i->sPtrs[i->ptrPos]->end; 773 774 return(-1); 775} 776 777void sraRgnReleaseIterator(sraRectangleIterator* i) 778{ 779 free(i->sPtrs); 780 free(i); 781} 782 783void 784sraRgnPrint(const sraRegion *rgn) { 785 sraSpanListPrint((sraSpanList*)rgn); 786} 787 788rfbBool 789sraClipRect(int *x, int *y, int *w, int *h, 790 int cx, int cy, int cw, int ch) { 791 if (*x < cx) { 792 *w -= (cx-*x); 793 *x = cx; 794 } 795 if (*y < cy) { 796 *h -= (cy-*y); 797 *y = cy; 798 } 799 if (*x+*w > cx+cw) { 800 *w = (cx+cw)-*x; 801 } 802 if (*y+*h > cy+ch) { 803 *h = (cy+ch)-*y; 804 } 805 return (*w>0) && (*h>0); 806} 807 808rfbBool 809sraClipRect2(int *x, int *y, int *x2, int *y2, 810 int cx, int cy, int cx2, int cy2) { 811 if (*x < cx) 812 *x = cx; 813 if (*y < cy) 814 *y = cy; 815 if (*x >= cx2) 816 *x = cx2-1; 817 if (*y >= cy2) 818 *y = cy2-1; 819 if (*x2 <= cx) 820 *x2 = cx+1; 821 if (*y2 <= cy) 822 *y2 = cy+1; 823 if (*x2 > cx2) 824 *x2 = cx2; 825 if (*y2 > cy2) 826 *y2 = cy2; 827 return (*x2>*x) && (*y2>*y); 828} 829 830/* test */ 831 832#ifdef SRA_TEST 833/* pipe the output to sort|uniq -u and you'll get the errors. */ 834int main(int argc, char** argv) 835{ 836 sraRegionPtr region, region1, region2; 837 sraRectangleIterator* i; 838 sraRect rect; 839 rfbBool b; 840 841 region = sraRgnCreateRect(10, 10, 600, 300); 842 region1 = sraRgnCreateRect(40, 50, 350, 200); 843 region2 = sraRgnCreateRect(0, 0, 20, 40); 844 845 sraRgnPrint(region); 846 printf("\n[(10-300)[(10-600)]]\n\n"); 847 848 b = sraRgnSubtract(region, region1); 849 printf("%s ",b?"true":"false"); 850 sraRgnPrint(region); 851 printf("\ntrue [(10-50)[(10-600)](50-200)[(10-40)(350-600)](200-300)[(10-600)]]\n\n"); 852 853 sraRgnOr(region, region2); 854 printf("%ld\n6\n\n", sraRgnCountRects(region)); 855 856 i = sraRgnGetIterator(region); 857 while(sraRgnIteratorNext(i, &rect)) 858 printf("%dx%d+%d+%d ", 859 rect.x2-rect.x1,rect.y2-rect.y1, 860 rect.x1,rect.y1); 861 sraRgnReleaseIterator(i); 862 printf("\n20x10+0+0 600x30+0+10 590x10+10+40 30x150+10+50 250x150+350+50 590x100+10+200 \n\n"); 863 864 i = sraRgnGetReverseIterator(region,1,0); 865 while(sraRgnIteratorNext(i, &rect)) 866 printf("%dx%d+%d+%d ", 867 rect.x2-rect.x1,rect.y2-rect.y1, 868 rect.x1,rect.y1); 869 sraRgnReleaseIterator(i); 870 printf("\n20x10+0+0 600x30+0+10 590x10+10+40 250x150+350+50 30x150+10+50 590x100+10+200 \n\n"); 871 872 i = sraRgnGetReverseIterator(region,1,1); 873 while(sraRgnIteratorNext(i, &rect)) 874 printf("%dx%d+%d+%d ", 875 rect.x2-rect.x1,rect.y2-rect.y1, 876 rect.x1,rect.y1); 877 sraRgnReleaseIterator(i); 878 printf("\n590x100+10+200 250x150+350+50 30x150+10+50 590x10+10+40 600x30+0+10 20x10+0+0 \n\n"); 879 880 sraRgnDestroy(region); 881 sraRgnDestroy(region1); 882 sraRgnDestroy(region2); 883 884 return(0); 885} 886#endif 887