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 | |
9 | namespace flutter { |
10 | |
11 | ContainerLayer::ContainerLayer() {} |
12 | |
13 | void ContainerLayer::Add(std::shared_ptr<Layer> layer) { |
14 | layers_.emplace_back(std::move(layer)); |
15 | } |
16 | |
17 | void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { |
18 | TRACE_EVENT0("flutter" , "ContainerLayer::Preroll" ); |
19 | |
20 | SkRect child_paint_bounds = SkRect::MakeEmpty(); |
21 | PrerollChildren(context, matrix, &child_paint_bounds); |
22 | set_paint_bounds(child_paint_bounds); |
23 | } |
24 | |
25 | void ContainerLayer::Paint(PaintContext& context) const { |
26 | FML_DCHECK(needs_painting()); |
27 | |
28 | PaintChildren(context); |
29 | } |
30 | |
31 | void ContainerLayer::PrerollChildren(PrerollContext* context, |
32 | const SkMatrix& child_matrix, |
33 | SkRect* child_paint_bounds) { |
34 | #if defined(LEGACY_FUCHSIA_EMBEDDER) |
35 | // If there is embedded Fuchsia content in the scene (a ChildSceneLayer), |
36 | // Layers that appear above the embedded content will be turned into their own |
37 | // Scenic layers. |
38 | child_layer_exists_below_ = context->child_scene_layer_exists_below; |
39 | context->child_scene_layer_exists_below = false; |
40 | #endif |
41 | |
42 | // Platform views have no children, so context->has_platform_view should |
43 | // always be false. |
44 | FML_DCHECK(!context->has_platform_view); |
45 | bool child_has_platform_view = false; |
46 | for (auto& layer : layers_) { |
47 | // Reset context->has_platform_view to false so that layers aren't treated |
48 | // as if they have a platform view based on one being previously found in a |
49 | // sibling tree. |
50 | context->has_platform_view = false; |
51 | |
52 | layer->Preroll(context, child_matrix); |
53 | |
54 | if (layer->needs_system_composite()) { |
55 | set_needs_system_composite(true); |
56 | } |
57 | child_paint_bounds->join(layer->paint_bounds()); |
58 | |
59 | child_has_platform_view = |
60 | child_has_platform_view || context->has_platform_view; |
61 | } |
62 | |
63 | context->has_platform_view = child_has_platform_view; |
64 | |
65 | #if defined(LEGACY_FUCHSIA_EMBEDDER) |
66 | if (child_layer_exists_below_) { |
67 | set_needs_system_composite(true); |
68 | } |
69 | context->child_scene_layer_exists_below = |
70 | context->child_scene_layer_exists_below || child_layer_exists_below_; |
71 | #endif |
72 | } |
73 | |
74 | void ContainerLayer::PaintChildren(PaintContext& context) const { |
75 | FML_DCHECK(needs_painting()); |
76 | |
77 | // Intentionally not tracing here as there should be no self-time |
78 | // and the trace event on this common function has a small overhead. |
79 | for (auto& layer : layers_) { |
80 | if (layer->needs_painting()) { |
81 | layer->Paint(context); |
82 | } |
83 | } |
84 | } |
85 | |
86 | void ContainerLayer::TryToPrepareRasterCache(PrerollContext* context, |
87 | Layer* layer, |
88 | const SkMatrix& matrix) { |
89 | if (!context->has_platform_view && context->raster_cache && |
90 | SkRect::Intersects(context->cull_rect, layer->paint_bounds())) { |
91 | context->raster_cache->Prepare(context, layer, matrix); |
92 | } |
93 | } |
94 | |
95 | #if defined(LEGACY_FUCHSIA_EMBEDDER) |
96 | |
97 | void ContainerLayer::CheckForChildLayerBelow(PrerollContext* context) { |
98 | // All ContainerLayers make the check in PrerollChildren. |
99 | } |
100 | |
101 | void ContainerLayer::UpdateScene(SceneUpdateContext& context) { |
102 | UpdateSceneChildren(context); |
103 | } |
104 | |
105 | void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) { |
106 | FML_DCHECK(needs_system_composite()); |
107 | |
108 | std::optional<SceneUpdateContext::Frame> frame; |
109 | if (child_layer_exists_below_) { |
110 | frame.emplace( |
111 | context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT, |
112 | SkScalarRoundToInt(context.alphaf() * 255), "flutter::ContainerLayer" ); |
113 | frame->AddPaintLayer(this); |
114 | } |
115 | |
116 | for (auto& layer : layers_) { |
117 | if (layer->needs_system_composite()) { |
118 | layer->UpdateScene(context); |
119 | } |
120 | } |
121 | } |
122 | |
123 | #endif |
124 | |
125 | MergedContainerLayer::MergedContainerLayer() { |
126 | // Ensure the layer has only one direct child. |
127 | // |
128 | // Any children will actually be added as children of this empty |
129 | // ContainerLayer which can be accessed via ::GetContainerLayer(). |
130 | // If only one child is ever added to this layer then that child |
131 | // will become the layer returned from ::GetCacheableChild(). |
132 | // If multiple child layers are added, then this implicit container |
133 | // child becomes the cacheable child, but at the potential cost of |
134 | // not being as stable in the raster cache from frame to frame. |
135 | ContainerLayer::Add(std::make_shared<ContainerLayer>()); |
136 | } |
137 | |
138 | void MergedContainerLayer::Add(std::shared_ptr<Layer> layer) { |
139 | GetChildContainer()->Add(std::move(layer)); |
140 | } |
141 | |
142 | ContainerLayer* MergedContainerLayer::GetChildContainer() const { |
143 | FML_DCHECK(layers().size() == 1); |
144 | |
145 | return static_cast<ContainerLayer*>(layers()[0].get()); |
146 | } |
147 | |
148 | Layer* MergedContainerLayer::GetCacheableChild() const { |
149 | ContainerLayer* child_container = GetChildContainer(); |
150 | if (child_container->layers().size() == 1) { |
151 | return child_container->layers()[0].get(); |
152 | } |
153 | |
154 | return child_container; |
155 | } |
156 | |
157 | } // namespace flutter |
158 | |