1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/display/unified_mouse_warp_controller.h"
9 #include "ash/display/display_util.h"
10 #include "ash/display/mirror_window_controller.h"
11 #include "ash/display/mouse_cursor_event_filter.h"
12 #include "ash/host/ash_window_tree_host.h"
13 #include "ash/shell.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ui/aura/env.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/display/display.h"
18 #include "ui/display/display_finder.h"
19 #include "ui/display/manager/display_manager.h"
20 #include "ui/display/screen.h"
21 #include "ui/events/test/event_generator.h"
22 #include "ui/wm/core/coordinate_conversion.h"
29 // Native point at a warp edge before warping.
30 gfx::Point native_point_at_edge;
32 // Expected DIP point after warping.
33 gfx::Point expected_point_after_warp;
35 // Expected display ID after warping.
36 int64_t expected_target_display_id;
41 class UnifiedMouseWarpControllerTest : public AshTestBase {
43 UnifiedMouseWarpControllerTest() = default;
45 UnifiedMouseWarpControllerTest(const UnifiedMouseWarpControllerTest&) =
47 UnifiedMouseWarpControllerTest& operator=(
48 const UnifiedMouseWarpControllerTest&) = delete;
50 ~UnifiedMouseWarpControllerTest() override = default;
52 void SetUp() override {
54 display_manager()->SetUnifiedDesktopEnabled(true);
58 bool MoveMouseToNativePoint(const gfx::Point& point_in_native,
59 int64_t* out_original_mirroring_display_id) {
60 for (auto display : display_manager()->software_mirroring_display_list()) {
61 display::ManagedDisplayInfo info =
62 display_manager()->GetDisplayInfo(display.id());
63 if (info.bounds_in_native().Contains(point_in_native)) {
64 *out_original_mirroring_display_id = info.id();
65 gfx::Point point_in_mirroring_host = point_in_native;
66 const gfx::Point& origin = info.bounds_in_native().origin();
67 // Convert to mirroring host.
68 point_in_mirroring_host.Offset(-origin.x(), -origin.y());
70 // Move the mouse inside the host.
71 AshWindowTreeHost* ash_host =
73 ->window_tree_host_manager()
74 ->mirror_window_controller()
75 ->GetAshWindowTreeHostForDisplayId(info.id());
76 ui::test::EventGenerator gen(ash_host->AsWindowTreeHost()->window());
77 gen.MoveMouseToWithNative(point_in_mirroring_host,
78 point_in_mirroring_host);
85 bool TestIfMouseWarpsAt(const gfx::Point& point_in_native) {
86 static_cast<UnifiedMouseWarpController*>(
87 Shell::Get()->mouse_cursor_filter()->mouse_warp_controller_for_test())
88 ->update_location_for_test();
89 int64_t orig_mirroring_display_id;
90 if (!MoveMouseToNativePoint(point_in_native, &orig_mirroring_display_id))
93 aura::Window* root = Shell::GetPrimaryRootWindow();
94 gfx::Point new_location_in_unified_host =
95 aura::Env::GetInstance()->last_mouse_location();
96 // Convert screen to the host.
97 root->GetHost()->ConvertDIPToPixels(&new_location_in_unified_host);
99 auto iter = display::FindDisplayContainingPoint(
100 display_manager()->software_mirroring_display_list(),
101 new_location_in_unified_host);
102 if (iter == display_manager()->software_mirroring_display_list().end())
104 return orig_mirroring_display_id != iter->id();
107 MouseCursorEventFilter* event_filter() {
108 return Shell::Get()->mouse_cursor_filter();
111 UnifiedMouseWarpController* mouse_warp_controller() {
112 return static_cast<UnifiedMouseWarpController*>(
113 event_filter()->mouse_warp_controller_for_test());
116 // |expected_edges| should have a row for each display which contains the
117 // expected native bounds of the shared edges with that display in the order
118 // "top", "left", "right", "bottom".
119 // If |matrix| is empty, default unified layout will be used.
120 void BoundaryTestBody(
121 const std::string& displays_specs,
122 const display::UnifiedDesktopLayoutMatrix& matrix,
123 const std::vector<std::vector<std::string>>& expected_edges) {
124 UpdateDisplay(displays_specs);
125 display_manager()->SetUnifiedDesktopMatrix(matrix);
127 // Let the UnifiedMouseWarpController compute the bounds by
128 // generating a mouse move event.
129 GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
130 const display::Displays& mirroring_displays =
131 display_manager()->software_mirroring_display_list();
133 ASSERT_EQ(expected_edges.size(), mirroring_displays.size());
135 for (const auto& display : mirroring_displays) {
136 const int64_t id = display.id();
137 std::stringstream scoped_trace_message;
138 scoped_trace_message << "Edges of display with ID: " << id
139 << " at index: " << index;
140 SCOPED_TRACE(scoped_trace_message.str());
141 const auto& display_expected_edges = expected_edges[index++];
142 const auto& display_actual_edges =
143 mouse_warp_controller()->displays_edges_map_.at(id);
144 ASSERT_EQ(display_expected_edges.size(), display_actual_edges.size());
145 for (size_t i = 0; i < display_expected_edges.size(); ++i) {
146 EXPECT_EQ(display_expected_edges[i],
147 display_actual_edges[i]
148 .edge_native_bounds_in_source_display.ToString());
153 void WarpTestBody(const std::vector<WarpGroup>& warp_groups) {
154 for (const auto& group : warp_groups) {
155 EXPECT_TRUE(TestIfMouseWarpsAt(group.native_point_at_edge));
157 gfx::Point new_location = aura::Env::GetInstance()->last_mouse_location();
158 EXPECT_EQ(group.expected_point_after_warp, new_location);
160 // Convert screen to the host.
161 aura::Window* root = Shell::GetPrimaryRootWindow();
162 root->GetHost()->ConvertDIPToPixels(&new_location);
164 auto iter = display::FindDisplayContainingPoint(
165 display_manager()->software_mirroring_display_list(), new_location);
167 display_manager()->software_mirroring_display_list().end());
168 EXPECT_EQ(group.expected_target_display_id, iter->id());
172 void NoWarpTestBody() {
173 // Touch the left edge of the first display.
174 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(0, 10)));
175 // Touch the top edge of the first display.
176 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 0)));
177 // Touch the bottom edge of the first display.
178 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 499)));
180 // Touch the right edge of the second display.
181 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(1099, 10)));
182 // Touch the top edge of the second display.
183 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(610, 0)));
184 // Touch the bottom edge of the second display.
185 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(610, 499)));
189 // Verifies if MouseCursorEventFilter's bounds calculation works correctly.
190 TEST_F(UnifiedMouseWarpControllerTest, BoundaryTest) {
193 BoundaryTestBody("500x400,0+450-700x400",
194 {}, // Empty matrix (use horizontal layout).
195 {{"499,0 1x400"}, {"0,450 1x400"}});
196 BoundaryTestBody("500x400,0+450-700x600",
197 {}, // Empty matrix (use horizontal layout).
198 {{"499,0 1x400"}, {"0,450 1x600"}});
202 BoundaryTestBody("500x400*2,0+450-700x400",
203 {}, // Empty matrix (use horizontal layout).
204 {{"499,0 1x400"}, {"0,450 1x400"}});
205 BoundaryTestBody("500x400*2,0+450-700x600",
206 {}, // Empty matrix (use horizontal layout).
207 {{"499,0 1x400"}, {"0,450 1x600"}});
211 BoundaryTestBody("500x400,0+450-700x400*2",
212 {}, // Empty matrix (use horizontal layout).
213 {{"499,0 1x400"}, {"0,450 1x400"}});
214 BoundaryTestBody("500x400,0+450-700x600*2",
215 {}, // Empty matrix (use horizontal layout).
216 {{"499,0 1x400"}, {"0,450 1x600"}});
220 BoundaryTestBody("500x400*2,0+450-700x400*2",
221 {}, // Empty matrix (use horizontal layout).
222 {{"499,0 1x400"}, {"0,450 1x400"}});
223 BoundaryTestBody("500x400*2,0+450-700x600*2",
224 {}, // Empty matrix (use horizontal layout).
225 {{"499,0 1x400"}, {"0,450 1x600"}});
229 TEST_F(UnifiedMouseWarpControllerTest, BoundaryAndWarpSimpleTest) {
230 const std::vector<std::vector<std::string>> expected_edges = {
233 "1919,0 1x1080", // Right with display 1.
237 "1930,0 1x1200", // Left with display 0.
241 BoundaryTestBody("0+0-1920x1080,1930+0-1920x1200",
242 {} /* empty matrix = default */, expected_edges);
244 display::DisplayIdList list = display_manager()->GetConnectedDisplayIdList();
245 ASSERT_EQ(2u, list.size());
247 // Assert mouse warps in all bounds to the correct display.
248 const std::vector<WarpGroup> warp_groups = {
249 {{1919, 500}, {1920, 499}, list[1]}, // Display 0 --> 1.
250 {{1930, 600}, {1918, 540}, list[0]}, // Display 1 --> 0.
252 WarpTestBody(warp_groups);
255 TEST_F(UnifiedMouseWarpControllerTest, BoundaryTestGrid) {
256 // Update displays here first so we get the correct display IDs list. The
257 // below are the native bounds.
258 const std::string display_specs =
259 "0+0-500x300,510+0-400x500,920+0-300x600,"
260 "0+600-200x300,210+600-700x200,920+600-350x480,"
261 "0+1080-300x500,310+1080-600x599,920+1080-400x450";
262 UpdateDisplay(display_specs);
263 display_manager()->SetUnifiedDesktopEnabled(true);
264 display::DisplayIdList list = display_manager()->GetConnectedDisplayIdList();
265 ASSERT_EQ(9u, list.size());
267 // Test a very general case of a 3 x 3 matrix.
268 // 0:[500 x 300] 1:[400 x 500] 2:[300 x 600]
269 // 3:[200 x 300] 4:[700 x 200] 5:[350 x 480]
270 // 6:[300 x 500] 7:[600 x 599] 8:[400 x 450]
271 display::UnifiedDesktopLayoutMatrix matrix;
273 matrix[0].emplace_back(list[0]);
274 matrix[0].emplace_back(list[1]);
275 matrix[0].emplace_back(list[2]);
276 matrix[1].emplace_back(list[3]);
277 matrix[1].emplace_back(list[4]);
278 matrix[1].emplace_back(list[5]);
279 matrix[2].emplace_back(list[6]);
280 matrix[2].emplace_back(list[7]);
281 matrix[2].emplace_back(list[8]);
283 const std::vector<std::vector<std::string>> expected_edges = {
286 "499,0 1x300", // Right with display 1.
287 "0,299 121x1", // Bottom with display 3.
288 "121,299 379x1", // Bottom with display 4.
292 "510,0 1x500", // Left with display 0.
293 "909,0 1x500", // Right with display 2.
294 "510,499 400x1", // Bottom with display 4.
298 "920,0 1x600", // Left with display 1.
299 "920,599 34x1", // Bottom with display 4.
300 "954,599 266x1", // Bottom with display 5.
304 "0,600 199x1", // Top with display 0.
305 "199,600 1x300", // Right with display 4.
306 "0,899 199x1", // Bottom with display 6.
310 "210,600 416x1", // Top with display 0.
311 "626,600 264x1", // Top with display 1.
312 "890,600 18x1", // Top with display 2.
313 "210,600 1x200", // Left with display 3.
314 "909,600 1x200", // Right with display 5.
315 "210,799 102x1", // Bottom with display 6.
316 "312,799 393x1", // Bottom with display 7.
317 "705,799 203x1", // Bottom with display 8.
321 "920,600 350x1", // Top with display 2.
322 "920,600 1x480", // Left with display 4.
323 "920,1079 350x1", // Bottom with display 8.
327 "0,1080 169x1", // Top with display 3.
328 "169,1080 130x1", // Top with display 4.
329 "299,1080 1x500", // Right with display 7.
333 "310,1080 600x1", // Top with display 4.
334 "310,1080 1x599", // Left with display 6.
335 "909,1080 1x599", // Right with display 8.
339 "920,1080 233x1", // Top with display 4.
340 "1153,1080 167x1", // Top with display 5.
341 "920,1080 1x450", // Left with display 7.
345 BoundaryTestBody(display_specs, matrix, expected_edges);
347 ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
349 // Assert mouse warps in all bounds to the correct display.
350 const std::vector<WarpGroup> warp_groups = {
351 {{499, 10}, {500, 9}, list[1]}, // Display 0 --> 1.
352 {{10, 299}, {9, 300}, list[3]}, // Display 0 --> 3.
353 {{130, 299}, {129, 300}, list[4]}, // Display 0 --> 4.
355 {{510, 10}, {498, 6}, list[0]}, // Display 1 --> 0.
356 {{909, 50}, {740, 30}, list[2]}, // Display 1 --> 2.
357 {{600, 499}, {553, 300}, list[4]}, // Display 1 --> 4.
359 {{920, 50}, {738, 24}, list[1]}, // Display 2 --> 1.
360 {{930, 599}, {744, 300}, list[4]}, // Display 2 --> 4.
361 {{970, 599}, {764, 300}, list[5]}, // Display 2 --> 5.
363 {{10, 600}, {6, 298}, list[0]}, // Display 3 --> 0.
364 {{199, 700}, {121, 359}, list[4]}, // Display 3 --> 4.
365 {{100, 899}, {59, 482}, list[6]}, // Display 3 --> 6.
367 {{250, 600}, {157, 298}, list[0]}, // Display 4 --> 0.
368 {{700, 600}, {566, 298}, list[1]}, // Display 4 --> 1.
369 {{900, 600}, {748, 299}, list[2]}, // Display 4 --> 2.
370 {{210, 700}, {120, 391}, list[3]}, // Display 4 --> 3.
371 {{909, 650}, {757, 344}, list[5]}, // Display 4 --> 5.
372 {{250, 799}, {156, 482}, list[6]}, // Display 4 --> 6.
373 {{500, 799}, {383, 482}, list[7]}, // Display 4 --> 7.
374 {{800, 799}, {656, 482}, list[8]}, // Display 4 --> 8.
376 {{950, 600}, {768, 299}, list[2]}, // Display 5 --> 2.
377 {{920, 750}, {756, 355}, list[4]}, // Display 5 --> 4.
378 {{1000, 1079}, {786, 482}, list[8]}, // Display 5 --> 8.
380 {{100, 1080}, {70, 480}, list[3]}, // Display 6 --> 3.
381 {{200, 1080}, {141, 480}, list[4]}, // Display 6 --> 4.
382 {{299, 1200}, {214, 566}, list[7]}, // Display 6 --> 7.
384 {{500, 1080}, {326, 480}, list[4]}, // Display 7 --> 4.
385 {{310, 1500}, {212, 731}, list[6]}, // Display 7 --> 6.
386 {{909, 1500}, {572, 731}, list[8]}, // Display 7 --> 8.
388 {{1000, 1080}, {634, 480}, list[4]}, // Display 8 --> 4.
389 {{1200, 1080}, {793, 481}, list[5]}, // Display 8 --> 5.
390 {{920, 1500}, {570, 814}, list[7]}, // Display 8 --> 7.
392 WarpTestBody(warp_groups);
395 // Verifies if the mouse pointer correctly moves to another display in
396 // unified desktop mode.
397 TEST_F(UnifiedMouseWarpControllerTest, WarpMouse) {
398 UpdateDisplay("600x500,700+0-600x500");
399 ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
401 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10)));
402 // Touch the right edge of the first display. Pointer should warp.
403 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(599, 10)));
404 EXPECT_EQ("601,10", // by 2px.
405 aura::Env::GetInstance()->last_mouse_location().ToString());
407 // Touch the left edge of the second display. Pointer should warp.
408 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(700, 10)));
409 EXPECT_EQ("598,10", // by 2px.
410 aura::Env::GetInstance()->last_mouse_location().ToString());
412 SCOPED_TRACE("1x1 NO WARP");
416 // With 2X and 1X displays
417 UpdateDisplay("600x500*2,700+0-600x500");
418 ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
420 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10)));
421 // Touch the right edge of the first display. Pointer should warp.
422 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(599, 10)));
423 EXPECT_EQ("300,5", // moved to 601 by 2px, divided by 2 (dsf).
424 aura::Env::GetInstance()->last_mouse_location().ToString());
426 // Touch the left edge of the second display. Pointer should warp.
427 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(700, 10)));
428 EXPECT_EQ("299,5", // moved to 598 by 2px, divided by 2 (dsf).
429 aura::Env::GetInstance()->last_mouse_location().ToString());
432 SCOPED_TRACE("2x1 NO WARP");
436 // With 1X and 2X displays
437 UpdateDisplay("600x500,700+0-600x500*2");
438 ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
440 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10)));
441 // Touch the right edge of the first display. Pointer should warp.
442 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(599, 10)));
443 EXPECT_EQ("601,10", // by 2px.
444 aura::Env::GetInstance()->last_mouse_location().ToString());
446 // Touch the left edge of the second display. Pointer should warp.
447 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(700, 10)));
448 EXPECT_EQ("598,10", // by 2px.
449 aura::Env::GetInstance()->last_mouse_location().ToString());
451 SCOPED_TRACE("1x2 NO WARP");
455 // With two 2X displays
456 UpdateDisplay("600x500*2,700+0-600x500*2");
457 ASSERT_EQ(1, display::Screen::GetScreen()->GetNumDisplays());
459 EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10)));
460 // Touch the right edge of the first display. Pointer should warp.
461 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(599, 10)));
462 EXPECT_EQ("300,5", // by 2px.
463 aura::Env::GetInstance()->last_mouse_location().ToString());
465 // Touch the left edge of the second display. Pointer should warp.
466 EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(700, 10)));
467 EXPECT_EQ("299,5", // moved to 598 by 2px, divided by 2 (dsf).
468 aura::Env::GetInstance()->last_mouse_location().ToString());
470 SCOPED_TRACE("1x2 NO WARP");