blob: 3d5b6d0db728b0d9969e247132c89bcbdf5052fd [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/ui/ws2/client_root.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "services/ui/ws2/client_change.h"
#include "services/ui/ws2/client_change_tracker.h"
#include "services/ui/ws2/server_window.h"
#include "services/ui/ws2/window_service.h"
#include "services/ui/ws2/window_tree.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/client_surface_embedder.h"
#include "ui/aura/mus/property_converter.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/property_change_reason.h"
namespace ui {
namespace ws2 {
ClientRoot::ClientRoot(WindowTree* window_tree,
aura::Window* window,
bool is_top_level)
: window_tree_(window_tree), window_(window), is_top_level_(is_top_level) {
window_->AddObserver(this);
if (window_->GetHost())
window->GetHost()->AddObserver(this);
// TODO: wire up gfx::Insets() correctly below. See usage in
// aura::ClientSurfaceEmbedder for details. Insets here are used for
// guttering.
client_surface_embedder_ = std::make_unique<aura::ClientSurfaceEmbedder>(
window_, is_top_level, gfx::Insets());
// Ensure there is a valid LocalSurfaceId (if necessary).
UpdateLocalSurfaceIdIfNecessary();
}
ClientRoot::~ClientRoot() {
ServerWindow* server_window = ServerWindow::GetMayBeNull(window_);
window_->RemoveObserver(this);
if (window_->GetHost())
window_->GetHost()->RemoveObserver(this);
viz::HostFrameSinkManager* host_frame_sink_manager =
window_->env()->context_factory_private()->GetHostFrameSinkManager();
host_frame_sink_manager->InvalidateFrameSinkId(
server_window->frame_sink_id());
}
void ClientRoot::RegisterVizEmbeddingSupport() {
// This function should only be called once.
viz::HostFrameSinkManager* host_frame_sink_manager =
window_->env()->context_factory_private()->GetHostFrameSinkManager();
viz::FrameSinkId frame_sink_id =
ServerWindow::GetMayBeNull(window_)->frame_sink_id();
host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id, this);
window_->SetEmbedFrameSinkId(frame_sink_id);
UpdatePrimarySurfaceId();
}
bool ClientRoot::ShouldAssignLocalSurfaceId() {
// First level embeddings have their LocalSurfaceId assigned by the
// WindowService. First level embeddings have no embeddings above them.
if (is_top_level_)
return true;
ServerWindow* server_window = ServerWindow::GetMayBeNull(window_);
return server_window->owning_window_tree() == nullptr;
}
void ClientRoot::UpdateLocalSurfaceIdIfNecessary() {
if (!ShouldAssignLocalSurfaceId())
return;
gfx::Size size_in_pixels =
ui::ConvertSizeToPixel(window_->layer(), window_->bounds().size());
ServerWindow* server_window = ServerWindow::GetMayBeNull(window_);
// It's expected by cc code that any time the size changes a new
// LocalSurfaceId is used.
if (last_surface_size_in_pixels_ != size_in_pixels ||
!server_window->local_surface_id().has_value() ||
!server_window->local_surface_id()->is_valid() ||
last_device_scale_factor_ != window_->layer()->device_scale_factor()) {
server_window->set_local_surface_id(
parent_local_surface_id_allocator_.GenerateId());
last_surface_size_in_pixels_ = size_in_pixels;
last_device_scale_factor_ = window_->layer()->device_scale_factor();
}
}
void ClientRoot::UpdatePrimarySurfaceId() {
UpdateLocalSurfaceIdIfNecessary();
ServerWindow* server_window = ServerWindow::GetMayBeNull(window_);
if (server_window->local_surface_id().has_value()) {
client_surface_embedder_->SetPrimarySurfaceId(viz::SurfaceId(
window_->GetFrameSinkId(), *server_window->local_surface_id()));
if (fallback_surface_info_) {
client_surface_embedder_->SetFallbackSurfaceInfo(*fallback_surface_info_);
fallback_surface_info_.reset();
}
}
}
void ClientRoot::CheckForScaleFactorChange() {
if (!ShouldAssignLocalSurfaceId() ||
last_device_scale_factor_ == window_->layer()->device_scale_factor()) {
return;
}
HandleBoundsOrScaleFactorChange(is_top_level_ ? window_->GetBoundsInScreen()
: window_->bounds());
}
void ClientRoot::HandleBoundsOrScaleFactorChange(const gfx::Rect& old_bounds) {
UpdatePrimarySurfaceId();
client_surface_embedder_->UpdateSizeAndGutters();
// See comments in WindowTree::SetWindowBoundsImpl() for details on
// why this always notifies the client.
window_tree_->window_tree_client_->OnWindowBoundsChanged(
window_tree_->TransportIdForWindow(window_), old_bounds,
is_top_level_ ? window_->GetBoundsInScreen() : window_->bounds(),
ServerWindow::GetMayBeNull(window_)->local_surface_id());
}
void ClientRoot::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (window_tree_->property_change_tracker_->IsProcessingChangeForWindow(
window, ClientChangeType::kProperty)) {
// Do not send notifications for changes intiated by the client.
return;
}
std::string transport_name;
std::unique_ptr<std::vector<uint8_t>> transport_value;
if (window_tree_->window_service()
->property_converter()
->ConvertPropertyForTransport(window, key, &transport_name,
&transport_value)) {
base::Optional<std::vector<uint8_t>> transport_value_mojo;
if (transport_value)
transport_value_mojo.emplace(std::move(*transport_value));
window_tree_->window_tree_client_->OnWindowSharedPropertyChanged(
window_tree_->TransportIdForWindow(window), transport_name,
transport_value_mojo);
}
}
void ClientRoot::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) {
HandleBoundsOrScaleFactorChange(old_bounds);
}
void ClientRoot::OnWindowAddedToRootWindow(aura::Window* window) {
DCHECK_EQ(window, window_);
DCHECK(window->GetHost());
window->GetHost()->AddObserver(this);
CheckForScaleFactorChange();
}
void ClientRoot::OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) {
DCHECK_EQ(window, window_);
DCHECK(window->GetHost());
window->GetHost()->RemoveObserver(this);
}
void ClientRoot::OnHostResized(aura::WindowTreeHost* host) {
// This function is also called when the device-scale-factor changes too.
CheckForScaleFactorChange();
}
void ClientRoot::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
ServerWindow* server_window = ServerWindow::GetMayBeNull(window_);
if (server_window->local_surface_id().has_value()) {
DCHECK(!fallback_surface_info_);
client_surface_embedder_->SetFallbackSurfaceInfo(surface_info);
} else {
fallback_surface_info_ = std::make_unique<viz::SurfaceInfo>(surface_info);
}
if (!window_tree_->client_name().empty()) {
// OnFirstSurfaceActivation() should only be called after
// AttachCompositorFrameSink().
DCHECK(server_window->attached_compositor_frame_sink());
window_tree_->window_service()->OnFirstSurfaceActivation(
window_tree_->client_name());
}
}
void ClientRoot::OnFrameTokenChanged(uint32_t frame_token) {
// TODO: this needs to call through to WindowTreeClient.
// https://crbug.com/848022.
}
} // namespace ws2
} // namespace ui