2 * Copyright (c) 2001 James "Wez" Weatherall, Johannes E. Schindelin
4 * A general purpose region clipping library
5 * Only deals with rectangular regions, though.
9 #include <rfb/rfbregion.h>
11 /* -=- Internal Span structure */
15 typedef struct sraSpan {
16 struct sraSpan *_next;
17 struct sraSpan *_prev;
20 struct sraRegion *subspan;
23 typedef struct sraRegion {
28 /* -=- Span routines */
30 sraSpanList *sraSpanListDup(const sraSpanList *src);
31 void sraSpanListDestroy(sraSpanList *list);
34 sraSpanCreate(int start, int end, const sraSpanList *subspan) {
35 sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan));
36 item->_next = item->_prev = NULL;
39 item->subspan = sraSpanListDup(subspan);
44 sraSpanDup(const sraSpan *src) {
46 if (!src) return NULL;
47 span = sraSpanCreate(src->start, src->end, src->subspan);
52 sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) {
53 newspan->_next = after->_next;
54 newspan->_prev = after;
55 after->_next->_prev = newspan;
56 after->_next = newspan;
60 sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) {
61 newspan->_next = before;
62 newspan->_prev = before->_prev;
63 before->_prev->_next = newspan;
64 before->_prev = newspan;
68 sraSpanRemove(sraSpan *span) {
69 span->_prev->_next = span->_next;
70 span->_next->_prev = span->_prev;
74 sraSpanDestroy(sraSpan *span) {
75 if (span->subspan) sraSpanListDestroy(span->subspan);
81 sraSpanCheck(const sraSpan *span, const char *text) {
82 /* Check the span is valid! */
83 if (span->start == span->end) {
85 printf(":%d-%d\n", span->start, span->end);
90 /* -=- SpanList routines */
92 static void sraSpanPrint(const sraSpan *s);
95 sraSpanListPrint(const sraSpanList *l) {
101 curr = l->front._next;
103 while (curr != &(l->back)) {
111 sraSpanPrint(const sraSpan *s) {
112 printf("(%d-%d)", (s->start), (s->end));
114 sraSpanListPrint(s->subspan);
118 sraSpanListCreate(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;
128 sraSpanListDup(const sraSpanList *src) {
129 sraSpanList *newlist;
130 sraSpan *newspan, *curr;
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));
145 sraSpanListDestroy(sraSpanList *list) {
146 sraSpan *curr, *next;
147 while (list->front._next != &(list->back)) {
148 curr = list->front._next;
151 sraSpanDestroy(curr);
158 sraSpanListMakeEmpty(sraSpanList *list) {
159 sraSpan *curr, *next;
160 while (list->front._next != &(list->back)) {
161 curr = list->front._next;
164 sraSpanDestroy(curr);
167 list->front._next = &(list->back);
168 list->front._prev = NULL;
169 list->back._prev = &(list->front);
170 list->back._next = NULL;
174 sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) {
181 rfbErr("sraSpanListEqual:incompatible spans (only one NULL!)\n");
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))) {
199 if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) {
207 sraSpanListEmpty(const sraSpanList *list) {
208 return (list->front._next == &(list->back));
212 sraSpanListCount(const sraSpanList *list) {
213 sraSpan *curr = list->front._next;
214 unsigned long count = 0;
215 while (curr != &(list->back)) {
217 count += sraSpanListCount(curr->subspan);
227 sraSpanMergePrevious(sraSpan *dest) {
228 sraSpan *prev = dest->_prev;
230 while ((prev->_prev) &&
231 (prev->end == dest->start) &&
232 (sraSpanListEqual(prev->subspan, dest->subspan))) {
234 printf("merge_prev:");
240 dest->start = prev->start;
242 sraSpanDestroy(prev);
248 sraSpanMergeNext(sraSpan *dest) {
249 sraSpan *next = dest->_next;
250 while ((next->_next) &&
251 (next->start == dest->end) &&
252 (sraSpanListEqual(next->subspan, dest->subspan))) {
254 printf("merge_next:");
260 dest->end = next->end;
262 sraSpanDestroy(next);
268 sraSpanListOr(sraSpanList *dest, const sraSpanList *src) {
269 sraSpan *d_curr, *s_curr;
276 rfbErr("sraSpanListOr:incompatible spans (only one NULL!)\n");
281 d_curr = dest->front._next;
282 s_curr = src->front._next;
283 s_start = s_curr->start;
285 while (s_curr != &(src->back)) {
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)) {
292 sraSpanInsertBefore(sraSpanCreate(s_start, s_end,
295 if (d_curr != &(dest->back))
296 sraSpanMergePrevious(d_curr);
297 s_curr = s_curr->_next;
298 s_start = s_curr->start;
302 /* - If the new span overlaps the existing one */
303 if ((s_start < d_curr->end) &&
304 (s_end > d_curr->start)) {
306 /* - Insert new span before the existing destination one? */
307 if (s_start < d_curr->start) {
308 sraSpanInsertBefore(sraSpanCreate(s_start,
312 sraSpanMergePrevious(d_curr);
315 /* Split the existing span if necessary */
316 if (s_end < d_curr->end) {
317 sraSpanInsertAfter(sraSpanCreate(s_end,
323 if (s_start > d_curr->start) {
324 sraSpanInsertBefore(sraSpanCreate(d_curr->start,
328 d_curr->start = s_start;
331 /* Recursively OR subspans */
332 sraSpanListOr(d_curr->subspan, s_curr->subspan);
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);
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;
345 s_curr = s_curr->_next;
346 s_start = s_curr->start;
350 /* - No overlap. Move to the next destination span */
351 d_curr = d_curr->_next;
358 sraSpanListAnd(sraSpanList *dest, const sraSpanList *src) {
359 sraSpan *d_curr, *s_curr, *d_next;
365 rfbErr("sraSpanListAnd:incompatible spans (only one NULL!)\n");
370 d_curr = dest->front._next;
371 s_curr = src->front._next;
372 while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
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;
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);
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;
394 if (s_curr->end < d_curr->end) {
395 /* - The end of the span does not match */
396 sraSpanInsertAfter(sraSpanCreate(s_curr->end,
400 d_curr->end = s_curr->end;
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);
411 /* Merge this span with previous or next? */
412 if (d_curr->_prev != &(dest->front))
413 sraSpanMergePrevious(d_curr);
415 /* - Move on to the next span */
417 if (s_curr->end >= d_curr->end) {
418 d_next = d_curr->_next;
420 if (s_curr->end <= d_curr->end) {
421 s_curr = s_curr->_next;
427 while (d_curr != &(dest->back)) {
428 sraSpan *next = d_curr->_next;
429 sraSpanRemove(d_curr);
430 sraSpanDestroy(d_curr);
434 return !sraSpanListEmpty(dest);
438 sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) {
439 sraSpan *d_curr, *s_curr;
445 rfbErr("sraSpanListSubtract:incompatible spans (only one NULL!)\n");
450 d_curr = dest->front._next;
451 s_curr = src->front._next;
452 while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) {
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;
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;
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,
472 d_curr->start = s_curr->start;
474 if (s_curr->end < d_curr->end) {
475 sraSpanInsertAfter(sraSpanCreate(s_curr->end,
479 d_curr->end = s_curr->end;
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);
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);
496 /* - Move on to the next span */
497 if (s_curr->end > d_curr->end) {
498 d_curr = d_curr->_next;
500 s_curr = s_curr->_next;
505 return !sraSpanListEmpty(dest);
508 /* -=- Region routines */
512 return (sraRegion*)sraSpanListCreate();
516 sraRgnCreateRect(int x1, int y1, int x2, int y2) {
517 sraSpanList *vlist, *hlist;
518 sraSpan *vspan, *hspan;
520 /* - Build the horizontal portion of the span */
521 hlist = sraSpanListCreate();
522 hspan = sraSpanCreate(x1, x2, NULL);
523 sraSpanInsertAfter(hspan, &(hlist->front));
525 /* - Build the vertical portion of the span */
526 vlist = sraSpanListCreate();
527 vspan = sraSpanCreate(y1, y2, hlist);
528 sraSpanInsertAfter(vspan, &(vlist->front));
530 sraSpanListDestroy(hlist);
532 return (sraRegion*)vlist;
536 sraRgnCreateRgn(const sraRegion *src) {
537 return (sraRegion*)sraSpanListDup((sraSpanList*)src);
541 sraRgnDestroy(sraRegion *rgn) {
542 sraSpanListDestroy((sraSpanList*)rgn);
546 sraRgnMakeEmpty(sraRegion *rgn) {
547 sraSpanListMakeEmpty((sraSpanList*)rgn);
550 /* -=- Boolean Region ops */
553 sraRgnAnd(sraRegion *dst, const sraRegion *src) {
554 return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src);
558 sraRgnOr(sraRegion *dst, const sraRegion *src) {
559 sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src);
563 sraRgnSubtract(sraRegion *dst, const sraRegion *src) {
564 return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src);
568 sraRgnOffset(sraRegion *dst, int dx, int dy) {
569 sraSpan *vcurr, *hcurr;
571 vcurr = ((sraSpanList*)dst)->front._next;
572 while (vcurr != &(((sraSpanList*)dst)->back)) {
576 hcurr = vcurr->subspan->front._next;
577 while (hcurr != &(vcurr->subspan->back)) {
580 hcurr = hcurr->_next;
583 vcurr = vcurr->_next;
587 sraRegion *sraRgnBBox(const sraRegion *src) {
588 int xmin=((unsigned int)(int)-1)>>1,ymin=xmin,xmax=1-xmin,ymax=xmax;
589 sraSpan *vcurr, *hcurr;
592 return sraRgnCreate();
594 vcurr = ((sraSpanList*)src)->front._next;
595 while (vcurr != &(((sraSpanList*)src)->back)) {
596 if(vcurr->start<ymin)
601 hcurr = vcurr->subspan->front._next;
602 while (hcurr != &(vcurr->subspan->back)) {
603 if(hcurr->start<xmin)
607 hcurr = hcurr->_next;
610 vcurr = vcurr->_next;
613 if(xmax<xmin || ymax<ymin)
614 return sraRgnCreate();
616 return sraRgnCreateRect(xmin,ymin,xmax,ymax);
620 sraRgnPopRect(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;
626 /* - Pick correct order */
628 vcurr = ((sraSpanList*)rgn)->back._prev;
629 vend = &(((sraSpanList*)rgn)->front);
631 vcurr = ((sraSpanList*)rgn)->front._next;
632 vend = &(((sraSpanList*)rgn)->back);
636 rect->y1 = vcurr->start;
637 rect->y2 = vcurr->end;
639 /* - Pick correct order */
641 hcurr = vcurr->subspan->back._prev;
642 hend = &(vcurr->subspan->front);
644 hcurr = vcurr->subspan->front._next;
645 hend = &(vcurr->subspan->back);
649 rect->x1 = hcurr->start;
650 rect->x2 = hcurr->end;
652 sraSpanRemove(hcurr);
653 sraSpanDestroy(hcurr);
655 if (sraSpanListEmpty(vcurr->subspan)) {
656 sraSpanRemove(vcurr);
657 sraSpanDestroy(vcurr);
661 printf("poprect:(%dx%d)-(%dx%d)\n",
662 rect->x1, rect->y1, rect->x2, rect->y2);
672 sraRgnCountRects(const sraRegion *rgn) {
673 unsigned long count = sraSpanListCount((sraSpanList*)rgn);
678 sraRgnEmpty(const sraRegion *rgn) {
679 return sraSpanListEmpty((sraSpanList*)rgn);
683 sraRectangleIterator *sraRgnGetIterator(sraRegion *s)
685 /* these values have to be multiples of 4 */
688 sraRectangleIterator *i =
689 (sraRectangleIterator*)malloc(sizeof(sraRectangleIterator));
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);
702 i->ptrSize = DEFSIZE;
703 i->sPtrs[0] = &(s->front);
704 i->sPtrs[1] = &(s->back);
711 sraRectangleIterator *sraRgnGetReverseIterator(sraRegion *s,rfbBool reverseX,rfbBool reverseY)
713 sraRectangleIterator *i = sraRgnGetIterator(s);
715 i->sPtrs[1] = &(s->front);
716 i->sPtrs[0] = &(s->back);
718 i->reverseX = reverseX;
719 i->reverseY = reverseY;
723 static rfbBool sraReverse(sraRectangleIterator *i)
725 return( ((i->ptrPos&2) && i->reverseX) ||
726 (!(i->ptrPos&2) && i->reverseY));
729 static sraSpan* sraNextSpan(sraRectangleIterator *i)
732 return(i->sPtrs[i->ptrPos]->_prev);
734 return(i->sPtrs[i->ptrPos]->_next);
737 rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r)
739 /* is the subspan finished? */
740 while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) {
742 if(i->ptrPos < 0) /* the end */
746 i->sPtrs[i->ptrPos] = sraNextSpan(i);
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);
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);
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);
764 if((i->ptrPos%4)!=2) {
765 rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos);
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;
777 void sraRgnReleaseIterator(sraRectangleIterator* i)
784 sraRgnPrint(const sraRegion *rgn) {
785 sraSpanListPrint((sraSpanList*)rgn);
789 sraClipRect(int *x, int *y, int *w, int *h,
790 int cx, int cy, int cw, int ch) {
805 return (*w>0) && (*h>0);
809 sraClipRect2(int *x, int *y, int *x2, int *y2,
810 int cx, int cy, int cx2, int cy2) {
827 return (*x2>*x) && (*y2>*y);
833 /* pipe the output to sort|uniq -u and you'll get the errors. */
834 int main(int argc, char** argv)
836 sraRegionPtr region, region1, region2;
837 sraRectangleIterator* i;
841 region = sraRgnCreateRect(10, 10, 600, 300);
842 region1 = sraRgnCreateRect(40, 50, 350, 200);
843 region2 = sraRgnCreateRect(0, 0, 20, 40);
846 printf("\n[(10-300)[(10-600)]]\n\n");
848 b = sraRgnSubtract(region, region1);
849 printf("%s ",b?"true":"false");
851 printf("\ntrue [(10-50)[(10-600)](50-200)[(10-40)(350-600)](200-300)[(10-600)]]\n\n");
853 sraRgnOr(region, region2);
854 printf("%ld\n6\n\n", sraRgnCountRects(region));
856 i = sraRgnGetIterator(region);
857 while(sraRgnIteratorNext(i, &rect))
858 printf("%dx%d+%d+%d ",
859 rect.x2-rect.x1,rect.y2-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");
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,
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");
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,
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");
880 sraRgnDestroy(region);
881 sraRgnDestroy(region1);
882 sraRgnDestroy(region2);