OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/win/dpi.h" | 5 #include "ui/gfx/dpi.h" |
6 | 6 |
7 #include <windows.h> | 7 #include "base/logging.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" | 8 #include "ui/gfx/display.h" |
12 #include "ui/gfx/point_conversions.h" | 9 #include "ui/gfx/point_conversions.h" |
13 #include "ui/gfx/rect_conversions.h" | 10 #include "ui/gfx/rect_conversions.h" |
14 #include "ui/gfx/size_conversions.h" | 11 #include "ui/gfx/size_conversions.h" |
15 | 12 |
13 #if defined(OS_WIN) | |
14 #include <windows.h> | |
15 #include "base/win/registry.h" | |
16 #include "base/win/scoped_hdc.h" | |
17 #include "base/win/windows_version.h" | |
18 #endif | |
19 | |
20 #if defined(OS_LINUX) | |
21 #include "ui/gfx/linux_font_delegate.h" | |
22 #endif | |
23 | |
16 namespace { | 24 namespace { |
17 | 25 |
18 int kDefaultDPIX = 96; | 26 int kDefaultDPI = 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 | 27 |
33 float g_device_scale_factor = 0.0f; | 28 float g_device_scale_factor = 0.0f; |
34 | 29 |
35 float GetUnforcedDeviceScaleFactor() { | 30 float GetUnforcedDeviceScaleFactor() { |
36 // If the global device scale factor is initialized use it. This is to ensure | 31 // 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 | 32 // 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 | 33 // GetDeviceScaleFactor function here because it fires a DCHECK if the |
39 // g_device_scale_factor global is 0. | 34 // g_device_scale_factor global is 0. |
40 if (g_device_scale_factor) | 35 if (g_device_scale_factor) |
41 return g_device_scale_factor; | 36 return g_device_scale_factor; |
42 return static_cast<float>(gfx::GetDPI().width()) / | 37 return static_cast<float>(gfx::GetDPI().width()) / |
43 static_cast<float>(kDefaultDPIX); | 38 static_cast<float>(kDefaultDPI); |
44 } | 39 } |
45 | 40 |
46 // Duplicated from Win8.1 SDK ShellScalingApi.h | 41 #if defined(OS_WIN) |
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, | 42 DWORD ReadRegistryValue(HKEY root, |
93 const wchar_t* base_key, | 43 const wchar_t* base_key, |
94 const wchar_t* value_name, | 44 const wchar_t* value_name, |
95 DWORD default_value) { | 45 DWORD default_value) { |
96 base::win::RegKey reg_key(HKEY_CURRENT_USER, | 46 base::win::RegKey reg_key(HKEY_CURRENT_USER, |
97 base_key, | 47 base_key, |
98 KEY_QUERY_VALUE); | 48 KEY_QUERY_VALUE); |
99 DWORD value; | 49 DWORD value; |
100 if (reg_key.Valid() && | 50 if (reg_key.Valid() && |
101 reg_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) { | 51 reg_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) { |
102 return value; | 52 return value; |
103 } | 53 } |
104 return default_value; | 54 return default_value; |
105 } | 55 } |
56 #endif | |
106 | 57 |
107 } // namespace | 58 } // namespace |
108 | 59 |
60 | |
109 namespace gfx { | 61 namespace gfx { |
110 | 62 |
111 void InitDeviceScaleFactor(float scale) { | 63 void InitDeviceScaleFactor(float scale) { |
112 DCHECK_NE(0.0f, scale); | 64 DCHECK_NE(0.0f, scale); |
oshima
2014/10/20 21:11:59
what happens if the scale is between 0.0 and 1.0 ?
scottmg
2014/10/22 18:54:14
Assets and fonts seem to be rendered at 1.0, but s
| |
113 g_device_scale_factor = scale; | 65 g_device_scale_factor = scale; |
114 } | 66 } |
115 | 67 |
68 float GetDeviceScaleFactor() { | |
69 DCHECK_NE(0.0f, g_device_scale_factor); | |
70 return g_device_scale_factor; | |
71 } | |
72 | |
73 bool IsDeviceScaleFactorSet() { | |
74 return g_device_scale_factor != 0.0f; | |
75 } | |
76 | |
77 void ForceHighDPISupportForTesting(float scale) { | |
78 g_device_scale_factor = scale; | |
79 } | |
80 | |
81 bool IsInHighDPIMode() { | |
82 return GetDPIScale() > 1.0; | |
83 } | |
84 | |
116 Size GetDPI() { | 85 Size GetDPI() { |
117 static int dpi_x = 0; | 86 static int dpi_x = 0; |
118 static int dpi_y = 0; | 87 static int dpi_y = 0; |
119 static bool should_initialize = true; | 88 static bool should_initialize = true; |
120 | 89 |
121 if (should_initialize) { | 90 if (should_initialize) { |
122 should_initialize = false; | 91 should_initialize = false; |
92 #if defined(OS_WIN) | |
123 base::win::ScopedGetDC screen_dc(NULL); | 93 base::win::ScopedGetDC screen_dc(NULL); |
124 // This value is safe to cache for the life time of the app since the | 94 // 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 | 95 // user must logout to change the DPI setting. This value also applies |
126 // to all screens. | 96 // to all screens. |
127 dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX); | 97 dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX); |
128 dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY); | 98 dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY); |
99 #else | |
100 const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance(); | |
101 if (delegate) | |
102 dpi_x = delegate->GetFontDPI(); | |
103 if (dpi_x <= 0) | |
104 dpi_x = 96; | |
105 dpi_y = dpi_x; | |
106 #endif | |
129 } | 107 } |
130 return Size(dpi_x, dpi_y); | 108 return Size(dpi_x, dpi_y); |
131 } | 109 } |
132 | 110 |
133 float GetDPIScale() { | 111 float GetDPIScale() { |
134 if (IsHighDPIEnabled()) { | 112 if (IsHighDPIEnabled()) { |
135 if (gfx::Display::HasForceDeviceScaleFactor()) | 113 if (gfx::Display::HasForceDeviceScaleFactor()) |
136 return gfx::Display::GetForcedDeviceScaleFactor(); | 114 return gfx::Display::GetForcedDeviceScaleFactor(); |
137 float dpi_scale = GetUnforcedDeviceScaleFactor(); | 115 float dpi_scale = GetUnforcedDeviceScaleFactor(); |
138 if (dpi_scale <= 1.25) { | 116 if (dpi_scale <= 1.25) { |
139 // Force 125% and below to 100% scale. We do this to maintain previous | 117 // 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. | 118 // (non-DPI-aware) behavior where only the font size was boosted. |
141 dpi_scale = 1.0; | 119 dpi_scale = 1.0; |
142 } | 120 } |
143 return dpi_scale; | 121 return dpi_scale; |
144 } | 122 } |
145 return 1.0; | 123 return 1.0; |
146 } | 124 } |
147 | 125 |
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) { | 126 Point ScreenToDIPPoint(const Point& pixel_point) { |
185 return ToFlooredPoint(ScalePoint(pixel_point, | 127 return ToFlooredPoint(ScalePoint(pixel_point, |
186 1.0f / GetDeviceScaleFactor())); | 128 1.0f / GetDeviceScaleFactor())); |
187 } | 129 } |
188 | 130 |
189 Point DIPToScreenPoint(const Point& dip_point) { | 131 Point DIPToScreenPoint(const Point& dip_point) { |
190 return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor())); | 132 return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor())); |
191 } | 133 } |
192 | 134 |
193 Rect ScreenToDIPRect(const Rect& pixel_bounds) { | 135 Rect ScreenToDIPRect(const Rect& pixel_bounds) { |
(...skipping 16 matching lines...) Expand all Loading... | |
210 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. | 152 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. |
211 return ToCeiledSize( | 153 return ToCeiledSize( |
212 ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor())); | 154 ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor())); |
213 } | 155 } |
214 | 156 |
215 Size DIPToScreenSize(const Size& dip_size) { | 157 Size DIPToScreenSize(const Size& dip_size) { |
216 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. | 158 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. |
217 return ToCeiledSize(ScaleSize(dip_size, GetDeviceScaleFactor())); | 159 return ToCeiledSize(ScaleSize(dip_size, GetDeviceScaleFactor())); |
218 } | 160 } |
219 | 161 |
162 bool IsHighDPIEnabled() { | |
163 #if defined(OS_WIN) | |
164 static const wchar_t kRegistryProfilePath[] = | |
165 L"Software\\Google\\Chrome\\Profile"; | |
166 static const wchar_t kHighDPISupportW[] = L"high-dpi-support"; | |
167 | |
168 // Flag stored in HKEY_CURRENT_USER\SOFTWARE\\Google\\Chrome\\Profile, | |
169 // under the DWORD value high-dpi-support. | |
170 // Default is disabled. | |
171 static DWORD value = ReadRegistryValue( | |
172 HKEY_CURRENT_USER, kRegistryProfilePath, kHighDPISupportW, TRUE); | |
173 return value != 0; | |
174 #elif defined(OS_LINUX) | |
175 return true; | |
176 #endif | |
177 } | |
178 | |
179 | |
180 #if defined(OS_WIN) | |
181 | |
182 namespace win { | |
183 | |
184 namespace { | |
185 | |
186 // Duplicated from Win8.1 SDK ShellScalingApi.h | |
187 typedef enum PROCESS_DPI_AWARENESS { | |
188 PROCESS_DPI_UNAWARE = 0, | |
189 PROCESS_SYSTEM_DPI_AWARE = 1, | |
190 PROCESS_PER_MONITOR_DPI_AWARE = 2 | |
191 } PROCESS_DPI_AWARENESS; | |
192 | |
193 typedef enum MONITOR_DPI_TYPE { | |
194 MDT_EFFECTIVE_DPI = 0, | |
195 MDT_ANGULAR_DPI = 1, | |
196 MDT_RAW_DPI = 2, | |
197 MDT_DEFAULT = MDT_EFFECTIVE_DPI | |
198 } MONITOR_DPI_TYPE; | |
199 | |
200 // Win8.1 supports monitor-specific DPI scaling. | |
201 bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { | |
202 typedef BOOL(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS); | |
203 SetProcessDpiAwarenessPtr set_process_dpi_awareness_func = | |
204 reinterpret_cast<SetProcessDpiAwarenessPtr>( | |
205 GetProcAddress(GetModuleHandleA("user32.dll"), | |
206 "SetProcessDpiAwarenessInternal")); | |
207 if (set_process_dpi_awareness_func) { | |
208 HRESULT hr = set_process_dpi_awareness_func(value); | |
209 if (SUCCEEDED(hr)) { | |
210 VLOG(1) << "SetProcessDpiAwareness succeeded."; | |
211 return true; | |
212 } else if (hr == E_ACCESSDENIED) { | |
213 LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. " | |
214 "Function called twice, or manifest was used."; | |
215 } | |
216 } | |
217 return false; | |
218 } | |
219 | |
220 // This function works for Windows Vista through Win8. Win8.1 must use | |
221 // SetProcessDpiAwareness[Wrapper] | |
222 BOOL SetProcessDPIAwareWrapper() { | |
223 typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); | |
224 SetProcessDPIAwarePtr set_process_dpi_aware_func = | |
225 reinterpret_cast<SetProcessDPIAwarePtr>( | |
226 GetProcAddress(GetModuleHandleA("user32.dll"), | |
227 "SetProcessDPIAware")); | |
228 return set_process_dpi_aware_func && | |
229 set_process_dpi_aware_func(); | |
230 } | |
231 | |
232 } // namespace | |
233 | |
234 void EnableHighDPISupport() { | |
235 if (IsHighDPIEnabled() && | |
236 !SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) { | |
237 SetProcessDPIAwareWrapper(); | |
238 } | |
239 } | |
240 | |
220 int GetSystemMetricsInDIP(int metric) { | 241 int GetSystemMetricsInDIP(int metric) { |
221 return static_cast<int>(GetSystemMetrics(metric) / | 242 return static_cast<int>(GetSystemMetrics(metric) / |
222 GetDeviceScaleFactor() + 0.5); | 243 GetDeviceScaleFactor() + 0.5); |
223 } | 244 } |
224 | 245 |
225 bool IsDeviceScaleFactorSet() { | 246 } // namespace win |
226 return g_device_scale_factor != 0.0f; | |
227 } | |
228 | 247 |
229 } // namespace win | 248 #endif // OS_WIN |
oshima
2014/10/20 21:11:59
consider moving win impl to dip_win.cc ?
scottmg
2014/10/22 18:54:14
Done.
| |
249 | |
230 } // namespace gfx | 250 } // namespace gfx |
OLD | NEW |