Coverage Report

Created: 2026-03-20 06:59

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