// 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 #include #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 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 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 FakeDisplayDelegate::GetAvailableColorCalibrationProfiles( const DisplaySnapshot& output) { return std::vector(); } bool FakeDisplayDelegate::SetColorCalibrationProfile( const DisplaySnapshot& output, ColorCalibrationProfile new_profile) { return false; } bool FakeDisplayDelegate::SetColorCorrection( const DisplaySnapshot& output, const std::vector& degamma_lut, const std::vector& gamma_lut, const std::vector& 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 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