blob: d00bdcf16124c02a6f8b0a8e12802e91f7463d4c [file] [log] [blame]
// Copyright 2017 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 "ui/aura/mus/client_surface_embedder.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_owner.h"
#include "ui/gfx/geometry/dip_util.h"
namespace aura {
ClientSurfaceEmbedder::ClientSurfaceEmbedder(
Window* window,
bool inject_gutter,
const gfx::Insets& client_area_insets)
: window_(window),
surface_layer_owner_(std::make_unique<ui::LayerOwner>(
std::make_unique<ui::Layer>(ui::LAYER_TEXTURED))),
inject_gutter_(inject_gutter),
client_area_insets_(client_area_insets) {
surface_layer_owner_->layer()->set_name("ClientSurfaceEmbedder");
surface_layer_owner_->layer()->SetMasksToBounds(true);
// The frame provided by the parent window->layer() needs to show through
// the surface layer.
surface_layer_owner_->layer()->SetFillsBoundsOpaquely(false);
window_->layer()->Add(surface_layer_owner_->layer());
// Window's layer may contain content from this client (the embedder), e.g.
// this is the case with window decorations provided by Window Manager.
// This content should appear underneath the content of the embedded client.
window_->layer()->StackAtTop(surface_layer_owner_->layer());
}
ClientSurfaceEmbedder::~ClientSurfaceEmbedder() = default;
void ClientSurfaceEmbedder::SetSurfaceId(const viz::SurfaceId& surface_id) {
surface_layer_owner_->layer()->SetShowSurface(
surface_id, window_->bounds().size(), SK_ColorWHITE,
cc::DeadlinePolicy::UseDefaultDeadline(),
false /* stretch_content_to_fill_bounds */);
}
bool ClientSurfaceEmbedder::HasPrimarySurfaceId() const {
return surface_layer_owner_->layer()->GetSurfaceId() != nullptr;
}
void ClientSurfaceEmbedder::SetFallbackSurfaceInfo(
const viz::SurfaceInfo& surface_info) {
fallback_surface_info_ = surface_info;
UpdateSizeAndGutters();
}
void ClientSurfaceEmbedder::SetClientAreaInsets(
const gfx::Insets& client_area_insets) {
if (client_area_insets_ == client_area_insets)
return;
client_area_insets_ = client_area_insets;
if (inject_gutter_)
UpdateSizeAndGutters();
}
void ClientSurfaceEmbedder::UpdateSizeAndGutters() {
surface_layer_owner_->layer()->SetBounds(gfx::Rect(window_->bounds().size()));
if (!inject_gutter_)
return;
gfx::Size fallback_surface_size_in_dip;
if (fallback_surface_info_.is_valid()) {
float fallback_device_scale_factor =
fallback_surface_info_.device_scale_factor();
fallback_surface_size_in_dip = gfx::ConvertSizeToDIP(
fallback_device_scale_factor, fallback_surface_info_.size_in_pixels());
}
gfx::Rect window_bounds(window_->bounds());
if (!window_->transparent() &&
fallback_surface_size_in_dip.width() < window_bounds.width()) {
right_gutter_owner_ = std::make_unique<ui::LayerOwner>(
std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR));
// TODO(fsamuel): Use the embedded client's background color.
right_gutter_owner_->layer()->SetColor(SK_ColorWHITE);
int width = window_bounds.width() - fallback_surface_size_in_dip.width();
// The right gutter also includes the bottom-right corner, if necessary.
int height = window_bounds.height() - client_area_insets_.height();
right_gutter_owner_->layer()->SetBounds(gfx::Rect(
client_area_insets_.left() + fallback_surface_size_in_dip.width(),
client_area_insets_.top(), width, height));
window_->layer()->Add(right_gutter_owner_->layer());
} else {
right_gutter_owner_.reset();
}
// Only create a bottom gutter if a fallback surface is available. Otherwise,
// the right gutter will fill the whole window until a fallback is available.
if (!window_->transparent() && !fallback_surface_size_in_dip.IsEmpty() &&
fallback_surface_size_in_dip.height() < window_bounds.height()) {
bottom_gutter_owner_ = std::make_unique<ui::LayerOwner>(
std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR));
// TODO(fsamuel): Use the embedded client's background color.
bottom_gutter_owner_->layer()->SetColor(SK_ColorWHITE);
int width = fallback_surface_size_in_dip.width();
int height = window_bounds.height() - fallback_surface_size_in_dip.height();
bottom_gutter_owner_->layer()->SetBounds(
gfx::Rect(0, fallback_surface_size_in_dip.height(), width, height));
window_->layer()->Add(bottom_gutter_owner_->layer());
} else {
bottom_gutter_owner_.reset();
}
window_->layer()->StackAtTop(surface_layer_owner_->layer());
}
ui::Layer* ClientSurfaceEmbedder::RightGutterForTesting() {
return right_gutter_owner_ ? right_gutter_owner_->layer() : nullptr;
}
ui::Layer* ClientSurfaceEmbedder::BottomGutterForTesting() {
return bottom_gutter_owner_ ? bottom_gutter_owner_->layer() : nullptr;
}
const viz::SurfaceId& ClientSurfaceEmbedder::GetSurfaceIdForTesting() const {
return *surface_layer_owner_->layer()->GetSurfaceId();
}
} // namespace aura