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
6
7#include <optional>
8
9namespace flutter {
10
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
123 DlRect* child_paint_bounds) {
124 // Platform views have no children, so context->has_platform_view should
125 // always be false.
126 FML_DCHECK(!context->has_platform_view);
127 FML_DCHECK(!context->has_texture_layer);
128
129 bool child_has_platform_view = false;
130 bool child_has_texture_layer = false;
131 bool all_renderable_state_flags = LayerStateStack::kCallerCanApplyAnything;
132
133 for (auto& layer : layers_) {
134 // Reset context->has_platform_view and context->has_texture_layer to false
135 // so that layers aren't treated as if they have a platform view or texture
136 // layer based on one being previously found in a sibling tree.
137 context->has_platform_view = false;
138 context->has_texture_layer = false;
139
140 // Initialize the renderable state flags to false to force the layer to
141 // opt-in to applying state attributes during its |Preroll|
142 context->renderable_state_flags = 0;
143
144 layer->Preroll(context);
145
146 all_renderable_state_flags &= context->renderable_state_flags;
147 if (child_paint_bounds->IntersectsWithRect(layer->paint_bounds())) {
148 // This will allow inheritance by a linear sequence of non-overlapping
149 // children, but will fail with a grid or other arbitrary 2D layout.
150 // See https://github.com/flutter/flutter/issues/93899
151 all_renderable_state_flags = 0;
152 }
153 *child_paint_bounds = child_paint_bounds->Union(layer->paint_bounds());
154
155 child_has_platform_view =
156 child_has_platform_view || context->has_platform_view;
157 child_has_texture_layer =
158 child_has_texture_layer || context->has_texture_layer;
159 }
160
161 context->has_platform_view = child_has_platform_view;
162 context->has_texture_layer = child_has_texture_layer;
163 context->renderable_state_flags = all_renderable_state_flags;
164 set_subtree_has_platform_view(child_has_platform_view);
165 set_children_renderable_state_flags(all_renderable_state_flags);
167}
168
170 // We can no longer call FML_DCHECK here on the needs_painting(context)
171 // condition as that test is only valid for the PaintContext that
172 // is initially handed to a layer's Paint() method. By the time the
173 // layer calls PaintChildren(), though, it may have modified the
174 // PaintContext so the test doesn't work in this "context".
175
176 // Apply any outstanding state that the children cannot individually
177 // and collectively handle.
178 auto restore = context.state_stack.applyState(
180
181 // Intentionally not tracing here as there should be no self-time
182 // and the trace event on this common function has a small overhead.
183 for (auto& layer : layers_) {
184 if (layer->needs_painting(context)) {
185 layer->Paint(context);
186 }
187 }
188}
189
190} // namespace flutter
void set_children_renderable_state_flags(int flags)
int children_renderable_state_flags() const
void Preroll(PrerollContext *context) override
void Paint(PaintContext &context) const override
const DlRect & child_paint_bounds() const
void PreservePaintRegion(DiffContext *context) override
void PrerollChildren(PrerollContext *context, DlRect *child_paint_bounds)
virtual void Add(std::shared_ptr< Layer > layer)
void PaintChildren(PaintContext &context) const override
void Diff(DiffContext *context, const Layer *old_layer) override
virtual void DiffChildren(DiffContext *context, const ContainerLayer *old_layer)
void set_child_paint_bounds(const DlRect &bounds)
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
virtual void PreservePaintRegion(DiffContext *context)
Definition layer.h:149
void set_subtree_has_platform_view(bool value)
Definition layer.h:188
virtual bool IsReplacing(DiffContext *context, const Layer *old_layer) const
Definition layer.h:139
void set_paint_bounds(const DlRect &paint_bounds)
Definition layer.h:209
bool needs_painting(PaintContext &context) const
Definition layer.h:218
static constexpr int kCallerCanApplyAnything
AutoRestore applyState(const DlRect &bounds, int can_apply_flags)
#define FML_DCHECK(condition)
Definition logging.h:122
LayerStateStack & state_stack
Definition layer.h:91
constexpr TRect Union(const TRect &o) const
Definition rect.h:513
constexpr bool IntersectsWithRect(const TRect &o) const
Definition rect.h:546