1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/base/win/dpi.h" 6 7 #include <windows.h> 8 #include "base/command_line.h" 9 #include "base/win/scoped_hdc.h" 10 #include "ui/base/layout.h" 11 #include "base/win/registry.h" 12 #include "ui/base/ui_base_switches.h" 13 #include "ui/gfx/display.h" 14 #include "ui/gfx/point_conversions.h" 15 #include "ui/gfx/rect_conversions.h" 16 #include "ui/gfx/size_conversions.h" 17 18 namespace { 19 20 int kDefaultDPIX = 96; 21 int kDefaultDPIY = 96; 22 23 // Tests to see if the command line flag "--high-dpi-support" is set. 24 bool IsHighDPIEnabled() { 25 // Default is disabled. 26 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kHighDPISupport)) { 27 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 28 switches::kHighDPISupport).compare("1") == 0; 29 } 30 return false; 31 } 32 33 // Gets the device scale factor. If support is enabled, this will return the 34 // best available scale based on the screen's pixel density. This can be 35 // affected (overridden) by --force-device-scale-factor=x 36 float GetDeviceScaleFactorImpl() { 37 if (IsHighDPIEnabled()) { 38 float scale = gfx::Display::HasForceDeviceScaleFactor() ? 39 gfx::Display::GetForcedDeviceScaleFactor() : ui::GetDPIScale(); 40 // Quantize to nearest supported scale factor. 41 scale = ui::GetScaleFactorScale(ui::GetScaleFactorFromScale(scale)); 42 return scale; 43 } 44 return 1.0f; 45 } 46 47 BOOL IsProcessDPIAwareWrapper() { 48 typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID); 49 IsProcessDPIAwarePtr is_process_dpi_aware_func = 50 reinterpret_cast<IsProcessDPIAwarePtr>( 51 GetProcAddress(GetModuleHandleA("user32.dll"), "IsProcessDPIAware")); 52 if (is_process_dpi_aware_func) 53 return is_process_dpi_aware_func(); 54 return FALSE; 55 } 56 57 } // namespace 58 59 namespace ui { 60 61 gfx::Size GetDPI() { 62 static int dpi_x = 0; 63 static int dpi_y = 0; 64 static bool should_initialize = true; 65 66 if (should_initialize) { 67 should_initialize = false; 68 base::win::ScopedGetDC screen_dc(NULL); 69 // This value is safe to cache for the life time of the app since the 70 // user must logout to change the DPI setting. This value also applies 71 // to all screens. 72 dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX); 73 dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY); 74 } 75 return gfx::Size(dpi_x, dpi_y); 76 } 77 78 float GetDPIScale() { 79 if (IsHighDPIEnabled()) { 80 return static_cast<float>(GetDPI().width()) / 81 static_cast<float>(kDefaultDPIX); 82 } 83 return 1.0; 84 } 85 86 bool IsInHighDPIMode() { 87 return GetDPIScale() > 1.0; 88 } 89 90 void EnableHighDPISupport() { 91 if (IsHighDPIEnabled()) { 92 typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); 93 SetProcessDPIAwarePtr set_process_dpi_aware_func = 94 reinterpret_cast<SetProcessDPIAwarePtr>( 95 GetProcAddress(GetModuleHandleA("user32.dll"), 96 "SetProcessDPIAware")); 97 if (set_process_dpi_aware_func) 98 set_process_dpi_aware_func(); 99 } 100 } 101 102 namespace win { 103 104 float GetDeviceScaleFactor() { 105 static const float device_scale_factor = GetDeviceScaleFactorImpl(); 106 return device_scale_factor; 107 } 108 109 gfx::Point ScreenToDIPPoint(const gfx::Point& pixel_point) { 110 return gfx::ToFlooredPoint( 111 gfx::ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor())); 112 } 113 114 gfx::Point DIPToScreenPoint(const gfx::Point& dip_point) { 115 return gfx::ToFlooredPoint( 116 gfx::ScalePoint(dip_point, GetDeviceScaleFactor())); 117 } 118 119 gfx::Rect ScreenToDIPRect(const gfx::Rect& pixel_bounds) { 120 // TODO(kevers): Switch to non-deprecated method for float to int conversions. 121 return gfx::ToFlooredRectDeprecated( 122 gfx::ScaleRect(pixel_bounds, 1.0f / GetDeviceScaleFactor())); 123 } 124 125 gfx::Rect DIPToScreenRect(const gfx::Rect& dip_bounds) { 126 // TODO(kevers): Switch to non-deprecated method for float to int conversions. 127 return gfx::ToFlooredRectDeprecated( 128 gfx::ScaleRect(dip_bounds, GetDeviceScaleFactor())); 129 } 130 131 gfx::Size ScreenToDIPSize(const gfx::Size& size_in_pixels) { 132 return gfx::ToFlooredSize( 133 gfx::ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor())); 134 } 135 136 gfx::Size DIPToScreenSize(const gfx::Size& dip_size) { 137 return gfx::ToFlooredSize(gfx::ScaleSize(dip_size, GetDeviceScaleFactor())); 138 } 139 140 int GetSystemMetricsInDIP(int metric) { 141 return static_cast<int>(GetSystemMetrics(metric) / 142 GetDeviceScaleFactor() + 0.5); 143 } 144 145 double GetUndocumentedDPIScale() { 146 // TODO(girard): Remove this code when chrome is DPIAware. 147 static double scale = -1.0; 148 if (scale == -1.0) { 149 scale = 1.0; 150 if (!IsProcessDPIAwareWrapper()) { 151 base::win::RegKey key(HKEY_CURRENT_USER, 152 L"Control Panel\\Desktop\\WindowMetrics", 153 KEY_QUERY_VALUE); 154 if (key.Valid()) { 155 DWORD value = 0; 156 if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) { 157 scale = static_cast<double>(value) / kDefaultDPIX; 158 } 159 } 160 } 161 } 162 return scale; 163 } 164 165 } // namespace win 166 167 } // namespace ui 168