blob: ffe5a1968fb145818ffae3b036ed2c60dcb8e59c [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/ws/test_ws/test_window_service.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "mojo/public/cpp/bindings/map.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/ws/public/mojom/constants.mojom.h"
#include "services/ws/test_ws/test_gpu_interface_provider.h"
#include "services/ws/window_service.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/property_utils.h"
#include "ui/aura/window_tracker.h"
#include "ui/compositor/test/context_factories_for_test.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_sink.h"
#include "ui/gl/test/gl_surface_test_support.h"
#include "ui/wm/core/window_util.h"
namespace ws {
namespace test {
class TestWindowService::VisibilitySynchronizer : public aura::WindowTracker {
public:
VisibilitySynchronizer() = default;
~VisibilitySynchronizer() override = default;
private:
// aura::WindowObserver:
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override {
if (key == aura::client::kShowStateKey) {
if (wm::WindowStateIs(window, ui::SHOW_STATE_MINIMIZED))
window->Hide();
else
window->Show();
}
}
DISALLOW_COPY_AND_ASSIGN(VisibilitySynchronizer);
};
TestWindowService::TestWindowService(
service_manager::mojom::ServiceRequest request)
: service_binding_(this, std::move(request)) {}
TestWindowService::~TestWindowService() {
Shutdown(base::NullCallback());
}
void TestWindowService::InitForInProcess(
ui::ContextFactory* context_factory,
ui::ContextFactoryPrivate* context_factory_private,
std::unique_ptr<GpuInterfaceProvider> gpu_interface_provider) {
is_in_process_ = true;
aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>(
aura::Env::CreateLocalInstanceForInProcess());
SetupAuraTestHelper(context_factory, context_factory_private);
gpu_interface_provider_ = std::move(gpu_interface_provider);
visibility_synchronizer_ = std::make_unique<VisibilitySynchronizer>();
}
void TestWindowService::InitForOutOfProcess() {
visibility_synchronizer_ = std::make_unique<VisibilitySynchronizer>();
#if defined(OS_CHROMEOS)
// Use gpu service only for ChromeOS to run content_browsertests in mash.
//
// To use this code path for all platforms, we need to fix the following
// flaky failure on Win7 bot:
// gl_surface_egl.cc:
// EGL Driver message (Critical) eglInitialize: No available renderers
// gl_initializer_win.cc:
// GLSurfaceEGL::InitializeOneOff failed.
CreateGpuHost();
#else
gl::GLSurfaceTestSupport::InitializeOneOff();
CreateAuraTestHelper();
#endif // defined(OS_CHROMEOS)
}
std::unique_ptr<aura::Window> TestWindowService::NewTopLevel(
aura::PropertyConverter* property_converter,
const base::flat_map<std::string, std::vector<uint8_t>>& properties) {
std::unique_ptr<aura::Window> top_level = std::make_unique<aura::Window>(
nullptr, aura::client::WINDOW_TYPE_UNKNOWN, aura_test_helper_->GetEnv());
aura::SetWindowType(top_level.get(), aura::GetWindowTypeFromProperties(
mojo::FlatMapToMap(properties)));
top_level->Init(ui::LAYER_NOT_DRAWN);
aura_test_helper_->root_window()->AddChild(top_level.get());
for (auto property : properties) {
property_converter->SetPropertyFromTransportValue(
top_level.get(), property.first, &property.second);
}
if (maximize_next_window_) {
top_level->SetProperty(aura::client::kShowStateKey,
ui::SHOW_STATE_MAXIMIZED);
maximize_next_window_ = false;
}
visibility_synchronizer_->Add(top_level.get());
return top_level;
}
void TestWindowService::RunWindowMoveLoop(aura::Window* window,
mojom::MoveLoopSource source,
const gfx::Point& cursor,
DoneCallback callback) {
window_move_done_callback_ = std::move(callback);
}
void TestWindowService::CancelWindowMoveLoop() {
CHECK(!window_move_done_callback_.is_null());
std::move(window_move_done_callback_).Run(false);
}
void TestWindowService::RunDragLoop(aura::Window* window,
const ui::OSExchangeData& data,
const gfx::Point& screen_location,
uint32_t drag_operation,
ui::DragDropTypes::DragEventSource source,
DragDropCompletedCallback callback) {
std::move(callback).Run(drag_drop_client_.StartDragAndDrop(
data, window->GetRootWindow(), window, screen_location, drag_operation,
source));
}
void TestWindowService::CancelDragLoop(aura::Window* window) {
drag_drop_client_.DragCancel();
}
ui::EventTarget* TestWindowService::GetGlobalEventTarget() {
return aura_test_helper_->root_window();
}
aura::Window* TestWindowService::GetRootWindowForDisplayId(int64_t display_id) {
if (display::Screen::GetScreen()->GetAllDisplays().size() > 1)
NOTIMPLEMENTED_LOG_ONCE() << "Add test support for multiple displays.";
return aura_test_helper_->root_window();
}
void TestWindowService::OnStart() {
CHECK(!started_);
started_ = true;
registry_.AddInterface(base::BindRepeating(
&TestWindowService::BindServiceFactory, base::Unretained(this)));
registry_.AddInterface(base::BindRepeating(&TestWindowService::BindTestWs,
base::Unretained(this)));
if (!is_in_process_) {
DCHECK(!aura_test_helper_);
InitForOutOfProcess();
}
}
void TestWindowService::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void TestWindowService::CreateService(
service_manager::mojom::ServiceRequest request,
const std::string& name,
service_manager::mojom::PIDReceiverPtr pid_receiver) {
DCHECK_EQ(name, mojom::kServiceName);
// Defer CreateService if |aura_test_helper_| is not created.
if (!aura_test_helper_) {
DCHECK(!pending_create_service_);
pending_create_service_ = base::BindOnce(
&TestWindowService::CreateService, base::Unretained(this),
std::move(request), name, std::move(pid_receiver));
return;
}
DCHECK(!ui_service_created_);
ui_service_created_ = true;
window_service_ = std::make_unique<WindowService>(
this, std::move(gpu_interface_provider_),
aura_test_helper_->focus_client(), /*decrement_client_ids=*/false,
aura_test_helper_->GetEnv());
window_service_->BindServiceRequest(std::move(request));
pid_receiver->SetPID(base::GetCurrentProcId());
}
void TestWindowService::OnGpuServiceInitialized() {
CreateAuraTestHelper();
if (pending_create_service_)
std::move(pending_create_service_).Run();
}
void TestWindowService::MaximizeNextWindow(MaximizeNextWindowCallback cb) {
maximize_next_window_ = true;
std::move(cb).Run();
}
void TestWindowService::Shutdown(
test_ws::mojom::TestWs::ShutdownCallback callback) {
// WindowService depends upon Screen, which is owned by AuraTestHelper.
window_service_.reset();
// |aura_test_helper_| could be null when exiting before fully initialized.
if (aura_test_helper_) {
aura::client::SetScreenPositionClient(aura_test_helper_->root_window(),
nullptr);
// AuraTestHelper expects TearDown() to be called.
aura_test_helper_->TearDown();
aura_test_helper_.reset();
}
ui::TerminateContextFactoryForTests();
if (callback)
std::move(callback).Run();
}
void TestWindowService::BindServiceFactory(
service_manager::mojom::ServiceFactoryRequest request) {
service_factory_bindings_.AddBinding(this, std::move(request));
}
void TestWindowService::BindTestWs(test_ws::mojom::TestWsRequest request) {
test_ws_bindings_.AddBinding(this, std::move(request));
}
void TestWindowService::CreateGpuHost() {
discardable_shared_memory_manager_ =
std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
gpu_host_ = std::make_unique<gpu_host::GpuHost>(
this, service_binding_.GetConnector(),
discardable_shared_memory_manager_.get());
gpu_interface_provider_ = std::make_unique<TestGpuInterfaceProvider>(
gpu_host_.get(), discardable_shared_memory_manager_.get());
// |aura_test_helper_| is created later in OnGpuServiceInitialized.
}
void TestWindowService::CreateAuraTestHelper() {
DCHECK(!aura_test_helper_);
ui::ContextFactory* context_factory = nullptr;
ui::ContextFactoryPrivate* context_factory_private = nullptr;
ui::InitializeContextFactoryForTests(false /* enable_pixel_output */,
&context_factory,
&context_factory_private);
aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>();
SetupAuraTestHelper(context_factory, context_factory_private);
}
void TestWindowService::SetupAuraTestHelper(
ui::ContextFactory* context_factory,
ui::ContextFactoryPrivate* context_factory_private) {
aura_test_helper_->SetUp(context_factory, context_factory_private);
aura::client::SetScreenPositionClient(aura_test_helper_->root_window(),
&screen_position_client_);
}
} // namespace test
} // namespace ws