@@ -190,6 +190,51 @@ size_t DlRegion::unionLineSpans(std::vector<Span>& res,
190
190
return new_span - res.data ();
191
191
}
192
192
193
+ size_t DlRegion::intersectLineSpans (std::vector<Span>& res,
194
+ const SpanBuffer& a_buffer,
195
+ SpanChunkHandle a_handle,
196
+ const SpanBuffer& b_buffer,
197
+ SpanChunkHandle b_handle) {
198
+ const Span *begin1, *end1;
199
+ a_buffer.getSpans (a_handle, begin1, end1);
200
+
201
+ const Span *begin2, *end2;
202
+ b_buffer.getSpans (b_handle, begin2, end2);
203
+
204
+ // Worst case scenario, interleaved overlapping spans
205
+ // AAAA BBBB CCCC
206
+ // XXX YYYY XXXX
207
+ size_t min_size = (end1 - begin1) + (end2 - begin2) - 1 ;
208
+ if (res.size () < min_size) {
209
+ res.resize (min_size);
210
+ }
211
+
212
+ // Pointer to the next span to be written.
213
+ Span* new_span = res.data ();
214
+
215
+ while (begin1 != end1 && begin2 != end2) {
216
+ if (begin1->right <= begin2->left ) {
217
+ ++begin1;
218
+ } else if (begin2->right <= begin1->left ) {
219
+ ++begin2;
220
+ } else {
221
+ int32_t left = std::max (begin1->left , begin2->left );
222
+ int32_t right = std::min (begin1->right , begin2->right );
223
+ FML_DCHECK (left < right);
224
+ FML_DCHECK (new_span < res.data () + res.size ());
225
+ *new_span++ = {left, right};
226
+ if (begin1->right == right) {
227
+ ++begin1;
228
+ }
229
+ if (begin2->right == right) {
230
+ ++begin2;
231
+ }
232
+ }
233
+ }
234
+
235
+ return new_span - res.data ();
236
+ }
237
+
193
238
void DlRegion::addRects (const std::vector<SkIRect>& unsorted_rects) {
194
239
size_t count = unsorted_rects.size ();
195
240
std::vector<const SkIRect*> rects (count);
@@ -326,41 +371,35 @@ void DlRegion::addRects(const std::vector<SkIRect>& unsorted_rects) {
326
371
#endif
327
372
}
328
373
374
+ void DlRegion::appendLine (int32_t top,
375
+ int32_t bottom,
376
+ const Span* begin,
377
+ const Span* end) {
378
+ if (lines_.empty ()) {
379
+ lines_.push_back (makeLine (top, bottom, begin, end));
380
+ } else {
381
+ if (lines_.back ().bottom == top && spansEqual (lines_.back (), begin, end)) {
382
+ lines_.back ().bottom = bottom;
383
+ } else {
384
+ lines_.push_back (makeLine (top, bottom, begin, end));
385
+ }
386
+ }
387
+ }
388
+
329
389
DlRegion DlRegion::MakeUnion (const DlRegion& a, const DlRegion& b) {
330
390
DlRegion res;
331
391
332
- res.span_buffer_ .reserve (a.span_buffer_ .capacity () +
333
- b.span_buffer_ .capacity ());
334
392
res.bounds_ = a.bounds_ ;
335
393
res.bounds_ .join (b.bounds_ );
336
394
395
+ res.span_buffer_ .reserve (a.span_buffer_ .capacity () +
396
+ b.span_buffer_ .capacity ());
397
+
337
398
auto & lines = res.lines_ ;
338
399
lines.reserve (a.lines_ .size () + b.lines_ .size ());
339
400
340
- auto append_spans = [&](int32_t top, int32_t bottom, const Span* begin,
341
- const Span* end) {
342
- if (lines.empty ()) {
343
- lines.push_back (res.makeLine (top, bottom, begin, end));
344
- } else {
345
- if (lines.back ().bottom == top &&
346
- res.spansEqual (lines.back (), begin, end)) {
347
- lines.back ().bottom = bottom;
348
- } else {
349
- lines.push_back (res.makeLine (top, bottom, begin, end));
350
- }
351
- }
352
- };
353
-
354
- auto append_line = [&](int32_t top, int32_t bottom, const SpanBuffer& buffer,
355
- SpanChunkHandle chunk_handle) {
356
- const Span *begin, *end;
357
- buffer.getSpans (chunk_handle, begin, end);
358
- append_spans (top, bottom, begin, end);
359
- };
360
-
361
401
auto a_lines = a.lines_ ;
362
402
auto b_lines = b.lines_ ;
363
-
364
403
auto a_it = a_lines.begin ();
365
404
auto b_it = b_lines.begin ();
366
405
@@ -371,20 +410,20 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
371
410
372
411
while (a_it != a_lines.end () && b_it != b_lines.end ()) {
373
412
if (a_it->bottom <= b_it->top ) {
374
- append_line (a_it->top , a_it->bottom , a_buffer, a_it->chunk_handle );
413
+ res. appendLine (a_it->top , a_it->bottom , a_buffer, a_it->chunk_handle );
375
414
++a_it;
376
415
} else if (b_it->bottom <= a_it->top ) {
377
- append_line (b_it->top , b_it->bottom , b_buffer, b_it->chunk_handle );
416
+ res. appendLine (b_it->top , b_it->bottom , b_buffer, b_it->chunk_handle );
378
417
++b_it;
379
418
} else {
380
419
if (a_it->top < b_it->top ) {
381
- append_line (a_it->top , b_it->top , a_buffer, a_it->chunk_handle );
420
+ res. appendLine (a_it->top , b_it->top , a_buffer, a_it->chunk_handle );
382
421
a_it->top = b_it->top ;
383
422
if (a_it->top == b_it->bottom ) {
384
423
++a_it;
385
424
}
386
425
} else if (b_it->top < a_it->top ) {
387
- append_line (b_it->top , a_it->top , b_buffer, b_it->chunk_handle );
426
+ res. appendLine (b_it->top , a_it->top , b_buffer, b_it->chunk_handle );
388
427
b_it->top = a_it->top ;
389
428
if (b_it->top == a_it->bottom ) {
390
429
++b_it;
@@ -396,7 +435,7 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
396
435
FML_DCHECK (new_bottom > b_it->top );
397
436
auto size = unionLineSpans (tmp, a_buffer, a_it->chunk_handle , b_buffer,
398
437
b_it->chunk_handle );
399
- append_spans (a_it->top , new_bottom, tmp.data (), tmp.data () + size);
438
+ res. appendLine (a_it->top , new_bottom, tmp.data (), tmp.data () + size);
400
439
a_it->top = b_it->top = new_bottom;
401
440
if (a_it->top == a_it->bottom ) {
402
441
++a_it;
@@ -411,18 +450,68 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
411
450
FML_DCHECK (a_it == a_lines.end () || b_it == b_lines.end ());
412
451
413
452
while (a_it != a_lines.end ()) {
414
- append_line (a_it->top , a_it->bottom , a_buffer, a_it->chunk_handle );
453
+ res. appendLine (a_it->top , a_it->bottom , a_buffer, a_it->chunk_handle );
415
454
++a_it;
416
455
}
417
456
418
457
while (b_it != b_lines.end ()) {
419
- append_line (b_it->top , b_it->bottom , b_buffer, b_it->chunk_handle );
458
+ res. appendLine (b_it->top , b_it->bottom , b_buffer, b_it->chunk_handle );
420
459
++b_it;
421
460
}
422
461
423
462
return res;
424
463
}
425
464
465
+ DlRegion DlRegion::MakeIntersection (const DlRegion& a, const DlRegion& b) {
466
+ DlRegion res;
467
+ if (!SkIRect::Intersects (a.bounds_ , b.bounds_ )) {
468
+ return res;
469
+ }
470
+
471
+ res.span_buffer_ .reserve (
472
+ std::max (a.span_buffer_ .capacity (), b.span_buffer_ .capacity ()));
473
+
474
+ auto & lines = res.lines_ ;
475
+ lines.reserve (std::min (a.lines_ .size (), b.lines_ .size ()));
476
+
477
+ auto a_lines = a.lines_ ;
478
+ auto b_lines = b.lines_ ;
479
+ auto a_it = a_lines.begin ();
480
+ auto b_it = b_lines.begin ();
481
+
482
+ auto & a_buffer = a.span_buffer_ ;
483
+ auto & b_buffer = b.span_buffer_ ;
484
+
485
+ std::vector<Span> tmp;
486
+
487
+ while (a_it != a_lines.end () && b_it != b_lines.end ()) {
488
+ if (a_it->bottom <= b_it->top ) {
489
+ ++a_it;
490
+ } else if (b_it->bottom <= a_it->top ) {
491
+ ++b_it;
492
+ } else {
493
+ auto top = std::max (a_it->top , b_it->top );
494
+ auto bottom = std::min (a_it->bottom , b_it->bottom );
495
+ auto size = intersectLineSpans (tmp, a_buffer, a_it->chunk_handle ,
496
+ b_buffer, b_it->chunk_handle );
497
+ if (size > 0 ) {
498
+ res.appendLine (top, bottom, tmp.data (), tmp.data () + size);
499
+ res.bounds_ .join (SkIRect::MakeLTRB (
500
+ tmp.data ()->left , top, (tmp.data () + size - 1 )->right , bottom));
501
+ }
502
+ a_it->top = b_it->top = bottom;
503
+ if (a_it->top == a_it->bottom ) {
504
+ ++a_it;
505
+ }
506
+ if (b_it->top == b_it->bottom ) {
507
+ ++b_it;
508
+ }
509
+ }
510
+ }
511
+ FML_DCHECK (a_it == a_lines.end () || b_it == b_lines.end ());
512
+ return res;
513
+ }
514
+
426
515
std::vector<SkIRect> DlRegion::getRects (bool deband) const {
427
516
std::vector<SkIRect> rects;
428
517
size_t rect_count = 0 ;
0 commit comments