| OLD | NEW |
| (Empty) |
| 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/win/scoped_hdc.h" | |
| 9 #include "base/win/windows_version.h" | |
| 10 #include "base/win/registry.h" | |
| 11 #include "ui/gfx/display.h" | |
| 12 #include "ui/gfx/point_conversions.h" | |
| 13 #include "ui/gfx/rect_conversions.h" | |
| 14 #include "ui/gfx/size_conversions.h" | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 int kDefaultDPIX = 96; | |
| 19 int kDefaultDPIY = 96; | |
| 20 | |
| 21 bool force_highdpi_for_testing = false; | |
| 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 // If the global device scale factor is initialized use it. This is to ensure | |
| 37 // we use the same scale factor across all callsites. We don't use the | |
| 38 // GetDeviceScaleFactor function here because it fires a DCHECK if the | |
| 39 // g_device_scale_factor global is 0. | |
| 40 if (g_device_scale_factor) | |
| 41 return g_device_scale_factor; | |
| 42 return static_cast<float>(gfx::GetDPI().width()) / | |
| 43 static_cast<float>(kDefaultDPIX); | |
| 44 } | |
| 45 | |
| 46 // Duplicated from Win8.1 SDK ShellScalingApi.h | |
| 47 typedef enum PROCESS_DPI_AWARENESS { | |
| 48 PROCESS_DPI_UNAWARE = 0, | |
| 49 PROCESS_SYSTEM_DPI_AWARE = 1, | |
| 50 PROCESS_PER_MONITOR_DPI_AWARE = 2 | |
| 51 } PROCESS_DPI_AWARENESS; | |
| 52 | |
| 53 typedef enum MONITOR_DPI_TYPE { | |
| 54 MDT_EFFECTIVE_DPI = 0, | |
| 55 MDT_ANGULAR_DPI = 1, | |
| 56 MDT_RAW_DPI = 2, | |
| 57 MDT_DEFAULT = MDT_EFFECTIVE_DPI | |
| 58 } MONITOR_DPI_TYPE; | |
| 59 | |
| 60 // Win8.1 supports monitor-specific DPI scaling. | |
| 61 bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { | |
| 62 typedef BOOL(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS); | |
| 63 SetProcessDpiAwarenessPtr set_process_dpi_awareness_func = | |
| 64 reinterpret_cast<SetProcessDpiAwarenessPtr>( | |
| 65 GetProcAddress(GetModuleHandleA("user32.dll"), | |
| 66 "SetProcessDpiAwarenessInternal")); | |
| 67 if (set_process_dpi_awareness_func) { | |
| 68 HRESULT hr = set_process_dpi_awareness_func(value); | |
| 69 if (SUCCEEDED(hr)) { | |
| 70 VLOG(1) << "SetProcessDpiAwareness succeeded."; | |
| 71 return true; | |
| 72 } else if (hr == E_ACCESSDENIED) { | |
| 73 LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. " | |
| 74 "Function called twice, or manifest was used."; | |
| 75 } | |
| 76 } | |
| 77 return false; | |
| 78 } | |
| 79 | |
| 80 // This function works for Windows Vista through Win8. Win8.1 must use | |
| 81 // SetProcessDpiAwareness[Wrapper] | |
| 82 BOOL SetProcessDPIAwareWrapper() { | |
| 83 typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); | |
| 84 SetProcessDPIAwarePtr set_process_dpi_aware_func = | |
| 85 reinterpret_cast<SetProcessDPIAwarePtr>( | |
| 86 GetProcAddress(GetModuleHandleA("user32.dll"), | |
| 87 "SetProcessDPIAware")); | |
| 88 return set_process_dpi_aware_func && | |
| 89 set_process_dpi_aware_func(); | |
| 90 } | |
| 91 | |
| 92 DWORD ReadRegistryValue(HKEY root, | |
| 93 const wchar_t* base_key, | |
| 94 const wchar_t* value_name, | |
| 95 DWORD default_value) { | |
| 96 base::win::RegKey reg_key(HKEY_CURRENT_USER, | |
| 97 base_key, | |
| 98 KEY_QUERY_VALUE); | |
| 99 DWORD value; | |
| 100 if (reg_key.Valid() && | |
| 101 reg_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) { | |
| 102 return value; | |
| 103 } | |
| 104 return default_value; | |
| 105 } | |
| 106 | |
| 107 } // namespace | |
| 108 | |
| 109 namespace gfx { | |
| 110 | |
| 111 void InitDeviceScaleFactor(float scale) { | |
| 112 DCHECK_NE(0.0f, scale); | |
| 113 g_device_scale_factor = scale; | |
| 114 } | |
| 115 | |
| 116 Size GetDPI() { | |
| 117 static int dpi_x = 0; | |
| 118 static int dpi_y = 0; | |
| 119 static bool should_initialize = true; | |
| 120 | |
| 121 if (should_initialize) { | |
| 122 should_initialize = false; | |
| 123 base::win::ScopedGetDC screen_dc(NULL); | |
| 124 // This value is safe to cache for the life time of the app since the | |
| 125 // user must logout to change the DPI setting. This value also applies | |
| 126 // to all screens. | |
| 127 dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX); | |
| 128 dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY); | |
| 129 } | |
| 130 return Size(dpi_x, dpi_y); | |
| 131 } | |
| 132 | |
| 133 float GetDPIScale() { | |
| 134 if (IsHighDPIEnabled()) { | |
| 135 if (gfx::Display::HasForceDeviceScaleFactor()) | |
| 136 return gfx::Display::GetForcedDeviceScaleFactor(); | |
| 137 float dpi_scale = GetUnforcedDeviceScaleFactor(); | |
| 138 if (dpi_scale <= 1.25) { | |
| 139 // Force 125% and below to 100% scale. We do this to maintain previous | |
| 140 // (non-DPI-aware) behavior where only the font size was boosted. | |
| 141 dpi_scale = 1.0; | |
| 142 } | |
| 143 return dpi_scale; | |
| 144 } | |
| 145 return 1.0; | |
| 146 } | |
| 147 | |
| 148 void ForceHighDPISupportForTesting(float scale) { | |
| 149 g_device_scale_factor = scale; | |
| 150 } | |
| 151 | |
| 152 bool IsHighDPIEnabled() { | |
| 153 // Flag stored in HKEY_CURRENT_USER\SOFTWARE\\Google\\Chrome\\Profile, | |
| 154 // under the DWORD value high-dpi-support. | |
| 155 // Default is disabled. | |
| 156 static DWORD value = ReadRegistryValue( | |
| 157 HKEY_CURRENT_USER, gfx::win::kRegistryProfilePath, | |
| 158 gfx::win::kHighDPISupportW, TRUE); | |
| 159 return value != 0; | |
| 160 } | |
| 161 | |
| 162 bool IsInHighDPIMode() { | |
| 163 return GetDPIScale() > 1.0; | |
| 164 } | |
| 165 | |
| 166 void EnableHighDPISupport() { | |
| 167 if (IsHighDPIEnabled() && | |
| 168 !SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) { | |
| 169 SetProcessDPIAwareWrapper(); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 namespace win { | |
| 174 | |
| 175 GFX_EXPORT const wchar_t kRegistryProfilePath[] = | |
| 176 L"Software\\Google\\Chrome\\Profile"; | |
| 177 GFX_EXPORT const wchar_t kHighDPISupportW[] = L"high-dpi-support"; | |
| 178 | |
| 179 float GetDeviceScaleFactor() { | |
| 180 DCHECK_NE(0.0f, g_device_scale_factor); | |
| 181 return g_device_scale_factor; | |
| 182 } | |
| 183 | |
| 184 Point ScreenToDIPPoint(const Point& pixel_point) { | |
| 185 return ToFlooredPoint(ScalePoint(pixel_point, | |
| 186 1.0f / GetDeviceScaleFactor())); | |
| 187 } | |
| 188 | |
| 189 Point DIPToScreenPoint(const Point& dip_point) { | |
| 190 return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor())); | |
| 191 } | |
| 192 | |
| 193 Rect ScreenToDIPRect(const Rect& pixel_bounds) { | |
| 194 // It's important we scale the origin and size separately. If we instead | |
| 195 // calculated the size from the floored origin and ceiled right the size could | |
| 196 // vary depending upon where the two points land. That would cause problems | |
| 197 // for the places this code is used (in particular mapping from native window | |
| 198 // bounds to DIPs). | |
| 199 return Rect(ScreenToDIPPoint(pixel_bounds.origin()), | |
| 200 ScreenToDIPSize(pixel_bounds.size())); | |
| 201 } | |
| 202 | |
| 203 Rect DIPToScreenRect(const Rect& dip_bounds) { | |
| 204 // See comment in ScreenToDIPRect for why we calculate size like this. | |
| 205 return Rect(DIPToScreenPoint(dip_bounds.origin()), | |
| 206 DIPToScreenSize(dip_bounds.size())); | |
| 207 } | |
| 208 | |
| 209 Size ScreenToDIPSize(const Size& size_in_pixels) { | |
| 210 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. | |
| 211 return ToCeiledSize( | |
| 212 ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor())); | |
| 213 } | |
| 214 | |
| 215 Size DIPToScreenSize(const Size& dip_size) { | |
| 216 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. | |
| 217 return ToCeiledSize(ScaleSize(dip_size, GetDeviceScaleFactor())); | |
| 218 } | |
| 219 | |
| 220 int GetSystemMetricsInDIP(int metric) { | |
| 221 return static_cast<int>(GetSystemMetrics(metric) / | |
| 222 GetDeviceScaleFactor() + 0.5); | |
| 223 } | |
| 224 | |
| 225 bool IsDeviceScaleFactorSet() { | |
| 226 return g_device_scale_factor != 0.0f; | |
| 227 } | |
| 228 | |
| 229 } // namespace win | |
| 230 } // namespace gfx | |
| OLD | NEW |