Flutter Engine
 
Loading...
Searching...
No Matches
dl_region.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8
9namespace flutter {
10
11// Threshold for switching from linear search through span lines to binary
12// search.
14
15DlRegion::SpanBuffer::SpanBuffer(DlRegion::SpanBuffer&& m)
16 : capacity_(m.capacity_), size_(m.size_), spans_(m.spans_) {
17 m.size_ = 0;
18 m.capacity_ = 0;
19 m.spans_ = nullptr;
20};
21
22DlRegion::SpanBuffer::SpanBuffer(const DlRegion::SpanBuffer& m)
23 : capacity_(m.capacity_), size_(m.size_) {
24 if (m.spans_ == nullptr) {
25 spans_ = nullptr;
26 } else {
27 spans_ = static_cast<Span*>(std::malloc(capacity_ * sizeof(Span)));
28 memcpy(spans_, m.spans_, size_ * sizeof(Span));
29 }
30};
31
32DlRegion::SpanBuffer& DlRegion::SpanBuffer::operator=(
33 const DlRegion::SpanBuffer& buffer) {
34 SpanBuffer copy(buffer);
35 std::swap(*this, copy);
36 return *this;
37}
38
39DlRegion::SpanBuffer& DlRegion::SpanBuffer::operator=(
40 DlRegion::SpanBuffer&& buffer) {
41 std::swap(capacity_, buffer.capacity_);
42 std::swap(size_, buffer.size_);
43 std::swap(spans_, buffer.spans_);
44 return *this;
45}
46
47DlRegion::SpanBuffer::~SpanBuffer() {
48 free(spans_);
49}
50
51void DlRegion::SpanBuffer::reserve(size_t capacity) {
52 if (capacity_ < capacity) {
53 spans_ = static_cast<Span*>(std::realloc(spans_, capacity * sizeof(Span)));
54 capacity_ = capacity;
55 }
56}
57
58DlRegion::SpanChunkHandle DlRegion::SpanBuffer::storeChunk(const Span* begin,
59 const Span* end) {
60 size_t chunk_size = end - begin;
61 size_t min_capacity = size_ + chunk_size + 1;
62 if (capacity_ < min_capacity) {
63 size_t new_capacity = std::max(min_capacity, capacity_ * 2);
64 new_capacity = std::max(new_capacity, static_cast<size_t>(512));
65 reserve(new_capacity);
66 }
67 SpanChunkHandle res = size_;
68 size_ += chunk_size + 1;
69 setChunkSize(res, chunk_size);
70
71 auto* dst = spans_ + res + 1;
72 memmove(dst, begin, chunk_size * sizeof(Span));
73
74 return res;
75}
76
77size_t DlRegion::SpanBuffer::getChunkSize(SpanChunkHandle handle) const {
78 FML_DCHECK(handle < size_);
79 return spans_[handle].left;
80}
81
82void DlRegion::SpanBuffer::setChunkSize(SpanChunkHandle handle, size_t size) {
83 FML_DCHECK(handle < size_);
84 FML_DCHECK(spans_ != nullptr);
85 // NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
86 spans_[handle].left = size;
87}
88
89void DlRegion::SpanBuffer::getSpans(SpanChunkHandle handle,
90 const DlRegion::Span*& begin,
91 const DlRegion::Span*& end) const {
92 FML_DCHECK(handle < size_);
93 begin = spans_ + handle + 1;
94 end = begin + getChunkSize(handle);
95}
96
97DlRegion::DlRegion(const std::vector<DlIRect>& rects) {
98 setRects(rects);
99}
100
101DlRegion::DlRegion(const DlIRect& rect) : bounds_(rect) {
102 Span span{rect.GetLeft(), rect.GetRight()};
103 lines_.push_back(makeLine(rect.GetTop(), rect.GetBottom(), &span, &span + 1));
104}
105
106bool DlRegion::spansEqual(SpanLine& line,
107 const Span* begin,
108 const Span* end) const {
109 const Span *our_begin, *our_end;
110 span_buffer_.getSpans(line.chunk_handle, our_begin, our_end);
111 size_t our_size = our_end - our_begin;
112 size_t their_size = end - begin;
113 if (our_size != their_size) {
114 return false;
115 }
116
117 return memcmp(our_begin, begin, our_size * sizeof(Span)) == 0;
118}
119
120DlRegion::SpanLine DlRegion::makeLine(int32_t top,
121 int32_t bottom,
122 const SpanVec& v) {
123 return makeLine(top, bottom, v.data(), v.data() + v.size());
124}
125
126DlRegion::SpanLine DlRegion::makeLine(int32_t top,
127 int32_t bottom,
128 const Span* begin,
129 const Span* end) {
130 auto handle = span_buffer_.storeChunk(begin, end);
131 return {top, bottom, handle};
132}
133
134// Returns number of valid spans in res. For performance reasons res is never
135// downsized.
136size_t DlRegion::unionLineSpans(std::vector<Span>& res,
137 const SpanBuffer& a_buffer,
138 SpanChunkHandle a_handle,
139 const SpanBuffer& b_buffer,
140 SpanChunkHandle b_handle) {
141 class OrderedSpanAccumulator {
142 public:
143 explicit OrderedSpanAccumulator(std::vector<Span>& res) : res(res) {}
144
145 void accumulate(const Span& span) {
146 if (span.left > last_ || len == 0) {
147 res[len++] = span;
148 last_ = span.right;
149 } else if (span.right > last_) {
150 FML_DCHECK(len > 0);
151 res[len - 1].right = span.right;
152 last_ = span.right;
153 }
154 }
155
156 size_t len = 0;
157 std::vector<Span>& res;
158
159 private:
160 int32_t last_ = std::numeric_limits<int32_t>::min();
161 };
162
163 const Span *begin1, *end1;
164 a_buffer.getSpans(a_handle, begin1, end1);
165
166 const Span *begin2, *end2;
167 b_buffer.getSpans(b_handle, begin2, end2);
168
169 size_t min_size = (end1 - begin1) + (end2 - begin2);
170 if (res.size() < min_size) {
171 res.resize(min_size);
172 }
173
174 OrderedSpanAccumulator accumulator(res);
175
176 while (true) {
177 if (begin1->left < begin2->left) {
178 accumulator.accumulate(*begin1++);
179 if (begin1 == end1) {
180 break;
181 }
182 } else {
183 // Either 2 is first, or they are equal, in which case add 2 now
184 // and we might combine 1 with it next time around
185 accumulator.accumulate(*begin2++);
186 if (begin2 == end2) {
187 break;
188 }
189 }
190 }
191
192 FML_DCHECK(begin1 == end1 || begin2 == end2);
193
194 while (begin1 < end1) {
195 accumulator.accumulate(*begin1++);
196 }
197 while (begin2 < end2) {
198 accumulator.accumulate(*begin2++);
199 }
200
201 FML_DCHECK(begin1 == end1 && begin2 == end2);
202
203 return accumulator.len;
204}
205
206size_t DlRegion::intersectLineSpans(std::vector<Span>& res,
207 const SpanBuffer& a_buffer,
208 SpanChunkHandle a_handle,
209 const SpanBuffer& b_buffer,
210 SpanChunkHandle b_handle) {
211 const Span *begin1, *end1;
212 a_buffer.getSpans(a_handle, begin1, end1);
213
214 const Span *begin2, *end2;
215 b_buffer.getSpans(b_handle, begin2, end2);
216
217 // Worst case scenario, interleaved overlapping spans
218 // AAAA BBBB CCCC
219 // XXX YYYY XXXX
220 size_t min_size = (end1 - begin1) + (end2 - begin2) - 1;
221 if (res.size() < min_size) {
222 res.resize(min_size);
223 }
224
225 // Pointer to the next span to be written.
226 Span* new_span = res.data();
227
228 while (begin1 != end1 && begin2 != end2) {
229 if (begin1->right <= begin2->left) {
230 ++begin1;
231 } else if (begin2->right <= begin1->left) {
232 ++begin2;
233 } else {
234 int32_t left = std::max(begin1->left, begin2->left);
235 int32_t right = std::min(begin1->right, begin2->right);
236 FML_DCHECK(left < right);
237 FML_DCHECK(new_span < res.data() + res.size());
238 *new_span++ = {left, right};
239 if (begin1->right == right) {
240 ++begin1;
241 }
242 if (begin2->right == right) {
243 ++begin2;
244 }
245 }
246 }
247
248 return new_span - res.data();
249}
250
251void DlRegion::setRects(const std::vector<DlIRect>& unsorted_rects) {
252 // setRects can only be called on empty regions.
253 FML_DCHECK(lines_.empty());
254
255 size_t count = unsorted_rects.size();
256 std::vector<const DlIRect*> rects(count);
257 for (size_t i = 0; i < count; i++) {
258 rects[i] = &unsorted_rects[i];
259 bounds_ = bounds_.Union(unsorted_rects[i]);
260 }
261 std::sort(rects.begin(), rects.end(), [](const DlIRect* a, const DlIRect* b) {
262 if (a->GetTop() < b->GetTop()) {
263 return true;
264 }
265 if (a->GetTop() > b->GetTop()) {
266 return false;
267 }
268 return a->GetLeft() < b->GetLeft();
269 });
270
271 size_t active_end = 0;
272 size_t next_rect = 0;
273 int32_t cur_y = std::numeric_limits<int32_t>::min();
274 SpanVec working_spans;
275
276#ifdef DlRegion_DO_STATS
277 size_t active_rect_count = 0;
278 size_t span_count = 0;
279 int pass_count = 0;
280 int line_count = 0;
281#endif
282
283 while (next_rect < count || active_end > 0) {
284 // First prune passed rects out of the active list
285 size_t preserve_end = 0;
286 for (size_t i = 0; i < active_end; i++) {
287 const DlIRect* r = rects[i];
288 if (r->GetBottom() > cur_y) {
289 rects[preserve_end++] = r;
290 }
291 }
292 active_end = preserve_end;
293
294 // If we have no active rects any more, jump to the top of the
295 // next available input rect.
296 if (active_end == 0) {
297 if (next_rect >= count) {
298 // No active rects and no more rects to bring in. We are done.
299 break;
300 }
301 cur_y = rects[next_rect]->GetTop();
302 }
303
304 // Next, insert any new rects we've reached into the active list
305 while (next_rect < count) {
306 const DlIRect* r = rects[next_rect];
307 if (r->IsEmpty()) {
308 continue;
309 }
310 if (r->GetTop() > cur_y) {
311 break;
312 }
313 // We now know that we will be inserting this rect into active list
314 next_rect++;
315 size_t insert_at = active_end++;
316 while (insert_at > 0) {
317 const DlIRect* ir = rects[insert_at - 1];
318 if (ir->GetLeft() <= r->GetLeft()) {
319 break;
320 }
321 rects[insert_at--] = ir;
322 }
323 rects[insert_at] = r;
324 }
325
326 // We either preserved some rects in the active list or added more from
327 // the remaining input rects, or we would have exited the loop above.
328 FML_DCHECK(active_end != 0);
329 working_spans.clear();
330 FML_DCHECK(working_spans.empty());
331
332#ifdef DlRegion_DO_STATS
333 active_rect_count += active_end;
334 pass_count++;
335#endif
336
337 // [start_x, end_x) always represents a valid span to be inserted
338 // [cur_y, end_y) is the intersecting range over which all spans are valid
339 int32_t start_x = rects[0]->GetLeft();
340 int32_t end_x = rects[0]->GetRight();
341 int32_t end_y = rects[0]->GetBottom();
342 for (size_t i = 1; i < active_end; i++) {
343 const DlIRect* r = rects[i];
344 if (r->GetLeft() > end_x) {
345 working_spans.emplace_back(start_x, end_x);
346 start_x = r->GetLeft();
347 end_x = r->GetRight();
348 } else if (end_x < r->GetRight()) {
349 end_x = r->GetRight();
350 }
351 if (end_y > r->GetBottom()) {
352 end_y = r->GetBottom();
353 }
354 }
355 working_spans.emplace_back(start_x, end_x);
356
357 // end_y must not pass by the top of the next input rect
358 if (next_rect < count && end_y > rects[next_rect]->GetTop()) {
359 end_y = rects[next_rect]->GetTop();
360 }
361
362 // If all of the rules above work out, we should never collapse the
363 // current range of Y coordinates to empty
364 FML_DCHECK(end_y > cur_y);
365
366 if (!lines_.empty() && lines_.back().bottom == cur_y &&
367 spansEqual(lines_.back(), working_spans.data(),
368 working_spans.data() + working_spans.size())) {
369 lines_.back().bottom = end_y;
370 } else {
371#ifdef DlRegion_DO_STATS
372 span_count += working_spans.size();
373 line_count++;
374#endif
375 lines_.push_back(makeLine(cur_y, end_y, working_spans));
376 }
377 cur_y = end_y;
378 }
379
380#ifdef DlRegion_DO_STATS
381 double span_avg = ((double)span_count) / line_count;
382 double active_avg = ((double)active_rect_count) / pass_count;
383 FML_LOG(ERROR) << lines_.size() << " lines for " << count
384 << " input rects, avg " << span_avg
385 << " spans per line and avg " << active_avg
386 << " active rects per loop";
387#endif
388}
389
390void DlRegion::appendLine(int32_t top,
391 int32_t bottom,
392 const Span* begin,
393 const Span* end) {
394 if (lines_.empty()) {
395 lines_.push_back(makeLine(top, bottom, begin, end));
396 } else {
397 if (lines_.back().bottom == top && spansEqual(lines_.back(), begin, end)) {
398 lines_.back().bottom = bottom;
399 } else {
400 lines_.push_back(makeLine(top, bottom, begin, end));
401 }
402 }
403}
404
405DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
406 if (a.isEmpty()) {
407 return b;
408 } else if (b.isEmpty()) {
409 return a;
410 } else if (a.isSimple() && a.bounds_.Contains(b.bounds_)) {
411 return a;
412 } else if (b.isSimple() && b.bounds_.Contains(a.bounds_)) {
413 return b;
414 }
415
416 DlRegion res;
417 res.bounds_ = a.bounds_.Union(b.bounds_);
418 res.span_buffer_.reserve(a.span_buffer_.capacity() +
419 b.span_buffer_.capacity());
420
421 auto& lines = res.lines_;
422 lines.reserve(a.lines_.size() + b.lines_.size());
423
424 auto a_it = a.lines_.begin();
425 auto b_it = b.lines_.begin();
426 auto a_end = a.lines_.end();
427 auto b_end = b.lines_.end();
428
429 FML_DCHECK(a_it != a_end && b_it != b_end);
430
431 auto& a_buffer = a.span_buffer_;
432 auto& b_buffer = b.span_buffer_;
433
434 std::vector<Span> tmp;
435
436 int32_t cur_top = std::numeric_limits<int32_t>::min();
437
438 while (a_it != a_end && b_it != b_end) {
439 auto a_top = std::max(cur_top, a_it->top);
440 auto b_top = std::max(cur_top, b_it->top);
441 if (a_it->bottom <= b_top) {
442 res.appendLine(a_top, a_it->bottom, a_buffer, a_it->chunk_handle);
443 ++a_it;
444 } else if (b_it->bottom <= a_top) {
445 res.appendLine(b_top, b_it->bottom, b_buffer, b_it->chunk_handle);
446 ++b_it;
447 } else {
448 if (a_top < b_top) {
449 res.appendLine(a_top, b_top, a_buffer, a_it->chunk_handle);
450 cur_top = b_top;
451 if (cur_top == a_it->bottom) {
452 ++a_it;
453 }
454 } else if (b_top < a_top) {
455 res.appendLine(b_top, a_top, b_buffer, b_it->chunk_handle);
456 cur_top = a_top;
457 if (cur_top == b_it->bottom) {
458 ++b_it;
459 }
460 } else {
461 auto new_bottom = std::min(a_it->bottom, b_it->bottom);
462 FML_DCHECK(a_top == b_top);
463 FML_DCHECK(new_bottom > a_top);
464 FML_DCHECK(new_bottom > b_top);
465 auto size = unionLineSpans(tmp, a_buffer, a_it->chunk_handle, b_buffer,
466 b_it->chunk_handle);
467 res.appendLine(a_top, new_bottom, tmp.data(), tmp.data() + size);
468 cur_top = new_bottom;
469 if (cur_top == a_it->bottom) {
470 ++a_it;
471 }
472 if (cur_top == b_it->bottom) {
473 ++b_it;
474 }
475 }
476 }
477 }
478
479 FML_DCHECK(a_it == a_end || b_it == b_end);
480
481 while (a_it != a_end) {
482 auto a_top = std::max(cur_top, a_it->top);
483 res.appendLine(a_top, a_it->bottom, a_buffer, a_it->chunk_handle);
484 ++a_it;
485 }
486
487 while (b_it != b_end) {
488 auto b_top = std::max(cur_top, b_it->top);
489 res.appendLine(b_top, b_it->bottom, b_buffer, b_it->chunk_handle);
490 ++b_it;
491 }
492
493 return res;
494}
495
496DlRegion DlRegion::MakeIntersection(const DlRegion& a, const DlRegion& b) {
497 if (!a.bounds_.IntersectsWithRect(b.bounds_)) {
498 return DlRegion();
499 } else if (a.isSimple() && b.isSimple()) {
500 auto res = a.bounds_.Intersection(b.bounds_);
501 FML_DCHECK(res.has_value());
502 return res.has_value() ? DlRegion(res.value()) : DlRegion();
503 } else if (a.isSimple() && a.bounds_.Contains(b.bounds_)) {
504 return b;
505 } else if (b.isSimple() && b.bounds_.Contains(a.bounds_)) {
506 return a;
507 }
508
509 DlRegion res;
510 res.span_buffer_.reserve(
511 std::max(a.span_buffer_.capacity(), b.span_buffer_.capacity()));
512
513 auto& lines = res.lines_;
514 lines.reserve(std::min(a.lines_.size(), b.lines_.size()));
515
516 std::vector<SpanLine>::const_iterator a_it, b_it;
517 getIntersectionIterators(a.lines_, b.lines_, a_it, b_it);
518
519 auto a_end = a.lines_.end();
520 auto b_end = b.lines_.end();
521
522 auto& a_buffer = a.span_buffer_;
523 auto& b_buffer = b.span_buffer_;
524
525 std::vector<Span> tmp;
526
527 int32_t cur_top = std::numeric_limits<int32_t>::min();
528
529 while (a_it != a_end && b_it != b_end) {
530 auto a_top = std::max(cur_top, a_it->top);
531 auto b_top = std::max(cur_top, b_it->top);
532 if (a_it->bottom <= b_top) {
533 ++a_it;
534 } else if (b_it->bottom <= a_top) {
535 ++b_it;
536 } else {
537 auto top = std::max(a_top, b_top);
538 auto bottom = std::min(a_it->bottom, b_it->bottom);
539 FML_DCHECK(top < bottom);
540 auto size = intersectLineSpans(tmp, a_buffer, a_it->chunk_handle,
541 b_buffer, b_it->chunk_handle);
542 if (size > 0) {
543 res.appendLine(top, bottom, tmp.data(), tmp.data() + size);
544 res.bounds_ = res.bounds_.Union(DlIRect::MakeLTRB(
545 tmp.data()->left, top, (tmp.data() + size - 1)->right, bottom));
546 }
547 cur_top = bottom;
548 if (cur_top == a_it->bottom) {
549 ++a_it;
550 }
551 if (cur_top == b_it->bottom) {
552 ++b_it;
553 }
554 }
555 }
556 FML_DCHECK(a_it == a_end || b_it == b_end);
557 return res;
558}
559
560std::vector<DlIRect> DlRegion::getRects(bool deband) const {
561 std::vector<DlIRect> rects;
562 if (isEmpty()) {
563 return rects;
564 } else if (isSimple()) {
565 rects.push_back(bounds_);
566 return rects;
567 }
568
569 size_t rect_count = 0;
570 size_t previous_span_end = 0;
571 for (const auto& line : lines_) {
572 rect_count += span_buffer_.getChunkSize(line.chunk_handle);
573 }
574 rects.reserve(rect_count);
575
576 for (const auto& line : lines_) {
577 const Span *span_begin, *span_end;
578 span_buffer_.getSpans(line.chunk_handle, span_begin, span_end);
579 for (const auto* span = span_begin; span < span_end; ++span) {
580 int32_t top = line.top;
581 if (deband) {
582 auto iter = rects.begin() + previous_span_end;
583 // If there is rectangle previously in rects on which this one is a
584 // vertical continuation, remove the previous rectangle and expand
585 // this one vertically to cover the area.
586 while (iter != rects.begin()) {
587 --iter;
588 if (iter->GetBottom() < top) {
589 // Went all the way to previous span line.
590 break;
591 } else if (iter->GetLeft() == span->left &&
592 iter->GetRight() == span->right) {
593 FML_DCHECK(iter->GetBottom() == top);
594 top = iter->GetTop();
595 rects.erase(iter);
596 --previous_span_end;
597 break;
598 }
599 }
600 }
601 rects.push_back(
602 DlIRect::MakeLTRB(span->left, top, span->right, line.bottom));
603 }
604 previous_span_end = rects.size();
605 }
606 return rects;
607}
608
609bool DlRegion::isComplex() const {
610 return lines_.size() > 1 ||
611 (lines_.size() == 1 &&
612 span_buffer_.getChunkSize(lines_.front().chunk_handle) > 1);
613}
614
615bool DlRegion::intersects(const DlIRect& rect) const {
616 if (isEmpty()) {
617 return false;
618 }
619
620 auto bounds_intersect = bounds_.IntersectsWithRect(rect);
621
622 if (isSimple()) {
623 return bounds_intersect;
624 }
625
626 if (!bounds_intersect) {
627 return false;
628 }
629
630 auto it = lines_.begin();
631 auto end = lines_.end();
632 if (lines_.size() > kBinarySearchThreshold &&
633 it[kBinarySearchThreshold].bottom <= rect.GetTop()) {
634 it = std::lower_bound(
635 lines_.begin() + kBinarySearchThreshold + 1, lines_.end(),
636 rect.GetTop(),
637 [](const SpanLine& line, int32_t top) { return line.bottom <= top; });
638 } else {
639 while (it != end && it->bottom <= rect.GetTop()) {
640 ++it;
641 continue;
642 }
643 }
644 while (it != end && it->top < rect.GetBottom()) {
645 FML_DCHECK(rect.GetTop() < it->bottom && it->top < rect.GetBottom());
646 const Span *begin, *end;
647 span_buffer_.getSpans(it->chunk_handle, begin, end);
648 while (begin != end && begin->left < rect.GetRight()) {
649 if (begin->right > rect.GetLeft()) {
650 return true;
651 }
652 ++begin;
653 }
654 ++it;
655 }
656
657 return false;
658}
659
660bool DlRegion::spansIntersect(const Span* begin1,
661 const Span* end1,
662 const Span* begin2,
663 const Span* end2) {
664 while (begin1 != end1 && begin2 != end2) {
665 if (begin1->right <= begin2->left) {
666 ++begin1;
667 } else if (begin2->right <= begin1->left) {
668 ++begin2;
669 } else {
670 return true;
671 }
672 }
673 return false;
674}
675
676void DlRegion::getIntersectionIterators(
677 const std::vector<SpanLine>& a_lines,
678 const std::vector<SpanLine>& b_lines,
679 std::vector<SpanLine>::const_iterator& a_it,
680 std::vector<SpanLine>::const_iterator& b_it) {
681 a_it = a_lines.begin();
682 auto a_end = a_lines.end();
683 b_it = b_lines.begin();
684 auto b_end = b_lines.end();
685
686 FML_DCHECK(a_it != a_end && b_it != b_end);
687
688 auto a_len = a_end - a_it;
689 auto b_len = b_end - b_it;
690
691 if (a_len > kBinarySearchThreshold &&
692 a_it[kBinarySearchThreshold].bottom <= b_it->top) {
693 a_it = std::lower_bound(
694 a_lines.begin() + kBinarySearchThreshold + 1, a_lines.end(), b_it->top,
695 [](const SpanLine& line, int32_t top) { return line.bottom <= top; });
696 } else if (b_len > kBinarySearchThreshold &&
697 b_it[kBinarySearchThreshold].bottom <= a_it->top) {
698 b_it = std::lower_bound(
699 b_lines.begin() + kBinarySearchThreshold + 1, b_lines.end(), a_it->top,
700 [](const SpanLine& line, int32_t top) { return line.bottom <= top; });
701 }
702}
703
704bool DlRegion::intersects(const DlRegion& region) const {
705 if (isEmpty() || region.isEmpty()) {
706 return false;
707 }
708
709 auto our_complex = isComplex();
710 auto their_complex = region.isComplex();
711 auto bounds_intersect = bounds_.IntersectsWithRect(region.bounds_);
712
713 if (!our_complex && !their_complex) {
714 return bounds_intersect;
715 }
716
717 if (!bounds_intersect) {
718 return false;
719 }
720
721 if (!our_complex) {
722 return region.intersects(bounds_);
723 }
724
725 if (!their_complex) {
726 return intersects(region.bounds_);
727 }
728
729 std::vector<SpanLine>::const_iterator ours, theirs;
730 getIntersectionIterators(lines_, region.lines_, ours, theirs);
731 auto ours_end = lines_.end();
732 auto theirs_end = region.lines_.end();
733
734 while (ours != ours_end && theirs != theirs_end) {
735 if (ours->bottom <= theirs->top) {
736 ++ours;
737 } else if (theirs->bottom <= ours->top) {
738 ++theirs;
739 } else {
740 FML_DCHECK(ours->top < theirs->bottom && theirs->top < ours->bottom);
741 const Span *ours_begin, *ours_end;
742 span_buffer_.getSpans(ours->chunk_handle, ours_begin, ours_end);
743 const Span *theirs_begin, *theirs_end;
744 region.span_buffer_.getSpans(theirs->chunk_handle, theirs_begin,
745 theirs_end);
746 if (spansIntersect(ours_begin, ours_end, theirs_begin, theirs_end)) {
747 return true;
748 }
749 if (ours->bottom < theirs->bottom) {
750 ++ours;
751 } else {
752 ++theirs;
753 }
754 }
755 }
756 return false;
757}
758
759} // namespace flutter
bool isEmpty() const
Returns true if region is empty (contains no rectangles).
Definition dl_region.h:62
bool isSimple() const
Definition dl_region.h:69
bool isComplex() const
Returns true if region is not empty and contains more than one rectangle.
Definition dl_region.cc:609
bool intersects(const DlIRect &rect) const
Returns whether this region intersects with a rectangle.
Definition dl_region.cc:615
if(end==-1)
#define FML_LOG(severity)
Definition logging.h:101
#define FML_DCHECK(condition)
Definition logging.h:122
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
impeller::IRect32 DlIRect
const int kBinarySearchThreshold
Definition dl_region.cc:13
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
constexpr auto GetBottom() const
Definition rect.h:357
constexpr auto GetTop() const
Definition rect.h:353
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition rect.h:528
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition rect.h:231
constexpr TRect Union(const TRect &o) const
Definition rect.h:513
constexpr bool IntersectsWithRect(const TRect &o) const
Definition rect.h:546
constexpr auto GetLeft() const
Definition rect.h:351
constexpr auto GetRight() const
Definition rect.h:355
const size_t end