blob: c539c0aca17939ba7b09d84ff4b111508b0d6a52 [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 "services/ui/display/screen_manager_forwarding.h"
#include <utility>
#include "base/bind.h"
#include "chromeos/system/devicemode.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/display/screen_base.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/fake_display_controller.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/ozone/public/ozone_platform.h"
namespace display {
namespace {
// Finds the display mode in |snapshot| that corresponds to |mode_to_find|.
const DisplayMode* GetCorrespondingMode(const DisplaySnapshot& snapshot,
const DisplayMode* mode_to_find) {
if (!mode_to_find)
return nullptr;
for (auto& mode : snapshot.modes()) {
if (mode->size() == mode_to_find->size() &&
mode->is_interlaced() == mode_to_find->is_interlaced() &&
mode->refresh_rate() == mode_to_find->refresh_rate()) {
return mode.get();
}
}
NOTREACHED();
return nullptr;
}
} // namespace
ScreenManagerForwarding::ScreenManagerForwarding(Mode mode)
: is_in_process_(mode == Mode::IN_WM_PROCESS),
screen_(std::make_unique<display::ScreenBase>()),
binding_(this),
dev_controller_binding_(this) {
if (!is_in_process_)
Screen::SetScreenInstance(screen_.get());
}
ScreenManagerForwarding::~ScreenManagerForwarding() {
if (native_display_delegate_)
native_display_delegate_->RemoveObserver(this);
if (!is_in_process_)
Screen::SetScreenInstance(nullptr);
}
void ScreenManagerForwarding::AddInterfaces(
service_manager::BinderRegistryWithArgs<
const service_manager::BindSourceInfo&>* registry) {
registry->AddInterface<mojom::NativeDisplayDelegate>(
base::Bind(&ScreenManagerForwarding::BindNativeDisplayDelegateRequest,
base::Unretained(this)));
registry->AddInterface<mojom::DevDisplayController>(
base::Bind(&ScreenManagerForwarding::BindDevDisplayControllerRequest,
base::Unretained(this)));
}
void ScreenManagerForwarding::Init(ScreenManagerDelegate* delegate) {
// Done in NativeDisplayDelegate::Initialize() instead.
}
void ScreenManagerForwarding::RequestCloseDisplay(int64_t display_id) {
if (!fake_display_controller_)
return;
// Tell NativeDisplayDelegate to remove the display. This triggers an
// OnConfigurationChanged() and the corresponding display snapshot will be
// gone.
fake_display_controller_->RemoveDisplay(display_id);
}
display::ScreenBase* ScreenManagerForwarding::GetScreen() {
return screen_.get();
}
void ScreenManagerForwarding::OnConfigurationChanged() {
if (observer_.is_bound())
observer_->OnConfigurationChanged();
}
void ScreenManagerForwarding::OnDisplaySnapshotsInvalidated() {
snapshot_map_.clear();
}
void ScreenManagerForwarding::Initialize(
mojom::NativeDisplayObserverPtr observer,
InitializeCallback callback) {
DCHECK(!native_display_delegate_);
observer_ = std::move(observer);
native_display_delegate_ =
ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate();
native_display_delegate_->AddObserver(this);
native_display_delegate_->Initialize();
// FakeDisplayController is only applicable when not running on a CrOS device.
if (!chromeos::IsRunningAsSystemCompositor()) {
fake_display_controller_ =
native_display_delegate_->GetFakeDisplayController();
}
// Provide the list of display snapshots initially. ForwardingDisplayDelegate
// will wait synchronously for this.
native_display_delegate_->GetDisplays(
base::BindOnce(&ScreenManagerForwarding::ForwardGetDisplays,
base::Unretained(this), std::move(callback)));
// When ForwardingDisplayDelegate receives this it will start asynchronous
// operation and redo any configuration that was skipped.
observer_->OnConfigurationChanged();
}
void ScreenManagerForwarding::TakeDisplayControl(
TakeDisplayControlCallback callback) {
DCHECK(native_display_delegate_);
native_display_delegate_->TakeDisplayControl(std::move(callback));
}
void ScreenManagerForwarding::RelinquishDisplayControl(
RelinquishDisplayControlCallback callback) {
DCHECK(native_display_delegate_);
native_display_delegate_->RelinquishDisplayControl(std::move(callback));
}
void ScreenManagerForwarding::GetDisplays(GetDisplaysCallback callback) {
DCHECK(native_display_delegate_);
native_display_delegate_->GetDisplays(
base::BindOnce(&ScreenManagerForwarding::ForwardGetDisplays,
base::Unretained(this), std::move(callback)));
}
void ScreenManagerForwarding::Configure(
int64_t display_id,
base::Optional<std::unique_ptr<display::DisplayMode>> mode,
const gfx::Point& origin,
ConfigureCallback callback) {
DCHECK(native_display_delegate_);
DisplaySnapshot* snapshot = snapshot_map_[display_id];
if (!snapshot) {
std::move(callback).Run(false);
return;
}
// We need a pointer to the mode in |snapshot|, not the equivalent mode we
// received over Mojo.
const DisplayMode* snapshot_mode =
mode ? GetCorrespondingMode(*snapshot, mode->get()) : nullptr;
native_display_delegate_->Configure(
*snapshot, snapshot_mode, origin,
base::BindOnce(&ScreenManagerForwarding::ForwardConfigure,
base::Unretained(this), snapshot, snapshot_mode, origin,
std::move(callback)));
}
void ScreenManagerForwarding::GetHDCPState(int64_t display_id,
GetHDCPStateCallback callback) {
DCHECK(native_display_delegate_);
const DisplaySnapshot* snapshot = snapshot_map_[display_id];
if (!snapshot) {
std::move(callback).Run(false, HDCP_STATE_UNDESIRED);
return;
}
native_display_delegate_->GetHDCPState(*snapshot, std::move(callback));
}
void ScreenManagerForwarding::SetHDCPState(int64_t display_id,
display::HDCPState state,
SetHDCPStateCallback callback) {
DCHECK(native_display_delegate_);
const DisplaySnapshot* snapshot = snapshot_map_[display_id];
if (!snapshot) {
std::move(callback).Run(false);
return;
}
native_display_delegate_->SetHDCPState(*snapshot, state, std::move(callback));
}
void ScreenManagerForwarding::SetColorCorrection(
int64_t display_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix) {
DCHECK(native_display_delegate_);
const DisplaySnapshot* snapshot = snapshot_map_[display_id];
if (!snapshot)
return;
native_display_delegate_->SetColorCorrection(*snapshot, degamma_lut,
gamma_lut, correction_matrix);
}
void ScreenManagerForwarding::ToggleAddRemoveDisplay() {
if (!fake_display_controller_)
return;
int num_displays = screen_->GetNumDisplays();
if (num_displays == 1) {
// If we have one display, add a second display with the same size.
Display primary_display = screen_->GetPrimaryDisplay();
fake_display_controller_->AddDisplay(primary_display.GetSizeInPixel());
} else if (num_displays > 1) {
// If we have more than one display, remove the first display we find that
// isn't the primary display.
Display primary_display = screen_->GetPrimaryDisplay();
for (auto& display : screen_->display_list().displays()) {
if (display.id() != primary_display.id()) {
fake_display_controller_->RemoveDisplay(display.id());
break;
}
}
} else {
// If we have no displays, add one with a default size.
fake_display_controller_->AddDisplay(gfx::Size(1024, 768));
}
}
void ScreenManagerForwarding::BindNativeDisplayDelegateRequest(
mojom::NativeDisplayDelegateRequest request,
const service_manager::BindSourceInfo& source_info) {
DCHECK(!binding_.is_bound());
binding_.Bind(std::move(request));
}
void ScreenManagerForwarding::BindDevDisplayControllerRequest(
mojom::DevDisplayControllerRequest request,
const service_manager::BindSourceInfo& source_info) {
DCHECK(!dev_controller_binding_.is_bound());
dev_controller_binding_.Bind(std::move(request));
}
void ScreenManagerForwarding::ForwardGetDisplays(
GetDisplaysCallback callback,
const std::vector<DisplaySnapshot*>& snapshots) {
snapshot_map_.clear();
std::vector<std::unique_ptr<DisplaySnapshot>> snapshot_clones;
for (auto* snapshot : snapshots) {
snapshot_map_[snapshot->display_id()] = snapshot;
// Clone display snapshots to send over IPC.
snapshot_clones.push_back(snapshot->Clone());
}
std::move(callback).Run(std::move(snapshot_clones));
}
void ScreenManagerForwarding::ForwardConfigure(
DisplaySnapshot* snapshot,
const DisplayMode* mode,
const gfx::Point& origin,
mojom::NativeDisplayDelegate::ConfigureCallback callback,
bool status) {
if (status) {
// Modify display snapshot similar to how ConfigureDisplaysTask would. Ozone
// DRM needs these to be changed and ConfigureDisplaysTasks can't do it.
snapshot->set_current_mode(mode);
snapshot->set_origin(origin);
}
std::move(callback).Run(status);
}
} // namespace display