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
5#include "ui/aura/window_targeter.h"
6
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/events/test/test_event_handler.h"
12
13namespace aura {
14
15// Always returns the same window.
16class StaticWindowTargeter : public ui::EventTargeter {
17 public:
18  explicit StaticWindowTargeter(aura::Window* window)
19      : window_(window) {}
20  virtual ~StaticWindowTargeter() {}
21
22 private:
23  // ui::EventTargeter:
24  virtual ui::EventTarget* FindTargetForLocatedEvent(
25      ui::EventTarget* root,
26      ui::LocatedEvent* event) OVERRIDE {
27    return window_;
28  }
29
30  Window* window_;
31
32  DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter);
33};
34
35class WindowTargeterTest : public test::AuraTestBase {
36 public:
37  WindowTargeterTest() {}
38  virtual ~WindowTargeterTest() {}
39
40  Window* root_window() { return AuraTestBase::root_window(); }
41};
42
43gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) {
44  gfx::RectF bounds = gfx::Rect(window->bounds().size());
45  Window* root = window->GetRootWindow();
46  CHECK(window->layer());
47  CHECK(root->layer());
48  gfx::Transform transform;
49  if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform))
50    return gfx::RectF();
51  transform.TransformRect(&bounds);
52  return bounds;
53}
54
55TEST_F(WindowTargeterTest, Basic) {
56  test::TestWindowDelegate delegate;
57  scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate));
58  Window* one = CreateNormalWindow(2, window.get(), &delegate);
59  Window* two = CreateNormalWindow(3, window.get(), &delegate);
60
61  window->SetBounds(gfx::Rect(0, 0, 100, 100));
62  one->SetBounds(gfx::Rect(0, 0, 500, 100));
63  two->SetBounds(gfx::Rect(501, 0, 500, 1000));
64
65  root_window()->Show();
66
67  ui::test::TestEventHandler handler;
68  one->AddPreTargetHandler(&handler);
69
70  ui::MouseEvent press(ui::ET_MOUSE_PRESSED,
71                       gfx::Point(20, 20),
72                       gfx::Point(20, 20),
73                       ui::EF_NONE,
74                       ui::EF_NONE);
75  DispatchEventUsingWindowDispatcher(&press);
76  EXPECT_EQ(1, handler.num_mouse_events());
77
78  handler.Reset();
79  DispatchEventUsingWindowDispatcher(&press);
80  EXPECT_EQ(1, handler.num_mouse_events());
81
82  one->RemovePreTargetHandler(&handler);
83}
84
85TEST_F(WindowTargeterTest, ScopedWindowTargeter) {
86  test::TestWindowDelegate delegate;
87  scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate));
88  Window* child = CreateNormalWindow(2, window.get(), &delegate);
89
90  window->SetBounds(gfx::Rect(30, 30, 100, 100));
91  child->SetBounds(gfx::Rect(20, 20, 50, 50));
92  root_window()->Show();
93
94  ui::EventTarget* root = root_window();
95  ui::EventTargeter* targeter = root->GetEventTargeter();
96
97  gfx::Point event_location(60, 60);
98  {
99    ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
100                         ui::EF_NONE, ui::EF_NONE);
101    EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
102  }
103
104  // Install a targeter on |window| so that the events never reach the child.
105  scoped_ptr<ScopedWindowTargeter> scoped_targeter(
106      new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>(
107          new StaticWindowTargeter(window.get()))));
108  {
109    ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
110                         ui::EF_NONE, ui::EF_NONE);
111    EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse));
112  }
113  scoped_targeter.reset();
114  {
115    ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
116                         ui::EF_NONE, ui::EF_NONE);
117    EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse));
118  }
119}
120
121// Test that ScopedWindowTargeter does not crash if the window for which it
122// replaces the targeter gets destroyed before it does.
123TEST_F(WindowTargeterTest, ScopedWindowTargeterWindowDestroyed) {
124  test::TestWindowDelegate delegate;
125  scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate));
126  scoped_ptr<ScopedWindowTargeter> scoped_targeter(
127      new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>(
128          new StaticWindowTargeter(window.get()))));
129
130  window.reset();
131  scoped_targeter.reset();
132
133  // We did not crash!
134}
135
136TEST_F(WindowTargeterTest, TargetTransformedWindow) {
137  root_window()->Show();
138
139  test::TestWindowDelegate delegate;
140  scoped_ptr<Window> window(CreateNormalWindow(2, root_window(), &delegate));
141
142  const gfx::Rect window_bounds(100, 20, 400, 80);
143  window->SetBounds(window_bounds);
144
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::EF_NONE, ui::EF_NONE);
151    EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
152  }
153
154  // Scale |window| by 50%. This should move it away from underneath
155  // |event_location|, so an event in that location will not be targeted to it.
156  gfx::Transform transform;
157  transform.Scale(0.5, 0.5);
158  window->SetTransform(transform);
159  EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(),
160            GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
161  {
162    ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
163                         ui::EF_NONE, ui::EF_NONE);
164    EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse));
165  }
166
167  transform = gfx::Transform();
168  transform.Translate(200, 10);
169  transform.Scale(0.5, 0.5);
170  window->SetTransform(transform);
171  EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(),
172            GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString());
173  {
174    ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
175                         ui::EF_NONE, ui::EF_NONE);
176    EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse));
177  }
178}
179
180}  // namespace aura
181