Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/codec/region.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 *
4
 * Copyright 2014 Thincast Technologies GmbH
5
 * Copyright 2014 Hardening <contact@hardening-consulting.com>
6
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2017 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 * http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/assert.h>
23
#include <winpr/memory.h>
24
#include <freerdp/log.h>
25
#include <freerdp/codec/region.h>
26
27
#define TAG FREERDP_TAG("codec")
28
29
/*
30
 * The functions in this file implement the Region abstraction largely inspired from
31
 * pixman library. The following comment is taken from the pixman code.
32
 *
33
 * A Region is simply a set of disjoint(non-overlapping) rectangles, plus an
34
 * "extent" rectangle which is the smallest single rectangle that contains all
35
 * the non-overlapping rectangles.
36
 *
37
 * A Region is implemented as a "y-x-banded" array of rectangles.  This array
38
 * imposes two degrees of order.  First, all rectangles are sorted by top side
39
 * y coordinate first (y1), and then by left side x coordinate (x1).
40
 *
41
 * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
42
 * band has the same top y coordinate (y1), and each has the same bottom y
43
 * coordinate (y2).  Thus all rectangles in a band differ only in their left
44
 * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
45
 * there is no separate list of band start pointers.
46
 *
47
 * The y-x band representation does not minimize rectangles.  In particular,
48
 * if a rectangle vertically crosses a band (the rectangle has scanlines in
49
 * the y1 to y2 area spanned by the band), then the rectangle may be broken
50
 * down into two or more smaller rectangles stacked one atop the other.
51
 *
52
 *  -----------                             -----------
53
 *  |         |                             |         |             band 0
54
 *  |         |  --------                   -----------  --------
55
 *  |         |  |      |  in y-x banded    |         |  |      |   band 1
56
 *  |         |  |      |  form is          |         |  |      |
57
 *  -----------  |      |                   -----------  --------
58
 *               |      |                                |      |   band 2
59
 *               --------                                --------
60
 *
61
 * An added constraint on the rectangles is that they must cover as much
62
 * horizontal area as possible: no two rectangles within a band are allowed
63
 * to touch.
64
 *
65
 * Whenever possible, bands will be merged together to cover a greater vertical
66
 * distance (and thus reduce the number of rectangles). Two bands can be merged
67
 * only if the bottom of one touches the top of the other and they have
68
 * rectangles in the same places (of the same width, of course).
69
 */
70
71
struct S_REGION16_DATA
72
{
73
  long size;
74
  long nbRects;
75
};
76
77
static REGION16_DATA empty_region = { 0, 0 };
78
79
void region16_init(REGION16* region)
80
13.3k
{
81
13.3k
  WINPR_ASSERT(region);
82
13.3k
  ZeroMemory(region, sizeof(REGION16));
83
13.3k
  region->data = &empty_region;
84
13.3k
}
85
86
int region16_n_rects(const REGION16* region)
87
36
{
88
36
  WINPR_ASSERT(region);
89
36
  WINPR_ASSERT(region->data);
90
36
  return region->data->nbRects;
91
36
}
92
93
const RECTANGLE_16* region16_rects(const REGION16* region, UINT32* nbRects)
94
928
{
95
928
  REGION16_DATA* data = NULL;
96
97
928
  if (nbRects)
98
928
    *nbRects = 0;
99
100
928
  if (!region)
101
0
    return NULL;
102
103
928
  data = region->data;
104
105
928
  if (!data)
106
0
    return NULL;
107
108
928
  if (nbRects)
109
928
    *nbRects = data->nbRects;
110
111
928
  return (RECTANGLE_16*)(data + 1);
112
928
}
113
114
static INLINE RECTANGLE_16* region16_rects_noconst(REGION16* region)
115
9
{
116
9
  REGION16_DATA* data = NULL;
117
9
  data = region->data;
118
119
9
  if (!data)
120
0
    return NULL;
121
122
9
  return (RECTANGLE_16*)(&data[1]);
123
9
}
124
125
const RECTANGLE_16* region16_extents(const REGION16* region)
126
18
{
127
18
  if (!region)
128
0
    return NULL;
129
130
18
  return &region->extents;
131
18
}
132
133
static RECTANGLE_16* region16_extents_noconst(REGION16* region)
134
18
{
135
18
  if (!region)
136
0
    return NULL;
137
138
18
  return &region->extents;
139
18
}
140
141
BOOL rectangle_is_empty(const RECTANGLE_16* rect)
142
0
{
143
  /* A rectangle with width <= 0 or height <= 0 should be regarded
144
   * as empty.
145
   */
146
0
  return ((rect->left >= rect->right) || (rect->top >= rect->bottom)) ? TRUE : FALSE;
147
0
}
148
149
BOOL region16_is_empty(const REGION16* region)
150
0
{
151
0
  WINPR_ASSERT(region);
152
0
  WINPR_ASSERT(region->data);
153
0
  return (region->data->nbRects == 0);
154
0
}
155
156
BOOL rectangles_equal(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
157
0
{
158
0
  return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
159
0
          (r1->bottom == r2->bottom))
160
0
             ? TRUE
161
0
             : FALSE;
162
0
}
163
164
BOOL rectangles_intersects(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
165
0
{
166
0
  RECTANGLE_16 tmp = { 0 };
167
0
  return rectangles_intersection(r1, r2, &tmp);
168
0
}
169
170
BOOL rectangles_intersection(const RECTANGLE_16* r1, const RECTANGLE_16* r2, RECTANGLE_16* dst)
171
0
{
172
0
  dst->left = MAX(r1->left, r2->left);
173
0
  dst->right = MIN(r1->right, r2->right);
174
0
  dst->top = MAX(r1->top, r2->top);
175
0
  dst->bottom = MIN(r1->bottom, r2->bottom);
176
0
  return (dst->left < dst->right) && (dst->top < dst->bottom);
177
0
}
178
179
void region16_clear(REGION16* region)
180
919
{
181
919
  WINPR_ASSERT(region);
182
919
  WINPR_ASSERT(region->data);
183
184
919
  if ((region->data->size > 0) && (region->data != &empty_region))
185
0
    free(region->data);
186
187
919
  region->data = &empty_region;
188
919
  ZeroMemory(&region->extents, sizeof(region->extents));
189
919
}
190
191
static INLINE REGION16_DATA* allocateRegion(long nbItems)
192
18
{
193
18
  long allocSize = sizeof(REGION16_DATA) + (nbItems * sizeof(RECTANGLE_16));
194
18
  REGION16_DATA* ret = (REGION16_DATA*)malloc(allocSize);
195
196
18
  if (!ret)
197
0
    return ret;
198
199
18
  ret->size = allocSize;
200
18
  ret->nbRects = nbItems;
201
18
  return ret;
202
18
}
203
204
BOOL region16_copy(REGION16* dst, const REGION16* src)
205
0
{
206
0
  WINPR_ASSERT(dst);
207
0
  WINPR_ASSERT(dst->data);
208
0
  WINPR_ASSERT(src);
209
0
  WINPR_ASSERT(src->data);
210
211
0
  if (dst == src)
212
0
    return TRUE;
213
214
0
  dst->extents = src->extents;
215
216
0
  if ((dst->data->size > 0) && (dst->data != &empty_region))
217
0
    free(dst->data);
218
219
0
  if (src->data->size == 0)
220
0
    dst->data = &empty_region;
221
0
  else
222
0
  {
223
0
    dst->data = allocateRegion(src->data->nbRects);
224
225
0
    if (!dst->data)
226
0
      return FALSE;
227
228
0
    CopyMemory(dst->data, src->data, src->data->size);
229
0
  }
230
231
0
  return TRUE;
232
0
}
233
234
void region16_print(const REGION16* region)
235
919
{
236
919
  const RECTANGLE_16* rects = NULL;
237
919
  UINT32 nbRects = 0;
238
919
  int currentBandY = -1;
239
919
  rects = region16_rects(region, &nbRects);
240
919
  WLog_DBG(TAG, "nrects=%" PRIu32 "", nbRects);
241
242
919
  for (UINT32 i = 0; i < nbRects; i++, rects++)
243
0
  {
244
0
    if (rects->top != currentBandY)
245
0
    {
246
0
      currentBandY = rects->top;
247
0
      WLog_DBG(TAG, "band %d: ", currentBandY);
248
0
    }
249
250
0
    WLog_DBG(TAG, "(%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16 ")", rects->left, rects->top,
251
0
             rects->right, rects->bottom);
252
0
  }
253
919
}
254
255
static void region16_copy_band_with_union(RECTANGLE_16* dst, const RECTANGLE_16* src,
256
                                          const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
257
                                          const RECTANGLE_16* unionRect, UINT32* dstCounter,
258
                                          const RECTANGLE_16** srcPtr, RECTANGLE_16** dstPtr)
259
9
{
260
9
  UINT16 refY = src->top;
261
9
  const RECTANGLE_16* startOverlap = NULL;
262
9
  const RECTANGLE_16* endOverlap = NULL;
263
264
  /* merges a band with the given rect
265
   * Input:
266
   *                   unionRect
267
   *               |               |
268
   *               |               |
269
   * ==============+===============+================================
270
   *   |Item1|  |Item2| |Item3|  |Item4|    |Item5|            Band
271
   * ==============+===============+================================
272
   *    before     |    overlap    |          after
273
   *
274
   * Resulting band:
275
   *   +-----+  +----------------------+    +-----+
276
   *   |Item1|  |      Item2           |    |Item3|
277
   *   +-----+  +----------------------+    +-----+
278
   *
279
   *  We first copy as-is items that are before Item2, the first overlapping
280
   *  item.
281
   *  Then we find the last one that overlap unionRect to agregate Item2, Item3
282
   *  and Item4 to create Item2.
283
   *  Finally Item5 is copied as Item3.
284
   *
285
   *  When no unionRect is provided, we skip the two first steps to just copy items
286
   */
287
288
9
  if (unionRect)
289
0
  {
290
    /* items before unionRect */
291
0
    while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
292
0
    {
293
0
      dst->top = newTop;
294
0
      dst->bottom = newBottom;
295
0
      dst->right = src->right;
296
0
      dst->left = src->left;
297
0
      src++;
298
0
      dst++;
299
0
      *dstCounter += 1;
300
0
    }
301
302
    /* treat items overlapping with unionRect */
303
0
    startOverlap = unionRect;
304
0
    endOverlap = unionRect;
305
306
0
    if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
307
0
      startOverlap = src;
308
309
0
    while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
310
0
    {
311
0
      src++;
312
0
    }
313
314
0
    if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
315
0
    {
316
0
      endOverlap = src;
317
0
      src++;
318
0
    }
319
320
0
    dst->bottom = newBottom;
321
0
    dst->top = newTop;
322
0
    dst->left = startOverlap->left;
323
0
    dst->right = endOverlap->right;
324
0
    dst++;
325
0
    *dstCounter += 1;
326
0
  }
327
328
  /* treat remaining items on the same band */
329
18
  while ((src < end) && (src->top == refY))
330
9
  {
331
9
    dst->top = newTop;
332
9
    dst->bottom = newBottom;
333
9
    dst->right = src->right;
334
9
    dst->left = src->left;
335
9
    src++;
336
9
    dst++;
337
9
    *dstCounter += 1;
338
9
  }
339
340
9
  if (srcPtr)
341
9
    *srcPtr = src;
342
343
9
  *dstPtr = dst;
344
9
}
345
346
static RECTANGLE_16* next_band(RECTANGLE_16* band1, RECTANGLE_16* endPtr, int* nbItems)
347
0
{
348
0
  UINT16 refY = band1->top;
349
0
  *nbItems = 0;
350
351
0
  while ((band1 < endPtr) && (band1->top == refY))
352
0
  {
353
0
    band1++;
354
0
    *nbItems += 1;
355
0
  }
356
357
0
  return band1;
358
0
}
359
360
static BOOL band_match(const RECTANGLE_16* band1, const RECTANGLE_16* band2,
361
                       const RECTANGLE_16* endPtr)
362
0
{
363
0
  int refBand2 = band2->top;
364
0
  const RECTANGLE_16* band2Start = band2;
365
366
0
  while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
367
0
  {
368
0
    if ((band1->left != band2->left) || (band1->right != band2->right))
369
0
      return FALSE;
370
371
0
    band1++;
372
0
    band2++;
373
0
  }
374
375
0
  if (band1 != band2Start)
376
0
    return FALSE;
377
378
0
  return (band2 == endPtr) || (band2->top != refBand2);
379
0
}
380
381
/** compute if the rectangle is fully included in the band
382
 * @param band a pointer on the beginning of the band
383
 * @param endPtr end of the region
384
 * @param rect the rectangle to test
385
 * @return if rect is fully included in an item of the band
386
 */
387
static BOOL rectangle_contained_in_band(const RECTANGLE_16* band, const RECTANGLE_16* endPtr,
388
                                        const RECTANGLE_16* rect)
389
0
{
390
0
  UINT16 refY = band->top;
391
392
0
  if ((band->top > rect->top) || (rect->bottom > band->bottom))
393
0
    return FALSE;
394
395
  /* note: as the band is sorted from left to right, once we've seen an item
396
   *    that is after rect->left we're sure that the result is False.
397
   */
398
0
  while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
399
0
  {
400
0
    if (rect->right <= band->right)
401
0
      return TRUE;
402
403
0
    band++;
404
0
  }
405
406
0
  return FALSE;
407
0
}
408
409
static BOOL region16_simplify_bands(REGION16* region)
410
9
{
411
  /** Simplify consecutive bands that touch and have the same items
412
   *
413
   *  ====================          ====================
414
   *     | 1 |  | 2   |               |   |  |     |
415
   *  ====================            |   |  |     |
416
   *     | 1 |  | 2   |    ====>    | 1 |  |  2  |
417
   *  ====================            |   |  |     |
418
   *     | 1 |  | 2   |               |   |  |     |
419
   *  ====================          ====================
420
   *
421
   */
422
9
  RECTANGLE_16* endBand = NULL;
423
9
  int nbRects = 0;
424
9
  int finalNbRects = 0;
425
9
  int bandItems = 0;
426
9
  int toMove = 0;
427
9
  finalNbRects = nbRects = region16_n_rects(region);
428
429
9
  if (nbRects < 2)
430
9
    return TRUE;
431
432
0
  RECTANGLE_16* band1 = region16_rects_noconst(region);
433
0
  RECTANGLE_16* endPtr = band1 + nbRects;
434
435
0
  do
436
0
  {
437
0
    RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
438
439
0
    if (band2 == endPtr)
440
0
      break;
441
442
0
    if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
443
0
    {
444
      /* adjust the bottom of band1 items */
445
0
      RECTANGLE_16* tmp = band1;
446
447
0
      while (tmp < band2)
448
0
      {
449
0
        tmp->bottom = band2->bottom;
450
0
        tmp++;
451
0
      }
452
453
      /* override band2, we don't move band1 pointer as the band after band2
454
       * may be merged too */
455
0
      endBand = band2 + bandItems;
456
0
      toMove = (endPtr - endBand) * sizeof(RECTANGLE_16);
457
458
0
      if (toMove)
459
0
        MoveMemory(band2, endBand, toMove);
460
461
0
      finalNbRects -= bandItems;
462
0
      endPtr -= bandItems;
463
0
    }
464
0
    else
465
0
    {
466
0
      band1 = band2;
467
0
    }
468
0
  } while (TRUE);
469
470
0
  if (finalNbRects != nbRects)
471
0
  {
472
0
    size_t allocSize = sizeof(REGION16_DATA) + (finalNbRects * sizeof(RECTANGLE_16));
473
0
    REGION16_DATA* data = realloc(region->data, allocSize);
474
0
    if (!data)
475
0
      free(region->data);
476
0
    region->data = data;
477
478
0
    if (!region->data)
479
0
    {
480
0
      region->data = &empty_region;
481
0
      return FALSE;
482
0
    }
483
484
0
    region->data->nbRects = finalNbRects;
485
0
    region->data->size = allocSize;
486
0
  }
487
488
0
  return TRUE;
489
0
}
490
491
BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
492
18
{
493
18
  const RECTANGLE_16* srcExtents = NULL;
494
18
  RECTANGLE_16* dstExtents = NULL;
495
18
  const RECTANGLE_16* currentBand = NULL;
496
18
  const RECTANGLE_16* endSrcRect = NULL;
497
18
  const RECTANGLE_16* nextBand = NULL;
498
18
  REGION16_DATA* newItems = NULL;
499
18
  REGION16_DATA* tmpItems = NULL;
500
18
  RECTANGLE_16* dstRect = NULL;
501
18
  UINT32 usedRects = 0;
502
18
  UINT32 srcNbRects = 0;
503
18
  UINT16 topInterBand = 0;
504
18
  WINPR_ASSERT(src);
505
18
  WINPR_ASSERT(dst);
506
18
  srcExtents = region16_extents(src);
507
18
  dstExtents = region16_extents_noconst(dst);
508
509
18
  if (!region16_n_rects(src))
510
9
  {
511
    /* source is empty, so the union is rect */
512
9
    dst->extents = *rect;
513
9
    dst->data = allocateRegion(1);
514
515
9
    if (!dst->data)
516
0
      return FALSE;
517
518
9
    dstRect = region16_rects_noconst(dst);
519
9
    dstRect->top = rect->top;
520
9
    dstRect->left = rect->left;
521
9
    dstRect->right = rect->right;
522
9
    dstRect->bottom = rect->bottom;
523
9
    return TRUE;
524
9
  }
525
526
9
  newItems = allocateRegion((1 + region16_n_rects(src)) * 4);
527
528
9
  if (!newItems)
529
0
    return FALSE;
530
531
9
  dstRect = (RECTANGLE_16*)(&newItems[1]);
532
9
  usedRects = 0;
533
534
  /* adds the piece of rect that is on the top of src */
535
9
  if (rect->top < srcExtents->top)
536
0
  {
537
0
    dstRect->top = rect->top;
538
0
    dstRect->left = rect->left;
539
0
    dstRect->right = rect->right;
540
0
    dstRect->bottom = MIN(srcExtents->top, rect->bottom);
541
0
    usedRects++;
542
0
    dstRect++;
543
0
  }
544
545
  /* treat possibly overlapping region */
546
9
  currentBand = region16_rects(src, &srcNbRects);
547
9
  endSrcRect = currentBand + srcNbRects;
548
549
18
  while (currentBand < endSrcRect)
550
9
  {
551
9
    if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
552
9
        rectangle_contained_in_band(currentBand, endSrcRect, rect))
553
9
    {
554
      /* no overlap between rect and the band, rect is totally below or totally above
555
       * the current band, or rect is already covered by an item of the band.
556
       * let's copy all the rectangles from this band
557
                  +----+
558
                  |    |   rect (case 1)
559
                  +----+
560
561
         =================
562
      band of srcRect
563
       =================
564
              +----+
565
              |    |   rect (case 2)
566
              +----+
567
      */
568
9
      region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
569
9
                                    currentBand->bottom, NULL, &usedRects, &nextBand,
570
9
                                    &dstRect);
571
9
      topInterBand = rect->top;
572
9
    }
573
0
    else
574
0
    {
575
      /* rect overlaps the band:
576
                 |    |  |    |
577
      ====^=================|    |==|    |=========================== band
578
      |   top split     |    |  |    |
579
      v                 | 1  |  | 2  |
580
      ^                 |    |  |    |  +----+   +----+
581
      |   merge zone    |    |  |    |  |    |   | 4  |
582
      v                 +----+  |    |  |    |   +----+
583
      ^                         |    |  | 3  |
584
      |   bottom split          |    |  |    |
585
      ====v=========================|    |==|    |===================
586
                 |    |  |    |
587
588
       possible cases:
589
       1) no top split, merge zone then a bottom split. The band will be splitted
590
        in two
591
       2) not band split, only the merge zone, band merged with rect but not splitted
592
       3) a top split, the merge zone and no bottom split. The band will be split
593
       in two
594
       4) a top split, the merge zone and also a bottom split. The band will be
595
       splitted in 3, but the coalesce algorithm may merge the created bands
596
       */
597
0
      UINT16 mergeTop = currentBand->top;
598
0
      UINT16 mergeBottom = currentBand->bottom;
599
600
      /* test if we need a top split, case 3 and 4 */
601
0
      if (rect->top > currentBand->top)
602
0
      {
603
0
        region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
604
0
                                      rect->top, NULL, &usedRects, &nextBand, &dstRect);
605
0
        mergeTop = rect->top;
606
0
      }
607
608
      /* do the merge zone (all cases) */
609
0
      if (rect->bottom < currentBand->bottom)
610
0
        mergeBottom = rect->bottom;
611
612
0
      region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeTop, mergeBottom,
613
0
                                    rect, &usedRects, &nextBand, &dstRect);
614
615
      /* test if we need a bottom split, case 1 and 4 */
616
0
      if (rect->bottom < currentBand->bottom)
617
0
      {
618
0
        region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeBottom,
619
0
                                      currentBand->bottom, NULL, &usedRects, &nextBand,
620
0
                                      &dstRect);
621
0
      }
622
623
0
      topInterBand = currentBand->bottom;
624
0
    }
625
626
    /* test if a piece of rect should be inserted as a new band between
627
     * the current band and the next one. band n and n+1 shouldn't touch.
628
     *
629
     * ==============================================================
630
     *                                                        band n
631
     *            +------+                    +------+
632
     * ===========| rect |====================|      |===============
633
     *            |      |    +------+        |      |
634
     *            +------+    | rect |        | rect |
635
     *                        +------+        |      |
636
     * =======================================|      |================
637
     *                                        +------+         band n+1
638
     * ===============================================================
639
     *
640
     */
641
9
    if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
642
9
        (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
643
0
    {
644
0
      dstRect->right = rect->right;
645
0
      dstRect->left = rect->left;
646
0
      dstRect->top = topInterBand;
647
0
      dstRect->bottom = MIN(nextBand->top, rect->bottom);
648
0
      dstRect++;
649
0
      usedRects++;
650
0
    }
651
652
9
    currentBand = nextBand;
653
9
  }
654
655
  /* adds the piece of rect that is below src */
656
9
  if (srcExtents->bottom < rect->bottom)
657
0
  {
658
0
    dstRect->top = MAX(srcExtents->bottom, rect->top);
659
0
    dstRect->left = rect->left;
660
0
    dstRect->right = rect->right;
661
0
    dstRect->bottom = rect->bottom;
662
0
    usedRects++;
663
0
    dstRect++;
664
0
  }
665
666
9
  if ((src == dst) && (dst->data != &empty_region))
667
9
    free(dst->data);
668
669
9
  dstExtents->top = MIN(rect->top, srcExtents->top);
670
9
  dstExtents->left = MIN(rect->left, srcExtents->left);
671
9
  dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
672
9
  dstExtents->right = MAX(rect->right, srcExtents->right);
673
9
  newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16));
674
9
  tmpItems = realloc(newItems, newItems->size);
675
9
  if (!tmpItems)
676
0
    free(newItems);
677
9
  newItems = tmpItems;
678
9
  dst->data = newItems;
679
680
9
  if (!dst->data)
681
0
    return FALSE;
682
683
9
  dst->data->nbRects = usedRects;
684
9
  return region16_simplify_bands(dst);
685
9
}
686
687
BOOL region16_intersects_rect(const REGION16* src, const RECTANGLE_16* arg2)
688
0
{
689
0
  const RECTANGLE_16* rect = NULL;
690
0
  const RECTANGLE_16* endPtr = NULL;
691
0
  const RECTANGLE_16* srcExtents = NULL;
692
0
  UINT32 nbRects = 0;
693
694
0
  if (!src || !src->data || !arg2)
695
0
    return FALSE;
696
697
0
  rect = region16_rects(src, &nbRects);
698
699
0
  if (!nbRects)
700
0
    return FALSE;
701
702
0
  srcExtents = region16_extents(src);
703
704
0
  if (nbRects == 1)
705
0
    return rectangles_intersects(srcExtents, arg2);
706
707
0
  if (!rectangles_intersects(srcExtents, arg2))
708
0
    return FALSE;
709
710
0
  for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
711
0
  {
712
0
    if (rectangles_intersects(rect, arg2))
713
0
      return TRUE;
714
0
  }
715
716
0
  return FALSE;
717
0
}
718
719
BOOL region16_intersect_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
720
0
{
721
0
  REGION16_DATA* newItems = NULL;
722
0
  const RECTANGLE_16* srcPtr = NULL;
723
0
  const RECTANGLE_16* endPtr = NULL;
724
0
  const RECTANGLE_16* srcExtents = NULL;
725
0
  RECTANGLE_16* dstPtr = NULL;
726
0
  UINT32 nbRects = 0;
727
0
  UINT32 usedRects = 0;
728
0
  RECTANGLE_16 common;
729
0
  RECTANGLE_16 newExtents;
730
0
  WINPR_ASSERT(src);
731
0
  WINPR_ASSERT(src->data);
732
0
  srcPtr = region16_rects(src, &nbRects);
733
734
0
  if (!nbRects)
735
0
  {
736
0
    region16_clear(dst);
737
0
    return TRUE;
738
0
  }
739
740
0
  srcExtents = region16_extents(src);
741
742
0
  if (nbRects == 1)
743
0
  {
744
0
    BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
745
0
    region16_clear(dst);
746
747
0
    if (intersects)
748
0
      return region16_union_rect(dst, dst, &common);
749
750
0
    return TRUE;
751
0
  }
752
753
0
  newItems = allocateRegion(nbRects);
754
755
0
  if (!newItems)
756
0
    return FALSE;
757
758
0
  dstPtr = (RECTANGLE_16*)(&newItems[1]);
759
0
  usedRects = 0;
760
0
  ZeroMemory(&newExtents, sizeof(newExtents));
761
762
  /* accumulate intersecting rectangles, the final region16_simplify_bands() will
763
   * do all the bad job to recreate correct rectangles
764
   */
765
0
  for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
766
0
  {
767
0
    if (rectangles_intersection(srcPtr, rect, &common))
768
0
    {
769
0
      *dstPtr = common;
770
0
      usedRects++;
771
0
      dstPtr++;
772
773
0
      if (rectangle_is_empty(&newExtents))
774
0
      {
775
        /* Check if the existing newExtents is empty. If it is empty, use
776
         * new common directly. We do not need to check common rectangle
777
         * because the rectangles_intersection() ensures that it is not empty.
778
         */
779
0
        newExtents = common;
780
0
      }
781
0
      else
782
0
      {
783
0
        newExtents.top = MIN(common.top, newExtents.top);
784
0
        newExtents.left = MIN(common.left, newExtents.left);
785
0
        newExtents.bottom = MAX(common.bottom, newExtents.bottom);
786
0
        newExtents.right = MAX(common.right, newExtents.right);
787
0
      }
788
0
    }
789
0
  }
790
791
0
  newItems->nbRects = usedRects;
792
0
  newItems->size = sizeof(REGION16_DATA) + (usedRects * sizeof(RECTANGLE_16));
793
794
0
  if ((dst->data->size > 0) && (dst->data != &empty_region))
795
0
    free(dst->data);
796
797
0
  dst->data = realloc(newItems, newItems->size);
798
799
0
  if (!dst->data)
800
0
  {
801
0
    free(newItems);
802
0
    return FALSE;
803
0
  }
804
805
0
  dst->extents = newExtents;
806
0
  return region16_simplify_bands(dst);
807
0
}
808
809
void region16_uninit(REGION16* region)
810
13.3k
{
811
13.3k
  WINPR_ASSERT(region);
812
813
13.3k
  if (region->data)
814
13.3k
  {
815
13.3k
    if ((region->data->size > 0) && (region->data != &empty_region))
816
9
      free(region->data);
817
818
13.3k
    region->data = NULL;
819
13.3k
  }
820
13.3k
}