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/gfx/win/dpi.h" 6 7 #include <windows.h> 8 #include "base/command_line.h" 9 #include "base/win/scoped_hdc.h" 10 #include "base/win/windows_version.h" 11 #include "base/win/registry.h" 12 #include "ui/gfx/display.h" 13 #include "ui/gfx/switches.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 BOOL IsProcessDPIAwareWrapper() { 24 typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID); 25 IsProcessDPIAwarePtr is_process_dpi_aware_func = 26 reinterpret_cast<IsProcessDPIAwarePtr>( 27 GetProcAddress(GetModuleHandleA("user32.dll"), "IsProcessDPIAware")); 28 if (is_process_dpi_aware_func) 29 return is_process_dpi_aware_func(); 30 return FALSE; 31 } 32 33 float g_device_scale_factor = 0.0f; 34 35 float GetUnforcedDeviceScaleFactor() { 36 return static_cast<float>(gfx::GetDPI().width()) / 37 static_cast<float>(kDefaultDPIX); 38 } 39 40 float GetModernUIScaleWrapper() { 41 float result = 1.0f; 42 typedef float(WINAPI *GetModernUIScalePtr)(VOID); 43 HMODULE lib = LoadLibraryA("metro_driver.dll"); 44 if (lib) { 45 GetModernUIScalePtr func = 46 reinterpret_cast<GetModernUIScalePtr>( 47 GetProcAddress(lib, "GetModernUIScale")); 48 if (func) 49 result = func(); 50 FreeLibrary(lib); 51 } 52 return result; 53 } 54 55 } // namespace 56 57 namespace gfx { 58 59 float GetModernUIScale() { 60 return GetModernUIScaleWrapper(); 61 } 62 63 void InitDeviceScaleFactor(float scale) { 64 DCHECK_NE(0.0f, scale); 65 g_device_scale_factor = scale; 66 } 67 68 Size GetDPI() { 69 static int dpi_x = 0; 70 static int dpi_y = 0; 71 static bool should_initialize = true; 72 73 if (should_initialize) { 74 should_initialize = false; 75 base::win::ScopedGetDC screen_dc(NULL); 76 // This value is safe to cache for the life time of the app since the 77 // user must logout to change the DPI setting. This value also applies 78 // to all screens. 79 dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX); 80 dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY); 81 } 82 return Size(dpi_x, dpi_y); 83 } 84 85 float GetDPIScale() { 86 if (IsHighDPIEnabled()) { 87 return gfx::Display::HasForceDeviceScaleFactor() ? 88 gfx::Display::GetForcedDeviceScaleFactor() : 89 GetUnforcedDeviceScaleFactor(); 90 } 91 return 1.0; 92 } 93 94 bool IsHighDPIEnabled() { 95 // Default is disabled. 96 if (CommandLine::ForCurrentProcess()->HasSwitch( 97 switches::kHighDPISupport)) { 98 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 99 switches::kHighDPISupport).compare("1") == 0; 100 } 101 return false; 102 } 103 104 bool IsInHighDPIMode() { 105 return GetDPIScale() > 1.0; 106 } 107 108 void EnableHighDPISupport() { 109 if (IsHighDPIEnabled() && 110 (base::win::GetVersion() < base::win::VERSION_WIN8_1)) { 111 typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); 112 SetProcessDPIAwarePtr set_process_dpi_aware_func = 113 reinterpret_cast<SetProcessDPIAwarePtr>( 114 GetProcAddress(GetModuleHandleA("user32.dll"), 115 "SetProcessDPIAware")); 116 if (set_process_dpi_aware_func) 117 set_process_dpi_aware_func(); 118 } 119 } 120 121 namespace win { 122 123 float GetDeviceScaleFactor() { 124 DCHECK_NE(0.0f, g_device_scale_factor); 125 return g_device_scale_factor; 126 } 127 128 Point ScreenToDIPPoint(const Point& pixel_point) { 129 static float scaling_factor = 130 GetDeviceScaleFactor() > GetUnforcedDeviceScaleFactor() ? 131 1.0f / GetDeviceScaleFactor() : 132 1.0f; 133 return ToFlooredPoint(ScalePoint(pixel_point, 134 scaling_factor)); 135 } 136 137 Point DIPToScreenPoint(const Point& dip_point) { 138 return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor())); 139 } 140 141 Rect ScreenToDIPRect(const Rect& pixel_bounds) { 142 // TODO(kevers): Switch to non-deprecated method for float to int conversions. 143 return ToFlooredRectDeprecated( 144 ScaleRect(pixel_bounds, 1.0f / GetDeviceScaleFactor())); 145 } 146 147 Rect DIPToScreenRect(const Rect& dip_bounds) { 148 // TODO(kevers): Switch to non-deprecated method for float to int conversions. 149 return ToFlooredRectDeprecated( 150 ScaleRect(dip_bounds, GetDeviceScaleFactor())); 151 } 152 153 Size ScreenToDIPSize(const Size& size_in_pixels) { 154 return ToFlooredSize( 155 ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor())); 156 } 157 158 Size DIPToScreenSize(const Size& dip_size) { 159 return ToFlooredSize(ScaleSize(dip_size, GetDeviceScaleFactor())); 160 } 161 162 int GetSystemMetricsInDIP(int metric) { 163 return static_cast<int>(GetSystemMetrics(metric) / 164 GetDeviceScaleFactor() + 0.5); 165 } 166 167 double GetUndocumentedDPIScale() { 168 // TODO(girard): Remove this code when chrome is DPIAware. 169 static double scale = -1.0; 170 if (scale == -1.0) { 171 scale = 1.0; 172 if (!IsProcessDPIAwareWrapper()) { 173 base::win::RegKey key(HKEY_CURRENT_USER, 174 L"Control Panel\\Desktop\\WindowMetrics", 175 KEY_QUERY_VALUE); 176 if (key.Valid()) { 177 DWORD value = 0; 178 if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) { 179 scale = static_cast<double>(value) / kDefaultDPIX; 180 } 181 } 182 } 183 } 184 return scale; 185 } 186 187 double GetUndocumentedDPITouchScale() { 188 static double scale = 189 (base::win::GetVersion() < base::win::VERSION_WIN8_1) ? 190 GetUndocumentedDPIScale() : 1.0; 191 return scale; 192 } 193 194 } // namespace win 195 } // namespace gfx 196