5#include "flutter/display_list/geometry/dl_region.h"
7#include "flutter/fml/logging.h"
15DlRegion::SpanBuffer::SpanBuffer(DlRegion::SpanBuffer&&
m)
16 : capacity_(
m.capacity_), size_(
m.size_), spans_(
m.spans_) {
22DlRegion::SpanBuffer::SpanBuffer(
const DlRegion::SpanBuffer&
m)
23 : capacity_(
m.capacity_), size_(
m.size_) {
24 if (
m.spans_ ==
nullptr) {
27 spans_ =
static_cast<Span*
>(
std::malloc(capacity_ *
sizeof(Span)));
28 memcpy(spans_,
m.spans_, size_ *
sizeof(Span));
32DlRegion::SpanBuffer& DlRegion::SpanBuffer::operator=(
33 const DlRegion::SpanBuffer&
buffer) {
39DlRegion::SpanBuffer& DlRegion::SpanBuffer::operator=(
40 DlRegion::SpanBuffer&&
buffer) {
47DlRegion::SpanBuffer::~SpanBuffer() {
51void DlRegion::SpanBuffer::reserve(
size_t capacity) {
52 if (capacity_ < capacity) {
53 spans_ =
static_cast<Span*
>(
std::realloc(spans_, capacity *
sizeof(Span)));
58DlRegion::SpanChunkHandle DlRegion::SpanBuffer::storeChunk(
const Span*
begin,
62 if (capacity_ < min_capacity) {
63 size_t new_capacity =
std::max(min_capacity, capacity_ * 2);
64 new_capacity =
std::max(new_capacity,
size_t(512));
65 reserve(new_capacity);
67 SpanChunkHandle res = size_;
71 auto*
dst = spans_ + res + 1;
77size_t DlRegion::SpanBuffer::getChunkSize(SpanChunkHandle handle)
const {
79 return spans_[handle].left;
82void DlRegion::SpanBuffer::setChunkSize(SpanChunkHandle handle,
size_t size) {
86 spans_[handle].left =
size;
89void DlRegion::SpanBuffer::getSpans(SpanChunkHandle handle,
90 const DlRegion::Span*&
begin,
91 const DlRegion::Span*&
end)
const {
93 begin = spans_ + handle + 1;
97DlRegion::DlRegion(
const std::vector<SkIRect>& rects) {
102 Span span{
rect.left(),
rect.right()};
103 lines_.push_back(makeLine(
rect.top(),
rect.bottom(), &span, &span + 1));
106bool DlRegion::spansEqual(SpanLine&
line,
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;
113 if (our_size != their_size) {
117 return memcmp(our_begin,
begin, our_size *
sizeof(Span)) == 0;
120DlRegion::SpanLine DlRegion::makeLine(int32_t top,
123 return makeLine(top, bottom, v.data(), v.data() + v.size());
126DlRegion::SpanLine DlRegion::makeLine(int32_t top,
130 auto handle = span_buffer_.storeChunk(
begin, end);
131 return {top, bottom, handle};
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 {
143 explicit OrderedSpanAccumulator(std::vector<Span>& res) : res(res) {}
145 void accumulate(
const Span& span) {
146 if (span.left > last_ ||
len == 0) {
149 }
else if (span.right > last_) {
151 res[
len - 1].right = span.right;
157 std::vector<Span>& res;
163 const Span *begin1, *end1;
164 a_buffer.getSpans(a_handle, begin1, end1);
166 const Span *begin2, *end2;
167 b_buffer.getSpans(b_handle, begin2, end2);
169 size_t min_size = (end1 - begin1) + (end2 - begin2);
170 if (res.size() < min_size) {
171 res.resize(min_size);
174 OrderedSpanAccumulator accumulator(res);
177 if (begin1->left < begin2->left) {
178 accumulator.accumulate(*begin1++);
179 if (begin1 == end1) {
185 accumulator.accumulate(*begin2++);
186 if (begin2 == end2) {
194 while (begin1 < end1) {
195 accumulator.accumulate(*begin1++);
197 while (begin2 < end2) {
198 accumulator.accumulate(*begin2++);
203 return accumulator.len;
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);
214 const Span *begin2, *end2;
215 b_buffer.getSpans(b_handle, begin2, end2);
220 size_t min_size = (end1 - begin1) + (end2 - begin2) - 1;
221 if (res.size() < min_size) {
222 res.resize(min_size);
226 Span* new_span = res.data();
228 while (begin1 != end1 && begin2 != end2) {
229 if (begin1->right <= begin2->left) {
231 }
else if (begin2->right <= begin1->left) {
237 FML_DCHECK(new_span < res.data() + res.size());
239 if (begin1->right == right) {
242 if (begin2->right == right) {
248 return new_span - res.data();
251void DlRegion::setRects(
const std::vector<SkIRect>& unsorted_rects) {
255 size_t count = unsorted_rects.size();
256 std::vector<const SkIRect*> rects(
count);
257 for (
size_t i = 0;
i <
count;
i++) {
258 rects[
i] = &unsorted_rects[
i];
259 bounds_.
join(unsorted_rects[
i]);
262 if (a->top() < b->top()) {
265 if (
a->top() >
b->top()) {
268 return a->left() <
b->left();
271 size_t active_end = 0;
272 size_t next_rect = 0;
274 SpanVec working_spans;
276#ifdef DlRegion_DO_STATS
277 size_t active_rect_count = 0;
278 size_t span_count = 0;
283 while (next_rect < count || active_end > 0) {
285 size_t preserve_end = 0;
286 for (
size_t i = 0;
i < active_end;
i++) {
288 if (r->
bottom() > cur_y) {
289 rects[preserve_end++] = r;
292 active_end = preserve_end;
296 if (active_end == 0) {
297 if (next_rect >=
count) {
301 cur_y = rects[next_rect]->
top();
305 while (next_rect <
count) {
306 const SkIRect* r = rects[next_rect];
310 if (r->
top() > cur_y) {
315 size_t insert_at = active_end++;
316 while (insert_at > 0) {
317 const SkIRect* ir = rects[insert_at - 1];
321 rects[insert_at--] = ir;
323 rects[insert_at] = r;
329 working_spans.clear();
332#ifdef DlRegion_DO_STATS
333 active_rect_count += active_end;
339 int32_t start_x = rects[0]->left();
340 int32_t end_x = rects[0]->right();
341 int32_t end_y = rects[0]->bottom();
342 for (
size_t i = 1;
i < active_end;
i++) {
344 if (r->
left() > end_x) {
345 working_spans.emplace_back(start_x, end_x);
348 }
else if (end_x < r->
right()) {
351 if (end_y > r->
bottom()) {
355 working_spans.emplace_back(start_x, end_x);
358 if (next_rect < count && end_y > rects[next_rect]->top()) {
359 end_y = rects[next_rect]->top();
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;
371#ifdef DlRegion_DO_STATS
372 span_count += working_spans.size();
375 lines_.push_back(makeLine(cur_y, end_y, working_spans));
380#ifdef DlRegion_DO_STATS
381 double span_avg = ((double)span_count) / line_count;
382 double active_avg = ((double)active_rect_count) / pass_count;
384 <<
" input rects, avg " << span_avg
385 <<
" spans per line and avg " << active_avg
386 <<
" active rects per loop";
390void DlRegion::appendLine(int32_t top,
394 if (lines_.empty()) {
395 lines_.push_back(makeLine(top, bottom,
begin,
end));
397 if (lines_.back().bottom == top && spansEqual(lines_.back(),
begin,
end)) {
398 lines_.back().bottom = bottom;
400 lines_.push_back(makeLine(top, bottom,
begin,
end));
408 }
else if (
b.isEmpty()) {
410 }
else if (
a.isSimple() &&
a.bounds_.contains(
b.bounds_)) {
412 }
else if (
b.isSimple() &&
b.bounds_.contains(
a.bounds_)) {
417 res.bounds_ =
a.bounds_;
418 res.bounds_.
join(
b.bounds_);
419 res.span_buffer_.reserve(
a.span_buffer_.capacity() +
420 b.span_buffer_.capacity());
422 auto&
lines = res.lines_;
423 lines.reserve(
a.lines_.size() +
b.lines_.size());
425 auto a_it =
a.lines_.begin();
426 auto b_it =
b.lines_.begin();
427 auto a_end =
a.lines_.end();
428 auto b_end =
b.lines_.end();
432 auto& a_buffer =
a.span_buffer_;
433 auto& b_buffer =
b.span_buffer_;
435 std::vector<Span> tmp;
439 while (a_it != a_end && b_it != b_end) {
440 auto a_top =
std::max(cur_top, a_it->top);
441 auto b_top =
std::max(cur_top, b_it->top);
442 if (a_it->bottom <= b_top) {
443 res.appendLine(a_top, a_it->bottom, a_buffer, a_it->chunk_handle);
445 }
else if (b_it->bottom <= a_top) {
446 res.appendLine(b_top, b_it->bottom, b_buffer, b_it->chunk_handle);
450 res.appendLine(a_top, b_top, a_buffer, a_it->chunk_handle);
452 if (cur_top == a_it->bottom) {
455 }
else if (b_top < a_top) {
456 res.appendLine(b_top, a_top, b_buffer, b_it->chunk_handle);
458 if (cur_top == b_it->bottom) {
462 auto new_bottom =
std::min(a_it->bottom, b_it->bottom);
466 auto size = unionLineSpans(tmp, a_buffer, a_it->chunk_handle, b_buffer,
468 res.appendLine(a_top, new_bottom, tmp.data(), tmp.data() +
size);
469 cur_top = new_bottom;
470 if (cur_top == a_it->bottom) {
473 if (cur_top == b_it->bottom) {
482 while (a_it != a_end) {
483 auto a_top =
std::max(cur_top, a_it->top);
484 res.appendLine(a_top, a_it->bottom, a_buffer, a_it->chunk_handle);
488 while (b_it != b_end) {
489 auto b_top =
std::max(cur_top, b_it->top);
490 res.appendLine(b_top, b_it->bottom, b_buffer, b_it->chunk_handle);
500 }
else if (
a.isSimple() &&
b.isSimple()) {
506 }
else if (
a.isSimple() &&
a.bounds_.contains(
b.bounds_)) {
508 }
else if (
b.isSimple() &&
b.bounds_.contains(
a.bounds_)) {
513 res.span_buffer_.reserve(
514 std::max(
a.span_buffer_.capacity(),
b.span_buffer_.capacity()));
516 auto&
lines = res.lines_;
519 std::vector<SpanLine>::const_iterator a_it, b_it;
520 getIntersectionIterators(
a.lines_,
b.lines_, a_it, b_it);
522 auto a_end =
a.lines_.end();
523 auto b_end =
b.lines_.end();
525 auto& a_buffer =
a.span_buffer_;
526 auto& b_buffer =
b.span_buffer_;
528 std::vector<Span> tmp;
532 while (a_it != a_end && b_it != b_end) {
533 auto a_top =
std::max(cur_top, a_it->top);
534 auto b_top =
std::max(cur_top, b_it->top);
535 if (a_it->bottom <= b_top) {
537 }
else if (b_it->bottom <= a_top) {
541 auto bottom =
std::min(a_it->bottom, b_it->bottom);
543 auto size = intersectLineSpans(tmp, a_buffer, a_it->chunk_handle,
544 b_buffer, b_it->chunk_handle);
546 res.appendLine(top, bottom, tmp.data(), tmp.data() +
size);
548 tmp.data()->left, top, (tmp.data() +
size - 1)->right, bottom));
551 if (cur_top == a_it->bottom) {
554 if (cur_top == b_it->bottom) {
563std::vector<SkIRect> DlRegion::getRects(
bool deband)
const {
564 std::vector<SkIRect> rects;
567 }
else if (isSimple()) {
568 rects.push_back(bounds_);
572 size_t rect_count = 0;
573 size_t previous_span_end = 0;
574 for (
const auto&
line : lines_) {
575 rect_count += span_buffer_.getChunkSize(
line.chunk_handle);
577 rects.reserve(rect_count);
579 for (
const auto&
line : lines_) {
580 const Span *span_begin, *span_end;
581 span_buffer_.getSpans(
line.chunk_handle, span_begin, span_end);
582 for (
const auto* span = span_begin; span < span_end; ++span) {
585 auto iter = rects.begin() + previous_span_end;
589 while (iter != rects.begin()) {
591 if (iter->bottom() <
rect.top()) {
594 }
else if (iter->left() ==
rect.left() &&
595 iter->right() ==
rect.right()) {
597 rect.fTop = iter->fTop;
604 rects.push_back(
rect);
606 previous_span_end = rects.size();
611bool DlRegion::isComplex()
const {
612 return lines_.size() > 1 ||
613 (lines_.size() == 1 &&
614 span_buffer_.getChunkSize(lines_.front().chunk_handle) > 1);
625 return bounds_intersect;
628 if (!bounds_intersect) {
632 auto it = lines_.begin();
633 auto end = lines_.end();
636 it = std::lower_bound(
638 [](
const SpanLine&
line, int32_t top) { return line.bottom <= top; });
640 while (it !=
end && it->bottom <=
rect.fTop) {
645 while (it !=
end && it->top <
rect.fBottom) {
648 span_buffer_.getSpans(it->chunk_handle,
begin,
end);
661bool DlRegion::spansIntersect(
const Span* begin1,
665 while (begin1 != end1 && begin2 != end2) {
666 if (begin1->right <= begin2->left) {
668 }
else if (begin2->right <= begin1->left) {
677void DlRegion::getIntersectionIterators(
678 const std::vector<SpanLine>& a_lines,
679 const std::vector<SpanLine>& b_lines,
680 std::vector<SpanLine>::const_iterator& a_it,
681 std::vector<SpanLine>::const_iterator& b_it) {
682 a_it = a_lines.begin();
683 auto a_end = a_lines.end();
684 b_it = b_lines.begin();
685 auto b_end = b_lines.end();
689 auto a_len = a_end - a_it;
690 auto b_len = b_end - b_it;
694 a_it = std::lower_bound(
696 [](
const SpanLine&
line, int32_t top) { return line.bottom <= top; });
699 b_it = std::lower_bound(
701 [](
const SpanLine&
line, int32_t top) { return line.bottom <= top; });
710 auto our_complex = isComplex();
714 if (!our_complex && !their_complex) {
715 return bounds_intersect;
718 if (!bounds_intersect) {
726 if (!their_complex) {
727 return intersects(
region.bounds_);
730 std::vector<SpanLine>::const_iterator ours, theirs;
731 getIntersectionIterators(lines_,
region.lines_, ours, theirs);
732 auto ours_end = lines_.end();
733 auto theirs_end =
region.lines_.end();
735 while (ours != ours_end && theirs != theirs_end) {
736 if (ours->bottom <= theirs->top) {
738 }
else if (theirs->bottom <= ours->top) {
741 FML_DCHECK(ours->top < theirs->bottom && theirs->top < ours->bottom);
742 const Span *ours_begin, *ours_end;
743 span_buffer_.getSpans(ours->chunk_handle, ours_begin, ours_end);
744 const Span *theirs_begin, *theirs_end;
745 region.span_buffer_.getSpans(theirs->chunk_handle, theirs_begin,
747 if (spansIntersect(ours_begin, ours_end, theirs_begin, theirs_end)) {
750 if (ours->bottom < theirs->bottom) {
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
void swap(sk_sp< T > &a, sk_sp< T > &b)
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
bool intersects(const SkIRect &rect) const
static const char * begin(const StringSlice &s)
#define FML_LOG(severity)
#define FML_DCHECK(condition)
static float max(float r, float g, float b)
static float min(float r, float g, float b)
ClipOpAndAA opAA SkRegion region
sk_sp< SkBlender > blender SkRect rect
static intptr_t chunk_size(intptr_t bytes_left)
void * malloc(size_t size)
void * realloc(void *ptr, size_t size)
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 vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
const int kBinarySearchThreshold
it will be possible to load the file into Perfetto s trace viewer 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
bool intersect(const SkIRect &r)
static bool Intersects(const SkIRect &a, const SkIRect &b)
constexpr int32_t top() const
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
constexpr int32_t bottom() const
constexpr int32_t right() const
void join(const SkIRect &r)
constexpr int32_t left() const