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
19namespace flutter {
20namespace testing {
21
22ShellTest::ShellTest()
23 : thread_host_("io.flutter.test." + GetCurrentTestName() + ".",
24 ThreadHost::Type::Platform | ThreadHost::Type::IO |
25 ThreadHost::Type::UI | ThreadHost::Type::GPU) {}
26
27void 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
42void 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
52void 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
66void 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
76void 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
99void 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
106void 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
146void ShellTest::DispatchFakePointerData(Shell* shell) {
147 auto packet = std::make_unique<PointerDataPacket>(1);
148 DispatchPointerData(shell, std::move(packet));
149}
150
151void 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
163int ShellTest::UnreportedTimingsCount(Shell* shell) {
164 return shell->unreported_timings_.size();
165}
166
167void ShellTest::SetNeedsReportTimings(Shell* shell, bool value) {
168 shell->SetNeedsReportTimings(value);
169}
170
171bool ShellTest::GetNeedsReportTimings(Shell* shell) {
172 return shell->needs_report_timings_;
173}
174
175void 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
203std::shared_ptr<txt::FontCollection> ShellTest::GetFontCollection(
204 Shell* shell) {
205 return shell->weak_engine_->GetFontCollection().GetFontCollection();
206}
207
208Settings 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
227TaskRunners 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
237fml::TimePoint ShellTest::GetLatestFrameTargetTime(Shell* shell) const {
238 return shell->GetLatestFrameTargetTime();
239}
240
241std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
242 bool simulate_vsync) {
243 return CreateShell(std::move(settings), GetTaskRunnersForFixture(),
244 simulate_vsync);
245}
246
247std::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}
275void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
276 DestroyShell(std::move(shell), GetTaskRunnersForFixture());
277}
278
279void 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