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
IsProcessDPIAwareWrapper()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
GetUnforcedDeviceScaleFactor()35 float GetUnforcedDeviceScaleFactor() {
36 return static_cast<float>(gfx::GetDPI().width()) /
37 static_cast<float>(kDefaultDPIX);
38 }
39
GetModernUIScaleWrapper()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
GetModernUIScale()59 float GetModernUIScale() {
60 return GetModernUIScaleWrapper();
61 }
62
InitDeviceScaleFactor(float scale)63 void InitDeviceScaleFactor(float scale) {
64 DCHECK_NE(0.0f, scale);
65 g_device_scale_factor = scale;
66 }
67
GetDPI()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
GetDPIScale()85 float GetDPIScale() {
86 if (IsHighDPIEnabled()) {
87 return gfx::Display::HasForceDeviceScaleFactor() ?
88 gfx::Display::GetForcedDeviceScaleFactor() :
89 GetUnforcedDeviceScaleFactor();
90 }
91 return 1.0;
92 }
93
IsHighDPIEnabled()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
IsInHighDPIMode()104 bool IsInHighDPIMode() {
105 return GetDPIScale() > 1.0;
106 }
107
EnableHighDPISupport()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
GetDeviceScaleFactor()123 float GetDeviceScaleFactor() {
124 DCHECK_NE(0.0f, g_device_scale_factor);
125 return g_device_scale_factor;
126 }
127
ScreenToDIPPoint(const Point & pixel_point)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
DIPToScreenPoint(const Point & dip_point)137 Point DIPToScreenPoint(const Point& dip_point) {
138 return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor()));
139 }
140
ScreenToDIPRect(const Rect & pixel_bounds)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
DIPToScreenRect(const Rect & dip_bounds)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
ScreenToDIPSize(const Size & size_in_pixels)153 Size ScreenToDIPSize(const Size& size_in_pixels) {
154 return ToFlooredSize(
155 ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor()));
156 }
157
DIPToScreenSize(const Size & dip_size)158 Size DIPToScreenSize(const Size& dip_size) {
159 return ToFlooredSize(ScaleSize(dip_size, GetDeviceScaleFactor()));
160 }
161
GetSystemMetricsInDIP(int metric)162 int GetSystemMetricsInDIP(int metric) {
163 return static_cast<int>(GetSystemMetrics(metric) /
164 GetDeviceScaleFactor() + 0.5);
165 }
166
GetUndocumentedDPIScale()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
GetUndocumentedDPITouchScale()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