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 |