mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This re-lands #20496 and #21780 after fixing the semantics-enabling code that was causing the post-submit web_smoke_test to fail. Below is the description from the original PR: This is a PR for converting the dart:ui code in the engine to use a multi-window API. The goal here is to convert from the window singleton to an API that has the concept of multiple windows. Also, I'm matching up the new PlatformDispatcher class to talk directly to the PlatformConfiguration class in the engine. I'm not attempting to actually enable creating multiple windows here, just migrate to an API that has a concept of multiple windows. The multi-window API in this PR currently only ever creates one window. The design doc for this change is here. The major changes in this PR: Move the platfom-specific attributes out of Window, and into the new PlatformDispatcher class that holds all of the platform state, so that the platform code need only update the configuration on this class. Create FlutterView, FlutterWindow, and SingletonFlutterWindow classes to separate out the concepts of a view (of which there may be multiple in a window), a window (of which there may be multiple on a screen, and they host views), and a window where there is only ever expected to be one (this hosts the entire API of the former Window class, and will eventually be the type of the window singleton). Next step after this PR lands: Remove the Window class entirely (it is replaced by SingletonFlutterWindow). Some minor changes in the Framework are needed to switch to using SingletonFlutterWindow directly first. The Window class still exists in this PR, but will be removed as soon as the framework is converted to point to the SingletonFlutterWindow class instead. They share the same API, just have different names (Window is currently a subclass of SingletonFlutterWindow). The intention is that the Window name will be freed up to use as a widget class name in the framework for managing windows. The singleton called window will remain, and keep the same API it has now.
357 lines
13 KiB
C++
357 lines
13 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#define FML_USED_ON_EMBEDDER
|
|
|
|
#include "flutter/shell/common/shell_test.h"
|
|
|
|
#include "flutter/flow/layers/layer_tree.h"
|
|
#include "flutter/flow/layers/transform_layer.h"
|
|
#include "flutter/fml/build_config.h"
|
|
#include "flutter/fml/make_copyable.h"
|
|
#include "flutter/fml/mapping.h"
|
|
#include "flutter/runtime/dart_vm.h"
|
|
#include "flutter/shell/common/shell_test_platform_view.h"
|
|
#include "flutter/shell/common/vsync_waiter_fallback.h"
|
|
#include "flutter/testing/testing.h"
|
|
|
|
namespace flutter {
|
|
namespace testing {
|
|
|
|
ShellTest::ShellTest()
|
|
: thread_host_("io.flutter.test." + GetCurrentTestName() + ".",
|
|
ThreadHost::Type::Platform | ThreadHost::Type::IO |
|
|
ThreadHost::Type::UI | ThreadHost::Type::GPU) {}
|
|
|
|
void ShellTest::SendEnginePlatformMessage(
|
|
Shell* shell,
|
|
fml::RefPtr<PlatformMessage> message) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetPlatformTaskRunner(),
|
|
[shell, &latch, message = std::move(message)]() {
|
|
if (auto engine = shell->weak_engine_) {
|
|
engine->HandlePlatformMessage(std::move(message));
|
|
}
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::PlatformViewNotifyCreated(Shell* shell) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
|
|
shell->GetPlatformView()->NotifyCreated();
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::PlatformViewNotifyDestroyed(Shell* shell) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
|
|
shell->GetPlatformView()->NotifyDestroyed();
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::RunEngine(Shell* shell, RunConfiguration configuration) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetPlatformTaskRunner(),
|
|
[shell, &latch, &configuration]() {
|
|
shell->RunEngine(std::move(configuration),
|
|
[&latch](Engine::RunStatus run_status) {
|
|
ASSERT_EQ(run_status, Engine::RunStatus::Success);
|
|
latch.Signal();
|
|
});
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::RestartEngine(Shell* shell, RunConfiguration configuration) {
|
|
std::promise<bool> restarted;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetUITaskRunner(),
|
|
[shell, &restarted, &configuration]() {
|
|
restarted.set_value(shell->engine_->Restart(std::move(configuration)));
|
|
});
|
|
ASSERT_TRUE(restarted.get_future().get());
|
|
}
|
|
|
|
void ShellTest::VSyncFlush(Shell* shell, bool& will_draw_new_frame) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
shell->GetTaskRunners().GetPlatformTaskRunner(),
|
|
[shell, &will_draw_new_frame, &latch] {
|
|
// The following UI task ensures that all previous UI tasks are flushed.
|
|
fml::AutoResetWaitableEvent ui_latch;
|
|
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
|
[&ui_latch, &will_draw_new_frame]() {
|
|
will_draw_new_frame = true;
|
|
ui_latch.Signal();
|
|
});
|
|
|
|
ShellTestPlatformView* test_platform_view =
|
|
static_cast<ShellTestPlatformView*>(shell->GetPlatformView().get());
|
|
do {
|
|
test_platform_view->SimulateVSync();
|
|
} while (ui_latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(1)));
|
|
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) {
|
|
flutter::ViewportMetrics viewport_metrics = {
|
|
1, // device pixel ratio
|
|
width, // physical width
|
|
height, // physical height
|
|
0, // padding top
|
|
0, // padding right
|
|
0, // padding bottom
|
|
0, // padding left
|
|
0, // view inset top
|
|
0, // view inset right
|
|
0, // view inset bottom
|
|
0, // view inset left
|
|
0, // gesture inset top
|
|
0, // gesture inset right
|
|
0, // gesture inset bottom
|
|
0 // gesture inset left
|
|
};
|
|
// Set viewport to nonempty, and call Animator::BeginFrame to make the layer
|
|
// tree pipeline nonempty. Without either of this, the layer tree below
|
|
// won't be rasterized.
|
|
fml::AutoResetWaitableEvent latch;
|
|
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
|
[&latch, engine = shell->weak_engine_, viewport_metrics]() {
|
|
if (engine) {
|
|
engine->SetViewportMetrics(std::move(viewport_metrics));
|
|
const auto frame_begin_time = fml::TimePoint::Now();
|
|
const auto frame_end_time =
|
|
frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
|
|
engine->animator_->BeginFrame(frame_begin_time, frame_end_time);
|
|
}
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::NotifyIdle(Shell* shell, int64_t deadline) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
|
[&latch, engine = shell->weak_engine_, deadline]() {
|
|
if (engine) {
|
|
engine->NotifyIdle(deadline);
|
|
}
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::PumpOneFrame(Shell* shell,
|
|
double width,
|
|
double height,
|
|
LayerTreeBuilder builder) {
|
|
PumpOneFrame(shell, {1.0, width, height}, std::move(builder));
|
|
}
|
|
|
|
void ShellTest::PumpOneFrame(Shell* shell,
|
|
flutter::ViewportMetrics viewport_metrics,
|
|
LayerTreeBuilder builder) {
|
|
// Set viewport to nonempty, and call Animator::BeginFrame to make the layer
|
|
// tree pipeline nonempty. Without either of this, the layer tree below
|
|
// won't be rasterized.
|
|
fml::AutoResetWaitableEvent latch;
|
|
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
|
[&latch, engine = shell->weak_engine_, viewport_metrics]() {
|
|
engine->SetViewportMetrics(std::move(viewport_metrics));
|
|
const auto frame_begin_time = fml::TimePoint::Now();
|
|
const auto frame_end_time =
|
|
frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
|
|
engine->animator_->BeginFrame(frame_begin_time, frame_end_time);
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
|
|
latch.Reset();
|
|
// Call |Render| to rasterize a layer tree and trigger |OnFrameRasterized|
|
|
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
|
|
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
|
[&latch, runtime_delegate, &builder, viewport_metrics]() {
|
|
auto layer_tree = std::make_unique<LayerTree>(
|
|
SkISize::Make(viewport_metrics.physical_width,
|
|
viewport_metrics.physical_height),
|
|
static_cast<float>(viewport_metrics.device_pixel_ratio));
|
|
SkMatrix identity;
|
|
identity.setIdentity();
|
|
auto root_layer = std::make_shared<TransformLayer>(identity);
|
|
layer_tree->set_root_layer(root_layer);
|
|
if (builder) {
|
|
builder(root_layer);
|
|
}
|
|
runtime_delegate->Render(std::move(layer_tree));
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
void ShellTest::DispatchFakePointerData(Shell* shell) {
|
|
auto packet = std::make_unique<PointerDataPacket>(1);
|
|
DispatchPointerData(shell, std::move(packet));
|
|
}
|
|
|
|
void ShellTest::DispatchPointerData(Shell* shell,
|
|
std::unique_ptr<PointerDataPacket> packet) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
shell->GetTaskRunners().GetPlatformTaskRunner()->PostTask(
|
|
[&latch, shell, &packet]() {
|
|
// Goes through PlatformView to ensure packet is corrected converted.
|
|
shell->GetPlatformView()->DispatchPointerDataPacket(std::move(packet));
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
int ShellTest::UnreportedTimingsCount(Shell* shell) {
|
|
return shell->unreported_timings_.size();
|
|
}
|
|
|
|
void ShellTest::SetNeedsReportTimings(Shell* shell, bool value) {
|
|
shell->SetNeedsReportTimings(value);
|
|
}
|
|
|
|
bool ShellTest::GetNeedsReportTimings(Shell* shell) {
|
|
return shell->needs_report_timings_;
|
|
}
|
|
|
|
void ShellTest::StorePersistentCache(PersistentCache* cache,
|
|
const SkData& key,
|
|
const SkData& value) {
|
|
cache->store(key, value);
|
|
}
|
|
|
|
void ShellTest::OnServiceProtocol(
|
|
Shell* shell,
|
|
ServiceProtocolEnum some_protocol,
|
|
fml::RefPtr<fml::TaskRunner> task_runner,
|
|
const ServiceProtocol::Handler::ServiceProtocolMap& params,
|
|
rapidjson::Document* response) {
|
|
std::promise<bool> finished;
|
|
fml::TaskRunner::RunNowOrPostTask(
|
|
task_runner, [shell, some_protocol, params, response, &finished]() {
|
|
switch (some_protocol) {
|
|
case ServiceProtocolEnum::kGetSkSLs:
|
|
shell->OnServiceProtocolGetSkSLs(params, response);
|
|
break;
|
|
case ServiceProtocolEnum::kEstimateRasterCacheMemory:
|
|
shell->OnServiceProtocolEstimateRasterCacheMemory(params, response);
|
|
break;
|
|
case ServiceProtocolEnum::kSetAssetBundlePath:
|
|
shell->OnServiceProtocolSetAssetBundlePath(params, response);
|
|
break;
|
|
case ServiceProtocolEnum::kRunInView:
|
|
shell->OnServiceProtocolRunInView(params, response);
|
|
break;
|
|
}
|
|
finished.set_value(true);
|
|
});
|
|
finished.get_future().wait();
|
|
}
|
|
|
|
std::shared_ptr<txt::FontCollection> ShellTest::GetFontCollection(
|
|
Shell* shell) {
|
|
return shell->weak_engine_->GetFontCollection().GetFontCollection();
|
|
}
|
|
|
|
Settings ShellTest::CreateSettingsForFixture() {
|
|
Settings settings;
|
|
settings.leak_vm = false;
|
|
settings.task_observer_add = [](intptr_t key, fml::closure handler) {
|
|
fml::MessageLoop::GetCurrent().AddTaskObserver(key, handler);
|
|
};
|
|
settings.task_observer_remove = [](intptr_t key) {
|
|
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
|
};
|
|
settings.isolate_create_callback = [this]() {
|
|
native_resolver_->SetNativeResolverForIsolate();
|
|
};
|
|
#if OS_FUCHSIA
|
|
settings.verbose_logging = true;
|
|
#endif
|
|
SetSnapshotsAndAssets(settings);
|
|
return settings;
|
|
}
|
|
|
|
TaskRunners ShellTest::GetTaskRunnersForFixture() {
|
|
return {
|
|
"test",
|
|
thread_host_.platform_thread->GetTaskRunner(), // platform
|
|
thread_host_.raster_thread->GetTaskRunner(), // raster
|
|
thread_host_.ui_thread->GetTaskRunner(), // ui
|
|
thread_host_.io_thread->GetTaskRunner() // io
|
|
};
|
|
}
|
|
|
|
fml::TimePoint ShellTest::GetLatestFrameTargetTime(Shell* shell) const {
|
|
return shell->GetLatestFrameTargetTime();
|
|
}
|
|
|
|
std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
|
|
bool simulate_vsync) {
|
|
return CreateShell(std::move(settings), GetTaskRunnersForFixture(),
|
|
simulate_vsync);
|
|
}
|
|
|
|
std::unique_ptr<Shell> ShellTest::CreateShell(
|
|
Settings settings,
|
|
TaskRunners task_runners,
|
|
bool simulate_vsync,
|
|
std::shared_ptr<ShellTestExternalViewEmbedder>
|
|
shell_test_external_view_embedder) {
|
|
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
|
|
CreateVsyncWaiter create_vsync_waiter = [&]() {
|
|
if (simulate_vsync) {
|
|
return static_cast<std::unique_ptr<VsyncWaiter>>(
|
|
std::make_unique<ShellTestVsyncWaiter>(task_runners, vsync_clock));
|
|
} else {
|
|
return static_cast<std::unique_ptr<VsyncWaiter>>(
|
|
std::make_unique<VsyncWaiterFallback>(task_runners));
|
|
}
|
|
};
|
|
return Shell::Create(
|
|
task_runners, settings,
|
|
[vsync_clock, &create_vsync_waiter,
|
|
shell_test_external_view_embedder](Shell& shell) {
|
|
return ShellTestPlatformView::Create(
|
|
shell, shell.GetTaskRunners(), vsync_clock,
|
|
std::move(create_vsync_waiter),
|
|
ShellTestPlatformView::BackendType::kDefaultBackend,
|
|
shell_test_external_view_embedder);
|
|
},
|
|
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); });
|
|
}
|
|
void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
|
|
DestroyShell(std::move(shell), GetTaskRunnersForFixture());
|
|
}
|
|
|
|
void ShellTest::DestroyShell(std::unique_ptr<Shell> shell,
|
|
TaskRunners task_runners) {
|
|
fml::AutoResetWaitableEvent latch;
|
|
fml::TaskRunner::RunNowOrPostTask(task_runners.GetPlatformTaskRunner(),
|
|
[&shell, &latch]() mutable {
|
|
shell.reset();
|
|
latch.Signal();
|
|
});
|
|
latch.Wait();
|
|
}
|
|
|
|
} // namespace testing
|
|
} // namespace flutter
|