Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
container_layer.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
5#include "flutter/flow/layers/container_layer.h"
6
7#include <optional>
8
9namespace flutter {
10
11ContainerLayer::ContainerLayer() : child_paint_bounds_(SkRect::MakeEmpty()) {}
12
13void ContainerLayer::Diff(DiffContext* context, const Layer* old_layer) {
14 auto old_container = static_cast<const ContainerLayer*>(old_layer);
15 DiffContext::AutoSubtreeRestore subtree(context);
16 DiffChildren(context, old_container);
17 context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
18}
19
22 for (auto& layer : layers_) {
23 layer->PreservePaintRegion(context);
24 }
25}
26
28 const ContainerLayer* old_layer) {
29 if (context->IsSubtreeDirty()) {
30 for (auto& layer : layers_) {
31 layer->Diff(context, nullptr);
32 }
33 return;
34 }
35 FML_DCHECK(old_layer);
36
37 const auto& prev_layers = old_layer->layers_;
38
39 // first mismatched element
40 int new_children_top = 0;
41 int old_children_top = 0;
42
43 // last mismatched element
44 int new_children_bottom = layers_.size() - 1;
45 int old_children_bottom = prev_layers.size() - 1;
46
47 while ((old_children_top <= old_children_bottom) &&
48 (new_children_top <= new_children_bottom)) {
49 if (!layers_[new_children_top]->IsReplacing(
50 context, prev_layers[old_children_top].get())) {
51 break;
52 }
53 ++new_children_top;
54 ++old_children_top;
55 }
56
57 while ((old_children_top <= old_children_bottom) &&
58 (new_children_top <= new_children_bottom)) {
59 if (!layers_[new_children_bottom]->IsReplacing(
60 context, prev_layers[old_children_bottom].get())) {
61 break;
62 }
63 --new_children_bottom;
64 --old_children_bottom;
65 }
66
67 // old layers that don't match
68 for (int i = old_children_top; i <= old_children_bottom; ++i) {
69 auto layer = prev_layers[i];
70 context->AddDamage(context->GetOldLayerPaintRegion(layer.get()));
71 }
72
73 for (int i = 0; i < static_cast<int>(layers_.size()); ++i) {
74 if (i < new_children_top || i > new_children_bottom) {
75 int i_prev =
76 i < new_children_top ? i : prev_layers.size() - (layers_.size() - i);
77 auto layer = layers_[i];
78 auto prev_layer = prev_layers[i_prev];
79 auto paint_region = context->GetOldLayerPaintRegion(prev_layer.get());
80 if (layer == prev_layer && !paint_region.has_readback() &&
81 !paint_region.has_texture()) {
82 // for retained layers, stop processing the subtree and add existing
83 // region; We know current subtree is not dirty (every ancestor up to
84 // here matches) so the retained subtree will render identically to
85 // previous frame; We can only do this if there is no readback in the
86 // subtree. Layers that do readback must be able to register readback
87 // inside Diff
88 context->AddExistingPaintRegion(paint_region);
89
90 // While we don't need to diff retained layers, we still need to
91 // associate their paint region with current layer tree so that we can
92 // retrieve it in next frame diff
93 layer->PreservePaintRegion(context);
94 } else {
95 layer->Diff(context, prev_layer.get());
96 }
97 } else {
98 DiffContext::AutoSubtreeRestore subtree(context);
99 context->MarkSubtreeDirty();
100 auto layer = layers_[i];
101 layer->Diff(context, nullptr);
102 }
103 }
104}
105
106void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
107 layers_.emplace_back(std::move(layer));
108}
109
115
117 FML_DCHECK(needs_painting(context));
118
119 PaintChildren(context);
120}
121
122static bool safe_intersection_test(const SkRect* rect1, const SkRect& rect2) {
123 if (rect1->isEmpty() || rect2.isEmpty()) {
124 return false;
125 }
126 return rect1->intersects(rect2);
127}
128
130 SkRect* child_paint_bounds) {
131 // Platform views have no children, so context->has_platform_view should
132 // always be false.
133 FML_DCHECK(!context->has_platform_view);
134 FML_DCHECK(!context->has_texture_layer);
135
136 bool child_has_platform_view = false;
137 bool child_has_texture_layer = false;
138 bool all_renderable_state_flags = LayerStateStack::kCallerCanApplyAnything;
139
140 for (auto& layer : layers_) {
141 // Reset context->has_platform_view and context->has_texture_layer to false
142 // so that layers aren't treated as if they have a platform view or texture
143 // layer based on one being previously found in a sibling tree.
144 context->has_platform_view = false;
145 context->has_texture_layer = false;
146
147 // Initialize the renderable state flags to false to force the layer to
148 // opt-in to applying state attributes during its |Preroll|
149 context->renderable_state_flags = 0;
150
151 layer->Preroll(context);
152
153 all_renderable_state_flags &= context->renderable_state_flags;
154 if (safe_intersection_test(child_paint_bounds, layer->paint_bounds())) {
155 // This will allow inheritance by a linear sequence of non-overlapping
156 // children, but will fail with a grid or other arbitrary 2D layout.
157 // See https://github.com/flutter/flutter/issues/93899
158 all_renderable_state_flags = 0;
159 }
160 child_paint_bounds->join(layer->paint_bounds());
161
162 child_has_platform_view =
163 child_has_platform_view || context->has_platform_view;
164 child_has_texture_layer =
165 child_has_texture_layer || context->has_texture_layer;
166 }
167
168 context->has_platform_view = child_has_platform_view;
169 context->has_texture_layer = child_has_texture_layer;
170 context->renderable_state_flags = all_renderable_state_flags;
171 set_subtree_has_platform_view(child_has_platform_view);
172 set_children_renderable_state_flags(all_renderable_state_flags);
174}
175
177 // We can no longer call FML_DCHECK here on the needs_painting(context)
178 // condition as that test is only valid for the PaintContext that
179 // is initially handed to a layer's Paint() method. By the time the
180 // layer calls PaintChildren(), though, it may have modified the
181 // PaintContext so the test doesn't work in this "context".
182
183 // Apply any outstanding state that the children cannot individually
184 // and collectively handle.
185 auto restore = context.state_stack.applyState(
187
188 // Intentionally not tracing here as there should be no self-time
189 // and the trace event on this common function has a small overhead.
190 for (auto& layer : layers_) {
191 if (layer->needs_painting(context)) {
192 layer->Paint(context);
193 }
194 }
195}
196
197} // namespace flutter
void set_children_renderable_state_flags(int flags)
int children_renderable_state_flags() const
void Preroll(PrerollContext *context) override
void PrerollChildren(PrerollContext *context, SkRect *child_paint_bounds)
void Paint(PaintContext &context) const override
void PreservePaintRegion(DiffContext *context) override
virtual void Add(std::shared_ptr< Layer > layer)
void PaintChildren(PaintContext &context) const override
void Diff(DiffContext *context, const Layer *old_layer) override
void set_child_paint_bounds(const SkRect &bounds)
virtual void DiffChildren(DiffContext *context, const ContainerLayer *old_layer)
const SkRect & child_paint_bounds() const
void SetLayerPaintRegion(const Layer *layer, const PaintRegion &region)
void MarkSubtreeDirty(const PaintRegion &previous_paint_region=PaintRegion())
void AddDamage(const PaintRegion &damage)
PaintRegion CurrentSubtreeRegion() const
void AddExistingPaintRegion(const PaintRegion &region)
PaintRegion GetOldLayerPaintRegion(const Layer *layer) const
bool IsSubtreeDirty() const
AutoRestore applyState(const SkRect &bounds, int can_apply_flags)
static constexpr int kCallerCanApplyAnything
virtual void PreservePaintRegion(DiffContext *context)
Definition layer.h:162
void set_subtree_has_platform_view(bool value)
Definition layer.h:201
virtual bool IsReplacing(DiffContext *context, const Layer *old_layer) const
Definition layer.h:152
bool needs_painting(PaintContext &context) const
Definition layer.h:231
void set_paint_bounds(const SkRect &paint_bounds)
Definition layer.h:222
#define FML_DCHECK(condition)
Definition logging.h:103
static bool safe_intersection_test(const SkRect *rect1, const SkRect &rect2)
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
bool intersects(const SkRect &r) const
Definition SkRect.h:1121
bool isEmpty() const
Definition SkRect.h:693
void join(const SkRect &r)
Definition SkRect.cpp:126
LayerStateStack & state_stack
Definition layer.h:100