// Copyright (c) 2012 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/display.h" #include #include "base/command_line.h" #include "base/containers/contains.h" #include "base/logging.h" #include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "ui/display/display_switches.h" #include "ui/display/util/display_util.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/transform.h" #include "ui/gfx/icc_profile.h" namespace display { namespace { // This variable tracks whether the forced device scale factor switch needs to // be read from the command line, i.e. if it is set to -1 then the command line // is checked. int g_has_forced_device_scale_factor = -1; // This variable caches the forced device scale factor value which is read off // the command line. If the cache is invalidated by setting this variable to // -1.0, we read the forced device scale factor again. float g_forced_device_scale_factor = -1.0; // An allowance error epsilon caused by fractional scale factor to produce // expected DP display size. constexpr float kDisplaySizeAllowanceEpsilon = 0.01f; bool HasForceDeviceScaleFactorImpl() { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kForceDeviceScaleFactor); } float GetForcedDeviceScaleFactorImpl() { double scale_in_double = 1.0; if (HasForceDeviceScaleFactorImpl()) { std::string value = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kForceDeviceScaleFactor); if (!base::StringToDouble(value, &scale_in_double)) { LOG(ERROR) << "Failed to parse the default device scale factor:" << value; scale_in_double = 1.0; } } return static_cast(scale_in_double); } const char* ToRotationString(display::Display::Rotation rotation) { switch (rotation) { case display::Display::ROTATE_0: return "0"; case display::Display::ROTATE_90: return "90"; case display::Display::ROTATE_180: return "180"; case display::Display::ROTATE_270: return "270"; } NOTREACHED(); return "unkonwn"; } } // namespace // static float Display::GetForcedDeviceScaleFactor() { if (g_forced_device_scale_factor < 0) g_forced_device_scale_factor = GetForcedDeviceScaleFactorImpl(); return g_forced_device_scale_factor; } // static bool Display::HasForceDeviceScaleFactor() { if (g_has_forced_device_scale_factor == -1) g_has_forced_device_scale_factor = HasForceDeviceScaleFactorImpl(); return !!g_has_forced_device_scale_factor; } // static void Display::ResetForceDeviceScaleFactorForTesting() { g_has_forced_device_scale_factor = -1; g_forced_device_scale_factor = -1.0; } // static void Display::SetForceDeviceScaleFactor(double dsf) { // Reset any previously set values and unset the flag. g_has_forced_device_scale_factor = -1; g_forced_device_scale_factor = -1.0; base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kForceDeviceScaleFactor, base::StringPrintf("%.2f", dsf)); } // static gfx::ColorSpace Display::GetForcedRasterColorProfile() { DCHECK(HasForceRasterColorProfile()); std::string value = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kForceRasterColorProfile); return ForcedColorProfileStringToColorSpace(value); } // static bool Display::HasForceRasterColorProfile() { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kForceRasterColorProfile); } // static bool Display::HasEnsureForcedColorProfile() { static bool has_ensure_forced_color_profile = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnsureForcedColorProfile); return has_ensure_forced_color_profile; } // static display::Display::Rotation Display::DegreesToRotation(int degrees) { if (degrees == 0) return display::Display::ROTATE_0; if (degrees == 90) return display::Display::ROTATE_90; if (degrees == 180) return display::Display::ROTATE_180; if (degrees == 270) return display::Display::ROTATE_270; NOTREACHED(); return display::Display::ROTATE_0; } // static int Display::RotationToDegrees(display::Display::Rotation rotation) { switch (rotation) { case display::Display::ROTATE_0: return 0; case display::Display::ROTATE_90: return 90; case display::Display::ROTATE_180: return 180; case display::Display::ROTATE_270: return 270; } NOTREACHED(); return 0; } // static bool Display::IsValidRotation(int degrees) { return degrees == 0 || degrees == 90 || degrees == 180 || degrees == 270; } Display::Display() : Display(kInvalidDisplayId) {} Display::Display(int64_t id) : Display(id, gfx::Rect()) {} Display::Display(int64_t id, const gfx::Rect& bounds) : id_(id), bounds_(bounds), work_area_(bounds), device_scale_factor_(GetForcedDeviceScaleFactor()) { // On Android we need to ensure the platform supports a color profile before // using it. Using a not supported profile can result in fatal errors in the // GPU process. auto color_space = gfx::ColorSpace::CreateSRGB(); #if !BUILDFLAG(IS_ANDROID) if (HasForceDisplayColorProfile()) color_space = GetForcedDisplayColorProfile(); #endif color_spaces_ = gfx::DisplayColorSpaces(color_space); if (color_spaces_.SupportsHDR()) { color_depth_ = kHDR10BitsPerPixel; depth_per_component_ = kHDR10BitsPerComponent; } else { color_depth_ = kDefaultBitsPerPixel; depth_per_component_ = kDefaultBitsPerComponent; } #if defined(USE_AURA) if (!bounds.IsEmpty()) SetScaleAndBounds(device_scale_factor_, bounds); #endif } Display::Display(const Display& other) = default; Display::~Display() {} // static Display Display::GetDefaultDisplay() { return Display(kDefaultDisplayId, gfx::Rect(0, 0, 1920, 1080)); } int Display::RotationAsDegree() const { switch (rotation_) { case ROTATE_0: return 0; case ROTATE_90: return 90; case ROTATE_180: return 180; case ROTATE_270: return 270; } NOTREACHED(); return 0; } void Display::set_color_spaces(const gfx::DisplayColorSpaces& color_spaces) { color_spaces_ = color_spaces; if (color_spaces.SupportsHDR()) { color_depth_ = kHDR10BitsPerPixel; depth_per_component_ = kHDR10BitsPerComponent; } else { color_depth_ = kDefaultBitsPerPixel; depth_per_component_ = kDefaultBitsPerComponent; } } void Display::SetRotationAsDegree(int rotation) { switch (rotation) { case 0: rotation_ = ROTATE_0; break; case 90: rotation_ = ROTATE_90; break; case 180: rotation_ = ROTATE_180; break; case 270: rotation_ = ROTATE_270; break; default: // We should not reach that but we will just ignore the call if we do. NOTREACHED(); } } int Display::PanelRotationAsDegree() const { return RotationToDegrees(panel_rotation()); } gfx::Insets Display::GetWorkAreaInsets() const { return gfx::Insets::TLBR(work_area_.y() - bounds_.y(), work_area_.x() - bounds_.x(), bounds_.bottom() - work_area_.bottom(), bounds_.right() - work_area_.right()); } void Display::SetScaleAndBounds(float device_scale_factor, const gfx::Rect& bounds_in_pixel) { gfx::Insets insets = bounds_.InsetsFrom(work_area_); SetScale(device_scale_factor); gfx::RectF f(bounds_in_pixel); f.Scale(1.f / device_scale_factor_); bounds_ = gfx::ToEnclosedRectIgnoringError(f, kDisplaySizeAllowanceEpsilon); size_in_pixels_ = bounds_in_pixel.size(); UpdateWorkAreaFromInsets(insets); } void Display::SetScale(float device_scale_factor) { if (!HasForceDeviceScaleFactor()) { #if BUILDFLAG(IS_APPLE) // Unless an explicit scale factor was provided for testing, ensure the // scale is integral. device_scale_factor = static_cast(device_scale_factor); #endif device_scale_factor_ = device_scale_factor; } device_scale_factor_ = std::max(0.5f, device_scale_factor_); } void Display::SetSize(const gfx::Size& size_in_pixel) { gfx::Point origin = bounds_.origin(); #if defined(USE_AURA) origin = gfx::ScaleToFlooredPoint(origin, device_scale_factor_); #endif SetScaleAndBounds(device_scale_factor_, gfx::Rect(origin, size_in_pixel)); } void Display::UpdateWorkAreaFromInsets(const gfx::Insets& insets) { work_area_ = bounds_; work_area_.Inset(insets); } gfx::Size Display::GetSizeInPixel() const { if (!size_in_pixels_.IsEmpty()) return size_in_pixels_; return gfx::ScaleToFlooredSize(size(), device_scale_factor_); } std::string Display::ToString() const { return base::StringPrintf( "Display[%lld] bounds=[%s], workarea=[%s], scale=%g, rotation=%s, " "panel_rotation=%s %s.", static_cast(id_), bounds_.ToString().c_str(), work_area_.ToString().c_str(), device_scale_factor_, ToRotationString(rotation_), ToRotationString(panel_rotation()), IsInternal() ? "internal" : "external"); } bool Display::IsInternal() const { return is_valid() && display::IsInternalDisplayId(id_); } // static int64_t Display::InternalDisplayId() { auto& ids = GetInternalDisplayIds(); DCHECK_EQ(1u, ids.size()); return ids.size() ? *ids.begin() : kInvalidDisplayId; } bool Display::operator==(const Display& rhs) const { return id_ == rhs.id_ && bounds_ == rhs.bounds_ && size_in_pixels_ == rhs.size_in_pixels_ && work_area_ == rhs.work_area_ && device_scale_factor_ == rhs.device_scale_factor_ && rotation_ == rhs.rotation_ && touch_support_ == rhs.touch_support_ && accelerometer_support_ == rhs.accelerometer_support_ && maximum_cursor_size_ == rhs.maximum_cursor_size_ && color_spaces_ == rhs.color_spaces_ && color_depth_ == rhs.color_depth_ && depth_per_component_ == rhs.depth_per_component_ && is_monochrome_ == rhs.is_monochrome_ && display_frequency_ == rhs.display_frequency_ && label_ == rhs.label_; } } // namespace display