blob: cd03f310c7b0ce91ec92c23e0433f25b52a33462 [file] [log] [blame]
// Copyright 2021 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 "components/exo/test/shell_surface_builder.h"
#include <tuple>
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_positioning_utils.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/xdg_shell_surface.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "ui/aura/env.h"
#include "base/logging.h"
namespace {
// Internal structure that owns buffer, surface and subsurface instances.
// This is owned by the host window as an owned property.
struct Holder {
exo::Surface* root_surface = nullptr;
std::vector<std::tuple<std::unique_ptr<exo::Buffer>,
std::unique_ptr<exo::Surface>,
std::unique_ptr<exo::SubSurface>>>
sub_surfaces;
void AddRootSurface(const gfx::Size& size,
absl::optional<gfx::BufferFormat> buffer_format) {
auto surface = std::make_unique<exo::Surface>();
std::unique_ptr<exo::Buffer> buffer;
if (buffer_format) {
buffer = std::make_unique<exo::Buffer>(
aura::Env::GetInstance()
->context_factory()
->GetGpuMemoryBufferManager()
->CreateGpuMemoryBuffer(size, *buffer_format,
gfx::BufferUsage::GPU_READ,
gpu::kNullSurfaceHandle, nullptr));
surface->Attach(buffer.get());
}
root_surface = surface.get();
sub_surfaces.push_back(
std::make_tuple<>(std::move(buffer), std::move(surface), nullptr));
}
exo::Surface* AddChildSurface(exo::Surface* parent, const gfx::Rect& bounds) {
auto buffer = std::make_unique<exo::Buffer>(
aura::Env::GetInstance()
->context_factory()
->GetGpuMemoryBufferManager()
->CreateGpuMemoryBuffer(bounds.size(), gfx::BufferFormat::RGBA_8888,
gfx::BufferUsage::GPU_READ,
gpu::kNullSurfaceHandle, nullptr));
auto surface = std::make_unique<exo::Surface>();
surface->Attach(buffer.get());
auto sub_surface = std::make_unique<exo::SubSurface>(surface.get(), parent);
sub_surface->SetPosition(gfx::PointF(bounds.origin()));
auto* surface_ptr = surface.get();
sub_surfaces.push_back(std::make_tuple<>(
std::move(buffer), std::move(surface), std::move(sub_surface)));
return surface_ptr;
}
void DestroyRootSurface() {
DCHECK(root_surface);
for (auto& tuple : sub_surfaces) {
if (std::get<1>(tuple).get() == root_surface) {
std::get<0>(tuple).reset();
std::get<1>(tuple).reset();
std::get<2>(tuple).reset();
break;
}
}
root_surface = nullptr;
}
};
} // namespace
DEFINE_UI_CLASS_PROPERTY_TYPE(Holder*)
namespace exo {
namespace test {
namespace {
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(Holder, kBuilderResourceHolderKey, nullptr)
Holder* FindHolder(Surface* surface) {
aura::Window* window = surface->window();
Holder* holder = window->GetProperty(kBuilderResourceHolderKey);
while (!holder && window->parent()) {
window = window->parent();
holder = window->GetProperty(kBuilderResourceHolderKey);
}
return holder;
}
} // namespace
ShellSurfaceBuilder::ShellSurfaceBuilder(const gfx::Size& buffer_size)
: root_buffer_size_(buffer_size) {}
ShellSurfaceBuilder::~ShellSurfaceBuilder() = default;
ShellSurfaceBuilder& ShellSurfaceBuilder::SetNoRootBuffer() {
DCHECK(!built_);
root_buffer_format_.reset();
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetRootBufferFormat(
gfx::BufferFormat buffer_format) {
DCHECK(!built_);
root_buffer_format_ = buffer_format;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetOrigin(const gfx::Point& origin) {
DCHECK(!built_);
origin_ = origin;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetUseSystemModalContainer() {
DCHECK(!built_);
use_system_modal_container_ = true;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetNoCommit() {
DCHECK(!built_);
commit_on_build_ = false;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetCanMinimize(bool can_minimize) {
DCHECK(!built_);
can_minimize_ = can_minimize;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetMaximumSize(
const gfx::Size& size) {
DCHECK(!built_);
max_size_ = size;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetMinimumSize(
const gfx::Size& size) {
DCHECK(!built_);
min_size_ = size;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetDisableMovement() {
DCHECK(!built_);
disable_movement_ = true;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetCentered() {
DCHECK(!built_);
centered_ = true;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetParent(ShellSurface* parent) {
DCHECK(!built_);
parent_shell_surface_ = parent;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::SetAsPopup() {
DCHECK(!built_);
popup_ = true;
return *this;
}
ShellSurfaceBuilder& ShellSurfaceBuilder::EnableDefaultScaleCancellation() {
DCHECK(!built_);
default_scale_cancellation_ = true;
return *this;
}
// static
void ShellSurfaceBuilder::DestroyRootSurface(ShellSurfaceBase* shell_surface) {
Holder* holder =
shell_surface->host_window()->GetProperty(kBuilderResourceHolderKey);
DCHECK(holder);
holder->DestroyRootSurface();
}
// static
Surface* ShellSurfaceBuilder::AddChildSurface(Surface* parent,
const gfx::Rect& bounds) {
Holder* holder = FindHolder(parent);
DCHECK(holder);
return holder->AddChildSurface(parent, bounds);
}
std::unique_ptr<ShellSurface> ShellSurfaceBuilder::BuildShellSurface() {
// Create a ShellSurface instance.
DCHECK(!built_);
DCHECK(isConfigurationValidForShellSurface());
built_ = true;
Holder* holder = new Holder();
holder->AddRootSurface(root_buffer_size_, root_buffer_format_);
auto shell_surface = std::make_unique<ShellSurface>(
holder->root_surface, origin_, can_minimize_, GetContainer());
shell_surface->host_window()->SetProperty(kBuilderResourceHolderKey, holder);
// Set the properties specific to ShellSurface.
if (parent_shell_surface_)
shell_surface->SetParent(parent_shell_surface_);
if (popup_)
shell_surface->SetPopup();
SetCommonPropertiesAndCommitIfNecessary(shell_surface.get());
return shell_surface;
}
std::unique_ptr<ClientControlledShellSurface>
ShellSurfaceBuilder::BuildClientControlledShellSurface() {
// Create a ClientControlledShellSurface instance.
DCHECK(!built_);
DCHECK(isConfigurationValidForClientControlledShellSurface());
built_ = true;
Holder* holder = new Holder();
holder->AddRootSurface(root_buffer_size_, root_buffer_format_);
auto shell_surface = Display().CreateOrGetClientControlledShellSurface(
holder->root_surface, GetContainer(),
WMHelper::GetInstance()->GetDefaultDeviceScaleFactor(),
default_scale_cancellation_);
shell_surface->host_window()->SetProperty(kBuilderResourceHolderKey, holder);
// Set the properties specific to ClientControlledShellSurface.
shell_surface->SetApplicationId("arc");
// ARC's default min size is non-empty.
if (!min_size_.has_value())
shell_surface->SetMinimumSize(gfx::Size(1, 1));
shell_surface->set_delegate(
std::make_unique<ClientControlledShellSurfaceDelegate>(
shell_surface.get()));
SetCommonPropertiesAndCommitIfNecessary(shell_surface.get());
return shell_surface;
}
bool ShellSurfaceBuilder::isConfigurationValidForShellSurface() {
return !default_scale_cancellation_;
}
bool ShellSurfaceBuilder::
isConfigurationValidForClientControlledShellSurface() {
return !parent_shell_surface_ && !popup_;
}
void ShellSurfaceBuilder::SetCommonPropertiesAndCommitIfNecessary(
ShellSurfaceBase* shell_surface) {
if (disable_movement_)
shell_surface->DisableMovement();
if (max_size_.has_value())
shell_surface->SetMaximumSize(max_size_.value());
if (min_size_.has_value())
shell_surface->SetMinimumSize(min_size_.value());
if (commit_on_build_) {
shell_surface->root_surface()->Commit();
if (centered_)
ash::CenterWindow(shell_surface->GetWidget()->GetNativeWindow());
} else {
// 'SetCentered' requires its shell surface to be committed when creatted.
DCHECK(!centered_);
}
}
int ShellSurfaceBuilder::GetContainer() {
return use_system_modal_container_
? ash::kShellWindowId_SystemModalContainer
: ash::desks_util::GetActiveDeskContainerId();
}
} // namespace test
} // namespace exo