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/layer_tree.h" |
6 | |
7 | #include "flutter/flow/compositor_context.h" |
8 | #include "flutter/flow/layers/container_layer.h" |
9 | #include "flutter/flow/testing/mock_layer.h" |
10 | #include "flutter/fml/macros.h" |
11 | #include "flutter/testing/canvas_test.h" |
12 | #include "flutter/testing/mock_canvas.h" |
13 | #include "gtest/gtest.h" |
14 | |
15 | namespace flutter { |
16 | namespace testing { |
17 | |
18 | class LayerTreeTest : public CanvasTest { |
19 | public: |
20 | LayerTreeTest() |
21 | : layer_tree_(SkISize::Make(64, 64), 1.0f), |
22 | compositor_context_(fml::kDefaultFrameBudget), |
23 | root_transform_(SkMatrix::Translate(1.0f, 1.0f)), |
24 | scoped_frame_(compositor_context_.AcquireFrame(nullptr, |
25 | &mock_canvas(), |
26 | nullptr, |
27 | root_transform_, |
28 | false, |
29 | true, |
30 | nullptr)) {} |
31 | |
32 | LayerTree& layer_tree() { return layer_tree_; } |
33 | CompositorContext::ScopedFrame& frame() { return *scoped_frame_.get(); } |
34 | const SkMatrix& root_transform() { return root_transform_; } |
35 | |
36 | private: |
37 | LayerTree layer_tree_; |
38 | CompositorContext compositor_context_; |
39 | SkMatrix root_transform_; |
40 | std::unique_ptr<CompositorContext::ScopedFrame> scoped_frame_; |
41 | }; |
42 | |
43 | TEST_F(LayerTreeTest, PaintingEmptyLayerDies) { |
44 | auto layer = std::make_shared<ContainerLayer>(); |
45 | |
46 | layer_tree().set_root_layer(layer); |
47 | layer_tree().Preroll(frame()); |
48 | EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty()); |
49 | EXPECT_FALSE(layer->needs_painting()); |
50 | |
51 | layer_tree().Paint(frame()); |
52 | } |
53 | |
54 | TEST_F(LayerTreeTest, PaintBeforePreollDies) { |
55 | const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); |
56 | SkPath child_path; |
57 | child_path.addRect(child_bounds); |
58 | auto mock_layer = std::make_shared<MockLayer>(child_path); |
59 | auto layer = std::make_shared<ContainerLayer>(); |
60 | layer->Add(mock_layer); |
61 | |
62 | layer_tree().set_root_layer(layer); |
63 | EXPECT_EQ(mock_layer->paint_bounds(), kEmptyRect); |
64 | EXPECT_EQ(layer->paint_bounds(), kEmptyRect); |
65 | EXPECT_FALSE(mock_layer->needs_painting()); |
66 | EXPECT_FALSE(layer->needs_painting()); |
67 | |
68 | layer_tree().Paint(frame()); |
69 | EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>()); |
70 | } |
71 | |
72 | TEST_F(LayerTreeTest, Simple) { |
73 | const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); |
74 | const SkPath child_path = SkPath().addRect(child_bounds); |
75 | const SkPaint child_paint = SkPaint(SkColors::kCyan); |
76 | auto mock_layer = std::make_shared<MockLayer>(child_path, child_paint); |
77 | auto layer = std::make_shared<ContainerLayer>(); |
78 | layer->Add(mock_layer); |
79 | |
80 | layer_tree().set_root_layer(layer); |
81 | layer_tree().Preroll(frame()); |
82 | EXPECT_EQ(mock_layer->paint_bounds(), child_bounds); |
83 | EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds()); |
84 | EXPECT_TRUE(mock_layer->needs_painting()); |
85 | EXPECT_TRUE(layer->needs_painting()); |
86 | EXPECT_EQ(mock_layer->parent_matrix(), root_transform()); |
87 | |
88 | layer_tree().Paint(frame()); |
89 | EXPECT_EQ(mock_canvas().draw_calls(), |
90 | std::vector({MockCanvas::DrawCall{ |
91 | 0, MockCanvas::DrawPathData{child_path, child_paint}}})); |
92 | } |
93 | |
94 | TEST_F(LayerTreeTest, Multiple) { |
95 | const SkPath child_path1 = SkPath().addRect(5.0f, 6.0f, 20.5f, 21.5f); |
96 | const SkPath child_path2 = SkPath().addRect(8.0f, 2.0f, 16.5f, 14.5f); |
97 | const SkPaint child_paint1(SkColors::kGray); |
98 | const SkPaint child_paint2(SkColors::kGreen); |
99 | auto mock_layer1 = std::make_shared<MockLayer>( |
100 | child_path1, child_paint1, true /* fake_has_platform_view */); |
101 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2); |
102 | auto layer = std::make_shared<ContainerLayer>(); |
103 | layer->Add(mock_layer1); |
104 | layer->Add(mock_layer2); |
105 | |
106 | SkRect expected_total_bounds = child_path1.getBounds(); |
107 | expected_total_bounds.join(child_path2.getBounds()); |
108 | layer_tree().set_root_layer(layer); |
109 | layer_tree().Preroll(frame()); |
110 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
111 | EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); |
112 | EXPECT_EQ(layer->paint_bounds(), expected_total_bounds); |
113 | EXPECT_TRUE(mock_layer1->needs_painting()); |
114 | EXPECT_TRUE(mock_layer2->needs_painting()); |
115 | EXPECT_TRUE(layer->needs_painting()); |
116 | EXPECT_FALSE(mock_layer1->needs_system_composite()); |
117 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
118 | EXPECT_FALSE(layer->needs_system_composite()); |
119 | EXPECT_EQ(mock_layer1->parent_matrix(), root_transform()); |
120 | EXPECT_EQ(mock_layer2->parent_matrix(), root_transform()); |
121 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
122 | EXPECT_EQ(mock_layer2->parent_cull_rect(), |
123 | kGiantRect); // Siblings are independent |
124 | |
125 | layer_tree().Paint(frame()); |
126 | EXPECT_EQ( |
127 | mock_canvas().draw_calls(), |
128 | std::vector({MockCanvas::DrawCall{ |
129 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, |
130 | MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ |
131 | child_path2, child_paint2}}})); |
132 | } |
133 | |
134 | TEST_F(LayerTreeTest, MultipleWithEmpty) { |
135 | const SkPath child_path1 = SkPath().addRect(5.0f, 6.0f, 20.5f, 21.5f); |
136 | const SkPaint child_paint1(SkColors::kGray); |
137 | const SkPaint child_paint2(SkColors::kGreen); |
138 | auto mock_layer1 = std::make_shared<MockLayer>(child_path1, child_paint1); |
139 | auto mock_layer2 = std::make_shared<MockLayer>(SkPath(), child_paint2); |
140 | auto layer = std::make_shared<ContainerLayer>(); |
141 | layer->Add(mock_layer1); |
142 | layer->Add(mock_layer2); |
143 | |
144 | layer_tree().set_root_layer(layer); |
145 | layer_tree().Preroll(frame()); |
146 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
147 | EXPECT_EQ(mock_layer2->paint_bounds(), SkPath().getBounds()); |
148 | EXPECT_EQ(layer->paint_bounds(), child_path1.getBounds()); |
149 | EXPECT_TRUE(mock_layer1->needs_painting()); |
150 | EXPECT_FALSE(mock_layer2->needs_painting()); |
151 | EXPECT_TRUE(layer->needs_painting()); |
152 | EXPECT_FALSE(mock_layer1->needs_system_composite()); |
153 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
154 | EXPECT_FALSE(layer->needs_system_composite()); |
155 | EXPECT_EQ(mock_layer1->parent_matrix(), root_transform()); |
156 | EXPECT_EQ(mock_layer2->parent_matrix(), root_transform()); |
157 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
158 | EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); |
159 | |
160 | layer_tree().Paint(frame()); |
161 | EXPECT_EQ(mock_canvas().draw_calls(), |
162 | std::vector({MockCanvas::DrawCall{ |
163 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}})); |
164 | } |
165 | |
166 | TEST_F(LayerTreeTest, NeedsSystemComposite) { |
167 | const SkPath child_path1 = SkPath().addRect(5.0f, 6.0f, 20.5f, 21.5f); |
168 | const SkPath child_path2 = SkPath().addRect(8.0f, 2.0f, 16.5f, 14.5f); |
169 | const SkPaint child_paint1(SkColors::kGray); |
170 | const SkPaint child_paint2(SkColors::kGreen); |
171 | auto mock_layer1 = std::make_shared<MockLayer>( |
172 | child_path1, child_paint1, false /* fake_has_platform_view */, |
173 | true /* fake_needs_system_composite */); |
174 | auto mock_layer2 = std::make_shared<MockLayer>(child_path2, child_paint2); |
175 | auto layer = std::make_shared<ContainerLayer>(); |
176 | layer->Add(mock_layer1); |
177 | layer->Add(mock_layer2); |
178 | |
179 | SkRect expected_total_bounds = child_path1.getBounds(); |
180 | expected_total_bounds.join(child_path2.getBounds()); |
181 | layer_tree().set_root_layer(layer); |
182 | layer_tree().Preroll(frame()); |
183 | EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); |
184 | EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); |
185 | EXPECT_EQ(layer->paint_bounds(), expected_total_bounds); |
186 | EXPECT_TRUE(mock_layer1->needs_painting()); |
187 | EXPECT_TRUE(mock_layer2->needs_painting()); |
188 | EXPECT_TRUE(layer->needs_painting()); |
189 | EXPECT_TRUE(mock_layer1->needs_system_composite()); |
190 | EXPECT_FALSE(mock_layer2->needs_system_composite()); |
191 | EXPECT_TRUE(layer->needs_system_composite()); |
192 | EXPECT_EQ(mock_layer1->parent_matrix(), root_transform()); |
193 | EXPECT_EQ(mock_layer2->parent_matrix(), root_transform()); |
194 | EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect); |
195 | EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect); |
196 | |
197 | layer_tree().Paint(frame()); |
198 | EXPECT_EQ( |
199 | mock_canvas().draw_calls(), |
200 | std::vector({MockCanvas::DrawCall{ |
201 | 0, MockCanvas::DrawPathData{child_path1, child_paint1}}, |
202 | MockCanvas::DrawCall{0, MockCanvas::DrawPathData{ |
203 | child_path2, child_paint2}}})); |
204 | } |
205 | |
206 | } // namespace testing |
207 | } // namespace flutter |
208 | |