Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / ui / views / view_targeter_unittest.cc
blobe72618340cbcfbe4724a0dbe7437596f07008645
1 // Copyright 2014 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.
5 #include "ui/views/view_targeter.h"
7 #include "ui/events/event_targeter.h"
8 #include "ui/events/event_utils.h"
9 #include "ui/gfx/path.h"
10 #include "ui/views/masked_view_targeter.h"
11 #include "ui/views/test/views_test_base.h"
12 #include "ui/views/widget/root_view.h"
14 namespace views {
16 // A class used to define a triangular-shaped hit test mask on a View.
17 class TestMaskedViewTargeter : public MaskedViewTargeter {
18 public:
19 explicit TestMaskedViewTargeter(View* masked_view)
20 : MaskedViewTargeter(masked_view) {}
21 virtual ~TestMaskedViewTargeter() {}
23 private:
24 virtual bool GetHitTestMask(const View* view,
25 gfx::Path* mask) const OVERRIDE {
26 SkScalar w = SkIntToScalar(view->width());
27 SkScalar h = SkIntToScalar(view->height());
29 // Create a triangular mask within the bounds of |view|.
30 mask->moveTo(w / 2, 0);
31 mask->lineTo(w, h);
32 mask->lineTo(0, h);
33 mask->close();
35 return true;
38 DISALLOW_COPY_AND_ASSIGN(TestMaskedViewTargeter);
41 namespace test {
43 typedef ViewsTestBase ViewTargeterTest;
45 // Verifies that the the functions ViewTargeter::FindTargetForEvent()
46 // and ViewTargeter::FindNextBestTarget() are implemented correctly
47 // for key events.
48 TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) {
49 Widget widget;
50 Widget::InitParams init_params =
51 CreateParams(Widget::InitParams::TYPE_POPUP);
52 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
53 widget.Init(init_params);
55 View* content = new View;
56 View* child = new View;
57 View* grandchild = new View;
59 widget.SetContentsView(content);
60 content->AddChildView(child);
61 child->AddChildView(grandchild);
63 grandchild->SetFocusable(true);
64 grandchild->RequestFocus();
66 ui::EventTargeter* targeter = new ViewTargeter();
67 internal::RootView* root_view =
68 static_cast<internal::RootView*>(widget.GetRootView());
69 root_view->SetEventTargeter(make_scoped_ptr(targeter));
71 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
73 // The focused view should be the initial target of the event.
74 ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
75 &key_event);
76 EXPECT_EQ(grandchild, static_cast<View*>(current_target));
78 // Verify that FindNextBestTarget() will return the parent view of the
79 // argument (and NULL if the argument has no parent view).
80 current_target = targeter->FindNextBestTarget(grandchild, &key_event);
81 EXPECT_EQ(child, static_cast<View*>(current_target));
82 current_target = targeter->FindNextBestTarget(child, &key_event);
83 EXPECT_EQ(content, static_cast<View*>(current_target));
84 current_target = targeter->FindNextBestTarget(content, &key_event);
85 EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
86 current_target = targeter->FindNextBestTarget(widget.GetRootView(),
87 &key_event);
88 EXPECT_EQ(NULL, static_cast<View*>(current_target));
91 // Verifies that the the functions ViewTargeter::FindTargetForEvent()
92 // and ViewTargeter::FindNextBestTarget() are implemented correctly
93 // for scroll events.
94 TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) {
95 Widget widget;
96 Widget::InitParams init_params =
97 CreateParams(Widget::InitParams::TYPE_POPUP);
98 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
99 init_params.bounds = gfx::Rect(0, 0, 200, 200);
100 widget.Init(init_params);
102 // The coordinates used for SetBounds() are in the parent coordinate space.
103 View* content = new View;
104 content->SetBounds(0, 0, 100, 100);
105 View* child = new View;
106 child->SetBounds(50, 50, 20, 20);
107 View* grandchild = new View;
108 grandchild->SetBounds(0, 0, 5, 5);
110 widget.SetContentsView(content);
111 content->AddChildView(child);
112 child->AddChildView(grandchild);
114 ui::EventTargeter* targeter = new ViewTargeter();
115 internal::RootView* root_view =
116 static_cast<internal::RootView*>(widget.GetRootView());
117 root_view->SetEventTargeter(make_scoped_ptr(targeter));
119 // The event falls within the bounds of |child| and |content| but not
120 // |grandchild|, so |child| should be the initial target for the event.
121 ui::ScrollEvent scroll(ui::ET_SCROLL,
122 gfx::Point(60, 60),
123 ui::EventTimeForNow(),
125 0, 3,
126 0, 3,
128 ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
129 &scroll);
130 EXPECT_EQ(child, static_cast<View*>(current_target));
132 // Verify that FindNextBestTarget() will return the parent view of the
133 // argument (and NULL if the argument has no parent view).
134 current_target = targeter->FindNextBestTarget(child, &scroll);
135 EXPECT_EQ(content, static_cast<View*>(current_target));
136 current_target = targeter->FindNextBestTarget(content, &scroll);
137 EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
138 current_target = targeter->FindNextBestTarget(widget.GetRootView(),
139 &scroll);
140 EXPECT_EQ(NULL, static_cast<View*>(current_target));
142 // The event falls outside of the original specified bounds of |content|,
143 // |child|, and |grandchild|. But since |content| is the contents view,
144 // and contents views are resized to fill the entire area of the root
145 // view, the event's initial target should still be |content|.
146 scroll = ui::ScrollEvent(ui::ET_SCROLL,
147 gfx::Point(150, 150),
148 ui::EventTimeForNow(),
150 0, 3,
151 0, 3,
153 current_target = targeter->FindTargetForEvent(root_view, &scroll);
154 EXPECT_EQ(content, static_cast<View*>(current_target));
157 // Tests the basic functionality of the method
158 // ViewTargeter::SubtreeShouldBeExploredForEvent().
159 TEST_F(ViewTargeterTest, SubtreeShouldBeExploredForEvent) {
160 Widget widget;
161 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
162 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
163 params.bounds = gfx::Rect(0, 0, 650, 650);
164 widget.Init(params);
166 ui::EventTargeter* targeter = new ViewTargeter();
167 internal::RootView* root_view =
168 static_cast<internal::RootView*>(widget.GetRootView());
169 root_view->SetEventTargeter(make_scoped_ptr(targeter));
171 // The coordinates used for SetBounds() are in the parent coordinate space.
172 View v1, v2, v3;
173 v1.SetBounds(0, 0, 300, 300);
174 v2.SetBounds(100, 100, 100, 100);
175 v3.SetBounds(0, 0, 10, 10);
176 v3.SetVisible(false);
177 root_view->AddChildView(&v1);
178 v1.AddChildView(&v2);
179 v2.AddChildView(&v3);
181 // Note that the coordinates used below are in |v1|'s coordinate space,
182 // and that SubtreeShouldBeExploredForEvent() expects the event location
183 // to be in the coordinate space of the target's parent. |v1| and
184 // its parent share a common coordinate space.
186 // Event located within |v1| only.
187 gfx::Point point(10, 10);
188 ui::MouseEvent event(ui::ET_MOUSE_PRESSED, point, point,
189 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
190 EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
191 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
192 v1.ConvertEventToTarget(&v2, &event);
193 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
195 // Event located within |v1| and |v2| only.
196 event.set_location(gfx::Point(150, 150));
197 EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
198 EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
199 v1.ConvertEventToTarget(&v2, &event);
200 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
202 // Event located within |v1|, |v2|, and |v3|. Note that |v3| is not
203 // visible, so it cannot handle the event.
204 event.set_location(gfx::Point(105, 105));
205 EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
206 EXPECT_TRUE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
207 v1.ConvertEventToTarget(&v2, &event);
208 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
210 // Event located outside the bounds of all views.
211 event.set_location(gfx::Point(400, 400));
212 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v1, event));
213 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v2, event));
214 v1.ConvertEventToTarget(&v2, &event);
215 EXPECT_FALSE(targeter->SubtreeShouldBeExploredForEvent(&v3, event));
217 // TODO(tdanderson): Move the hit-testing unit tests out of view_unittest
218 // and into here. See crbug.com/355425.
221 // Tests that FindTargetForEvent() returns the correct target when some
222 // views in the view tree have a MaskedViewTargeter installed, i.e.,
223 // they have a custom-shaped hit test mask.
224 TEST_F(ViewTargeterTest, MaskedViewTargeter) {
225 Widget widget;
226 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
227 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
228 params.bounds = gfx::Rect(0, 0, 650, 650);
229 widget.Init(params);
231 ui::EventTargeter* targeter = new ViewTargeter();
232 internal::RootView* root_view =
233 static_cast<internal::RootView*>(widget.GetRootView());
234 root_view->SetEventTargeter(make_scoped_ptr(targeter));
236 // The coordinates used for SetBounds() are in the parent coordinate space.
237 View masked_view, unmasked_view, masked_child;
238 masked_view.SetBounds(0, 0, 200, 200);
239 unmasked_view.SetBounds(300, 0, 300, 300);
240 masked_child.SetBounds(0, 0, 100, 100);
241 root_view->AddChildView(&masked_view);
242 root_view->AddChildView(&unmasked_view);
243 unmasked_view.AddChildView(&masked_child);
245 // Install event targeters of type TestMaskedViewTargeter on the two masked
246 // views to define their hit test masks.
247 ui::EventTargeter* masked_targeter = new TestMaskedViewTargeter(&masked_view);
248 masked_view.SetEventTargeter(make_scoped_ptr(masked_targeter));
249 masked_targeter = new TestMaskedViewTargeter(&masked_child);
250 masked_child.SetEventTargeter(make_scoped_ptr(masked_targeter));
252 // Note that the coordinates used below are in the coordinate space of
253 // the root view.
255 // Event located within the hit test mask of |masked_view|.
256 ui::ScrollEvent scroll(ui::ET_SCROLL,
257 gfx::Point(100, 190),
258 ui::EventTimeForNow(),
265 ui::EventTarget* current_target =
266 targeter->FindTargetForEvent(root_view, &scroll);
267 EXPECT_EQ(&masked_view, static_cast<View*>(current_target));
269 // Event located outside the hit test mask of |masked_view|.
270 scroll.set_location(gfx::Point(10, 10));
271 current_target = targeter->FindTargetForEvent(root_view, &scroll);
272 EXPECT_EQ(root_view, static_cast<View*>(current_target));
274 // Event located within the hit test mask of |masked_child|.
275 scroll.set_location(gfx::Point(350, 3));
276 current_target = targeter->FindTargetForEvent(root_view, &scroll);
277 EXPECT_EQ(&masked_child, static_cast<View*>(current_target));
279 // Event located within the hit test mask of |masked_child|.
280 scroll.set_location(gfx::Point(300, 12));
281 current_target = targeter->FindTargetForEvent(root_view, &scroll);
282 EXPECT_EQ(&unmasked_view, static_cast<View*>(current_target));
284 // TODO(tdanderson): We should also test that targeting of masked views
285 // works correctly with gestures. See crbug.com/375822.
288 } // namespace test
289 } // namespace views