blob: c5d71fb4ef5fb6d08be9f45bd4f79349d0dc454e [file] [log] [blame]
// Copyright 2016 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/display/fake_display_delegate.h"
#include <string>
#include <utility>
#include "base/command_line.h"
#include "base/hash.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "ui/display/display.h"
#include "ui/display/display_switches.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/display/util/display_util.h"
namespace display {
namespace {
// The EDID specification marks the top bit of the manufacturer id as reserved.
const uint16_t kReservedManufacturerID = 1 << 15;
// A random product name hash.
const uint32_t kProductCodeHash = base::Hash("Very Generic Display");
// Delay for Configure() in milliseconds.
constexpr int64_t kConfigureDisplayDelayMs = 200;
} // namespace
FakeDisplayDelegate::FakeDisplayDelegate() {}
FakeDisplayDelegate::~FakeDisplayDelegate() {}
int64_t FakeDisplayDelegate::AddDisplay(const gfx::Size& display_size) {
DCHECK(!display_size.IsEmpty());
if (next_display_id_ == 0xFF) {
LOG(ERROR) << "Exceeded display id limit";
return kInvalidDisplayId;
}
int64_t id = GenerateDisplayID(kReservedManufacturerID, kProductCodeHash,
++next_display_id_);
FakeDisplaySnapshot::Builder builder;
builder.SetId(id).SetNativeMode(display_size);
return AddDisplay(builder.Build()) ? id : kInvalidDisplayId;
}
bool FakeDisplayDelegate::AddDisplay(std::unique_ptr<DisplaySnapshot> display) {
DCHECK(display);
int64_t display_id = display->display_id();
// Check there is no existing display with the same id.
for (auto& existing_display : displays_) {
if (existing_display->display_id() == display_id) {
LOG(ERROR) << "Display with id " << display_id << " already exists";
return false;
}
}
DVLOG(1) << "Added display " << display->ToString();
displays_.push_back(std::move(display));
OnConfigurationChanged();
return true;
}
bool FakeDisplayDelegate::RemoveDisplay(int64_t display_id) {
// Find display snapshot with matching id and remove it.
for (auto iter = displays_.begin(); iter != displays_.end(); ++iter) {
if ((*iter)->display_id() == display_id) {
DVLOG(1) << "Removed display " << (*iter)->ToString();
displays_.erase(iter);
OnConfigurationChanged();
return true;
}
}
return false;
}
void FakeDisplayDelegate::Initialize() {
DCHECK(!initialized_);
// The default display will be an internal display with a native resolution
// of 1024x768 if --screen-config not specified on the command line.
std::string command_str = "1024x768/i";
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kScreenConfig))
command_str = command_line->GetSwitchValueASCII(switches::kScreenConfig);
if (!InitializeFromSpecString(command_str)) {
NOTREACHED() << "Bad --" << switches::kScreenConfig << " flag provided.";
return;
}
initialized_ = true;
}
void FakeDisplayDelegate::GrabServer() {}
void FakeDisplayDelegate::UngrabServer() {}
void FakeDisplayDelegate::TakeDisplayControl(
const DisplayControlCallback& callback) {
callback.Run(false);
}
void FakeDisplayDelegate::RelinquishDisplayControl(
const DisplayControlCallback& callback) {
callback.Run(false);
}
void FakeDisplayDelegate::SyncWithServer() {}
void FakeDisplayDelegate::SetBackgroundColor(uint32_t color_argb) {}
void FakeDisplayDelegate::ForceDPMSOn() {}
void FakeDisplayDelegate::GetDisplays(const GetDisplaysCallback& callback) {
std::vector<DisplaySnapshot*> displays;
for (auto& display : displays_)
displays.push_back(display.get());
callback.Run(displays);
}
void FakeDisplayDelegate::AddMode(const DisplaySnapshot& output,
const DisplayMode* mode) {}
void FakeDisplayDelegate::Configure(const DisplaySnapshot& output,
const DisplayMode* mode,
const gfx::Point& origin,
const ConfigureCallback& callback) {
bool configure_success = false;
if (!mode) {
// This is a request to turn off the display.
configure_success = true;
} else {
// Check that |mode| is appropriate for the display snapshot.
for (const auto& existing_mode : output.modes()) {
if (existing_mode.get() == mode) {
configure_success = true;
break;
}
}
}
configure_callbacks_.push(base::Bind(callback, configure_success));
// Start the timer if it's not already running. If there are multiple queued
// configuration requests then ConfigureDone() will handle starting the
// next request.
if (!configure_timer_.IsRunning()) {
configure_timer_.Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(kConfigureDisplayDelayMs),
this, &FakeDisplayDelegate::ConfigureDone);
}
}
void FakeDisplayDelegate::CreateFrameBuffer(const gfx::Size& size) {}
void FakeDisplayDelegate::GetHDCPState(const DisplaySnapshot& output,
const GetHDCPStateCallback& callback) {
callback.Run(false, HDCP_STATE_UNDESIRED);
}
void FakeDisplayDelegate::SetHDCPState(const DisplaySnapshot& output,
HDCPState state,
const SetHDCPStateCallback& callback) {
callback.Run(false);
}
std::vector<ColorCalibrationProfile>
FakeDisplayDelegate::GetAvailableColorCalibrationProfiles(
const DisplaySnapshot& output) {
return std::vector<ColorCalibrationProfile>();
}
bool FakeDisplayDelegate::SetColorCalibrationProfile(
const DisplaySnapshot& output,
ColorCalibrationProfile new_profile) {
return false;
}
bool FakeDisplayDelegate::SetColorCorrection(
const DisplaySnapshot& output,
const std::vector<GammaRampRGBEntry>& degamma_lut,
const std::vector<GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix) {
return false;
}
void FakeDisplayDelegate::AddObserver(NativeDisplayObserver* observer) {
observers_.AddObserver(observer);
}
void FakeDisplayDelegate::RemoveObserver(NativeDisplayObserver* observer) {
observers_.RemoveObserver(observer);
}
FakeDisplayController* FakeDisplayDelegate::GetFakeDisplayController() {
return this;
}
bool FakeDisplayDelegate::InitializeFromSpecString(const std::string& str) {
// Start without any displays.
if (str == "none")
return true;
// Split on commas and parse each display string.
for (const std::string& part : base::SplitString(
str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
int64_t id = GenerateDisplayID(kReservedManufacturerID, kProductCodeHash,
next_display_id_);
std::unique_ptr<DisplaySnapshot> snapshot =
FakeDisplaySnapshot::CreateFromSpec(id, part);
if (snapshot) {
AddDisplay(std::move(snapshot));
next_display_id_++;
} else {
LOG(ERROR) << "Failed to parse display \"" << part << "\"";
return false;
}
}
return true;
}
void FakeDisplayDelegate::OnConfigurationChanged() {
if (!initialized_)
return;
for (NativeDisplayObserver& observer : observers_)
observer.OnConfigurationChanged();
}
void FakeDisplayDelegate::ConfigureDone() {
DCHECK(!configure_callbacks_.empty());
configure_callbacks_.front().Run();
configure_callbacks_.pop();
// If there are more configuration requests waiting then restart the timer.
if (!configure_callbacks_.empty()) {
configure_timer_.Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(kConfigureDisplayDelayMs),
this, &FakeDisplayDelegate::ConfigureDone);
}
}
} // namespace display