20 nested_byte_count_(0),
24 can_apply_group_opacity_(true),
25 is_ui_thread_safe_(true),
26 modifies_transparent_black_(false),
27 root_has_backdrop_filter_(false),
28 root_is_unbounded_(false),
35 std::vector<size_t>&& offsets,
37 size_t nested_byte_count,
38 uint32_t nested_op_count,
41 bool can_apply_group_opacity,
42 bool is_ui_thread_safe,
43 bool modifies_transparent_black,
45 bool root_has_backdrop_filter,
46 bool root_is_unbounded,
47 sk_sp<const DlRTree> rtree)
48 : storage_(
std::move(storage)),
49 offsets_(
std::move(offsets)),
51 nested_byte_count_(nested_byte_count),
52 nested_op_count_(nested_op_count),
53 total_depth_(total_depth),
54 unique_id_(next_unique_id()),
56 can_apply_group_opacity_(can_apply_group_opacity),
57 is_ui_thread_safe_(is_ui_thread_safe),
58 modifies_transparent_black_(modifies_transparent_black),
59 root_has_backdrop_filter_(root_has_backdrop_filter),
60 root_is_unbounded_(root_is_unbounded),
61 max_root_blend_mode_(max_root_blend_mode),
62 rtree_(
std::move(rtree)) {
67 DisposeOps(storage_, offsets_);
70uint32_t DisplayList::next_unique_id() {
71 static std::atomic<uint32_t> next_id{1};
74 id = next_id.fetch_add(+1, std::memory_order_relaxed);
88void DisplayList::RTreeResultsToIndexVector(
89 std::vector<DlIndex>& indices,
90 const std::vector<int>& rtree_results)
const {
92 auto cur_rect = rtree_results.begin();
93 auto end_rect = rtree_results.end();
94 if (cur_rect >= end_rect) {
97 DlIndex next_render_index = rtree_->id(*cur_rect++);
98 DlIndex next_restore_index = std::numeric_limits<DlIndex>::max();
99 std::vector<SaveInfo> save_infos;
100 for (
DlIndex index = 0u; index < offsets_.size(); index++) {
101 while (index > next_render_index) {
102 if (cur_rect < end_rect) {
103 next_render_index = rtree_->id(*cur_rect++);
107 while (!save_infos.empty()) {
108 SaveInfo& info = save_infos.back();
112 if (info.save_was_needed) {
113 FML_DCHECK(next_restore_index < offsets_.size());
114 indices.push_back(next_restore_index);
116 next_restore_index = info.previous_restore_index;
117 save_infos.pop_back();
122 const uint8_t* ptr = storage_.
base() + offsets_[index];
123 const DLOp* op =
reinterpret_cast<const DLOp*
>(ptr);
127 indices.push_back(index);
132 if (next_render_index < next_restore_index) {
133 indices.push_back(index);
139 if (index == next_render_index) {
140 indices.push_back(index);
146 bool needed = (next_render_index < next_restore_index);
147 save_infos.emplace_back(next_restore_index, needed);
149 case DisplayListOpType::kSave:
150 case DisplayListOpType::kSaveLayer:
151 case DisplayListOpType::kSaveLayerBackdrop:
153 static_cast<const SaveOpBase*
>(op)->restore_index;
159 indices.push_back(index);
167 SaveInfo& info = save_infos.back();
168 next_restore_index = info.previous_restore_index;
169 if (info.save_was_needed) {
170 indices.push_back(index);
172 save_infos.pop_back();
183 const uint8_t*
base = storage_.
base();
184 for (
size_t offset : offsets_) {
185 DispatchOneOp(receiver,
base + offset);
190 const DlIRect& cull_rect)
const {
195 const DlRect& cull_rect)
const {
203 const uint8_t*
base = storage_.
base();
204 for (
DlIndex index : op_indices) {
205 DispatchOneOp(receiver,
base + offsets_[index]);
211 const uint8_t* ptr)
const {
212 auto op =
reinterpret_cast<const DLOp*
>(ptr);
214#define DL_OP_DISPATCH(name) \
215 case DisplayListOpType::k##name: \
216 static_cast<const name##Op*>(op)->dispatch(receiver); \
226 <<
static_cast<int>(op->type);
230void DisplayList::DisposeOps(
const DisplayListStorage& storage,
231 const std::vector<size_t>& offsets) {
232 const uint8_t*
base = storage.base();
236 for (
size_t offset : offsets) {
237 auto op =
reinterpret_cast<const DLOp*
>(
base + offset);
239#define DL_OP_DISPOSE(name) \
240 case DisplayListOpType::k##name: \
241 if (!std::is_trivially_destructible_v<name##Op>) { \
242 static_cast<const name##Op*>(op)->~name##Op(); \
262 case DisplayListOpType::kSetAntiAlias:
263 case DisplayListOpType::kSetInvertColors:
264 case DisplayListOpType::kSetStrokeCap:
265 case DisplayListOpType::kSetStrokeJoin:
266 case DisplayListOpType::kSetStyle:
267 case DisplayListOpType::kSetStrokeWidth:
268 case DisplayListOpType::kSetStrokeMiter:
269 case DisplayListOpType::kSetColor:
270 case DisplayListOpType::kSetBlendMode:
271 case DisplayListOpType::kClearColorFilter:
272 case DisplayListOpType::kSetPodColorFilter:
273 case DisplayListOpType::kClearColorSource:
274 case DisplayListOpType::kSetPodColorSource:
275 case DisplayListOpType::kSetImageColorSource:
276 case DisplayListOpType::kSetRuntimeEffectColorSource:
277 case DisplayListOpType::kClearImageFilter:
278 case DisplayListOpType::kSetPodImageFilter:
279 case DisplayListOpType::kSetSharedImageFilter:
280 case DisplayListOpType::kClearMaskFilter:
281 case DisplayListOpType::kSetPodMaskFilter:
284 case DisplayListOpType::kSave:
286 case DisplayListOpType::kSaveLayer:
287 case DisplayListOpType::kSaveLayerBackdrop:
289 case DisplayListOpType::kRestore:
292 case DisplayListOpType::kTranslate:
293 case DisplayListOpType::kScale:
294 case DisplayListOpType::kRotate:
295 case DisplayListOpType::kSkew:
296 case DisplayListOpType::kTransform2DAffine:
297 case DisplayListOpType::kTransformFullPerspective:
298 case DisplayListOpType::kTransformReset:
301 case DisplayListOpType::kClipIntersectRect:
302 case DisplayListOpType::kClipIntersectOval:
303 case DisplayListOpType::kClipIntersectRoundRect:
304 case DisplayListOpType::kClipIntersectRoundSuperellipse:
305 case DisplayListOpType::kClipIntersectPath:
306 case DisplayListOpType::kClipDifferenceRect:
307 case DisplayListOpType::kClipDifferenceOval:
308 case DisplayListOpType::kClipDifferenceRoundRect:
309 case DisplayListOpType::kClipDifferenceRoundSuperellipse:
310 case DisplayListOpType::kClipDifferencePath:
313 case DisplayListOpType::kDrawPaint:
314 case DisplayListOpType::kDrawColor:
315 case DisplayListOpType::kDrawLine:
316 case DisplayListOpType::kDrawDashedLine:
317 case DisplayListOpType::kDrawRect:
318 case DisplayListOpType::kDrawOval:
319 case DisplayListOpType::kDrawCircle:
320 case DisplayListOpType::kDrawRoundRect:
321 case DisplayListOpType::kDrawDiffRoundRect:
322 case DisplayListOpType::kDrawRoundSuperellipse:
323 case DisplayListOpType::kDrawArc:
324 case DisplayListOpType::kDrawPath:
325 case DisplayListOpType::kDrawPoints:
326 case DisplayListOpType::kDrawLines:
327 case DisplayListOpType::kDrawPolygon:
328 case DisplayListOpType::kDrawVertices:
329 case DisplayListOpType::kDrawImage:
330 case DisplayListOpType::kDrawImageWithAttr:
331 case DisplayListOpType::kDrawImageRect:
332 case DisplayListOpType::kDrawImageNine:
333 case DisplayListOpType::kDrawImageNineWithAttr:
334 case DisplayListOpType::kDrawAtlas:
335 case DisplayListOpType::kDrawAtlasCulled:
336 case DisplayListOpType::kDrawText:
337 case DisplayListOpType::kDrawShadow:
338 case DisplayListOpType::kDrawShadowTransparentOccluder:
341 case DisplayListOpType::kDrawDisplayList:
351 static_assert(std::is_unsigned_v<DlIndex>);
352 if (index >= offsets_.size()) {
356 size_t offset = offsets_[index];
358 auto ptr = storage_.
base() + offset;
359 auto op =
reinterpret_cast<const DLOp*
>(ptr);
364 indices.reserve(
size);
366 indices.push_back(
i);
371 const DlRect& cull_rect)
const {
372 std::vector<DlIndex> indices;
375 std::vector<int> rect_indices;
376 rtree_->search(cull_rect, &rect_indices);
377 RTreeResultsToIndexVector(indices, rect_indices);
387 static_assert(std::is_unsigned_v<DlIndex>);
388 if (index >= offsets_.size()) {
392 size_t offset = offsets_[index];
394 auto ptr = storage_.
base() + offset;
396 DispatchOneOp(receiver, ptr);
402 const std::vector<size_t>& offsetsA,
404 const std::vector<size_t>& offsetsB) {
405 const uint8_t* base_a = storageA.
base();
406 const uint8_t* base_b = storageB.
base();
408 FML_DCHECK(offsetsA.size() == offsetsB.size());
410 size_t bulk_start = 0u;
411 for (
size_t i = 0;
i < offsetsA.size();
i++) {
412 size_t offset = offsetsA[
i];
414 auto opA =
reinterpret_cast<const DLOp*
>(base_a + offset);
415 auto opB =
reinterpret_cast<const DLOp*
>(base_b + offset);
416 if (opA->type != opB->type) {
421#define DL_OP_EQUALS(name) \
422 case DisplayListOpType::k##name: \
423 result = static_cast<const name##Op*>(opA)->equals( \
424 static_cast<const name##Op*>(opB)); \
443 if (bulk_start < offset) {
444 const uint8_t* bulk_start_a = base_a + bulk_start;
445 const uint8_t* bulk_start_b = base_b + bulk_start;
446 if (memcmp(bulk_start_a, bulk_start_b, offset - bulk_start) != 0) {
451 i + 1 < offsetsA.size() ? offsetsA[
i + 1] : storageA.
size();
455 if (bulk_start < storageA.
size()) {
457 const uint8_t* bulk_start_a = base_a + bulk_start;
458 const uint8_t* bulk_start_b = base_b + bulk_start;
459 if (memcmp(bulk_start_a, bulk_start_b, storageA.
size() - bulk_start) != 0) {
470 if (offsets_.size() != other->offsets_.size() ||
471 storage_.
size() != other->storage_.
size() ||
472 op_count_ != other->op_count_) {
475 if (storage_.
base() == other->storage_.
base()) {
478 return CompareOps(storage_, offsets_, other->storage_, other->offsets_);
DisplayListOpType GetOpType(DlIndex index) const
Return an enum describing the specific op type stored at the indicated index.
DisplayListOpCategory GetOpCategory(DlIndex index) const
Return an enum describing the general category of the operation record stored at the indicated index.
const DlRect & GetBounds() const
bool Equals(const DisplayList *other) const
std::vector< DlIndex > GetCulledIndices(const DlRect &cull_rect) const
Return a vector of valid indices for records stored in the DisplayList that must be dispatched if you...
void Dispatch(DlOpReceiver &ctx) const
uint8_t * base()
Returns a pointer to the base of the storage.
size_t size() const
Returns the currently allocated size.
size_t capacity() const
Returns the maximum currently allocated space.
Internal API for rendering recorded display lists to backends.
static const SaveLayerOptions kNoAttributes
SaveLayerOptions with_renders_with_attributes() const
static const SaveLayerOptions kWithAttributes
#define DL_OP_EQUALS(name)
#define DL_OP_DISPOSE(name)
#define DL_OP_DISPATCH(name)
#define FOR_EACH_DISPLAY_LIST_OP(V)
#define FML_UNREACHABLE()
#define FML_DCHECK(condition)
static void FillAllIndices(std::vector< DlIndex > &indices, DlIndex size)
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
static bool CompareOps(const DisplayListStorage &storageA, const std::vector< size_t > &offsetsA, const DisplayListStorage &storageB, const std::vector< size_t > &offsetsB)
flutter::SaveLayerOptions SaveLayerOptions
const DisplayListOpType type
SaveInfo(DlIndex previous_restore_index, bool save_was_needed)
DlIndex previous_restore_index
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)