window_targeter_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright (c) 2013 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. #include "ui/aura/window_targeter.h"
  5. #include <utility>
  6. #include "base/memory/raw_ptr.h"
  7. #include "ui/aura/scoped_window_targeter.h"
  8. #include "ui/aura/test/aura_test_base.h"
  9. #include "ui/aura/test/test_window_delegate.h"
  10. #include "ui/aura/window.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/display/display.h"
  13. #include "ui/display/screen.h"
  14. #include "ui/events/event_utils.h"
  15. #include "ui/events/test/test_event_handler.h"
  16. namespace aura {
  17. // Always returns the same window.
  18. class StaticWindowTargeter : public WindowTargeter {
  19. public:
  20. explicit StaticWindowTargeter(aura::Window* window) : window_(window) {}
  21. StaticWindowTargeter(const StaticWindowTargeter&) = delete;
  22. StaticWindowTargeter& operator=(const StaticWindowTargeter&) = delete;
  23. ~StaticWindowTargeter() override {}
  24. private:
  25. // aura::WindowTargeter:
  26. Window* FindTargetForLocatedEvent(Window* window,
  27. ui::LocatedEvent* event) override {
  28. return window_;
  29. }
  30. raw_ptr<Window> window_;
  31. };
  32. gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) {
  33. gfx::RectF bounds = gfx::RectF(gfx::SizeF(window->bounds().size()));
  34. Window* root = window->GetRootWindow();
  35. CHECK(window->layer());
  36. CHECK(root->layer());
  37. gfx::Transform transform;
  38. if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform))
  39. return gfx::RectF();
  40. transform.TransformRect(&bounds);
  41. return bounds;
  42. }
  43. using WindowTargeterTest = test::AuraTestBase;
  44. TEST_F(WindowTargeterTest, Basic) {
  45. test::TestWindowDelegate delegate;
  46. std::unique_ptr<Window> window(
  47. CreateNormalWindow(1, root_window(), &delegate));
  48. Window* one = CreateNormalWindow(2, window.get(), &delegate);
  49. Window* two = CreateNormalWindow(3, window.get(), &delegate);
  50. window->SetBounds(gfx::Rect(0, 0, 1000, 1000));
  51. one->SetBounds(gfx::Rect(0, 0, 500, 100));
  52. two->SetBounds(gfx::Rect(501, 0, 500, 1000));
  53. root_window()->Show();
  54. ui::test::TestEventHandler handler;
  55. one->AddPreTargetHandler(&handler);
  56. ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(20, 20),
  57. gfx::Point(20, 20), ui::EventTimeForNow(), ui::EF_NONE,
  58. ui::EF_NONE);
  59. DispatchEventUsingWindowDispatcher(&press);
  60. EXPECT_EQ(1, handler.num_mouse_events());
  61. handler.Reset();
  62. DispatchEventUsingWindowDispatcher(&press);
  63. EXPECT_EQ(1, handler.num_mouse_events());
  64. one->RemovePreTargetHandler(&handler);
  65. }
  66. TEST_F(WindowTargeterTest, FindTargetInRootWindow) {
  67. WindowTargeter targeter;
  68. display::Display display =
  69. display::Screen::GetScreen()->GetDisplayNearestWindow(root_window());
  70. EXPECT_EQ(display.bounds(), root_window()->GetBoundsInScreen());
  71. // Mouse and touch presses inside the display yield null targets.
  72. gfx::Point inside = display.bounds().CenterPoint();
  73. ui::MouseEvent mouse1(ui::ET_MOUSE_PRESSED, inside, inside,
  74. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  75. ui::TouchEvent touch1(ui::ET_TOUCH_PRESSED, inside, ui::EventTimeForNow(),
  76. ui::PointerDetails());
  77. touch1.set_root_location(inside);
  78. EXPECT_EQ(nullptr, targeter.FindTargetInRootWindow(root_window(), mouse1));
  79. EXPECT_EQ(nullptr, targeter.FindTargetInRootWindow(root_window(), touch1));
  80. // Touch presses outside the display yields the root window as a target.
  81. gfx::Point outside(display.bounds().right() + 10, inside.y());
  82. ui::MouseEvent mouse2(ui::ET_MOUSE_PRESSED, outside, outside,
  83. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  84. ui::TouchEvent touch2(ui::ET_TOUCH_PRESSED, outside, ui::EventTimeForNow(),
  85. ui::PointerDetails());
  86. touch2.set_root_location(outside);
  87. EXPECT_EQ(nullptr, targeter.FindTargetInRootWindow(root_window(), mouse2));
  88. EXPECT_EQ(root_window(),
  89. targeter.FindTargetInRootWindow(root_window(), touch2));
  90. }
  91. TEST_F(WindowTargeterTest, ScopedWindowTargeter) {
  92. test::TestWindowDelegate delegate;
  93. std::unique_ptr<Window> window(
  94. CreateNormalWindow(1, root_window(), &delegate));
  95. Window* child = CreateNormalWindow(2, window.get(), &delegate);
  96. window->SetBounds(gfx::Rect(30, 30, 100, 100));
  97. child->SetBounds(gfx::Rect(20, 20, 50, 50));
  98. root_window()->Show();
  99. ui::EventTarget* root = root_window();
  100. ui::EventTargeter* targeter = root->GetEventTargeter();
  101. gfx::Point event_location(60, 60);
  102. {
  103. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  104. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  105. EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
  106. }
  107. // Install a targeter on |window| so that the events never reach the child.
  108. std::unique_ptr<ScopedWindowTargeter> scoped_targeter(
  109. new ScopedWindowTargeter(window.get(),
  110. std::unique_ptr<WindowTargeter>(
  111. new StaticWindowTargeter(window.get()))));
  112. {
  113. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  114. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  115. EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse));
  116. }
  117. scoped_targeter.reset();
  118. {
  119. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  120. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  121. EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
  122. }
  123. }
  124. // Test that ScopedWindowTargeter does not crash if the window for which it
  125. // replaces the targeter gets destroyed before it does.
  126. TEST_F(WindowTargeterTest, ScopedWindowTargeterWindowDestroyed) {
  127. test::TestWindowDelegate delegate;
  128. std::unique_ptr<Window> window(
  129. CreateNormalWindow(1, root_window(), &delegate));
  130. std::unique_ptr<ScopedWindowTargeter> scoped_targeter(
  131. new ScopedWindowTargeter(window.get(),
  132. std::unique_ptr<aura::WindowTargeter>(
  133. new StaticWindowTargeter(window.get()))));
  134. window.reset();
  135. scoped_targeter.reset();
  136. // We did not crash!
  137. }
  138. TEST_F(WindowTargeterTest, TargetTransformedWindow) {
  139. root_window()->Show();
  140. test::TestWindowDelegate delegate;
  141. std::unique_ptr<Window> window(
  142. CreateNormalWindow(2, root_window(), &delegate));
  143. const gfx::Rect window_bounds(100, 20, 400, 80);
  144. window->SetBounds(window_bounds);
  145. ui::EventTarget* root_target = root_window();
  146. ui::EventTargeter* targeter = root_target->GetEventTargeter();
  147. gfx::Point event_location(490, 50);
  148. {
  149. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  150. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  151. EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
  152. }
  153. // Scale |window| by 50%. This should move it away from underneath
  154. // |event_location|, so an event in that location will not be targeted to it.
  155. gfx::Transform transform;
  156. transform.Scale(0.5, 0.5);
  157. window->SetTransform(transform);
  158. EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(),
  159. GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
  160. {
  161. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  162. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  163. EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse));
  164. }
  165. transform = gfx::Transform();
  166. transform.Translate(200, 10);
  167. transform.Scale(0.5, 0.5);
  168. window->SetTransform(transform);
  169. EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(),
  170. GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
  171. {
  172. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  173. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  174. EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
  175. }
  176. }
  177. class IdCheckingEventTargeter : public WindowTargeter {
  178. public:
  179. explicit IdCheckingEventTargeter(int id) : id_(id) {}
  180. ~IdCheckingEventTargeter() override {}
  181. protected:
  182. // WindowTargeter:
  183. bool SubtreeShouldBeExploredForEvent(Window* window,
  184. const ui::LocatedEvent& event) override {
  185. return (window->GetId() == id_ &&
  186. WindowTargeter::SubtreeShouldBeExploredForEvent(window, event));
  187. }
  188. private:
  189. int id_;
  190. };
  191. TEST_F(WindowTargeterTest, Bounds) {
  192. test::TestWindowDelegate delegate;
  193. std::unique_ptr<Window> parent(
  194. CreateNormalWindow(1, root_window(), &delegate));
  195. std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
  196. std::unique_ptr<Window> grandchild(
  197. CreateNormalWindow(1, child.get(), &delegate));
  198. parent->SetBounds(gfx::Rect(0, 0, 30, 30));
  199. child->SetBounds(gfx::Rect(5, 5, 20, 20));
  200. grandchild->SetBounds(gfx::Rect(5, 5, 5, 5));
  201. ASSERT_EQ(1u, root_window()->children().size());
  202. ASSERT_EQ(1u, root_window()->children()[0]->children().size());
  203. ASSERT_EQ(1u, root_window()->children()[0]->children()[0]->children().size());
  204. Window* parent_r = root_window()->children()[0];
  205. Window* child_r = parent_r->children()[0];
  206. Window* grandchild_r = child_r->children()[0];
  207. ui::EventTarget* root_target = root_window();
  208. ui::EventTargeter* targeter = root_target->GetEventTargeter();
  209. // Dispatch a mouse event that falls on the parent, but not on the child. When
  210. // the default event-targeter used, the event will still reach |grandchild|,
  211. // because the default targeter does not look at the bounds.
  212. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1),
  213. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  214. EXPECT_EQ(parent_r, targeter->FindTargetForEvent(root_target, &mouse));
  215. // Install a targeter on the |child| that looks at the window id as well
  216. // as the bounds and makes sure the event reaches the target only if the id of
  217. // the window is equal to 2 (incorrect). This causes the event to get handled
  218. // by |parent|.
  219. ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
  220. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  221. std::unique_ptr<aura::WindowTargeter> original_targeter =
  222. child_r->SetEventTargeter(std::make_unique<IdCheckingEventTargeter>(2));
  223. EXPECT_EQ(parent_r, targeter->FindTargetForEvent(root_target, &mouse2));
  224. // Now install a targeter on the |child| that looks at the window id as well
  225. // as the bounds and makes sure the event reaches the target only if the id of
  226. // the window is equal to 1 (correct).
  227. ui::MouseEvent mouse3(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
  228. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  229. child_r->SetEventTargeter(std::make_unique<IdCheckingEventTargeter>(1));
  230. EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &mouse3));
  231. // restore original WindowTargeter for |child|.
  232. child_r->SetEventTargeter(std::move(original_targeter));
  233. // Target |grandchild| location.
  234. ui::MouseEvent second(ui::ET_MOUSE_MOVED, gfx::Point(12, 12),
  235. gfx::Point(12, 12), ui::EventTimeForNow(), ui::EF_NONE,
  236. ui::EF_NONE);
  237. EXPECT_EQ(grandchild_r, targeter->FindTargetForEvent(root_target, &second));
  238. // Target |child| location.
  239. ui::MouseEvent third(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
  240. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  241. EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &third));
  242. }
  243. TEST_F(WindowTargeterTest, NonFullyContainedBounds) {
  244. test::TestWindowDelegate delegate;
  245. std::unique_ptr<Window> parent(
  246. CreateNormalWindow(1, root_window(), &delegate));
  247. std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
  248. parent->SetBounds(gfx::Rect(0, 0, 30, 30));
  249. child->SetBounds(gfx::Rect(15, 15, 5, 100));
  250. auto* targeter =
  251. static_cast<ui::EventTarget*>(root_window())->GetEventTargeter();
  252. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75),
  253. gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE,
  254. ui::EF_NONE);
  255. EXPECT_EQ(child.get(), targeter->FindTargetForEvent(root_window(), &mouse));
  256. }
  257. TEST_F(WindowTargeterTest, NonFullyContainedBoundsWithMasksToBounds) {
  258. test::TestWindowDelegate delegate;
  259. std::unique_ptr<Window> parent(
  260. CreateNormalWindow(1, root_window(), &delegate));
  261. std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
  262. parent->SetBounds(gfx::Rect(0, 0, 30, 30));
  263. parent->layer()->SetMasksToBounds(true);
  264. child->SetBounds(gfx::Rect(15, 15, 5, 100));
  265. auto* targeter =
  266. static_cast<ui::EventTarget*>(root_window())->GetEventTargeter();
  267. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75),
  268. gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE,
  269. ui::EF_NONE);
  270. EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_window(), &mouse));
  271. }
  272. class IgnoreWindowTargeter : public WindowTargeter {
  273. public:
  274. IgnoreWindowTargeter() {}
  275. ~IgnoreWindowTargeter() override {}
  276. private:
  277. // WindowTargeter:
  278. bool SubtreeShouldBeExploredForEvent(Window* window,
  279. const ui::LocatedEvent& event) override {
  280. return false;
  281. }
  282. };
  283. // Verifies that an EventTargeter installed on an EventTarget can dictate
  284. // whether the target itself can process an event.
  285. TEST_F(WindowTargeterTest, TargeterChecksOwningEventTarget) {
  286. test::TestWindowDelegate delegate;
  287. std::unique_ptr<Window> child(
  288. CreateNormalWindow(1, root_window(), &delegate));
  289. ui::EventTarget* root_target = root_window();
  290. ui::EventTargeter* targeter = root_target->GetEventTargeter();
  291. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
  292. gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
  293. ui::EF_NONE);
  294. EXPECT_EQ(child.get(), targeter->FindTargetForEvent(root_target, &mouse));
  295. // Install an event targeter on |child| which always prevents the target from
  296. // receiving event.
  297. child->SetEventTargeter(std::make_unique<IgnoreWindowTargeter>());
  298. ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
  299. gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
  300. ui::EF_NONE);
  301. EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse2));
  302. }
  303. } // namespace aura