add libvncserver
[presencevnc] / libvnc / libvncserver / rfbregion.c
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
13 struct sraRegion;
14
15 typedef struct sraSpan {
16   struct sraSpan *_next;
17   struct sraSpan *_prev;
18   int start;
19   int end;
20   struct sraRegion *subspan;
21 } sraSpan;
22
23 typedef struct sraRegion {
24   sraSpan front;
25   sraSpan back;
26 } sraSpanList;
27
28 /* -=- Span routines */
29
30 sraSpanList *sraSpanListDup(const sraSpanList *src);
31 void sraSpanListDestroy(sraSpanList *list);
32
33 static sraSpan *
34 sraSpanCreate(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
43 static sraSpan *
44 sraSpanDup(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
51 static void
52 sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) {
53   newspan->_next = after->_next;
54   newspan->_prev = after;
55   after->_next->_prev = newspan;
56   after->_next = newspan;
57 }
58
59 static void
60 sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) {
61   newspan->_next = before;
62   newspan->_prev = before->_prev;
63   before->_prev->_next = newspan;
64   before->_prev = newspan;
65 }
66
67 static void
68 sraSpanRemove(sraSpan *span) {
69   span->_prev->_next = span->_next;
70   span->_next->_prev = span->_prev;
71 }
72
73 static void
74 sraSpanDestroy(sraSpan *span) {
75   if (span->subspan) sraSpanListDestroy(span->subspan);
76   free(span);
77 }
78
79 #ifdef DEBUG
80 static void
81 sraSpanCheck(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
92 static void sraSpanPrint(const sraSpan *s);
93
94 static void
95 sraSpanListPrint(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
110 void
111 sraSpanPrint(const sraSpan *s) {
112   printf("(%d-%d)", (s->start), (s->end));
113   if (s->subspan)
114     sraSpanListPrint(s->subspan);
115 }
116
117 static sraSpanList *
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;
124   return item;
125 }
126
127 sraSpanList *
128 sraSpanListDup(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
144 void
145 sraSpanListDestroy(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
157 static void
158 sraSpanListMakeEmpty(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
173 static rfbBool
174 sraSpanListEqual(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
206 static rfbBool
207 sraSpanListEmpty(const sraSpanList *list) {
208   return (list->front._next == &(list->back));
209 }
210
211 static unsigned long
212 sraSpanListCount(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
226 static void
227 sraSpanMergePrevious(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
247 static void
248 sraSpanMergeNext(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
267 static void
268 sraSpanListOr(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
357 static rfbBool
358 sraSpanListAnd(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
437 static rfbBool
438 sraSpanListSubtract(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
510 sraRegion *
511 sraRgnCreate(void) {
512   return (sraRegion*)sraSpanListCreate();
513 }
514
515 sraRegion *
516 sraRgnCreateRect(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
535 sraRegion *
536 sraRgnCreateRgn(const sraRegion *src) {
537   return (sraRegion*)sraSpanListDup((sraSpanList*)src);
538 }
539
540 void
541 sraRgnDestroy(sraRegion *rgn) {
542   sraSpanListDestroy((sraSpanList*)rgn);
543 }
544
545 void
546 sraRgnMakeEmpty(sraRegion *rgn) {
547   sraSpanListMakeEmpty((sraSpanList*)rgn);
548 }
549
550 /* -=- Boolean Region ops */
551
552 rfbBool
553 sraRgnAnd(sraRegion *dst, const sraRegion *src) {
554   return sraSpanListAnd((sraSpanList*)dst, (sraSpanList*)src);
555 }
556
557 void
558 sraRgnOr(sraRegion *dst, const sraRegion *src) {
559   sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src);
560 }
561
562 rfbBool
563 sraRgnSubtract(sraRegion *dst, const sraRegion *src) {
564   return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src);
565 }
566
567 void
568 sraRgnOffset(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
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;
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
619 rfbBool
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;
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
671 unsigned long
672 sraRgnCountRects(const sraRegion *rgn) {
673   unsigned long count = sraSpanListCount((sraSpanList*)rgn);
674   return count;
675 }
676
677 rfbBool
678 sraRgnEmpty(const sraRegion *rgn) {
679   return sraSpanListEmpty((sraSpanList*)rgn);
680 }
681
682 /* iterator stuff */
683 sraRectangleIterator *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
711 sraRectangleIterator *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
723 static rfbBool sraReverse(sraRectangleIterator *i)
724 {
725   return( ((i->ptrPos&2) && i->reverseX) ||
726      (!(i->ptrPos&2) && i->reverseY));
727 }
728
729 static 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
737 rfbBool 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
777 void sraRgnReleaseIterator(sraRectangleIterator* i)
778 {
779   free(i->sPtrs);
780   free(i);
781 }
782
783 void
784 sraRgnPrint(const sraRegion *rgn) {
785         sraSpanListPrint((sraSpanList*)rgn);
786 }
787
788 rfbBool
789 sraClipRect(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
808 rfbBool
809 sraClipRect2(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. */
834 int 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