LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rfbregion.c
Go to the documentation of this file.
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 {
26 } sraSpanList;
27 
28 /* -=- Span routines */
29 
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 *
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
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 *
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 *
537  return (sraRegion*)sraSpanListDup((sraSpanList*)src);
538 }
539 
540 void
543 }
544 
545 void
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 
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
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 */
684 {
685  /* these values have to be multiples of 4 */
686 #define DEFSIZE 4
687 #define DEFSTEP 8
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 
712 {
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 
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 
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;
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);
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);
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);
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