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 | #define FML_USED_ON_EMBEDDER |
6 | |
7 | #include "flutter/shell/common/shell_test.h" |
8 | #include "flutter/shell/common/shell_test_platform_view.h" |
9 | |
10 | #include "flutter/flow/layers/layer_tree.h" |
11 | #include "flutter/flow/layers/transform_layer.h" |
12 | #include "flutter/fml/build_config.h" |
13 | #include "flutter/fml/make_copyable.h" |
14 | #include "flutter/fml/mapping.h" |
15 | #include "flutter/runtime/dart_vm.h" |
16 | #include "flutter/shell/common/vsync_waiter_fallback.h" |
17 | #include "flutter/testing/testing.h" |
18 | |
19 | namespace flutter { |
20 | namespace testing { |
21 | |
22 | ShellTest::ShellTest() |
23 | : thread_host_("io.flutter.test." + GetCurrentTestName() + "." , |
24 | ThreadHost::Type::Platform | ThreadHost::Type::IO | |
25 | ThreadHost::Type::UI | ThreadHost::Type::GPU) {} |
26 | |
27 | void ShellTest::SendEnginePlatformMessage( |
28 | Shell* shell, |
29 | fml::RefPtr<PlatformMessage> message) { |
30 | fml::AutoResetWaitableEvent latch; |
31 | fml::TaskRunner::RunNowOrPostTask( |
32 | shell->GetTaskRunners().GetPlatformTaskRunner(), |
33 | [shell, &latch, message = std::move(message)]() { |
34 | if (auto engine = shell->weak_engine_) { |
35 | engine->HandlePlatformMessage(std::move(message)); |
36 | } |
37 | latch.Signal(); |
38 | }); |
39 | latch.Wait(); |
40 | } |
41 | |
42 | void ShellTest::PlatformViewNotifyCreated(Shell* shell) { |
43 | fml::AutoResetWaitableEvent latch; |
44 | fml::TaskRunner::RunNowOrPostTask( |
45 | shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() { |
46 | shell->GetPlatformView()->NotifyCreated(); |
47 | latch.Signal(); |
48 | }); |
49 | latch.Wait(); |
50 | } |
51 | |
52 | void ShellTest::RunEngine(Shell* shell, RunConfiguration configuration) { |
53 | fml::AutoResetWaitableEvent latch; |
54 | fml::TaskRunner::RunNowOrPostTask( |
55 | shell->GetTaskRunners().GetPlatformTaskRunner(), |
56 | [shell, &latch, &configuration]() { |
57 | shell->RunEngine(std::move(configuration), |
58 | [&latch](Engine::RunStatus run_status) { |
59 | ASSERT_EQ(run_status, Engine::RunStatus::Success); |
60 | latch.Signal(); |
61 | }); |
62 | }); |
63 | latch.Wait(); |
64 | } |
65 | |
66 | void ShellTest::RestartEngine(Shell* shell, RunConfiguration configuration) { |
67 | std::promise<bool> restarted; |
68 | fml::TaskRunner::RunNowOrPostTask( |
69 | shell->GetTaskRunners().GetUITaskRunner(), |
70 | [shell, &restarted, &configuration]() { |
71 | restarted.set_value(shell->engine_->Restart(std::move(configuration))); |
72 | }); |
73 | ASSERT_TRUE(restarted.get_future().get()); |
74 | } |
75 | |
76 | void ShellTest::VSyncFlush(Shell* shell, bool& will_draw_new_frame) { |
77 | fml::AutoResetWaitableEvent latch; |
78 | shell->GetTaskRunners().GetPlatformTaskRunner()->PostTask( |
79 | [shell, &will_draw_new_frame, &latch] { |
80 | // The following UI task ensures that all previous UI tasks are flushed. |
81 | fml::AutoResetWaitableEvent ui_latch; |
82 | shell->GetTaskRunners().GetUITaskRunner()->PostTask( |
83 | [&ui_latch, &will_draw_new_frame]() { |
84 | will_draw_new_frame = true; |
85 | ui_latch.Signal(); |
86 | }); |
87 | |
88 | ShellTestPlatformView* test_platform_view = |
89 | static_cast<ShellTestPlatformView*>(shell->GetPlatformView().get()); |
90 | do { |
91 | test_platform_view->SimulateVSync(); |
92 | } while (ui_latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(1))); |
93 | |
94 | latch.Signal(); |
95 | }); |
96 | latch.Wait(); |
97 | } |
98 | |
99 | void ShellTest::PumpOneFrame(Shell* shell, |
100 | double width, |
101 | double height, |
102 | LayerTreeBuilder builder) { |
103 | PumpOneFrame(shell, {1.0, width, height}, std::move(builder)); |
104 | } |
105 | |
106 | void ShellTest::PumpOneFrame(Shell* shell, |
107 | flutter::ViewportMetrics viewport_metrics, |
108 | LayerTreeBuilder builder) { |
109 | // Set viewport to nonempty, and call Animator::BeginFrame to make the layer |
110 | // tree pipeline nonempty. Without either of this, the layer tree below |
111 | // won't be rasterized. |
112 | fml::AutoResetWaitableEvent latch; |
113 | shell->GetTaskRunners().GetUITaskRunner()->PostTask( |
114 | [&latch, engine = shell->weak_engine_, viewport_metrics]() { |
115 | engine->SetViewportMetrics(std::move(viewport_metrics)); |
116 | const auto frame_begin_time = fml::TimePoint::Now(); |
117 | const auto frame_end_time = |
118 | frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0); |
119 | engine->animator_->BeginFrame(frame_begin_time, frame_end_time); |
120 | latch.Signal(); |
121 | }); |
122 | latch.Wait(); |
123 | |
124 | latch.Reset(); |
125 | // Call |Render| to rasterize a layer tree and trigger |OnFrameRasterized| |
126 | fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_; |
127 | shell->GetTaskRunners().GetUITaskRunner()->PostTask( |
128 | [&latch, runtime_delegate, &builder, viewport_metrics]() { |
129 | auto layer_tree = std::make_unique<LayerTree>( |
130 | SkISize::Make(viewport_metrics.physical_width, |
131 | viewport_metrics.physical_height), |
132 | static_cast<float>(viewport_metrics.device_pixel_ratio)); |
133 | SkMatrix identity; |
134 | identity.setIdentity(); |
135 | auto root_layer = std::make_shared<TransformLayer>(identity); |
136 | layer_tree->set_root_layer(root_layer); |
137 | if (builder) { |
138 | builder(root_layer); |
139 | } |
140 | runtime_delegate->Render(std::move(layer_tree)); |
141 | latch.Signal(); |
142 | }); |
143 | latch.Wait(); |
144 | } |
145 | |
146 | void ShellTest::DispatchFakePointerData(Shell* shell) { |
147 | auto packet = std::make_unique<PointerDataPacket>(1); |
148 | DispatchPointerData(shell, std::move(packet)); |
149 | } |
150 | |
151 | void ShellTest::DispatchPointerData(Shell* shell, |
152 | std::unique_ptr<PointerDataPacket> packet) { |
153 | fml::AutoResetWaitableEvent latch; |
154 | shell->GetTaskRunners().GetPlatformTaskRunner()->PostTask( |
155 | [&latch, shell, &packet]() { |
156 | // Goes through PlatformView to ensure packet is corrected converted. |
157 | shell->GetPlatformView()->DispatchPointerDataPacket(std::move(packet)); |
158 | latch.Signal(); |
159 | }); |
160 | latch.Wait(); |
161 | } |
162 | |
163 | int ShellTest::UnreportedTimingsCount(Shell* shell) { |
164 | return shell->unreported_timings_.size(); |
165 | } |
166 | |
167 | void ShellTest::SetNeedsReportTimings(Shell* shell, bool value) { |
168 | shell->SetNeedsReportTimings(value); |
169 | } |
170 | |
171 | bool ShellTest::GetNeedsReportTimings(Shell* shell) { |
172 | return shell->needs_report_timings_; |
173 | } |
174 | |
175 | void ShellTest::OnServiceProtocol( |
176 | Shell* shell, |
177 | ServiceProtocolEnum some_protocol, |
178 | fml::RefPtr<fml::TaskRunner> task_runner, |
179 | const ServiceProtocol::Handler::ServiceProtocolMap& params, |
180 | rapidjson::Document* response) { |
181 | std::promise<bool> finished; |
182 | fml::TaskRunner::RunNowOrPostTask( |
183 | task_runner, [shell, some_protocol, params, response, &finished]() { |
184 | switch (some_protocol) { |
185 | case ServiceProtocolEnum::kGetSkSLs: |
186 | shell->OnServiceProtocolGetSkSLs(params, response); |
187 | break; |
188 | case ServiceProtocolEnum::kEstimateRasterCacheMemory: |
189 | shell->OnServiceProtocolEstimateRasterCacheMemory(params, response); |
190 | break; |
191 | case ServiceProtocolEnum::kSetAssetBundlePath: |
192 | shell->OnServiceProtocolSetAssetBundlePath(params, response); |
193 | break; |
194 | case ServiceProtocolEnum::kRunInView: |
195 | shell->OnServiceProtocolRunInView(params, response); |
196 | break; |
197 | } |
198 | finished.set_value(true); |
199 | }); |
200 | finished.get_future().wait(); |
201 | } |
202 | |
203 | std::shared_ptr<txt::FontCollection> ShellTest::GetFontCollection( |
204 | Shell* shell) { |
205 | return shell->weak_engine_->GetFontCollection().GetFontCollection(); |
206 | } |
207 | |
208 | Settings ShellTest::CreateSettingsForFixture() { |
209 | Settings settings; |
210 | settings.leak_vm = false; |
211 | settings.task_observer_add = [](intptr_t key, fml::closure handler) { |
212 | fml::MessageLoop::GetCurrent().AddTaskObserver(key, handler); |
213 | }; |
214 | settings.task_observer_remove = [](intptr_t key) { |
215 | fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); |
216 | }; |
217 | settings.isolate_create_callback = [this]() { |
218 | native_resolver_->SetNativeResolverForIsolate(); |
219 | }; |
220 | #if OS_FUCHSIA |
221 | settings.verbose_logging = true; |
222 | #endif |
223 | SetSnapshotsAndAssets(settings); |
224 | return settings; |
225 | } |
226 | |
227 | TaskRunners ShellTest::GetTaskRunnersForFixture() { |
228 | return { |
229 | "test" , |
230 | thread_host_.platform_thread->GetTaskRunner(), // platform |
231 | thread_host_.raster_thread->GetTaskRunner(), // raster |
232 | thread_host_.ui_thread->GetTaskRunner(), // ui |
233 | thread_host_.io_thread->GetTaskRunner() // io |
234 | }; |
235 | } |
236 | |
237 | fml::TimePoint ShellTest::GetLatestFrameTargetTime(Shell* shell) const { |
238 | return shell->GetLatestFrameTargetTime(); |
239 | } |
240 | |
241 | std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings, |
242 | bool simulate_vsync) { |
243 | return CreateShell(std::move(settings), GetTaskRunnersForFixture(), |
244 | simulate_vsync); |
245 | } |
246 | |
247 | std::unique_ptr<Shell> ShellTest::CreateShell( |
248 | Settings settings, |
249 | TaskRunners task_runners, |
250 | bool simulate_vsync, |
251 | std::shared_ptr<ShellTestExternalViewEmbedder> |
252 | shell_test_external_view_embedder) { |
253 | const auto vsync_clock = std::make_shared<ShellTestVsyncClock>(); |
254 | CreateVsyncWaiter create_vsync_waiter = [&]() { |
255 | if (simulate_vsync) { |
256 | return static_cast<std::unique_ptr<VsyncWaiter>>( |
257 | std::make_unique<ShellTestVsyncWaiter>(task_runners, vsync_clock)); |
258 | } else { |
259 | return static_cast<std::unique_ptr<VsyncWaiter>>( |
260 | std::make_unique<VsyncWaiterFallback>(task_runners)); |
261 | } |
262 | }; |
263 | return Shell::Create( |
264 | task_runners, settings, |
265 | [vsync_clock, &create_vsync_waiter, |
266 | shell_test_external_view_embedder](Shell& shell) { |
267 | return ShellTestPlatformView::Create( |
268 | shell, shell.GetTaskRunners(), vsync_clock, |
269 | std::move(create_vsync_waiter), |
270 | ShellTestPlatformView::BackendType::kDefaultBackend, |
271 | shell_test_external_view_embedder); |
272 | }, |
273 | [](Shell& shell) { return std::make_unique<Rasterizer>(shell); }); |
274 | } |
275 | void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) { |
276 | DestroyShell(std::move(shell), GetTaskRunnersForFixture()); |
277 | } |
278 | |
279 | void ShellTest::DestroyShell(std::unique_ptr<Shell> shell, |
280 | TaskRunners task_runners) { |
281 | fml::AutoResetWaitableEvent latch; |
282 | fml::TaskRunner::RunNowOrPostTask(task_runners.GetPlatformTaskRunner(), |
283 | [&shell, &latch]() mutable { |
284 | shell.reset(); |
285 | latch.Signal(); |
286 | }); |
287 | latch.Wait(); |
288 | } |
289 | |
290 | } // namespace testing |
291 | } // namespace flutter |
292 | |