Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1074)

Side by Side Diff: ui/gfx/screen_win.cc

Issue 1426933002: Refactor Windows DPI Point, Rect, and Size for Multiple Monitor DPI Awareness (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/screen_win.h" 5 #include "ui/gfx/screen_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/hash.h" 11 #include "base/hash.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/scoped_hdc.h"
scottmg 2015/10/28 18:48:21 I don't think this got used.
robliao 2015/10/29 00:30:24 Good catch. I had a plan that used HDC's before bu
14 #include "base/win/win_util.h" 15 #include "base/win/win_util.h"
15 #include "ui/gfx/display.h" 16 #include "ui/gfx/display.h"
17 #include "ui/gfx/geometry/point_conversions.h"
18 #include "ui/gfx/geometry/vector2d.h"
16 #include "ui/gfx/win/dpi.h" 19 #include "ui/gfx/win/dpi.h"
17 20
18 namespace { 21 namespace {
19 22
20 MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) { 23 gfx::Display GetDisplay(HMONITOR monitor) {
21 MONITORINFOEX monitor_info; 24 MONITORINFOEX monitor_info;
22 ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); 25 ::ZeroMemory(&monitor_info, sizeof(monitor_info));
23 monitor_info.cbSize = sizeof(monitor_info); 26 monitor_info.cbSize = sizeof(monitor_info);
24 GetMonitorInfo(monitor, &monitor_info); 27 ::GetMonitorInfo(monitor, &monitor_info);
25 return monitor_info;
26 }
27 28
28 gfx::Display GetDisplay(MONITORINFOEX& monitor_info) {
29 int64 id = static_cast<int64>( 29 int64 id = static_cast<int64>(
30 base::Hash(base::WideToUTF8(monitor_info.szDevice))); 30 base::Hash(base::WideToUTF8(monitor_info.szDevice)));
31 gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor); 31 gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor);
32 gfx::Display display(id, bounds); 32 gfx::Display display(id, bounds);
33 display.set_work_area(gfx::Rect(monitor_info.rcWork)); 33 display.set_work_area(gfx::Rect(monitor_info.rcWork));
34 display.SetScaleAndBounds(gfx::GetDPIScale(), bounds); 34 display.SetScaleAndBounds(gfx::GetDPIScale(), bounds);
35 35
36 DEVMODE mode; 36 DEVMODE mode;
37 memset(&mode, 0, sizeof(DEVMODE)); 37 ::ZeroMemory(&mode, sizeof(mode));
38 mode.dmSize = sizeof(DEVMODE); 38 mode.dmSize = sizeof(DEVMODE);
39 mode.dmDriverExtra = 0; 39 mode.dmDriverExtra = 0;
40 if (EnumDisplaySettings(monitor_info.szDevice, 40 if (::EnumDisplaySettings(monitor_info.szDevice,
41 ENUM_CURRENT_SETTINGS, 41 ENUM_CURRENT_SETTINGS,
42 &mode)) { 42 &mode)) {
43 switch (mode.dmDisplayOrientation) { 43 switch (mode.dmDisplayOrientation) {
44 case DMDO_DEFAULT: 44 case DMDO_DEFAULT:
45 display.set_rotation(gfx::Display::ROTATE_0); 45 display.set_rotation(gfx::Display::ROTATE_0);
46 break; 46 break;
47 case DMDO_90: 47 case DMDO_90:
48 display.set_rotation(gfx::Display::ROTATE_90); 48 display.set_rotation(gfx::Display::ROTATE_90);
49 break; 49 break;
50 case DMDO_180: 50 case DMDO_180:
51 display.set_rotation(gfx::Display::ROTATE_180); 51 display.set_rotation(gfx::Display::ROTATE_180);
52 break; 52 break;
53 case DMDO_270: 53 case DMDO_270:
54 display.set_rotation(gfx::Display::ROTATE_270); 54 display.set_rotation(gfx::Display::ROTATE_270);
55 break; 55 break;
56 default: 56 default:
57 NOTREACHED(); 57 NOTREACHED();
58 } 58 }
59 } 59 }
60 60
61 return display; 61 return display;
62 } 62 }
63 63
64 BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, 64 BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor,
65 HDC hdc, 65 HDC hdc,
66 LPRECT rect, 66 LPRECT rect,
67 LPARAM data) { 67 LPARAM data) {
68 std::vector<gfx::Display>* all_displays = 68 std::vector<gfx::Display>* all_displays =
69 reinterpret_cast<std::vector<gfx::Display>*>(data); 69 reinterpret_cast<std::vector<gfx::Display>*>(data);
70 DCHECK(all_displays); 70 DCHECK(all_displays);
71 71
72 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor); 72 gfx::Display display = GetDisplay(monitor);
73 gfx::Display display = GetDisplay(monitor_info);
74 all_displays->push_back(display); 73 all_displays->push_back(display);
75 return TRUE; 74 return TRUE;
76 } 75 }
77 76
78 std::vector<gfx::Display> GetDisplays() { 77 std::vector<gfx::Display> GetDisplays() {
79 std::vector<gfx::Display> displays; 78 std::vector<gfx::Display> displays;
80 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, 79 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback,
81 reinterpret_cast<LPARAM>(&displays)); 80 reinterpret_cast<LPARAM>(&displays));
82 return displays; 81 return displays;
83 } 82 }
84 83
85 } // namespace 84 } // namespace
86 85
87 namespace gfx { 86 namespace gfx {
88 87
89 ScreenWin::ScreenWin() 88 ScreenWin::ScreenWin()
90 : singleton_hwnd_observer_(new SingletonHwndObserver( 89 : singleton_hwnd_observer_(new SingletonHwndObserver(
91 base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))), 90 base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))),
92 displays_(GetDisplays()) { 91 displays_(GetDisplays()) {
93 } 92 }
94 93
95 ScreenWin::~ScreenWin() {} 94 ScreenWin::~ScreenWin() {}
96 95
96 // static
97 Point ScreenWin::ScreenToDIPPoint(const Point& pixel_point) {
98 gfx::Display display = GetDisplayNearestScreenPoint(pixel_point);
99 float device_scale_factor = display.device_scale_factor();
100 const Rect& monitor_bounds = display.bounds();
101 Vector2d origin(monitor_bounds.x(), monitor_bounds.y());
102
103 // Monitors are anchored to their physical coordinate regardless of DPI.
104 return ScaleToFlooredPoint(pixel_point - origin, 1.0f / device_scale_factor) +
105 origin;
106 }
107
108 // static
109 Point ScreenWin::DIPToScreenPoint(const Point& dip_point) {
110 // Because origins don't change for screen points and scaling factors are
111 // greater than 1, the monitor bounding rect always contains the DIP point.
112 gfx::Display display = GetDisplayNearestScreenPoint(dip_point);
113 float device_scale_factor = display.device_scale_factor();
scottmg 2015/10/28 18:48:21 DCHECK that device_scale_factor >= 1 (CrOS has som
robliao 2015/10/29 00:30:24 Added the DCHECK where we create the display in Ge
114 const Rect& monitor_bounds = display.bounds();
115 Vector2d origin(monitor_bounds.x(), monitor_bounds.y());
116
117 return ScaleToFlooredPoint(dip_point - origin, device_scale_factor) + origin;
118 }
119
120 // static
121 Point ScreenWin::ClientToDIPPoint(HWND hwnd, const Point& client_point) {
122 return ScaleToFlooredPoint(client_point, 1.0f / GetScaleFactorForHWND(hwnd));
123 }
124
125 Point ScreenWin::DIPToClientPoint(HWND hwnd, const Point& dip_point) {
126 return ScaleToFlooredPoint(dip_point, GetScaleFactorForHWND(hwnd));
127 }
128
129 // static
130 Rect ScreenWin::ScreenToDIPRect(HWND hwnd, const Rect& pixel_bounds) {
131 // It's important we scale the origin and size separately. If we instead
132 // calculated the size from the floored origin and ceiled right the size could
133 // vary depending upon where the two points land. That would cause problems
134 // for the places this code is used (in particular mapping from native window
135 // bounds to DIPs).
136 if (hwnd) {
137 return Rect(ScreenToDIPPoint(pixel_bounds.origin()),
138 ScreenToDIPSize(hwnd, pixel_bounds.size()));
scottmg 2015/10/28 18:48:21 indent
robliao 2015/10/29 00:30:24 Done.
139 }
140 float scale_factor =
141 GetDisplayNearestRect(pixel_bounds).device_scale_factor();
142 return Rect(ScreenToDIPPoint(pixel_bounds.origin()),
143 ScaleToCeiledSize(pixel_bounds.size(), 1.0f / scale_factor));
144 }
145
146 // static
147 Rect ScreenWin::DIPToScreenRect(HWND hwnd, const Rect& dip_bounds) {
148 // See comment in ScreenToDIPRect for why we calculate size like this.
149 if (hwnd) {
150 return Rect(DIPToScreenPoint(dip_bounds.origin()),
151 DIPToScreenSize(hwnd, dip_bounds.size()));
scottmg 2015/10/28 18:48:21 indent
robliao 2015/10/29 00:30:24 Done.
152 }
153 // Because origins don't change for screen points and scaling factors are
154 // greater than 1, the monitor bounding rect always contains the DIP point.
155 float scale_factor =
156 GetDisplayNearestRect(dip_bounds).device_scale_factor();
157 return Rect(DIPToScreenPoint(dip_bounds.origin()),
158 ScaleToCeiledSize(dip_bounds.size(), scale_factor));
159 }
160
161 // static
162 Rect ScreenWin::ClientToDIPRect(HWND hwnd, const Rect& pixel_bounds) {
163 // See comment in ScreenToDIPRect for why we calculate size like this.
164 return Rect(ClientToDIPPoint(hwnd, pixel_bounds.origin()),
165 ScreenToDIPSize(hwnd, pixel_bounds.size()));
166 }
167
168 // static
169 Rect ScreenWin::DIPToClientRect(HWND hwnd, const Rect& dip_bounds) {
170 // See comment in ScreenToDIPRect for why we calculate size like this.
171 return Rect(DIPToClientPoint(hwnd, dip_bounds.origin()),
172 DIPToScreenSize(hwnd, dip_bounds.size()));
173 }
174
175 // static
176 Size ScreenWin::ScreenToDIPSize(HWND hwnd, const Size& size_in_pixels) {
177 // Always ceil sizes. Otherwise we may be leaving off part of the bounds.
178 return ScaleToCeiledSize(size_in_pixels, 1.0f / GetScaleFactorForHWND(hwnd));
179 }
180
181 // static
182 Size ScreenWin::DIPToScreenSize(HWND hwnd, const Size& dip_size) {
183 // Always ceil sizes. Otherwise we may be leaving off part of the bounds.
184 return ScaleToCeiledSize(dip_size, GetScaleFactorForHWND(hwnd));
185 }
186
97 gfx::Point ScreenWin::GetCursorScreenPoint() { 187 gfx::Point ScreenWin::GetCursorScreenPoint() {
98 POINT pt; 188 POINT pt;
99 GetCursorPos(&pt); 189 GetCursorPos(&pt);
100 gfx::Point cursor_pos_pixels(pt); 190 gfx::Point cursor_pos_pixels(pt);
101 return gfx::win::ScreenToDIPPoint(cursor_pos_pixels); 191 return ScreenToDIPPoint(cursor_pos_pixels);
102 } 192 }
103 193
104 gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { 194 gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
105 POINT cursor_loc; 195 POINT cursor_loc;
106 HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; 196 HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL;
107 return GetNativeWindowFromHWND(hwnd); 197 return GetNativeWindowFromHWND(hwnd);
108 } 198 }
109 199
110 gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { 200 gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) {
111 gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); 201 gfx::Point point_in_pixels = DIPToScreenPoint(point);
112 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT())); 202 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT()));
113 } 203 }
114 204
115 int ScreenWin::GetNumDisplays() const { 205 int ScreenWin::GetNumDisplays() const {
116 return GetSystemMetrics(SM_CMONITORS); 206 return GetSystemMetrics(SM_CMONITORS);
117 } 207 }
118 208
119 std::vector<gfx::Display> ScreenWin::GetAllDisplays() const { 209 std::vector<gfx::Display> ScreenWin::GetAllDisplays() const {
120 return displays_; 210 return displays_;
121 } 211 }
122 212
123 gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { 213 gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
124 HWND window_hwnd = GetHWNDFromNativeView(window); 214 HWND window_hwnd = GetHWNDFromNativeView(window);
125 if (!window_hwnd) { 215 if (!window_hwnd) {
126 // When |window| isn't rooted to a display, we should just return the 216 // When |window| isn't rooted to a display, we should just return the
127 // default display so we get some correct display information like the 217 // default display so we get some correct display information like the
128 // scaling factor. 218 // scaling factor.
129 return GetPrimaryDisplay(); 219 return GetPrimaryDisplay();
130 } 220 }
131 221
132 MONITORINFOEX monitor_info; 222 return GetDisplayNearestHWND(window_hwnd);
133 monitor_info.cbSize = sizeof(monitor_info);
134 GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST),
135 &monitor_info);
136 return GetDisplay(monitor_info);
137 } 223 }
138 224
139 gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { 225 gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
140 gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); 226 return GetDisplayNearestScreenPoint(DIPToScreenPoint(point));
141 POINT initial_loc = { point_in_pixels.x(), point_in_pixels.y() };
142 HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST);
143 MONITORINFOEX mi;
144 ZeroMemory(&mi, sizeof(MONITORINFOEX));
145 mi.cbSize = sizeof(mi);
146 if (monitor && GetMonitorInfo(monitor, &mi)) {
147 return GetDisplay(mi);
148 }
149 return gfx::Display();
150 } 227 }
151 228
152 gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const { 229 gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const {
153 RECT other_bounds_rect = match_rect.ToRECT(); 230 return GetDisplayNearestRect(match_rect);
154 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
155 &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
156 return GetDisplay(monitor_info);
157 } 231 }
158 232
159 gfx::Display ScreenWin::GetPrimaryDisplay() const { 233 gfx::Display ScreenWin::GetPrimaryDisplay() const {
160 MONITORINFOEX mi = GetMonitorInfoForMonitor( 234 gfx::Display display =
161 MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY)); 235 GetDisplay(MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY));
162 gfx::Display display = GetDisplay(mi);
163 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP 236 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
164 // once more of the app is DIP-aware. 237 // once more of the app is DIP-aware.
165 if (GetDPIScale() == 1.0) { 238 if (display.device_scale_factor() == 1.0) {
166 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width()); 239 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
167 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height()); 240 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
168 } 241 }
169 return display; 242 return display;
170 } 243 }
171 244
172 void ScreenWin::AddObserver(DisplayObserver* observer) { 245 void ScreenWin::AddObserver(DisplayObserver* observer) {
173 change_notifier_.AddObserver(observer); 246 change_notifier_.AddObserver(observer);
174 } 247 }
175 248
176 void ScreenWin::RemoveObserver(DisplayObserver* observer) { 249 void ScreenWin::RemoveObserver(DisplayObserver* observer) {
177 change_notifier_.RemoveObserver(observer); 250 change_notifier_.RemoveObserver(observer);
178 } 251 }
179 252
253 // static
254 gfx::Display ScreenWin::GetDisplayNearestHWND(HWND hwnd) {
255 return GetDisplay(::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST));
256 }
257
258 // static
259 gfx::Display ScreenWin::GetDisplayNearestRect(const Rect& rect) {
260 RECT winRect = rect.ToRECT();
261 return GetDisplay(::MonitorFromRect(&winRect, MONITOR_DEFAULTTONEAREST));
262 }
263
264 // static
265 gfx::Display ScreenWin::GetDisplayNearestScreenPoint(
266 const Point& screen_point) {
267 POINT initial_loc = { screen_point.x(), screen_point.y() };
268 return GetDisplay(::MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST));
269 }
270
271 // static
272 float ScreenWin::GetScaleFactorForHWND(HWND hwnd) {
273 DCHECK(hwnd);
274 HWND hwndTopLevel = GetAncestor(hwnd, GA_ROOT);
275 return GetDisplayNearestHWND(hwndTopLevel).device_scale_factor();
276 }
277
278 // static
279 float ScreenWin::GetScaleFactorForScreenPoint(const Point& screen_point) {
280 return GetDisplayNearestScreenPoint(screen_point).device_scale_factor();
281 }
282
180 void ScreenWin::OnWndProc(HWND hwnd, 283 void ScreenWin::OnWndProc(HWND hwnd,
181 UINT message, 284 UINT message,
182 WPARAM wparam, 285 WPARAM wparam,
183 LPARAM lparam) { 286 LPARAM lparam) {
184 if (message != WM_DISPLAYCHANGE) 287 if (message != WM_DISPLAYCHANGE)
185 return; 288 return;
186 289
187 std::vector<gfx::Display> old_displays = displays_; 290 std::vector<gfx::Display> old_displays = displays_;
188 displays_ = GetDisplays(); 291 displays_ = GetDisplays();
189 292
190 change_notifier_.NotifyDisplaysChanged(old_displays, displays_); 293 change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
191 } 294 }
192 295
193 HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const { 296 HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const {
194 NOTREACHED(); 297 NOTREACHED();
195 return NULL; 298 return NULL;
196 } 299 }
197 300
198 NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { 301 NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
199 NOTREACHED(); 302 NOTREACHED();
200 return NULL; 303 return NULL;
201 } 304 }
202 305
203 } // namespace gfx 306 } // namespace gfx
OLDNEW
« ui/gfx/screen_win.h ('K') | « ui/gfx/screen_win.h ('k') | ui/gfx/win/dpi.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698