Coverage Report

Created: 2026-10-19 06:35

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
62.3k
sraSpanCreate(int start, int end, const sraSpanList *subspan) {
35
62.3k
  sraSpan *item = (sraSpan*)malloc(sizeof(sraSpan));
36
62.3k
  if (!item) return NULL;
37
62.3k
  item->_next = item->_prev = NULL;
38
62.3k
  item->start = start;
39
62.3k
  item->end = end;
40
62.3k
  item->subspan = sraSpanListDup(subspan);
41
62.3k
  return item;
42
62.3k
}
43
44
static sraSpan *
45
19.7k
sraSpanDup(const sraSpan *src) {
46
19.7k
  sraSpan *span;
47
19.7k
  if (!src) return NULL;
48
19.7k
  span = sraSpanCreate(src->start, src->end, src->subspan);
49
19.7k
  return span;
50
19.7k
}
51
52
static void
53
21.2k
sraSpanInsertAfter(sraSpan *newspan, sraSpan *after) {
54
21.2k
  if(newspan && after) {
55
21.2k
    newspan->_next = after->_next;
56
21.2k
    newspan->_prev = after;
57
21.2k
    after->_next->_prev = newspan;
58
21.2k
    after->_next = newspan;
59
21.2k
  }
60
21.2k
}
61
62
static void
63
41.0k
sraSpanInsertBefore(sraSpan *newspan, sraSpan *before) {
64
41.0k
  if(newspan && before) {
65
41.0k
    newspan->_next = before;
66
41.0k
    newspan->_prev = before->_prev;
67
41.0k
    before->_prev->_next = newspan;
68
41.0k
    before->_prev = newspan;
69
41.0k
  }
70
41.0k
}
71
72
static void
73
62.3k
sraSpanRemove(sraSpan *span) {
74
62.3k
  if(span) {
75
62.3k
    span->_prev->_next = span->_next;
76
62.3k
    span->_next->_prev = span->_prev;
77
62.3k
  }
78
62.3k
}
79
80
static void
81
62.3k
sraSpanDestroy(sraSpan *span) {
82
62.3k
  if (span->subspan) sraSpanListDestroy(span->subspan);
83
62.3k
  free(span);
84
62.3k
}
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
38.3k
sraSpanListCreate(void) {
126
38.3k
  sraSpanList *item = (sraSpanList*)malloc(sizeof(sraSpanList));
127
38.3k
  if (!item) return NULL;
128
38.3k
  item->front._next = &(item->back);
129
38.3k
  item->front._prev = NULL;
130
38.3k
  item->back._prev = &(item->front);
131
38.3k
  item->back._next = NULL;
132
38.3k
  return item;
133
38.3k
}
134
135
sraSpanList *
136
62.3k
sraSpanListDup(const sraSpanList *src) {
137
62.3k
  sraSpanList *newlist;
138
62.3k
  sraSpan *newspan, *curr;
139
140
62.3k
  if (!src) return NULL;
141
17.4k
  newlist = sraSpanListCreate();
142
17.4k
  curr = src->front._next;
143
37.2k
  while (curr != &(src->back)) {
144
19.7k
    newspan = sraSpanDup(curr);
145
19.7k
    sraSpanInsertBefore(newspan, &(newlist->back));
146
19.7k
    curr = curr->_next;
147
19.7k
  }
148
149
17.4k
  return newlist;
150
62.3k
}
151
152
void
153
38.3k
sraSpanListDestroy(sraSpanList *list) {
154
38.3k
  sraSpan *curr;
155
77.8k
  while (list->front._next != &(list->back)) {
156
39.5k
    curr = list->front._next;
157
39.5k
    sraSpanRemove(curr);
158
39.5k
    sraSpanDestroy(curr);
159
39.5k
  }
160
38.3k
  free(list);
161
38.3k
}
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
66.0k
sraSpanListEqual(const sraSpanList *s1, const sraSpanList *s2) {
179
66.0k
  sraSpan *sp1, *sp2;
180
181
66.0k
  if (!s1) {
182
42.6k
    if (!s2) {
183
42.6k
      return 1;
184
42.6k
    } else {
185
0
      rfbErr("sraSpanListEqual:incompatible spans (only one NULL!)\n");
186
0
      return FALSE;
187
0
    }
188
42.6k
  }
189
190
23.4k
  sp1 = s1->front._next;
191
23.4k
  sp2 = s2->front._next;
192
50.7k
  while ((sp1 != &(s1->back)) &&
193
40.6k
   (sp2 != &(s2->back))) {
194
39.0k
    if ((sp1->start != sp2->start) ||
195
30.6k
  (sp1->end != sp2->end) ||
196
27.3k
  (!sraSpanListEqual(sp1->subspan, sp2->subspan))) {
197
11.7k
      return 0;
198
11.7k
    }
199
27.3k
    sp1 = sp1->_next;
200
27.3k
    sp2 = sp2->_next;
201
27.3k
  }
202
203
11.7k
  if ((sp1 == &(s1->back)) && (sp2 == &(s2->back))) {
204
7.44k
    return 1;
205
7.44k
  } else {
206
4.25k
    return 0;
207
4.25k
  }    
208
11.7k
}
209
210
static rfbBool
211
2.43k
sraSpanListEmpty(const sraSpanList *list) {
212
2.43k
  return (list->front._next == &(list->back));
213
2.43k
}
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
27.1k
sraSpanMergePrevious(sraSpan *dest) {
232
27.1k
  sraSpan *prev = dest->_prev;
233
 
234
44.8k
  while ((prev->_prev) &&
235
31.9k
   (prev->end == dest->start) &&
236
26.2k
   (sraSpanListEqual(prev->subspan, dest->subspan))) {
237
    /*
238
    printf("merge_prev:");
239
    sraSpanPrint(prev);
240
    printf(" & ");
241
    sraSpanPrint(dest);
242
    printf("\n");
243
    */
244
17.6k
    dest->start = prev->start;
245
17.6k
    sraSpanRemove(prev);
246
17.6k
    sraSpanDestroy(prev);
247
17.6k
    prev = dest->_prev;
248
17.6k
  }
249
27.1k
}    
250
251
static void
252
14.1k
sraSpanMergeNext(sraSpan *dest) {
253
14.1k
  sraSpan *next = dest->_next;
254
19.2k
  while ((next->_next) &&
255
14.8k
   (next->start == dest->end) &&
256
12.4k
   (sraSpanListEqual(next->subspan, dest->subspan))) {
257
/*
258
    printf("merge_next:");
259
    sraSpanPrint(dest);
260
    printf(" & ");
261
    sraSpanPrint(next);
262
    printf("\n");
263
  */
264
5.08k
    dest->end = next->end;
265
5.08k
    sraSpanRemove(next);
266
5.08k
    sraSpanDestroy(next);
267
5.08k
    next = dest->_next;
268
5.08k
  }
269
14.1k
}
270
271
static void
272
31.5k
sraSpanListOr(sraSpanList *dest, const sraSpanList *src) {
273
31.5k
  sraSpan *d_curr, *s_curr;
274
31.5k
  int s_start, s_end;
275
276
31.5k
  if (!dest) {
277
10.1k
    if (!src) {
278
10.1k
      return;
279
10.1k
    } else {
280
0
      rfbErr("sraSpanListOr:incompatible spans (only one NULL!)\n");
281
0
      return;
282
0
    }
283
10.1k
  }
284
285
21.3k
  d_curr = dest->front._next;
286
21.3k
  s_curr = src->front._next;
287
21.3k
  s_start = s_curr->start;
288
21.3k
  s_end = s_curr->end;
289
69.4k
  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
48.1k
    if ((d_curr == &(dest->back)) ||
294
46.1k
    (d_curr->start >= s_end)) {
295
      /* - Add the span */
296
6.51k
      sraSpanInsertBefore(sraSpanCreate(s_start, s_end,
297
6.51k
          s_curr->subspan),
298
6.51k
        d_curr);
299
6.51k
      if (d_curr != &(dest->back))
300
4.56k
  sraSpanMergePrevious(d_curr);
301
6.51k
      s_curr = s_curr->_next;
302
6.51k
      s_start = s_curr->start;
303
6.51k
      s_end = s_curr->end;
304
41.5k
    } else {
305
306
      /* - If the new span overlaps the existing one */
307
41.5k
      if ((s_start < d_curr->end) &&
308
23.4k
    (s_end > d_curr->start)) {
309
310
  /* - Insert new span before the existing destination one? */
311
23.4k
  if (s_start < d_curr->start) {
312
2.61k
    sraSpanInsertBefore(sraSpanCreate(s_start,
313
2.61k
              d_curr->start,
314
2.61k
              s_curr->subspan),
315
2.61k
            d_curr);
316
2.61k
    sraSpanMergePrevious(d_curr);
317
2.61k
  }
318
319
  /* Split the existing span if necessary */
320
23.4k
  if (s_end < d_curr->end) {
321
5.22k
    sraSpanInsertAfter(sraSpanCreate(s_end,
322
5.22k
             d_curr->end,
323
5.22k
             d_curr->subspan),
324
5.22k
           d_curr);
325
5.22k
    d_curr->end = s_end;
326
5.22k
  }
327
23.4k
  if (s_start > d_curr->start) {
328
12.0k
    sraSpanInsertBefore(sraSpanCreate(d_curr->start,
329
12.0k
              s_start,
330
12.0k
              d_curr->subspan),
331
12.0k
            d_curr);
332
12.0k
    d_curr->start = s_start;
333
12.0k
  }
334
335
  /* Recursively OR subspans */
336
23.4k
  sraSpanListOr(d_curr->subspan, s_curr->subspan);
337
338
  /* Merge this span with previous or next? */
339
23.4k
  if (d_curr->_prev != &(dest->front))
340
20.0k
    sraSpanMergePrevious(d_curr);
341
23.4k
  if (d_curr->_next != &(dest->back))
342
14.1k
    sraSpanMergeNext(d_curr);
343
344
  /* Move onto the next pair to compare */
345
23.4k
  if (s_end > d_curr->end) {
346
8.58k
    s_start = d_curr->end;
347
8.58k
    d_curr = d_curr->_next;
348
14.8k
  } else {
349
14.8k
    s_curr = s_curr->_next;
350
14.8k
    s_start = s_curr->start;
351
14.8k
    s_end = s_curr->end;
352
14.8k
  }
353
23.4k
      } else {
354
  /* - No overlap.  Move to the next destination span */
355
18.1k
  d_curr = d_curr->_next;
356
18.1k
      }
357
41.5k
    }
358
48.1k
  }
359
21.3k
}
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.43k
sraSpanListSubtract(sraSpanList *dest, const sraSpanList *src) {
443
2.43k
  sraSpan *d_curr, *s_curr;
444
445
2.43k
  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.43k
  d_curr = dest->front._next;
455
2.43k
  s_curr = src->front._next;
456
2.43k
  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.43k
  return !sraSpanListEmpty(dest);
510
2.43k
}
511
512
/* -=- Region routines */
513
514
sraRegion *
515
4.75k
sraRgnCreate(void) {
516
4.75k
  return (sraRegion*)sraSpanListCreate();
517
4.75k
}
518
519
sraRegion *
520
8.03k
sraRgnCreateRect(int x1, int y1, int x2, int y2) {
521
8.03k
  sraSpanList *vlist, *hlist;
522
8.03k
  sraSpan *vspan, *hspan;
523
524
  /* - Build the horizontal portion of the span */
525
8.03k
  hlist = sraSpanListCreate();
526
8.03k
  hspan = sraSpanCreate(x1, x2, NULL);
527
8.03k
  sraSpanInsertAfter(hspan, &(hlist->front));
528
529
  /* - Build the vertical portion of the span */
530
8.03k
  vlist = sraSpanListCreate();
531
8.03k
  vspan = sraSpanCreate(y1, y2, hlist);
532
8.03k
  sraSpanInsertAfter(vspan, &(vlist->front));
533
534
8.03k
  sraSpanListDestroy(hlist);
535
536
8.03k
  return (sraRegion*)vlist;
537
8.03k
}
538
539
sraRegion *
540
0
sraRgnCreateRgn(const sraRegion *src) {
541
0
  return (sraRegion*)sraSpanListDup((sraSpanList*)src);
542
0
}
543
544
void
545
12.7k
sraRgnDestroy(sraRegion *rgn) {
546
12.7k
  sraSpanListDestroy((sraSpanList*)rgn);
547
12.7k
}
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
8.09k
sraRgnOr(sraRegion *dst, const sraRegion *src) {
563
8.09k
  sraSpanListOr((sraSpanList*)dst, (sraSpanList*)src);
564
8.09k
}
565
566
rfbBool
567
2.43k
sraRgnSubtract(sraRegion *dst, const sraRegion *src) {
568
2.43k
  return sraSpanListSubtract((sraSpanList*)dst, (sraSpanList*)src);
569
2.43k
}
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.20k
      int cx, int cy, int cx2, int cy2) {
815
2.20k
  if (*x < cx)
816
11
    *x = cx;
817
2.20k
  if (*y < cy)
818
15
    *y = cy;
819
2.20k
  if (*x >= cx2)
820
2.17k
    *x = cx2-1;
821
2.20k
  if (*y >= cy2)
822
2.16k
    *y = cy2-1;
823
2.20k
  if (*x2 <= cx)
824
0
    *x2 = cx+1;
825
2.20k
  if (*y2 <= cy)
826
0
    *y2 = cy+1;
827
2.20k
  if (*x2 > cx2)
828
2.17k
    *x2 = cx2;
829
2.20k
  if (*y2 > cy2)
830
2.16k
    *y2 = cy2;
831
2.20k
  return (*x2>*x) && (*y2>*y);
832
2.20k
}
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