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

Side by Side Diff: ui/gfx/win/display_manager.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: Fixed Other Unit Tests - Moved Inner Classes Outside Created 4 years, 11 months 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
(Empty)
1 // Copyright 2016 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/display_manager.h"
6
7 #include <windows.h>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "ui/gfx/win/display_info.h"
14 #include "ui/gfx/win/display_manager_observer.h"
15 #include "ui/gfx/win/dpi.h"
16 #include "ui/gfx/win/rect_util.h"
17 #include "ui/gfx/win/screen_win_display.h"
18 #include "ui/gfx/win/singleton_hwnd_observer.h"
19
20 namespace {
21
22 // Use Leaky since gfx::ScreenWin is leaked at exit, and LazyInstance instead of
23 // Singleton allows for a substitution for testing.
24 base::LazyInstance<scoped_ptr<gfx::win::DisplayManager>>::Leaky
25 g_display_manager = LAZY_INSTANCE_INITIALIZER;
26
27 BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor,
28 HDC hdc,
29 LPRECT rect,
30 LPARAM data) {
31 std::vector<gfx::win::DisplayInfo>* display_infos =
32 reinterpret_cast<std::vector<gfx::win::DisplayInfo>*>(data);
33 DCHECK(display_infos);
34 display_infos->push_back(gfx::win::DisplayInfo(monitor, gfx::GetDPIScale()));
35 return TRUE;
36 }
37
38 // static
39 MONITORINFOEX MonitorInfoFromHMONITOR(HMONITOR monitor) {
40 MONITORINFOEX monitor_info;
41 ::ZeroMemory(&monitor_info, sizeof(monitor_info));
42 monitor_info.cbSize = sizeof(monitor_info);
43 ::GetMonitorInfo(monitor, &monitor_info);
44 return monitor_info;
45 }
46
47 std::vector<gfx::win::DisplayInfo> GetDisplayInfosFromSystem() {
48 std::vector<gfx::win::DisplayInfo> display_infos;
49 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback,
50 reinterpret_cast<LPARAM>(&display_infos));
51 return display_infos;
52 }
53
54 // static
55 std::vector<gfx::win::DisplayInfo>::const_iterator FindTouchingDisplayInfo(
56 const gfx::win::ScreenWinDisplay& screen_win_display,
57 const std::vector<gfx::win::DisplayInfo>& display_infos) {
58 auto end = display_infos.end();
59 for (auto display_info = display_infos.begin();
60 display_info != end;
61 display_info++) {
62 gfx::win::RectEdge edge =
63 gfx::win::RectTouch(screen_win_display.physical_bounds(),
64 display_info->screen_rect());
65 if (edge != gfx::win::RectEdge::NONE)
66 return display_info;
67 }
68 return end;
69 }
70
71 std::vector<gfx::win::ScreenWinDisplay> GetScreenWinDisplaysFromDisplayInfos(
72 const std::vector<gfx::win::DisplayInfo>& display_infos) {
73 std::vector<gfx::win::DisplayInfo> display_infos_remaining = display_infos;
74
75 // Seed the primary display to layout all the other displays.
76 std::vector<gfx::win::ScreenWinDisplay> screen_win_displays;
77 for (auto current = display_infos_remaining.begin();
78 current != display_infos_remaining.end();
79 current++) {
80 if (current->screen_rect().origin().IsOrigin()) {
81 screen_win_displays.push_back(gfx::win::ScreenWinDisplay(*current));
82 display_infos_remaining.erase(current);
83 break;
84 }
85 }
86
87 // Scale touching display_infos relative to each other.
88 size_t display_infos_at_cycle_start = 0;
89 while ((display_infos_remaining.size() > 0) &&
90 (display_infos_remaining.size() != display_infos_at_cycle_start)) {
91 display_infos_at_cycle_start = display_infos_remaining.size();
92 for (const auto& screen_win_display : screen_win_displays) {
93 auto display_info = FindTouchingDisplayInfo(screen_win_display,
94 display_infos_remaining);
95 if (display_info != display_infos_remaining.end()) {
96 screen_win_displays.push_back(
97 gfx::win::ScreenWinDisplay(screen_win_display, *display_info));
98 display_infos_remaining.erase(display_info);
99 break;
100 }
101 }
102 }
103
104 // Under Windows DPI virtualization, not all display_infos touch, so scale
105 // the remaining display infos relative to the origin.
106 for (const auto& display_info : display_infos_remaining) {
107 screen_win_displays.push_back(gfx::win::ScreenWinDisplay(display_info));
108 }
109
110 return screen_win_displays;
111 }
112
113 } // namespace
114
115 namespace gfx {
116 namespace win {
117
118 // static
119 DisplayManager* DisplayManager::GetInstance() {
120 if (!g_display_manager.Get().get()) {
121 g_display_manager.Get().reset(new DisplayManager());
122 }
123 return g_display_manager.Get().get();
124 }
125
126 void DisplayManager::AddObserver(DisplayManagerObserver* observer) {
127 observer_list_.AddObserver(observer);
128 }
129
130 void DisplayManager::RemoveObserver(DisplayManagerObserver* observer) {
131 observer_list_.RemoveObserver(observer);
132 }
133
134 const std::vector<ScreenWinDisplay>& DisplayManager::GetScreenWinDisplays() {
135 return screen_win_displays_;
136 }
137
138 ScreenWinDisplay DisplayManager::GetScreenWinDisplay(
139 const MONITORINFOEX& monitor_info) const {
140 int64_t id = DisplayInfo::HashDeviceName(monitor_info.szDevice);
141 for (const auto& screen_win_display : screen_win_displays_) {
142 if (screen_win_display.display().id() == id)
143 return screen_win_display;
144 }
145 // When the system isn't initialized, it means we're likely under a test.
146 DCHECK_EQ(screen_win_displays_.size(), 0u);
147 return ScreenWinDisplay();
148 }
149
150 ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestHWND(HWND hwnd)
151 const {
152 return GetScreenWinDisplay(MonitorInfoFromWindow(hwnd));
153 }
154
155 ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestScreenRect(
156 const Rect& screen_rect) const {
157 return GetScreenWinDisplay(MonitorInfoFromScreenRect(screen_rect));
158 }
159
160 ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestScreenPoint(
161 const Point& screen_point) const {
162 return GetScreenWinDisplay(MonitorInfoFromScreenPoint(screen_point));
163 }
164
165 ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestDIPRect(
166 const Rect& dip_rect) const {
167 ScreenWinDisplay closest_display_win;
168 int64_t closest_distance_squared = INT64_MAX;
169 for (const auto& display_win : screen_win_displays_) {
170 Display display = display_win.display();
171 gfx::Rect dip_bounds = display.bounds();
172 int64_t distance_squared =
173 SquaredDistanceBetweenRects(dip_rect, dip_bounds);
174 if (distance_squared == 0) {
175 return display_win;
176 } else if (distance_squared < closest_distance_squared) {
177 closest_distance_squared = distance_squared;
178 closest_display_win = display_win;
179 }
180 }
181 return closest_display_win;
182 }
183
184 ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestDIPPoint(
185 const Point& dip_point) const {
186 ScreenWinDisplay primary_display_win;
187 for (const auto& display_win : screen_win_displays_) {
188 Display display = display_win.display();
189 gfx::Rect dip_bounds = display.bounds();
190 if (dip_bounds.Contains(dip_point))
191 return display_win;
192 else if (dip_bounds.origin().IsOrigin())
193 primary_display_win = display_win;
194 }
195 return primary_display_win;
196 }
197
198 ScreenWinDisplay DisplayManager::GetPrimaryScreenWinDisplay() const {
199 MONITORINFOEX monitor_info =
200 MonitorInfoFromHMONITOR(MonitorFromWindow(NULL,
201 MONITOR_DEFAULTTOPRIMARY));
202 ScreenWinDisplay screen_win_display = GetScreenWinDisplay(monitor_info);
203 gfx::Display display = screen_win_display.display();
204 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
205 // once more of the app is DIP-aware.
206 if (display.device_scale_factor() == 1.0) {
207 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
208 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
209 }
210 return screen_win_display;
211 }
212
213 float DisplayManager::GetScaleFactorForHWND(HWND hwnd) const {
214 DCHECK(hwnd);
215 HWND rootHwnd = GetRootWindow(hwnd);
216 ScreenWinDisplay screen_win_display =
217 GetScreenWinDisplayNearestHWND(rootHwnd);
218 return screen_win_display.display().device_scale_factor();
219 }
220
221 float DisplayManager::GetScaleFactorForScreenPoint(const Point& screen_point)
222 const {
223 ScreenWinDisplay screen_win_display =
224 GetScreenWinDisplayNearestScreenPoint(screen_point);
225 return screen_win_display.display().device_scale_factor();
226 }
227
228 MONITORINFOEX DisplayManager::MonitorInfoFromScreenPoint(
229 const gfx::Point& screen_point) const {
230 POINT initial_loc = { screen_point.x(), screen_point.y() };
231 return MonitorInfoFromHMONITOR(::MonitorFromPoint(initial_loc,
232 MONITOR_DEFAULTTONEAREST));
233 }
234
235 MONITORINFOEX DisplayManager::MonitorInfoFromScreenRect(
236 const gfx::Rect& screen_rect) const {
237 RECT win_rect = screen_rect.ToRECT();
238 return MonitorInfoFromHMONITOR(::MonitorFromRect(&win_rect,
239 MONITOR_DEFAULTTONEAREST));
240 }
241
242 MONITORINFOEX DisplayManager::MonitorInfoFromWindow(HWND hwnd) const {
243 return MonitorInfoFromHMONITOR(::MonitorFromWindow(hwnd,
244 MONITOR_DEFAULTTONEAREST));
245 }
246
247 HWND DisplayManager::GetRootWindow(HWND hwnd) const {
248 return GetAncestor(hwnd, GA_ROOT);
249 }
250
251 // static
252 void DisplayManager::SetInstanceForTesting(
253 scoped_ptr<DisplayManager> display_manager) {
254 g_display_manager.Get() = std::move(display_manager);
255 }
256
257 DisplayManager::DisplayManager() {
258 singleton_hwnd_observer_.reset(
259 new gfx::SingletonHwndObserver(
260 base::Bind(&DisplayManager::WndProc, base::Unretained(this))));
261 UpdateFromDisplayInfos(GetDisplayInfosFromSystem());
262 }
263
264 DisplayManager::~DisplayManager() = default;
265
266 void DisplayManager::UpdateFromDisplayInfos(
267 const std::vector<DisplayInfo>& display_infos) {
268 screen_win_displays_ = GetScreenWinDisplaysFromDisplayInfos(display_infos);
269 }
270
271 void DisplayManager::WndProc(HWND hwnd,
272 UINT message,
273 WPARAM wparam,LPARAM lparam) {
274 if (message != WM_DISPLAYCHANGE)
275 return;
276
277 std::vector<ScreenWinDisplay> old_displays = screen_win_displays_;
278 UpdateFromDisplayInfos(GetDisplayInfosFromSystem());
279
280 FOR_EACH_OBSERVER(DisplayManagerObserver,
281 observer_list_,
282 OnDisplaysChanged(old_displays, screen_win_displays_));
283 }
284
285 } // namespace win
286 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698