| /* -=- sraRegion.c |
| * Copyright (c) 2001 James "Wez" Weatherall, Johannes E. Schindelin |
| * |
| * A general purpose region clipping library |
| * Only deals with rectangular regions, though. |
| */ |
| |
| #include <rfb/rfb.h> |
| #include <rfb/rfbregion.h> |
| |
| /* -=- Internal Span structure */ |
| |
| struct sraRegion; |
| |
| typedef struct sraSpan { |
| struct sraSpan *_next; |
| struct sraSpan *_prev; |
| int start; |
| int end; |
| struct sraRegion *subspan; |
| } sraSpan; |
| |
| typedef struct sraRegion { |
| sraSpan front; |
| sraSpan back; |
| } sraSpanList; |
| |
| /* -=- Span routines */ |
| |
| sraSpanList *sraSpanListDup(const sraSpanList *src); |
| void sraSpanListDestroy(sraSpanList *list); |
| |
| static sraSpan * |
| sraSpanCreate(int start, int end, const sraSpanList *subspan) { |
| sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan)); |
| item->_next = item->_prev = NULL; |
| item->start = start; |
| item->end = end; |
| item->subspan = sraSpanListDup(subspan); |
| return item; |
| } |
| |
| static sraSpan * |
| sraSpanDup(const sraSpan *src) { |
| sraSpan *span; |
| if (!src) return NULL; |
| span = sraSpanCreate(src->start, src->end, src->subspan); |
| return span; |
| } |
| |
| static void |
| sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) { |
| newspan->_next = after->_next; |
| newspan->_prev = after; |
| after->_next->_prev = newspan; |
| after->_next = newspan; |
| } |
| |
| static void |
| sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) { |
| newspan->_next = before; |
| newspan->_prev = before->_prev; |
| before->_prev->_next = newspan; |
| before->_prev = newspan; |
| } |
| |
| static void |
| sraSpanRemove(sraSpan *span) { |
| span->_prev->_next = span->_next; |
| span->_next->_prev = span->_prev; |
| } |
| |
| static void |
| sraSpanDestroy(sraSpan *span) { |
| if (span->subspan) sraSpanListDestroy(span->subspan); |
| free(span); |
| } |
| |
| #ifdef DEBUG |
| static void |
| sraSpanCheck(const sraSpan *span, const char *text) { |
| /* Check the span is valid! */ |
| if (span->start == span->end) { |
| printf(text); |
| printf(":%d-%d\n", span->start, span->end); |
| } |
| } |
| #endif |
| |
| /* -=- SpanList routines */ |
| |
| static void sraSpanPrint(const sraSpan *s); |
| |
| static void |
| sraSpanListPrint(const sraSpanList *l) { |
| sraSpan *curr; |
| if (!l) { |
| printf("NULL"); |
| return; |
| } |
| curr = l->front._next; |
| printf("["); |
| while (curr != &(l->back)) { |
| sraSpanPrint(curr); |
| curr = curr->_next; |
| } |
| printf("]"); |
| } |
| |
| void |
| sraSpanPrint(const sraSpan *s) { |
| printf("(%d-%d)", (s->start), (s->end)); |
| if (s->subspan) |
| sraSpanListPrint(s->subspan); |
| } |
| |
| static sraSpanList * |
| sraSpanListCreate(void) { |
| sraSpanList *item = (sraSpanList*)malloc(sizeof(sraSpanList)); |
| item->front._next = &(item->back); |
| item->front._prev = NULL; |
| item->back._prev = &(item->front); |
| item->back._next = NULL; |
| return item; |
| } |
| |
| sraSpanList * |
| sraSpanListDup(const sraSpanList *src) { |
| sraSpanList *newlist; |
| sraSpan *newspan, *curr; |
| |
| if (!src) return NULL; |
| newlist = sraSpanListCreate(); |
| curr = src->front._next; |
| while (curr != &(src->back)) { |
| newspan = sraSpanDup(curr); |
| sraSpanInsertBefore(newspan, &(newlist->back)); |
| curr = curr->_next; |
| } |
| |
| return newlist; |
| } |
| |
| void |
| sraSpanListDestroy(sraSpanList *list) { |
| sraSpan *curr, *next; |
| while (list->front._next != &(list->back)) { |
| curr = list->front._next; |
| next = curr->_next; |
| sraSpanRemove(curr); |
| sraSpanDestroy(curr); |
| curr = next; |
| } |
| free(list); |
| } |
| |
| static void |
| sraSpanListMakeEmpty(sraSpanList *list) { |
| sraSpan *curr, *next; |
| while (list->front._next != &(list->back)) { |
| curr = list->front._next; |
| next = curr->_next; |
| sraSpanRemove(curr); |
| sraSpanDestroy(curr); |
| curr = next; |
| } |
| list->front._next = &(list->back); |
| list->front._prev = NULL; |
| list->back._prev = &(list->front); |
| list->back._next = NULL; |
| } |
| |
| static rfbBool |
| sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) { |
| sraSpan *sp1, *sp2; |
| |
| if (!s1) { |
| if (!s2) { |
| return 1; |
| } else { |
| rfbErr("sraSpanListEqual:incompatible spans (only one NULL!)\n"); |
| return FALSE; |
| } |
| } |
| |
| sp1 = s1->front._next; |
| sp2 = s2->front._next; |
| while ((sp1 != &(s1->back)) && |
| (sp2 != &(s2->back))) { |
| if ((sp1->start != sp2->start) || |
| (sp1->end != sp2->end) || |
| (!sraSpanListEqual(sp1->subspan, sp2->subspan))) { |
| return 0; |
| } |
| sp1 = sp1->_next; |
| sp2 = sp2->_next; |
| } |
| |
| if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| static rfbBool |
| sraSpanListEmpty(const sraSpanList *list) { |
| return (list->front._next == &(list->back)); |
| } |
| |
| static unsigned long |
| sraSpanListCount(const sraSpanList *list) { |
| sraSpan *curr = list->front._next; |
| unsigned long count = 0; |
| while (curr != &(list->back)) { |
| if (curr->subspan) { |
| count += sraSpanListCount(curr->subspan); |
| } else { |
| count += 1; |
| } |
| curr = curr->_next; |
| } |
| return count; |
| } |
| |
| static void |
| sraSpanMergePrevious(sraSpan *dest) { |
| sraSpan *prev = dest->_prev; |
| |
| while ((prev->_prev) && |
| (prev->end == dest->start) && |
| (sraSpanListEqual(prev->subspan, dest->subspan))) { |
| /* |
| printf("merge_prev:"); |
| sraSpanPrint(prev); |
| printf(" & "); |
| sraSpanPrint(dest); |
| printf("\n"); |
| */ |
| dest->start = prev->start; |
| sraSpanRemove(prev); |
| sraSpanDestroy(prev); |
| prev = dest->_prev; |
| } |
| } |
| |
| static void |
| sraSpanMergeNext(sraSpan *dest) { |
| sraSpan *next = dest->_next; |
| while ((next->_next) && |
| (next->start == dest->end) && |
| (sraSpanListEqual(next->subspan, dest->subspan))) { |
| /* |
| printf("merge_next:"); |
| sraSpanPrint(dest); |
| printf(" & "); |
| sraSpanPrint(next); |
| printf("\n"); |
| */ |
| dest->end = next->end; |
| sraSpanRemove(next); |
| sraSpanDestroy(next); |
| next = dest->_next; |
| } |
| } |
| |
| static void |
| sraSpanListOr(sraSpanList *dest, const sraSpanList *src) { |
| sraSpan *d_curr, *s_curr; |
| int s_start, s_end; |
| |
| if (!dest) { |
| if (!src) { |
| return; |
| } else { |
| rfbErr("sraSpanListOr:incompatible spans (only one NULL!)\n"); |
| return; |
| } |
| } |
| |
| d_curr = dest->front._next; |
| s_curr = src->front._next; |
| s_start = s_curr->start; |
| s_end = s_curr->end; |
| while (s_curr != &(src->back)) { |
| |
| /* - If we are at end of destination list OR |
| If the new span comes before the next destination one */ |
| if ((d_curr == &(dest->back)) || |
| (d_curr->start >= s_end)) { |
| /* - Add the span */ |
| sraSpanInsertBefore(sraSpanCreate(s_start, s_end, |
| s_curr->subspan), |
| d_curr); |
| if (d_curr != &(dest->back)) |
| sraSpanMergePrevious(d_curr); |
| s_curr = s_curr->_next; |
| s_start = s_curr->start; |
| s_end = s_curr->end; |
| } else { |
| |
| /* - If the new span overlaps the existing one */ |
| if ((s_start < d_curr->end) && |
| (s_end > d_curr->start)) { |
| |
| /* - Insert new span before the existing destination one? */ |
| if (s_start < d_curr->start) { |
| sraSpanInsertBefore(sraSpanCreate(s_start, |
| d_curr->start, |
| s_curr->subspan), |
| d_curr); |
| sraSpanMergePrevious(d_curr); |
| } |
| |
| /* Split the existing span if necessary */ |
| if (s_end < d_curr->end) { |
| sraSpanInsertAfter(sraSpanCreate(s_end, |
| d_curr->end, |
| d_curr->subspan), |
| d_curr); |
| d_curr->end = s_end; |
| } |
| if (s_start > d_curr->start) { |
| sraSpanInsertBefore(sraSpanCreate(d_curr->start, |
| s_start, |
| d_curr->subspan), |
| d_curr); |
| d_curr->start = s_start; |
| } |
| |
| /* Recursively OR subspans */ |
| sraSpanListOr(d_curr->subspan, s_curr->subspan); |
| |
| /* Merge this span with previous or next? */ |
| if (d_curr->_prev != &(dest->front)) |
| sraSpanMergePrevious(d_curr); |
| if (d_curr->_next != &(dest->back)) |
| sraSpanMergeNext(d_curr); |
| |
| /* Move onto the next pair to compare */ |
| if (s_end > d_curr->end) { |
| s_start = d_curr->end; |
| d_curr = d_curr->_next; |
| } else { |
| s_curr = s_curr->_next; |
| s_start = s_curr->start; |
| s_end = s_curr->end; |
| } |
| } else { |
| /* - No overlap. Move to the next destination span */ |
| d_curr = d_curr->_next; |
| } |
| } |
| } |
| } |
| |
| static rfbBool |
| sraSpanListAnd(sraSpanList *dest, const sraSpanList *src) { |
| sraSpan *d_curr, *s_curr, *d_next; |
| |
| if (!dest) { |
| if (!src) { |
| return 1; |
| } else { |
| rfbErr("sraSpanListAnd:incompatible spans (only one NULL!)\n"); |
| return FALSE; |
| } |
| } |
| |
| d_curr = dest->front._next; |
| s_curr = src->front._next; |
| while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) { |
| |
| /* - If we haven't reached a destination span yet then move on */ |
| if (d_curr->start >= s_curr->end) { |
| s_curr = s_curr->_next; |
| continue; |
| } |
| |
| /* - If we are beyond the current destination span then remove it */ |
| if (d_curr->end <= s_curr->start) { |
| sraSpan *next = d_curr->_next; |
| sraSpanRemove(d_curr); |
| sraSpanDestroy(d_curr); |
| d_curr = next; |
| continue; |
| } |
| |
| /* - If we partially overlap a span then split it up or remove bits */ |
| if (s_curr->start > d_curr->start) { |
| /* - The top bit of the span does not match */ |
| d_curr->start = s_curr->start; |
| } |
| if (s_curr->end < d_curr->end) { |
| /* - The end of the span does not match */ |
| sraSpanInsertAfter(sraSpanCreate(s_curr->end, |
| d_curr->end, |
| d_curr->subspan), |
| d_curr); |
| d_curr->end = s_curr->end; |
| } |
| |
| /* - Now recursively process the affected span */ |
| if (!sraSpanListAnd(d_curr->subspan, s_curr->subspan)) { |
| /* - The destination subspan is now empty, so we should remove it */ |
| sraSpan *next = d_curr->_next; |
| sraSpanRemove(d_curr); |
| sraSpanDestroy(d_curr); |
| d_curr = next; |
| } else { |
| /* Merge this span with previous or next? */ |
| if (d_curr->_prev != &(dest->front)) |
| sraSpanMergePrevious(d_curr); |
| |
| /* - Move on to the next span */ |
| d_next = d_curr; |
| if (s_curr->end >= d_curr->end) { |
| d_next = d_curr->_next; |
| } |
| if (s_curr->end <= d_curr->end) { |
| s_curr = s_curr->_next; |
| } |
| d_curr = d_next; |
| } |
| } |
| |
| while (d_curr != &(dest->back)) { |
| sraSpan *next = d_curr->_next; |
| sraSpanRemove(d_curr); |
| sraSpanDestroy(d_curr); |
| d_curr=next; |
| } |
| |
| return !sraSpanListEmpty(dest); |
| } |
| |
| static rfbBool |
| sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) { |
| sraSpan *d_curr, *s_curr; |
| |
| if (!dest) { |
| if (!src) { |
| return 1; |
| } else { |
| rfbErr("sraSpanListSubtract:incompatible spans (only one NULL!)\n"); |
| return FALSE; |
| } |
| } |
| |
| d_curr = dest->front._next; |
| s_curr = src->front._next; |
| while ((s_curr != &(src->back)) && (d_curr != &(dest->back))) { |
| |
| /* - If we haven't reached a destination span yet then move on */ |
| if (d_curr->start >= s_curr->end) { |
| s_curr = s_curr->_next; |
| continue; |
| } |
| |
| /* - If we are beyond the current destination span then skip it */ |
| if (d_curr->end <= s_curr->start) { |
| d_curr = d_curr->_next; |
| continue; |
| } |
| |
| /* - If we partially overlap the current span then split it up */ |
| if (s_curr->start > d_curr->start) { |
| sraSpanInsertBefore(sraSpanCreate(d_curr->start, |
| s_curr->start, |
| d_curr->subspan), |
| d_curr); |
| d_curr->start = s_curr->start; |
| } |
| if (s_curr->end < d_curr->end) { |
| sraSpanInsertAfter(sraSpanCreate(s_curr->end, |
| d_curr->end, |
| d_curr->subspan), |
| d_curr); |
| d_curr->end = s_curr->end; |
| } |
| |
| /* - Now recursively process the affected span */ |
| if ((!d_curr->subspan) || !sraSpanListSubtract(d_curr->subspan, s_curr->subspan)) { |
| /* - The destination subspan is now empty, so we should remove it */ |
| sraSpan *next = d_curr->_next; |
| sraSpanRemove(d_curr); |
| sraSpanDestroy(d_curr); |
| d_curr = next; |
| } else { |
| /* Merge this span with previous or next? */ |
| if (d_curr->_prev != &(dest->front)) |
| sraSpanMergePrevious(d_curr); |
| if (d_curr->_next != &(dest->back)) |
| sraSpanMergeNext(d_curr); |
| |
| /* - Move on to the next span */ |
| if (s_curr->end > d_curr->end) { |
| d_curr = d_curr->_next; |
| } else { |
| s_curr = s_curr->_next; |
| } |
| } |
| } |
| |
| return !sraSpanListEmpty(dest); |
| } |
| |
| /* -=- Region routines */ |
| |
| sraRegion * |
| sraRgnCreate(void) { |
| return (sraRegion*)sraSpanListCreate(); |
| } |
| |
| sraRegion * |
| sraRgnCreateRect(int x1, int y1, int x2, int y2) { |
| sraSpanList *vlist, *hlist; |
| sraSpan *vspan, *hspan; |
| |
| /* - Build the horizontal portion of the span */ |
| hlist = sraSpanListCreate(); |
| hspan = sraSpanCreate(x1, x2, NULL); |
| sraSpanInsertAfter(hspan, &(hlist->front)); |
| |
| /* - Build the vertical portion of the span */ |
| vlist = sraSpanListCreate(); |
| vspan = sraSpanCreate(y1, y2, hlist); |
| sraSpanInsertAfter(vspan, &(vlist->front)); |
| |
| sraSpanListDestroy(hlist); |
| |
| return (sraRegion*)vlist; |
| } |
| |
| sraRegion * |
| sraRgnCreateRgn(const sraRegion *src) { |
| return (sraRegion*)sraSpanListDup((sraSpanList*)src); |
| } |
| |
| void |
| sraRgnDestroy(sraRegion *rgn) { |
| sraSpanListDestroy((sraSpanList*)rgn); |
| } |
| |
| void |
| sraRgnMakeEmpty(sraRegion *rgn) { |
| sraSpanListMakeEmpty((sraSpanList*)rgn); |
| } |
| |
| /* -=- Boolean Region ops */ |
| |
| rfbBool |
| sraRgnAnd(sraRegion *dst, const sraRegion *src) { |
| return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src); |
| } |
| |
| void |
| sraRgnOr(sraRegion *dst, const sraRegion *src) { |
| sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src); |
| } |
| |
| rfbBool |
| sraRgnSubtract(sraRegion *dst, const sraRegion *src) { |
| return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src); |
| } |
| |
| void |
| sraRgnOffset(sraRegion *dst, int dx, int dy) { |
| sraSpan *vcurr, *hcurr; |
| |
| vcurr = ((sraSpanList*)dst)->front._next; |
| while (vcurr != &(((sraSpanList*)dst)->back)) { |
| vcurr->start += dy; |
| vcurr->end += dy; |
| |
| hcurr = vcurr->subspan->front._next; |
| while (hcurr != &(vcurr->subspan->back)) { |
| hcurr->start += dx; |
| hcurr->end += dx; |
| hcurr = hcurr->_next; |
| } |
| |
| vcurr = vcurr->_next; |
| } |
| } |
| |
| sraRegion *sraRgnBBox(const sraRegion *src) { |
| int xmin=((unsigned int)(int)-1)>>1,ymin=xmin,xmax=1-xmin,ymax=xmax; |
| sraSpan *vcurr, *hcurr; |
| |
| if(!src) |
| return sraRgnCreate(); |
| |
| vcurr = ((sraSpanList*)src)->front._next; |
| while (vcurr != &(((sraSpanList*)src)->back)) { |
| if(vcurr->start<ymin) |
| ymin=vcurr->start; |
| if(vcurr->end>ymax) |
| ymax=vcurr->end; |
| |
| hcurr = vcurr->subspan->front._next; |
| while (hcurr != &(vcurr->subspan->back)) { |
| if(hcurr->start<xmin) |
| xmin=hcurr->start; |
| if(hcurr->end>xmax) |
| xmax=hcurr->end; |
| hcurr = hcurr->_next; |
| } |
| |
| vcurr = vcurr->_next; |
| } |
| |
| if(xmax<xmin || ymax<ymin) |
| return sraRgnCreate(); |
| |
| return sraRgnCreateRect(xmin,ymin,xmax,ymax); |
| } |
| |
| rfbBool |
| sraRgnPopRect(sraRegion *rgn, sraRect *rect, unsigned long flags) { |
| sraSpan *vcurr, *hcurr; |
| sraSpan *vend, *hend; |
| rfbBool right2left = (flags & 2) == 2; |
| rfbBool bottom2top = (flags & 1) == 1; |
| |
| /* - Pick correct order */ |
| if (bottom2top) { |
| vcurr = ((sraSpanList*)rgn)->back._prev; |
| vend = &(((sraSpanList*)rgn)->front); |
| } else { |
| vcurr = ((sraSpanList*)rgn)->front._next; |
| vend = &(((sraSpanList*)rgn)->back); |
| } |
| |
| if (vcurr != vend) { |
| rect->y1 = vcurr->start; |
| rect->y2 = vcurr->end; |
| |
| /* - Pick correct order */ |
| if (right2left) { |
| hcurr = vcurr->subspan->back._prev; |
| hend = &(vcurr->subspan->front); |
| } else { |
| hcurr = vcurr->subspan->front._next; |
| hend = &(vcurr->subspan->back); |
| } |
| |
| if (hcurr != hend) { |
| rect->x1 = hcurr->start; |
| rect->x2 = hcurr->end; |
| |
| sraSpanRemove(hcurr); |
| sraSpanDestroy(hcurr); |
| |
| if (sraSpanListEmpty(vcurr->subspan)) { |
| sraSpanRemove(vcurr); |
| sraSpanDestroy(vcurr); |
| } |
| |
| #if 0 |
| printf("poprect:(%dx%d)-(%dx%d)\n", |
| rect->x1, rect->y1, rect->x2, rect->y2); |
| #endif |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| unsigned long |
| sraRgnCountRects(const sraRegion *rgn) { |
| unsigned long count = sraSpanListCount((sraSpanList*)rgn); |
| return count; |
| } |
| |
| rfbBool |
| sraRgnEmpty(const sraRegion *rgn) { |
| return sraSpanListEmpty((sraSpanList*)rgn); |
| } |
| |
| /* iterator stuff */ |
| sraRectangleIterator *sraRgnGetIterator(sraRegion *s) |
| { |
| /* these values have to be multiples of 4 */ |
| #define DEFSIZE 4 |
| #define DEFSTEP 8 |
| sraRectangleIterator *i = |
| (sraRectangleIterator*)malloc(sizeof(sraRectangleIterator)); |
| if(!i) |
| return NULL; |
| |
| /* we have to recurse eventually. So, the first sPtr is the pointer to |
| the sraSpan in the first level. the second sPtr is the pointer to |
| the sraRegion.back. The third and fourth sPtr are for the second |
| recursion level and so on. */ |
| i->sPtrs = (sraSpan**)malloc(sizeof(sraSpan*)*DEFSIZE); |
| if(!i->sPtrs) { |
| free(i); |
| return NULL; |
| } |
| i->ptrSize = DEFSIZE; |
| i->sPtrs[0] = &(s->front); |
| i->sPtrs[1] = &(s->back); |
| i->ptrPos = 0; |
| i->reverseX = 0; |
| i->reverseY = 0; |
| return i; |
| } |
| |
| sraRectangleIterator *sraRgnGetReverseIterator(sraRegion *s,rfbBool reverseX,rfbBool reverseY) |
| { |
| sraRectangleIterator *i = sraRgnGetIterator(s); |
| if(reverseY) { |
| i->sPtrs[1] = &(s->front); |
| i->sPtrs[0] = &(s->back); |
| } |
| i->reverseX = reverseX; |
| i->reverseY = reverseY; |
| return(i); |
| } |
| |
| static rfbBool sraReverse(sraRectangleIterator *i) |
| { |
| return( ((i->ptrPos&2) && i->reverseX) || |
| (!(i->ptrPos&2) && i->reverseY)); |
| } |
| |
| static sraSpan* sraNextSpan(sraRectangleIterator *i) |
| { |
| if(sraReverse(i)) |
| return(i->sPtrs[i->ptrPos]->_prev); |
| else |
| return(i->sPtrs[i->ptrPos]->_next); |
| } |
| |
| rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r) |
| { |
| /* is the subspan finished? */ |
| while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) { |
| i->ptrPos -= 2; |
| if(i->ptrPos < 0) /* the end */ |
| return(0); |
| } |
| |
| i->sPtrs[i->ptrPos] = sraNextSpan(i); |
| |
| /* is this a new subspan? */ |
| while(i->sPtrs[i->ptrPos]->subspan) { |
| if(i->ptrPos+2 > i->ptrSize) { /* array is too small */ |
| i->ptrSize += DEFSTEP; |
| i->sPtrs = (sraSpan**)realloc(i->sPtrs, sizeof(sraSpan*)*i->ptrSize); |
| } |
| i->ptrPos += 2; |
| if(sraReverse(i)) { |
| i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->back._prev; |
| i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->front); |
| } else { |
| i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->front._next; |
| i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->back); |
| } |
| } |
| |
| if((i->ptrPos%4)!=2) { |
| rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos); |
| return FALSE; |
| } |
| |
| r->y1 = i->sPtrs[i->ptrPos-2]->start; |
| r->y2 = i->sPtrs[i->ptrPos-2]->end; |
| r->x1 = i->sPtrs[i->ptrPos]->start; |
| r->x2 = i->sPtrs[i->ptrPos]->end; |
| |
| return(-1); |
| } |
| |
| void sraRgnReleaseIterator(sraRectangleIterator* i) |
| { |
| free(i->sPtrs); |
| free(i); |
| } |
| |
| void |
| sraRgnPrint(const sraRegion *rgn) { |
| sraSpanListPrint((sraSpanList*)rgn); |
| } |
| |
| rfbBool |
| sraClipRect(int *x, int *y, int *w, int *h, |
| int cx, int cy, int cw, int ch) { |
| if (*x < cx) { |
| *w -= (cx-*x); |
| *x = cx; |
| } |
| if (*y < cy) { |
| *h -= (cy-*y); |
| *y = cy; |
| } |
| if (*x+*w > cx+cw) { |
| *w = (cx+cw)-*x; |
| } |
| if (*y+*h > cy+ch) { |
| *h = (cy+ch)-*y; |
| } |
| return (*w>0) && (*h>0); |
| } |
| |
| rfbBool |
| sraClipRect2(int *x, int *y, int *x2, int *y2, |
| int cx, int cy, int cx2, int cy2) { |
| if (*x < cx) |
| *x = cx; |
| if (*y < cy) |
| *y = cy; |
| if (*x >= cx2) |
| *x = cx2-1; |
| if (*y >= cy2) |
| *y = cy2-1; |
| if (*x2 <= cx) |
| *x2 = cx+1; |
| if (*y2 <= cy) |
| *y2 = cy+1; |
| if (*x2 > cx2) |
| *x2 = cx2; |
| if (*y2 > cy2) |
| *y2 = cy2; |
| return (*x2>*x) && (*y2>*y); |
| } |
| |
| /* test */ |
| |
| #ifdef SRA_TEST |
| /* pipe the output to sort|uniq -u and you'll get the errors. */ |
| int main(int argc, char** argv) |
| { |
| sraRegionPtr region, region1, region2; |
| sraRectangleIterator* i; |
| sraRect rect; |
| rfbBool b; |
| |
| region = sraRgnCreateRect(10, 10, 600, 300); |
| region1 = sraRgnCreateRect(40, 50, 350, 200); |
| region2 = sraRgnCreateRect(0, 0, 20, 40); |
| |
| sraRgnPrint(region); |
| printf("\n[(10-300)[(10-600)]]\n\n"); |
| |
| b = sraRgnSubtract(region, region1); |
| printf("%s ",b?"true":"false"); |
| sraRgnPrint(region); |
| printf("\ntrue [(10-50)[(10-600)](50-200)[(10-40)(350-600)](200-300)[(10-600)]]\n\n"); |
| |
| sraRgnOr(region, region2); |
| printf("%ld\n6\n\n", sraRgnCountRects(region)); |
| |
| i = sraRgnGetIterator(region); |
| while(sraRgnIteratorNext(i, &rect)) |
| printf("%dx%d+%d+%d ", |
| rect.x2-rect.x1,rect.y2-rect.y1, |
| rect.x1,rect.y1); |
| sraRgnReleaseIterator(i); |
| printf("\n20x10+0+0 600x30+0+10 590x10+10+40 30x150+10+50 250x150+350+50 590x100+10+200 \n\n"); |
| |
| i = sraRgnGetReverseIterator(region,1,0); |
| while(sraRgnIteratorNext(i, &rect)) |
| printf("%dx%d+%d+%d ", |
| rect.x2-rect.x1,rect.y2-rect.y1, |
| rect.x1,rect.y1); |
| sraRgnReleaseIterator(i); |
| printf("\n20x10+0+0 600x30+0+10 590x10+10+40 250x150+350+50 30x150+10+50 590x100+10+200 \n\n"); |
| |
| i = sraRgnGetReverseIterator(region,1,1); |
| while(sraRgnIteratorNext(i, &rect)) |
| printf("%dx%d+%d+%d ", |
| rect.x2-rect.x1,rect.y2-rect.y1, |
| rect.x1,rect.y1); |
| sraRgnReleaseIterator(i); |
| printf("\n590x100+10+200 250x150+350+50 30x150+10+50 590x10+10+40 600x30+0+10 20x10+0+0 \n\n"); |
| |
| sraRgnDestroy(region); |
| sraRgnDestroy(region1); |
| sraRgnDestroy(region2); |
| |
| return(0); |
| } |
| #endif |