summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
authorrobliao <robliao@chromium.org>2016-02-08 15:08:59 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-08 23:10:24 +0000
commiteb17ae163b2ba4a2a67cd88a25b349249ed63f71 (patch)
treed13113581b539403b500ac5f3abb86ac75b5586c /ui/gfx
parent1e6df47dc783fdd43019576db1d7a86253c531a9 (diff)
downloadchromium_src-eb17ae163b2ba4a2a67cd88a25b349249ed63f71.zip
chromium_src-eb17ae163b2ba4a2a67cd88a25b349249ed63f71.tar.gz
chromium_src-eb17ae163b2ba4a2a67cd88a25b349249ed63f71.tar.bz2
ScreenWin Testability and Restructuring
To allow easier testing of ScreenWin, this CL restructures ScreenWin to allow override of system OS calls through virtual methods as well as override the available displays available in the system. This CL also adds support to hold system pixel display rects that will be used by multi-DPI aware scaling coming in a later CL. BUG=426656 Committed: https://crrev.com/663b48643605198c21bfb8b8f81968223833021f Cr-Commit-Position: refs/heads/master@{#373582} Review URL: https://codereview.chromium.org/1639623003 Cr-Commit-Position: refs/heads/master@{#374208}
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/BUILD.gn5
-rw-r--r--ui/gfx/display.h5
-rw-r--r--ui/gfx/gfx.gyp5
-rw-r--r--ui/gfx/screen_win.cc245
-rw-r--r--ui/gfx/screen_win.h59
-rw-r--r--ui/gfx/screen_win_unittest.cc611
-rw-r--r--ui/gfx/test/display_util.h23
-rw-r--r--ui/gfx/test/gfx_util.cc5
-rw-r--r--ui/gfx/win/display_info.cc60
-rw-r--r--ui/gfx/win/display_info.h44
-rw-r--r--ui/gfx/win/screen_win_display.cc38
-rw-r--r--ui/gfx/win/screen_win_display.h36
12 files changed, 997 insertions, 139 deletions
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index b640d21..a2edb90 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -214,6 +214,8 @@ component("gfx") {
"win/direct_manipulation.h",
"win/direct_write.cc",
"win/direct_write.h",
+ "win/display_info.cc",
+ "win/display_info.h",
"win/dpi.cc",
"win/dpi.h",
"win/hwnd_util.cc",
@@ -221,6 +223,8 @@ component("gfx") {
"win/physical_size.cc",
"win/physical_size.h",
"win/scoped_set_map_mode.h",
+ "win/screen_win_display.cc",
+ "win/screen_win_display.h",
"win/singleton_hwnd.cc",
"win/singleton_hwnd.h",
"win/singleton_hwnd_observer.cc",
@@ -594,6 +598,7 @@ source_set("test_support") {
"image/image_unittest_util.h",
"image/image_unittest_util_ios.mm",
"image/image_unittest_util_mac.mm",
+ "test/display_util.h",
"test/fontconfig_util_linux.cc",
"test/fontconfig_util_linux.h",
"test/gfx_util.cc",
diff --git a/ui/gfx/display.h b/ui/gfx/display.h
index 6076e49..a3bb0a8 100644
--- a/ui/gfx/display.h
+++ b/ui/gfx/display.h
@@ -154,6 +154,11 @@ class GFX_EXPORT Display final {
TouchSupport touch_support_;
};
+// This is declared here for use in gtest-based unit tests but is defined in
+// the gfx_test_support target. Depend on that to use this in your unit test.
+// This should not be used in production code - call ToString() instead.
+void PrintTo(const Display& display, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_DISPLAY_H_
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index c2bb097..a9c20d8 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -308,6 +308,8 @@
'win/direct_manipulation.h',
'win/direct_write.cc',
'win/direct_write.h',
+ 'win/display_info.cc',
+ 'win/display_info.h',
'win/dpi.cc',
'win/dpi.h',
'win/hwnd_util.cc',
@@ -315,6 +317,8 @@
"win/physical_size.cc",
"win/physical_size.h",
'win/scoped_set_map_mode.h',
+ 'win/screen_win_display.cc',
+ 'win/screen_win_display.h',
'win/singleton_hwnd.cc',
'win/singleton_hwnd.h',
'win/singleton_hwnd_observer.cc',
@@ -525,6 +529,7 @@
'image/image_unittest_util.h',
'image/image_unittest_util_ios.mm',
'image/image_unittest_util_mac.mm',
+ 'test/display_util.h',
'test/fontconfig_util_linux.cc',
'test/fontconfig_util_linux.h',
'test/gfx_util.cc',
diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc
index 3199f7a..46bce43 100644
--- a/ui/gfx/screen_win.cc
+++ b/ui/gfx/screen_win.cc
@@ -5,118 +5,97 @@
#include "ui/gfx/screen_win.h"
#include <windows.h>
-#include <stdint.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/hash.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/win_util.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/win/display_info.h"
#include "ui/gfx/win/dpi.h"
+#include "ui/gfx/win/screen_win_display.h"
namespace {
-MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) {
- MONITORINFOEX monitor_info;
- ZeroMemory(&monitor_info, sizeof(MONITORINFOEX));
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(monitor, &monitor_info);
- return monitor_info;
+std::vector<gfx::win::ScreenWinDisplay> DisplayInfosToScreenWinDisplays(
+ const std::vector<gfx::win::DisplayInfo>& display_infos) {
+ std::vector<gfx::win::ScreenWinDisplay> screen_win_displays;
+ for (const auto& display_info : display_infos)
+ screen_win_displays.push_back(gfx::win::ScreenWinDisplay(display_info));
+
+ return screen_win_displays;
}
-gfx::Display GetDisplay(const MONITORINFOEX& monitor_info) {
- int64_t id =
- static_cast<int64_t>(base::Hash(base::WideToUTF8(monitor_info.szDevice)));
- gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor);
- gfx::Display display(id);
- display.set_bounds(gfx::win::ScreenToDIPRect(bounds));
- display.set_work_area(
- gfx::win::ScreenToDIPRect(gfx::Rect(monitor_info.rcWork)));
- display.SetScaleAndBounds(gfx::GetDPIScale(), bounds);
-
- DEVMODE mode;
- memset(&mode, 0, sizeof(DEVMODE));
- mode.dmSize = sizeof(DEVMODE);
- mode.dmDriverExtra = 0;
- if (EnumDisplaySettings(monitor_info.szDevice,
- ENUM_CURRENT_SETTINGS,
- &mode)) {
- switch (mode.dmDisplayOrientation) {
- case DMDO_DEFAULT:
- display.set_rotation(gfx::Display::ROTATE_0);
- break;
- case DMDO_90:
- display.set_rotation(gfx::Display::ROTATE_90);
- break;
- case DMDO_180:
- display.set_rotation(gfx::Display::ROTATE_180);
- break;
- case DMDO_270:
- display.set_rotation(gfx::Display::ROTATE_270);
- break;
- default:
- NOTREACHED();
- }
- }
+std::vector<gfx::Display> ScreenWinDisplaysToDisplays(
+ const std::vector<gfx::win::ScreenWinDisplay>& screen_win_displays) {
+ std::vector<gfx::Display> displays;
+ for (const auto& screen_win_display : screen_win_displays)
+ displays.push_back(screen_win_display.display());
- return display;
+ return displays;
+}
+
+MONITORINFOEX MonitorInfoFromHMONITOR(HMONITOR monitor) {
+ MONITORINFOEX monitor_info;
+ ::ZeroMemory(&monitor_info, sizeof(monitor_info));
+ monitor_info.cbSize = sizeof(monitor_info);
+ ::GetMonitorInfo(monitor, &monitor_info);
+ return monitor_info;
}
BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor,
HDC hdc,
LPRECT rect,
LPARAM data) {
- std::vector<gfx::Display>* all_displays =
- reinterpret_cast<std::vector<gfx::Display>*>(data);
- DCHECK(all_displays);
-
- MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor);
- gfx::Display display = GetDisplay(monitor_info);
- all_displays->push_back(display);
+ std::vector<gfx::win::DisplayInfo>* display_infos =
+ reinterpret_cast<std::vector<gfx::win::DisplayInfo>*>(data);
+ DCHECK(display_infos);
+ display_infos->push_back(
+ gfx::win::DisplayInfo(MonitorInfoFromHMONITOR(monitor),
+ gfx::GetDPIScale()));
return TRUE;
}
-std::vector<gfx::Display> GetDisplays() {
- std::vector<gfx::Display> displays;
- EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback,
- reinterpret_cast<LPARAM>(&displays));
- return displays;
+std::vector<gfx::win::DisplayInfo> GetDisplayInfosFromSystem() {
+ std::vector<gfx::win::DisplayInfo> display_infos;
+ EnumDisplayMonitors(nullptr, nullptr, EnumMonitorCallback,
+ reinterpret_cast<LPARAM>(&display_infos));
+ DCHECK_EQ(static_cast<size_t>(::GetSystemMetrics(SM_CMONITORS)),
+ display_infos.size());
+ return display_infos;
}
} // namespace
namespace gfx {
-ScreenWin::ScreenWin()
- : singleton_hwnd_observer_(new SingletonHwndObserver(
- base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))),
- displays_(GetDisplays()) {
+ScreenWin::ScreenWin() {
+ Initialize();
}
-ScreenWin::~ScreenWin() {}
+ScreenWin::~ScreenWin() = default;
HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const {
NOTREACHED();
- return NULL;
+ return nullptr;
}
NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
NOTREACHED();
- return NULL;
+ return nullptr;
}
gfx::Point ScreenWin::GetCursorScreenPoint() {
POINT pt;
- GetCursorPos(&pt);
+ ::GetCursorPos(&pt);
gfx::Point cursor_pos_pixels(pt);
return gfx::win::ScreenToDIPPoint(cursor_pos_pixels);
}
gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
POINT cursor_loc;
- HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL;
+ HWND hwnd =
+ ::GetCursorPos(&cursor_loc) ? ::WindowFromPoint(cursor_loc) : nullptr;
return GetNativeWindowFromHWND(hwnd);
}
@@ -126,11 +105,11 @@ gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) {
}
int ScreenWin::GetNumDisplays() const {
- return GetSystemMetrics(SM_CMONITORS);
+ return static_cast<int>(screen_win_displays_.size());
}
std::vector<gfx::Display> ScreenWin::GetAllDisplays() const {
- return displays_;
+ return ScreenWinDisplaysToDisplays(screen_win_displays_);
}
gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
@@ -141,45 +120,26 @@ gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
// scaling factor.
return GetPrimaryDisplay();
}
-
- MONITORINFOEX monitor_info;
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST),
- &monitor_info);
- return GetDisplay(monitor_info);
+ gfx::win::ScreenWinDisplay screen_win_display =
+ GetScreenWinDisplayNearestHWND(window_hwnd);
+ return screen_win_display.display();
}
gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
- gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
- POINT initial_loc = { point_in_pixels.x(), point_in_pixels.y() };
- HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST);
- MONITORINFOEX mi;
- ZeroMemory(&mi, sizeof(MONITORINFOEX));
- mi.cbSize = sizeof(mi);
- if (monitor && GetMonitorInfo(monitor, &mi)) {
- return GetDisplay(mi);
- }
- return gfx::Display();
+ gfx::Point screen_point(gfx::win::DIPToScreenPoint(point));
+ gfx::win::ScreenWinDisplay screen_win_display =
+ GetScreenWinDisplayNearestScreenPoint(screen_point);
+ return screen_win_display.display();
}
gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const {
- RECT other_bounds_rect = match_rect.ToRECT();
- MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
- &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
- return GetDisplay(monitor_info);
+ gfx::win::ScreenWinDisplay screen_win_display =
+ GetScreenWinDisplayNearestScreenRect(match_rect);
+ return screen_win_display.display();
}
gfx::Display ScreenWin::GetPrimaryDisplay() const {
- MONITORINFOEX mi = GetMonitorInfoForMonitor(
- MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY));
- gfx::Display display = GetDisplay(mi);
- // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
- // once more of the app is DIP-aware.
- if (GetDPIScale() == 1.0) {
- DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
- DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
- }
- return display;
+ return GetPrimaryScreenWinDisplay().display();
}
void ScreenWin::AddObserver(DisplayObserver* observer) {
@@ -190,6 +150,41 @@ void ScreenWin::RemoveObserver(DisplayObserver* observer) {
change_notifier_.RemoveObserver(observer);
}
+void ScreenWin::UpdateFromDisplayInfos(
+ const std::vector<gfx::win::DisplayInfo>& display_infos) {
+ screen_win_displays_ = DisplayInfosToScreenWinDisplays(display_infos);
+}
+
+void ScreenWin::Initialize() {
+ singleton_hwnd_observer_.reset(
+ new gfx::SingletonHwndObserver(
+ base::Bind(&ScreenWin::OnWndProc, base::Unretained(this))));
+ UpdateFromDisplayInfos(GetDisplayInfosFromSystem());
+}
+
+MONITORINFOEX ScreenWin::MonitorInfoFromScreenPoint(
+ const gfx::Point& screen_point) const {
+ POINT initial_loc = { screen_point.x(), screen_point.y() };
+ return MonitorInfoFromHMONITOR(::MonitorFromPoint(initial_loc,
+ MONITOR_DEFAULTTONEAREST));
+}
+
+MONITORINFOEX ScreenWin::MonitorInfoFromScreenRect(const gfx::Rect& screen_rect)
+ const {
+ RECT win_rect = screen_rect.ToRECT();
+ return MonitorInfoFromHMONITOR(::MonitorFromRect(&win_rect,
+ MONITOR_DEFAULTTONEAREST));
+}
+
+MONITORINFOEX ScreenWin::MonitorInfoFromWindow(HWND hwnd,
+ DWORD default_options) const {
+ return MonitorInfoFromHMONITOR(::MonitorFromWindow(hwnd, default_options));
+}
+
+HWND ScreenWin::GetRootWindow(HWND hwnd) const {
+ return ::GetAncestor(hwnd, GA_ROOT);
+}
+
void ScreenWin::OnWndProc(HWND hwnd,
UINT message,
WPARAM wparam,
@@ -197,20 +192,52 @@ void ScreenWin::OnWndProc(HWND hwnd,
if (message != WM_DISPLAYCHANGE)
return;
- std::vector<gfx::Display> old_displays = displays_;
- displays_ = GetDisplays();
+ std::vector<gfx::Display> old_displays = GetAllDisplays();
+ UpdateFromDisplayInfos(GetDisplayInfosFromSystem());
+ change_notifier_.NotifyDisplaysChanged(old_displays, GetAllDisplays());
+}
- change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
+gfx::win::ScreenWinDisplay ScreenWin::GetScreenWinDisplayNearestHWND(HWND hwnd)
+ const {
+ return GetScreenWinDisplay(MonitorInfoFromWindow(hwnd,
+ MONITOR_DEFAULTTONEAREST));
}
-// static
-std::vector<gfx::Display> ScreenWin::GetDisplaysForMonitorInfos(
- const std::vector<MONITORINFOEX>& monitor_infos) {
- std::vector<gfx::Display> displays;
- for (const MONITORINFOEX& monitor_info : monitor_infos)
- displays.push_back(GetDisplay(monitor_info));
+gfx::win::ScreenWinDisplay ScreenWin::GetScreenWinDisplayNearestScreenRect(
+ const Rect& screen_rect) const {
+ return GetScreenWinDisplay(MonitorInfoFromScreenRect(screen_rect));
+}
- return displays;
+gfx::win::ScreenWinDisplay ScreenWin::GetScreenWinDisplayNearestScreenPoint(
+ const Point& screen_point) const {
+ return GetScreenWinDisplay(MonitorInfoFromScreenPoint(screen_point));
+}
+
+gfx::win::ScreenWinDisplay ScreenWin::GetPrimaryScreenWinDisplay() const {
+ MONITORINFOEX monitor_info = MonitorInfoFromWindow(nullptr,
+ MONITOR_DEFAULTTOPRIMARY);
+ gfx::win::ScreenWinDisplay screen_win_display =
+ GetScreenWinDisplay(monitor_info);
+ gfx::Display display = screen_win_display.display();
+ // The Windows primary monitor is defined to have an origin of (0, 0).
+ DCHECK_EQ(0, display.bounds().origin().x());
+ DCHECK_EQ(0, display.bounds().origin().y());
+ return screen_win_display;
+}
+
+gfx::win::ScreenWinDisplay ScreenWin::GetScreenWinDisplay(
+ const MONITORINFOEX& monitor_info) const {
+ int64_t id =
+ gfx::win::DisplayInfo::DeviceIdFromDeviceName(monitor_info.szDevice);
+ for (const auto& screen_win_display : screen_win_displays_) {
+ if (screen_win_display.display().id() == id)
+ return screen_win_display;
+ }
+ // There is 1:1 correspondence between MONITORINFOEX and ScreenWinDisplay.
+ // If we make it here, it means we have no displays and we should hand out the
+ // default display.
+ DCHECK_EQ(screen_win_displays_.size(), 0u);
+ return gfx::win::ScreenWinDisplay();
}
} // namespace gfx
diff --git a/ui/gfx/screen_win.h b/ui/gfx/screen_win.h
index b1488ae..2849e66 100644
--- a/ui/gfx/screen_win.h
+++ b/ui/gfx/screen_win.h
@@ -5,17 +5,30 @@
#ifndef UI_GFX_SCREEN_WIN_H_
#define UI_GFX_SCREEN_WIN_H_
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
+#include <windows.h>
+
+#include <vector>
+
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "ui/gfx/display_change_notifier.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
namespace gfx {
+class Display;
+class Point;
+class Rect;
+
+namespace win {
+
+class DisplayInfo;
+class ScreenWinDisplay;
+
+} // namespace win
+
class GFX_EXPORT ScreenWin : public Screen {
public:
ScreenWin();
@@ -28,7 +41,7 @@ class GFX_EXPORT ScreenWin : public Screen {
virtual NativeWindow GetNativeWindowFromHWND(HWND hwnd) const;
protected:
- // Overridden from gfx::Screen:
+ // gfx::Screen:
gfx::Point GetCursorScreenPoint() override;
gfx::NativeWindow GetWindowUnderCursor() override;
gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override;
@@ -41,22 +54,46 @@ class GFX_EXPORT ScreenWin : public Screen {
void AddObserver(DisplayObserver* observer) override;
void RemoveObserver(DisplayObserver* observer) override;
- private:
- FRIEND_TEST_ALL_PREFIXES(ScreenWinTest, SingleDisplay1x);
- FRIEND_TEST_ALL_PREFIXES(ScreenWinTest, SingleDisplay2x);
+ void UpdateFromDisplayInfos(
+ const std::vector<gfx::win::DisplayInfo>& display_infos);
+ // Virtual to support mocking by unit tests.
+ virtual void Initialize();
+ virtual MONITORINFOEX MonitorInfoFromScreenPoint(
+ const gfx::Point& screen_point) const;
+ virtual MONITORINFOEX MonitorInfoFromScreenRect(const gfx::Rect& screen_rect)
+ const;
+ virtual MONITORINFOEX MonitorInfoFromWindow(HWND hwnd, DWORD default_options)
+ const;
+ virtual HWND GetRootWindow(HWND hwnd) const;
+
+ private:
void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
- static std::vector<gfx::Display> GetDisplaysForMonitorInfos(
- const std::vector<MONITORINFOEX>& monitor_infos);
+ // Returns the ScreenWinDisplay closest to or enclosing |hwnd|.
+ gfx::win::ScreenWinDisplay GetScreenWinDisplayNearestHWND(HWND hwnd) const;
+
+ // Returns the ScreenWinDisplay closest to or enclosing |screen_rect|.
+ gfx::win::ScreenWinDisplay GetScreenWinDisplayNearestScreenRect(
+ const Rect& screen_rect) const;
+
+ // Returns the ScreenWinDisplay closest to or enclosing |screen_point|.
+ gfx::win::ScreenWinDisplay GetScreenWinDisplayNearestScreenPoint(
+ const Point& screen_point) const;
+
+ // Returns the ScreenWinDisplay corresponding to the primary monitor.
+ gfx::win::ScreenWinDisplay GetPrimaryScreenWinDisplay() const;
+
+ gfx::win::ScreenWinDisplay GetScreenWinDisplay(
+ const MONITORINFOEX& monitor_info) const;
// Helper implementing the DisplayObserver handling.
gfx::DisplayChangeNotifier change_notifier_;
scoped_ptr<SingletonHwndObserver> singleton_hwnd_observer_;
- // Current list of displays.
- std::vector<gfx::Display> displays_;
+ // Current list of ScreenWinDisplays.
+ std::vector<gfx::win::ScreenWinDisplay> screen_win_displays_;
DISALLOW_COPY_AND_ASSIGN(ScreenWin);
};
diff --git a/ui/gfx/screen_win_unittest.cc b/ui/gfx/screen_win_unittest.cc
index b1118c1..e011c94 100644
--- a/ui/gfx/screen_win_unittest.cc
+++ b/ui/gfx/screen_win_unittest.cc
@@ -4,17 +4,25 @@
#include "ui/gfx/screen_win.h"
+#include <windows.h>
+#include <inttypes.h>
+#include <stddef.h>
+
#include <cwchar>
+#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
-#include <windows.h>
-#include <stddef.h>
-
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/display.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/screen.h"
+#include "ui/gfx/test/display_util.h"
+#include "ui/gfx/win/display_info.h"
#include "ui/gfx/win/dpi.h"
+#include "ui/gfx/win/screen_win_display.h"
namespace gfx {
@@ -34,47 +42,612 @@ MONITORINFOEX CreateMonitorInfo(gfx::Rect monitor,
return monitor_info;
}
+class TestScreenWin : public gfx::ScreenWin {
+ public:
+ TestScreenWin(const std::vector<gfx::win::DisplayInfo>& display_infos,
+ const std::vector<MONITORINFOEX>& monitor_infos,
+ const std::unordered_map<HWND, gfx::Rect>& hwnd_map)
+ : monitor_infos_(monitor_infos),
+ hwnd_map_(hwnd_map) {
+ UpdateFromDisplayInfos(display_infos);
+ }
+
+ ~TestScreenWin() = default;
+
+ protected:
+ // gfx::ScreenWin:
+ HWND GetHWNDFromNativeView(NativeView window) const override {
+ // NativeView is only used as an identifier in this tests, so interchange
+ // NativeView with an HWND for convenience.
+ return reinterpret_cast<HWND>(window);
+ }
+
+ NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override {
+ // NativeWindow is only used as an identifier in this tests, so interchange
+ // an HWND for a NativeWindow for convenience.
+ return reinterpret_cast<NativeWindow>(hwnd);
+ }
+
+ private:
+ void Initialize() override {}
+
+ MONITORINFOEX MonitorInfoFromScreenPoint(const gfx::Point& screen_point) const
+ override {
+ for (const MONITORINFOEX& monitor_info : monitor_infos_) {
+ if (gfx::Rect(monitor_info.rcMonitor).Contains(screen_point))
+ return monitor_info;
+ }
+ NOTREACHED();
+ return monitor_infos_[0];
+ }
+
+ MONITORINFOEX MonitorInfoFromScreenRect(const gfx::Rect& screen_rect) const
+ override {
+ MONITORINFOEX candidate = monitor_infos_[0];
+ int largest_area = 0;
+ for (const MONITORINFOEX& monitor_info : monitor_infos_) {
+ gfx::Rect bounds(monitor_info.rcMonitor);
+ if (bounds.Intersects(screen_rect)) {
+ bounds.Intersect(screen_rect);
+ int area = bounds.height() * bounds.width();
+ if (largest_area < area) {
+ candidate = monitor_info;
+ largest_area = area;
+ }
+ }
+ }
+ EXPECT_NE(largest_area, 0);
+ return candidate;
+ }
+
+ MONITORINFOEX MonitorInfoFromWindow(HWND hwnd, DWORD default_options)
+ const override {
+ auto search = hwnd_map_.find(hwnd);
+ if (search != hwnd_map_.end())
+ return MonitorInfoFromScreenRect(search->second);
+
+ EXPECT_EQ(default_options, MONITOR_DEFAULTTOPRIMARY);
+ for (const auto& monitor_info : monitor_infos_) {
+ if (monitor_info.rcMonitor.left == 0 &&
+ monitor_info.rcMonitor.top == 0) {
+ return monitor_info;
+ }
+ }
+ NOTREACHED();
+ return monitor_infos_[0];
+ }
+
+ HWND GetRootWindow(HWND hwnd) const override {
+ return hwnd;
+ }
+
+ std::vector<MONITORINFOEX> monitor_infos_;
+ std::unordered_map<HWND, gfx::Rect> hwnd_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestScreenWin);
+};
+
+Screen* GetScreen() {
+ return gfx::Screen::GetScreen();
+}
+
} // namespace
-class ScreenWinTest : public testing::Test {
+// Allows tests to specify the screen and associated state.
+class TestScreenWinInitializer {
+ public:
+ virtual void AddMonitor(const gfx::Rect& pixel_bounds,
+ const gfx::Rect& pixel_work,
+ const wchar_t* device_name,
+ float device_scale_factor) = 0;
+
+ virtual HWND CreateFakeHwnd(const gfx::Rect& bounds) = 0;
+};
+
+class TestScreenWinManager : public TestScreenWinInitializer {
+ public:
+ TestScreenWinManager() = default;
+
+ ~TestScreenWinManager() {
+ gfx::Screen::SetScreenInstance(nullptr);
+ }
+
+ void AddMonitor(const gfx::Rect& pixel_bounds,
+ const gfx::Rect& pixel_work,
+ const wchar_t* device_name,
+ float device_scale_factor) override {
+ MONITORINFOEX monitor_info = CreateMonitorInfo(pixel_bounds,
+ pixel_work,
+ device_name);
+ monitor_infos_.push_back(monitor_info);
+ display_infos_.push_back(gfx::win::DisplayInfo(monitor_info,
+ device_scale_factor,
+ gfx::Display::ROTATE_0));
+ }
+
+ HWND CreateFakeHwnd(const gfx::Rect& bounds) override {
+ EXPECT_EQ(screen_win_, nullptr);
+ hwnd_map_.insert(std::pair<HWND, gfx::Rect>(++hwndLast_, bounds));
+ return hwndLast_;
+ }
+
+ void InitializeScreenWin() {
+ ASSERT_EQ(screen_win_, nullptr);
+ screen_win_.reset(new TestScreenWin(display_infos_,
+ monitor_infos_,
+ hwnd_map_));
+ gfx::Screen::SetScreenInstance(screen_win_.get());
+ }
+
+ ScreenWin* GetScreenWin() {
+ return screen_win_.get();
+ }
+
private:
+ HWND hwndLast_ = nullptr;
+ scoped_ptr<ScreenWin> screen_win_;
+ std::vector<MONITORINFOEX> monitor_infos_;
+ std::vector<gfx::win::DisplayInfo> display_infos_;
+ std::unordered_map<HWND, gfx::Rect> hwnd_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestScreenWinManager);
+};
+
+class ScreenWinTest : public testing::Test {
+ protected:
+ ScreenWinTest() = default;
+
void SetUp() override {
testing::Test::SetUp();
gfx::SetDefaultDeviceScaleFactor(1.0);
+ screen_win_initializer_.reset(new TestScreenWinManager());
+ SetUpScreen(screen_win_initializer_.get());
+ screen_win_initializer_->InitializeScreenWin();
}
void TearDown() override {
+ screen_win_initializer_.reset();
gfx::SetDefaultDeviceScaleFactor(1.0);
testing::Test::TearDown();
}
+
+ virtual void SetUpScreen(TestScreenWinInitializer* initializer) = 0;
+
+ NativeWindow GetNativeWindowFromHWND(HWND hwnd) const {
+ ScreenWin* screen_win = screen_win_initializer_->GetScreenWin();
+ return screen_win->GetNativeWindowFromHWND(hwnd);;
+ }
+
+ private:
+ scoped_ptr<TestScreenWinManager> screen_win_initializer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenWinTest);
};
-TEST_F(ScreenWinTest, SingleDisplay1x) {
- std::vector<MONITORINFOEX> monitor_infos;
- monitor_infos.push_back(CreateMonitorInfo(gfx::Rect(0, 0, 1920, 1200),
- gfx::Rect(0, 0, 1920, 1100),
- L"primary"));
- std::vector<gfx::Display> displays =
- ScreenWin::GetDisplaysForMonitorInfos(monitor_infos);
+// Single Display of 1.0 Device Scale Factor.
+class ScreenWinTestSingleDisplay1x : public ScreenWinTest {
+ public:
+ ScreenWinTestSingleDisplay1x() = default;
+
+ void SetUpScreen(TestScreenWinInitializer* initializer) override {
+ initializer->AddMonitor(gfx::Rect(0, 0, 1920, 1200),
+ gfx::Rect(0, 0, 1920, 1100),
+ L"primary",
+ 1.0);
+ fake_hwnd_ = initializer->CreateFakeHwnd(gfx::Rect(0, 0, 1920, 1100));
+ }
+ HWND GetFakeHwnd() {
+ return fake_hwnd_;
+ }
+
+ private:
+ HWND fake_hwnd_ = nullptr;
+};
+
+TEST_F(ScreenWinTestSingleDisplay1x, GetDisplays) {
+ std::vector<gfx::Display> displays = GetScreen()->GetAllDisplays();
ASSERT_EQ(1u, displays.size());
EXPECT_EQ(gfx::Rect(0, 0, 1920, 1200), displays[0].bounds());
EXPECT_EQ(gfx::Rect(0, 0, 1920, 1100), displays[0].work_area());
}
-TEST_F(ScreenWinTest, SingleDisplay2x) {
- gfx::SetDefaultDeviceScaleFactor(2.0);
+TEST_F(ScreenWinTestSingleDisplay1x, GetNumDisplays) {
+ EXPECT_EQ(1, GetScreen()->GetNumDisplays());
+}
- std::vector<MONITORINFOEX> monitor_infos;
- monitor_infos.push_back(CreateMonitorInfo(gfx::Rect(0, 0, 1920, 1200),
- gfx::Rect(0, 0, 1920, 1100),
- L"primary"));
- std::vector<gfx::Display> displays =
- ScreenWin::GetDisplaysForMonitorInfos(monitor_infos);
+TEST_F(ScreenWinTestSingleDisplay1x, GetDisplayNearestWindowPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ EXPECT_EQ(screen->GetPrimaryDisplay(),
+ screen->GetDisplayNearestWindow(nullptr));
+}
+
+TEST_F(ScreenWinTestSingleDisplay1x, GetDisplayNearestWindow) {
+ gfx::Screen* screen = GetScreen();
+ gfx::NativeWindow native_window = GetNativeWindowFromHWND(GetFakeHwnd());
+ EXPECT_EQ(screen->GetAllDisplays()[0],
+ screen->GetDisplayNearestWindow(native_window));
+}
+
+TEST_F(ScreenWinTestSingleDisplay1x, GetDisplayNearestPoint) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display display = screen->GetAllDisplays()[0];
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(0, 0)));
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(250, 952)));
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(1919, 1199)));
+}
+TEST_F(ScreenWinTestSingleDisplay1x, GetDisplayMatching) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display display = screen->GetAllDisplays()[0];
+ EXPECT_EQ(display, screen->GetDisplayMatching(gfx::Rect(0, 0, 100, 100)));
+ EXPECT_EQ(display,
+ screen->GetDisplayMatching(gfx::Rect(1819, 1099, 100, 100)));
+}
+
+TEST_F(ScreenWinTestSingleDisplay1x, GetPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ EXPECT_EQ(gfx::Point(0, 0), screen->GetPrimaryDisplay().bounds().origin());
+}
+
+// Single Display of 2.0 Device Scale Factor.
+class ScreenWinTestSingleDisplay2x : public ScreenWinTest {
+ public:
+ ScreenWinTestSingleDisplay2x() = default;
+
+ void SetUpScreen(TestScreenWinInitializer* initializer) override {
+ gfx::SetDefaultDeviceScaleFactor(2.0);
+ initializer->AddMonitor(gfx::Rect(0, 0, 1920, 1200),
+ gfx::Rect(0, 0, 1920, 1100),
+ L"primary",
+ 2.0);
+ fake_hwnd_ = initializer->CreateFakeHwnd(gfx::Rect(0, 0, 1920, 1100));
+ }
+
+ HWND GetFakeHwnd() {
+ return fake_hwnd_;
+ }
+
+ private:
+ HWND fake_hwnd_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenWinTestSingleDisplay2x);
+};
+
+TEST_F(ScreenWinTestSingleDisplay2x, GetDisplays) {
+ std::vector<gfx::Display> displays = GetScreen()->GetAllDisplays();
ASSERT_EQ(1u, displays.size());
EXPECT_EQ(gfx::Rect(0, 0, 960, 600), displays[0].bounds());
EXPECT_EQ(gfx::Rect(0, 0, 960, 550), displays[0].work_area());
}
+TEST_F(ScreenWinTestSingleDisplay2x, GetDisplayNearestPoint) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display display = screen->GetAllDisplays()[0];
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(0, 0)));
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(125, 476)));
+ EXPECT_EQ(display, screen->GetDisplayNearestPoint(gfx::Point(959, 599)));
+}
+
+TEST_F(ScreenWinTestSingleDisplay2x, GetDisplayMatching) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display display = screen->GetAllDisplays()[0];
+ EXPECT_EQ(display, screen->GetDisplayMatching(gfx::Rect(0, 0, 100, 100)));
+ EXPECT_EQ(display,
+ screen->GetDisplayMatching(gfx::Rect(1819, 1099, 100, 100)));
+}
+
+// Two Displays of 1.0 Device Scale Factor.
+class ScreenWinTestTwoDisplays1x : public ScreenWinTest {
+ public:
+ ScreenWinTestTwoDisplays1x() = default;
+
+ void SetUpScreen(TestScreenWinInitializer* initializer) override {
+ initializer->AddMonitor(gfx::Rect(0, 0, 1920, 1200),
+ gfx::Rect(0, 0, 1920, 1100),
+ L"primary",
+ 1.0);
+ initializer->AddMonitor(gfx::Rect(1920, 0, 800, 600),
+ gfx::Rect(1920, 0, 800, 600),
+ L"secondary",
+ 1.0);
+ fake_hwnd_left_ = initializer->CreateFakeHwnd(gfx::Rect(0, 0, 1920, 1100));
+ fake_hwnd_right_ =
+ initializer->CreateFakeHwnd(gfx::Rect(1920, 0, 800, 600));
+ }
+
+ HWND GetLeftFakeHwnd() {
+ return fake_hwnd_left_;
+ }
+
+ HWND GetRightFakeHwnd() {
+ return fake_hwnd_right_;
+ }
+
+ private:
+ HWND fake_hwnd_left_ = nullptr;
+ HWND fake_hwnd_right_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenWinTestTwoDisplays1x);
+};
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetDisplays) {
+ std::vector<gfx::Display> displays = GetScreen()->GetAllDisplays();
+ ASSERT_EQ(2u, displays.size());
+ EXPECT_EQ(gfx::Rect(0, 0, 1920, 1200), displays[0].bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 1920, 1100), displays[0].work_area());
+ EXPECT_EQ(gfx::Rect(1920, 0, 800, 600), displays[1].bounds());
+ EXPECT_EQ(gfx::Rect(1920, 0, 800, 600), displays[1].work_area());
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetNumDisplays) {
+ EXPECT_EQ(2, GetScreen()->GetNumDisplays());
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetDisplayNearestWindowPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ EXPECT_EQ(screen->GetPrimaryDisplay(),
+ screen->GetDisplayNearestWindow(nullptr));
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetDisplayNearestWindow) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ gfx::NativeWindow left_window = GetNativeWindowFromHWND(GetLeftFakeHwnd());
+ EXPECT_EQ(left_display, screen->GetDisplayNearestWindow(left_window));
+
+ gfx::NativeWindow right_window = GetNativeWindowFromHWND(GetRightFakeHwnd());
+ EXPECT_EQ(right_display, screen->GetDisplayNearestWindow(right_window));
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetDisplayNearestPoint) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(0, 0)));
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(250, 952)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayNearestPoint(gfx::Point(1919, 1199)));
+
+ EXPECT_EQ(right_display, screen->GetDisplayNearestPoint(gfx::Point(1920, 0)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(2000, 400)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(2719, 599)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetDisplayMatching) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(0, 0, 100, 100)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(1819, 1099, 100, 100)));
+
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(1920, 0, 100, 100)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(2619, 499, 100, 100)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays1x, GetPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display primary = screen->GetPrimaryDisplay();
+ EXPECT_EQ(gfx::Point(0, 0), primary.bounds().origin());
+}
+
+// Two Displays of 2.0 Device Scale Factor.
+class ScreenWinTestTwoDisplays2x : public ScreenWinTest {
+ public:
+ ScreenWinTestTwoDisplays2x() = default;
+
+ void SetUpScreen(TestScreenWinInitializer* initializer) override {
+ gfx::SetDefaultDeviceScaleFactor(2.0);
+ initializer->AddMonitor(gfx::Rect(0, 0, 1920, 1200),
+ gfx::Rect(0, 0, 1920, 1100),
+ L"primary",
+ 2.0);
+ initializer->AddMonitor(gfx::Rect(1920, 0, 800, 600),
+ gfx::Rect(1920, 0, 800, 600),
+ L"secondary",
+ 2.0);
+ fake_hwnd_left_ = initializer->CreateFakeHwnd(gfx::Rect(0, 0, 1920, 1100));
+ fake_hwnd_right_ =
+ initializer->CreateFakeHwnd(gfx::Rect(1920, 0, 800, 600));
+ }
+
+ HWND GetLeftFakeHwnd() {
+ return fake_hwnd_left_;
+ }
+
+ HWND GetRightFakeHwnd() {
+ return fake_hwnd_right_;
+ }
+
+ private:
+ HWND fake_hwnd_left_ = nullptr;
+ HWND fake_hwnd_right_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenWinTestTwoDisplays2x);
+};
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetDisplays) {
+ std::vector<gfx::Display> displays = GetScreen()->GetAllDisplays();
+ ASSERT_EQ(2u, displays.size());
+ EXPECT_EQ(gfx::Rect(0, 0, 960, 600), displays[0].bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 960, 550), displays[0].work_area());
+ EXPECT_EQ(gfx::Rect(960, 0, 400, 300), displays[1].bounds());
+ EXPECT_EQ(gfx::Rect(960, 0, 400, 300), displays[1].work_area());
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetDisplayNearestWindowPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ EXPECT_EQ(screen->GetPrimaryDisplay(),
+ screen->GetDisplayNearestWindow(nullptr));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetDisplayNearestWindow) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ gfx::NativeWindow left_window = GetNativeWindowFromHWND(GetLeftFakeHwnd());
+ EXPECT_EQ(left_display, screen->GetDisplayNearestWindow(left_window));
+
+ gfx::NativeWindow right_window = GetNativeWindowFromHWND(GetRightFakeHwnd());
+ EXPECT_EQ(right_display, screen->GetDisplayNearestWindow(right_window));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetDisplayNearestPoint) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(0, 0)));
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(125, 476)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayNearestPoint(gfx::Point(959, 599)));
+
+ EXPECT_EQ(right_display, screen->GetDisplayNearestPoint(gfx::Point(960, 0)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(1000, 200)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(1359, 299)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetDisplayMatching) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(0, 0, 100, 100)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(1819, 1099, 100, 100)));
+
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(1920, 0, 100, 100)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(2619, 499, 100, 100)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x, GetPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display primary = screen->GetPrimaryDisplay();
+ EXPECT_EQ(gfx::Point(0, 0), primary.bounds().origin());
+}
+
+// Two Displays of 2.0 (Left) and 1.0 (Right) Device Scale Factor under
+// Windows DPI Virtualization. Note that the displays do not form a euclidean
+// space.
+class ScreenWinTestTwoDisplays2x1xVirtualized : public ScreenWinTest {
+ public:
+ ScreenWinTestTwoDisplays2x1xVirtualized() = default;
+
+ void SetUpScreen(TestScreenWinInitializer* initializer) override {
+ gfx::SetDefaultDeviceScaleFactor(2.0);
+ initializer->AddMonitor(gfx::Rect(0, 0, 3200, 1600),
+ gfx::Rect(0, 0, 3200, 1500),
+ L"primary",
+ 2.0);
+ initializer->AddMonitor(gfx::Rect(6400, 0, 3840, 2400),
+ gfx::Rect(6400, 0, 3840, 2400),
+ L"secondary",
+ 2.0);
+ fake_hwnd_left_ = initializer->CreateFakeHwnd(gfx::Rect(0, 0, 3200, 1500));
+ fake_hwnd_right_ =
+ initializer->CreateFakeHwnd(gfx::Rect(6400, 0, 3840, 2400));
+ }
+
+ HWND GetLeftFakeHwnd() {
+ return fake_hwnd_left_;
+ }
+
+ HWND GetRightFakeHwnd() {
+ return fake_hwnd_right_;
+ }
+
+ private:
+ HWND fake_hwnd_left_ = nullptr;
+ HWND fake_hwnd_right_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenWinTestTwoDisplays2x1xVirtualized);
+};
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetDisplays) {
+ std::vector<gfx::Display> displays = GetScreen()->GetAllDisplays();
+ ASSERT_EQ(2u, displays.size());
+ EXPECT_EQ(gfx::Rect(0, 0, 1600, 800), displays[0].bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 1600, 750), displays[0].work_area());
+ EXPECT_EQ(gfx::Rect(3200, 0, 1920, 1200), displays[1].bounds());
+ EXPECT_EQ(gfx::Rect(3200, 0, 1920, 1200), displays[1].work_area());
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetNumDisplays) {
+ EXPECT_EQ(2, GetScreen()->GetNumDisplays());
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized,
+ GetDisplayNearestWindowPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ EXPECT_EQ(screen->GetPrimaryDisplay(),
+ screen->GetDisplayNearestWindow(nullptr));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetDisplayNearestWindow) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ gfx::NativeWindow left_window = GetNativeWindowFromHWND(GetLeftFakeHwnd());
+ EXPECT_EQ(left_display, screen->GetDisplayNearestWindow(left_window));
+
+ gfx::NativeWindow right_window = GetNativeWindowFromHWND(GetRightFakeHwnd());
+ EXPECT_EQ(right_display, screen->GetDisplayNearestWindow(right_window));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetDisplayNearestPoint) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(0, 0)));
+ EXPECT_EQ(left_display, screen->GetDisplayNearestPoint(gfx::Point(125, 476)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayNearestPoint(gfx::Point(1599, 799)));
+
+ EXPECT_EQ(right_display, screen->GetDisplayNearestPoint(gfx::Point(3200, 0)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(4000, 400)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayNearestPoint(gfx::Point(5119, 1199)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetDisplayMatching) {
+ gfx::Screen* screen = GetScreen();
+ const gfx::Display left_display = screen->GetAllDisplays()[0];
+ const gfx::Display right_display = screen->GetAllDisplays()[1];
+
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(0, 0, 100, 100)));
+ EXPECT_EQ(left_display,
+ screen->GetDisplayMatching(gfx::Rect(1819, 1099, 100, 100)));
+
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(6400, 0, 100, 100)));
+ EXPECT_EQ(right_display,
+ screen->GetDisplayMatching(gfx::Rect(10139, 2299, 100, 100)));
+}
+
+TEST_F(ScreenWinTestTwoDisplays2x1xVirtualized, GetPrimaryDisplay) {
+ gfx::Screen* screen = GetScreen();
+ gfx::Display primary = screen->GetPrimaryDisplay();
+ EXPECT_EQ(gfx::Point(0, 0), primary.bounds().origin());
+}
+
} // namespace gfx
diff --git a/ui/gfx/test/display_util.h b/ui/gfx/test/display_util.h
new file mode 100644
index 0000000..842af7f
--- /dev/null
+++ b/ui/gfx/test/display_util.h
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TEST_DISPLAY_UTIL_H_
+#define UI_GFX_TEST_DISPLAY_UTIL_H_
+
+#include "ui/gfx/display.h"
+
+namespace gfx {
+
+inline bool operator==(const gfx::Display& lhs, const gfx::Display& rhs) {
+ return lhs.id() == rhs.id() &&
+ lhs.bounds() == rhs.bounds() &&
+ lhs.work_area() == rhs.work_area() &&
+ lhs.device_scale_factor() == rhs.device_scale_factor() &&
+ lhs.rotation() == rhs.rotation() &&
+ lhs.touch_support() == rhs.touch_support();
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_TEST_DISPLAY_UTIL_H_
diff --git a/ui/gfx/test/gfx_util.cc b/ui/gfx/test/gfx_util.cc
index d8bf5f2..e2157fe 100644
--- a/ui/gfx/test/gfx_util.cc
+++ b/ui/gfx/test/gfx_util.cc
@@ -8,6 +8,7 @@
#include <sstream>
#include <string>
+#include "ui/gfx/display.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
@@ -95,6 +96,10 @@ void PrintTo(const BoxF& box, ::std::ostream* os) {
*os << box.ToString();
}
+void PrintTo(const Display& display, ::std::ostream* os) {
+ *os << display.ToString();
+}
+
void PrintTo(const Point& point, ::std::ostream* os) {
*os << point.ToString();
}
diff --git a/ui/gfx/win/display_info.cc b/ui/gfx/win/display_info.cc
new file mode 100644
index 0000000..4d65d91
--- /dev/null
+++ b/ui/gfx/win/display_info.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/win/display_info.h"
+
+#include "base/hash.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+gfx::Display::Rotation GetRotationForDevice(const wchar_t* device_name) {
+ DEVMODE mode;
+ ::ZeroMemory(&mode, sizeof(mode));
+ mode.dmSize = sizeof(mode);
+ mode.dmDriverExtra = 0;
+ if (::EnumDisplaySettings(device_name, ENUM_CURRENT_SETTINGS, &mode)) {
+ switch (mode.dmDisplayOrientation) {
+ case DMDO_DEFAULT:
+ return gfx::Display::ROTATE_0;
+ case DMDO_90:
+ return gfx::Display::ROTATE_90;
+ case DMDO_180:
+ return gfx::Display::ROTATE_180;
+ case DMDO_270:
+ return gfx::Display::ROTATE_270;
+ default:
+ NOTREACHED();
+ }
+ }
+ return gfx::Display::ROTATE_0;
+}
+
+} // namespace
+
+namespace gfx {
+namespace win {
+
+DisplayInfo::DisplayInfo(const MONITORINFOEX& monitor_info,
+ float device_scale_factor)
+ : DisplayInfo(monitor_info,
+ device_scale_factor,
+ GetRotationForDevice(monitor_info.szDevice)) {}
+
+DisplayInfo::DisplayInfo(const MONITORINFOEX& monitor_info,
+ float device_scale_factor,
+ gfx::Display::Rotation rotation)
+ : id_(DeviceIdFromDeviceName(monitor_info.szDevice)),
+ screen_rect_(monitor_info.rcMonitor),
+ screen_work_rect_(monitor_info.rcWork),
+ rotation_(rotation),
+ device_scale_factor_(device_scale_factor) {}
+
+// static
+int64_t DisplayInfo::DeviceIdFromDeviceName(const wchar_t* device_name) {
+ return static_cast<int64_t>(base::Hash(base::WideToUTF8(device_name)));
+}
+
+} // namespace win
+} // namespace gfx
diff --git a/ui/gfx/win/display_info.h b/ui/gfx/win/display_info.h
new file mode 100644
index 0000000..cd972df
--- /dev/null
+++ b/ui/gfx/win/display_info.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_WIN_DISPLAY_INFO_H_
+#define UI_GFX_WIN_DISPLAY_INFO_H_
+
+#include <windows.h>
+#include <stdint.h>
+
+#include "ui/gfx/display.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+namespace win {
+
+// Gathers the parameters necessary to create a gfx::win::ScreenWinDisplay.
+class GFX_EXPORT DisplayInfo final {
+ public:
+ DisplayInfo(const MONITORINFOEX& monitor_info, float device_scale_factor);
+ DisplayInfo(const MONITORINFOEX& monitor_info,
+ float device_scale_factor,
+ gfx::Display::Rotation rotation);
+
+ static int64_t DeviceIdFromDeviceName(const wchar_t* device_name);
+
+ int64_t id() const { return id_; }
+ gfx::Display::Rotation rotation() const { return rotation_; }
+ const gfx::Rect& screen_rect() const { return screen_rect_; }
+ const gfx::Rect& screen_work_rect() const { return screen_work_rect_; }
+ float device_scale_factor() const { return device_scale_factor_; }
+
+ private:
+ int64_t id_;
+ gfx::Display::Rotation rotation_;
+ gfx::Rect screen_rect_;
+ gfx::Rect screen_work_rect_;
+ float device_scale_factor_;
+};
+
+} // namespace win
+} // namespace gfx
+
+#endif // UI_GFX_WIN_DISPLAY_INFO_H_
diff --git a/ui/gfx/win/screen_win_display.cc b/ui/gfx/win/screen_win_display.cc
new file mode 100644
index 0000000..ccef28a
--- /dev/null
+++ b/ui/gfx/win/screen_win_display.cc
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/win/screen_win_display.h"
+
+#include "ui/gfx/win/display_info.h"
+#include "ui/gfx/win/dpi.h"
+
+namespace {
+
+gfx::Display CreateDisplayFromDisplayInfo(
+ const gfx::win::DisplayInfo& display_info) {
+ gfx::Display display(display_info.id());
+ gfx::Rect dip_screen_bounds(
+ gfx::win::ScreenToDIPRect(display_info.screen_rect()));
+ display.set_bounds(dip_screen_bounds);
+ display.set_work_area(
+ gfx::win::ScreenToDIPRect(display_info.screen_work_rect()));
+ display.SetScaleAndBounds(display_info.device_scale_factor(),
+ display_info.screen_rect());
+ display.set_rotation(display_info.rotation());
+ return display;
+}
+
+} // namespace
+
+namespace gfx {
+namespace win {
+
+ScreenWinDisplay::ScreenWinDisplay() = default;
+
+ScreenWinDisplay::ScreenWinDisplay(const DisplayInfo& display_info)
+ : display_(CreateDisplayFromDisplayInfo(display_info)),
+ pixel_bounds_(display_info.screen_rect()) {}
+
+} // namespace win
+} // namespace gfx
diff --git a/ui/gfx/win/screen_win_display.h b/ui/gfx/win/screen_win_display.h
new file mode 100644
index 0000000..07278c3
--- /dev/null
+++ b/ui/gfx/win/screen_win_display.h
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_WIN_SCREEN_WIN_DISPLAY_H_
+#define UI_GFX_WIN_SCREEN_WIN_DISPLAY_H_
+
+#include <windows.h>
+
+#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace gfx {
+namespace win {
+
+class DisplayInfo;
+
+// A display used by gfx::ScreenWin.
+// It holds a display and additional parameters used for DPI calculations.
+class ScreenWinDisplay final {
+ public:
+ ScreenWinDisplay();
+ explicit ScreenWinDisplay(const DisplayInfo& display_info);
+
+ const gfx::Display& display() const { return display_; }
+ const gfx::Rect& pixel_bounds() const { return pixel_bounds_; }
+
+ private:
+ gfx::Display display_;
+ gfx::Rect pixel_bounds_;
+};
+
+} // namespace win
+} // namespace gfx
+
+#endif // UI_GFX_WIN_SCREEN_WIN_DISPLAY_H_