OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/view_targeter.h" | 5 #include "ui/views/view_targeter.h" |
6 | 6 |
7 #include "ui/events/event_targeter.h" | 7 #include "ui/events/event_targeter.h" |
8 #include "ui/events/event_utils.h" | 8 #include "ui/events/event_utils.h" |
9 #include "ui/gfx/path.h" | 9 #include "ui/gfx/path.h" |
10 #include "ui/views/masked_targeter_delegate.h" | 10 #include "ui/views/masked_targeter_delegate.h" |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 mask->lineTo(0, h); | 69 mask->lineTo(0, h); |
70 mask->close(); | 70 mask->close(); |
71 return true; | 71 return true; |
72 } | 72 } |
73 | 73 |
74 DISALLOW_COPY_AND_ASSIGN(TestMaskedView); | 74 DISALLOW_COPY_AND_ASSIGN(TestMaskedView); |
75 }; | 75 }; |
76 | 76 |
77 namespace test { | 77 namespace test { |
78 | 78 |
79 typedef ViewsTestBase ViewTargeterTest; | 79 // TODO(tdanderson): Clean up this test suite by moving common code/state into |
| 80 // ViewTargeterTest and overriding SetUp(), TearDown(), etc. |
| 81 // See crbug.com/355680. |
| 82 class ViewTargeterTest : public ViewsTestBase { |
| 83 public: |
| 84 ViewTargeterTest() {} |
| 85 virtual ~ViewTargeterTest() {} |
| 86 |
| 87 void SetGestureHandler(internal::RootView* root_view, View* handler) { |
| 88 root_view->gesture_handler_ = handler; |
| 89 } |
| 90 |
| 91 void SetAllowGestureEventRetargeting(internal::RootView* root_view, |
| 92 bool allow) { |
| 93 root_view->allow_gesture_event_retargeting_ = allow; |
| 94 } |
| 95 |
| 96 private: |
| 97 DISALLOW_COPY_AND_ASSIGN(ViewTargeterTest); |
| 98 }; |
80 | 99 |
81 namespace { | 100 namespace { |
82 | 101 |
83 gfx::Point ConvertPointToView(View* view, const gfx::Point& p) { | 102 gfx::Point ConvertPointToView(View* view, const gfx::Point& p) { |
84 gfx::Point tmp(p); | 103 gfx::Point tmp(p); |
85 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); | 104 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); |
86 return tmp; | 105 return tmp; |
87 } | 106 } |
88 | 107 |
89 gfx::Rect ConvertRectToView(View* view, const gfx::Rect& r) { | 108 gfx::Rect ConvertRectToView(View* view, const gfx::Rect& r) { |
(...skipping 20 matching lines...) Expand all Loading... |
110 | 129 |
111 widget.SetContentsView(content); | 130 widget.SetContentsView(content); |
112 content->AddChildView(child); | 131 content->AddChildView(child); |
113 child->AddChildView(grandchild); | 132 child->AddChildView(grandchild); |
114 | 133 |
115 grandchild->SetFocusable(true); | 134 grandchild->SetFocusable(true); |
116 grandchild->RequestFocus(); | 135 grandchild->RequestFocus(); |
117 | 136 |
118 internal::RootView* root_view = | 137 internal::RootView* root_view = |
119 static_cast<internal::RootView*>(widget.GetRootView()); | 138 static_cast<internal::RootView*>(widget.GetRootView()); |
120 ViewTargeter* view_targeter = new ViewTargeter(root_view); | 139 ui::EventTargeter* targeter = root_view->targeter(); |
121 ui::EventTargeter* targeter = view_targeter; | |
122 root_view->SetEventTargeter(make_scoped_ptr(view_targeter)); | |
123 | 140 |
124 ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE); | 141 ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE); |
125 | 142 |
126 // The focused view should be the initial target of the event. | 143 // The focused view should be the initial target of the event. |
127 ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view, | 144 ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view, |
128 &key_event); | 145 &key_event); |
129 EXPECT_EQ(grandchild, static_cast<View*>(current_target)); | 146 EXPECT_EQ(grandchild, static_cast<View*>(current_target)); |
130 | 147 |
131 // Verify that FindNextBestTarget() will return the parent view of the | 148 // Verify that FindNextBestTarget() will return the parent view of the |
132 // argument (and NULL if the argument has no parent view). | 149 // argument (and NULL if the argument has no parent view). |
(...skipping 26 matching lines...) Expand all Loading... |
159 child->SetBounds(50, 50, 20, 20); | 176 child->SetBounds(50, 50, 20, 20); |
160 View* grandchild = new View; | 177 View* grandchild = new View; |
161 grandchild->SetBounds(0, 0, 5, 5); | 178 grandchild->SetBounds(0, 0, 5, 5); |
162 | 179 |
163 widget.SetContentsView(content); | 180 widget.SetContentsView(content); |
164 content->AddChildView(child); | 181 content->AddChildView(child); |
165 child->AddChildView(grandchild); | 182 child->AddChildView(grandchild); |
166 | 183 |
167 internal::RootView* root_view = | 184 internal::RootView* root_view = |
168 static_cast<internal::RootView*>(widget.GetRootView()); | 185 static_cast<internal::RootView*>(widget.GetRootView()); |
169 ViewTargeter* view_targeter = new ViewTargeter(root_view); | 186 ui::EventTargeter* targeter = root_view->targeter(); |
170 ui::EventTargeter* targeter = view_targeter; | |
171 root_view->SetEventTargeter(make_scoped_ptr(view_targeter)); | |
172 | 187 |
173 // The event falls within the bounds of |child| and |content| but not | 188 // The event falls within the bounds of |child| and |content| but not |
174 // |grandchild|, so |child| should be the initial target for the event. | 189 // |grandchild|, so |child| should be the initial target for the event. |
175 ui::ScrollEvent scroll(ui::ET_SCROLL, | 190 ui::ScrollEvent scroll(ui::ET_SCROLL, |
176 gfx::Point(60, 60), | 191 gfx::Point(60, 60), |
177 ui::EventTimeForNow(), | 192 ui::EventTimeForNow(), |
178 0, | 193 0, |
179 0, 3, | 194 0, 3, |
180 0, 3, | 195 0, 3, |
181 2); | 196 2); |
(...skipping 19 matching lines...) Expand all Loading... |
201 gfx::Point(150, 150), | 216 gfx::Point(150, 150), |
202 ui::EventTimeForNow(), | 217 ui::EventTimeForNow(), |
203 0, | 218 0, |
204 0, 3, | 219 0, 3, |
205 0, 3, | 220 0, 3, |
206 2); | 221 2); |
207 current_target = targeter->FindTargetForEvent(root_view, &scroll); | 222 current_target = targeter->FindTargetForEvent(root_view, &scroll); |
208 EXPECT_EQ(content, static_cast<View*>(current_target)); | 223 EXPECT_EQ(content, static_cast<View*>(current_target)); |
209 } | 224 } |
210 | 225 |
| 226 // Convenience to make constructing a GestureEvent simpler. |
| 227 class GestureEventForTest : public ui::GestureEvent { |
| 228 public: |
| 229 GestureEventForTest(ui::EventType type, int x, int y) |
| 230 : GestureEvent(x, |
| 231 y, |
| 232 0, |
| 233 base::TimeDelta(), |
| 234 ui::GestureEventDetails(type, 0.0f, 0.0f)) {} |
| 235 |
| 236 GestureEventForTest(ui::GestureEventDetails details, int x, int y) |
| 237 : GestureEvent(x, y, 0, base::TimeDelta(), details) {} |
| 238 }; |
| 239 |
| 240 // Verifies that the the functions ViewTargeter::FindTargetForEvent() |
| 241 // and ViewTargeter::FindNextBestTarget() are implemented correctly |
| 242 // for gesture events. |
| 243 TEST_F(ViewTargeterTest, ViewTargeterForGestureEvents) { |
| 244 Widget widget; |
| 245 Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| 246 init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 247 init_params.bounds = gfx::Rect(0, 0, 200, 200); |
| 248 widget.Init(init_params); |
| 249 |
| 250 // The coordinates used for SetBounds() are in the parent coordinate space. |
| 251 View* content = new View; |
| 252 content->SetBounds(0, 0, 100, 100); |
| 253 View* child = new View; |
| 254 child->SetBounds(50, 50, 20, 20); |
| 255 View* grandchild = new View; |
| 256 grandchild->SetBounds(0, 0, 5, 5); |
| 257 |
| 258 widget.SetContentsView(content); |
| 259 content->AddChildView(child); |
| 260 child->AddChildView(grandchild); |
| 261 |
| 262 internal::RootView* root_view = |
| 263 static_cast<internal::RootView*>(widget.GetRootView()); |
| 264 ui::EventTargeter* targeter = root_view->targeter(); |
| 265 |
| 266 // Define a GESTURE_TAP and a GESTURE_SCROLL_BEGIN. |
| 267 gfx::Rect bounding_box(gfx::Point(46, 46), gfx::Size(8, 8)); |
| 268 gfx::Point center_point(bounding_box.CenterPoint()); |
| 269 ui::GestureEventDetails details(ui::ET_GESTURE_TAP, 0.0f, 0.0f); |
| 270 details.set_bounding_box(bounding_box); |
| 271 GestureEventForTest tap(details, center_point.x(), center_point.y()); |
| 272 details = ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0.0f, 0.0f); |
| 273 details.set_bounding_box(bounding_box); |
| 274 GestureEventForTest scroll_begin(details, center_point.x(), center_point.y()); |
| 275 |
| 276 // Assume that the view currently handling gestures has been set as |
| 277 // |grandchild| by a previous gesture event. Thus subsequent gesture events |
| 278 // should be initially targeted to |grandchild|, and re-targeting should |
| 279 // be prohibited for all gesture event types except for GESTURE_SCROLL_BEGIN |
| 280 // (which should be re-targeted to the parent of |grandchild|). |
| 281 SetAllowGestureEventRetargeting(root_view, false); |
| 282 SetGestureHandler(root_view, grandchild); |
| 283 EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap)); |
| 284 EXPECT_EQ(NULL, targeter->FindNextBestTarget(grandchild, &tap)); |
| 285 EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin)); |
| 286 EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin)); |
| 287 |
| 288 // Assume that the view currently handling gestures is still set as |
| 289 // |grandchild|, but this was not done by a previous gesture. Thus we are |
| 290 // in the process of finding the View to which subsequent gestures will be |
| 291 // dispatched, so all gesture events should be re-targeted up the ancestor |
| 292 // chain. |
| 293 SetAllowGestureEventRetargeting(root_view, true); |
| 294 EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &tap)); |
| 295 EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin)); |
| 296 |
| 297 // Assume that the default gesture handler was set by the previous gesture, |
| 298 // but that this handler is currently NULL. No gesture events should be |
| 299 // re-targeted in this case (regardless of the view that is passed in to |
| 300 // FindNextBestTarget() as the previous target). |
| 301 SetGestureHandler(root_view, NULL); |
| 302 SetAllowGestureEventRetargeting(root_view, false); |
| 303 EXPECT_EQ(NULL, targeter->FindNextBestTarget(child, &tap)); |
| 304 EXPECT_EQ(NULL, targeter->FindNextBestTarget(NULL, &tap)); |
| 305 EXPECT_EQ(NULL, targeter->FindNextBestTarget(content, &scroll_begin)); |
| 306 |
| 307 // If no default gesture handler is currently set, targeting should be |
| 308 // performed using the location of the gesture event. |
| 309 SetAllowGestureEventRetargeting(root_view, true); |
| 310 EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap)); |
| 311 EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin)); |
| 312 } |
| 313 |
211 // Tests that the functions ViewTargeterDelegate::DoesIntersectRect() | 314 // Tests that the functions ViewTargeterDelegate::DoesIntersectRect() |
212 // and MaskedTargeterDelegate::DoesIntersectRect() work as intended when | 315 // and MaskedTargeterDelegate::DoesIntersectRect() work as intended when |
213 // called on views which are derived from ViewTargeterDelegate. | 316 // called on views which are derived from ViewTargeterDelegate. |
214 // Also verifies that ViewTargeterDelegate::DoesIntersectRect() can | 317 // Also verifies that ViewTargeterDelegate::DoesIntersectRect() can |
215 // be called from the ViewTargeter installed on RootView. | 318 // be called from the ViewTargeter installed on RootView. |
216 TEST_F(ViewTargeterTest, DoesIntersectRect) { | 319 TEST_F(ViewTargeterTest, DoesIntersectRect) { |
217 Widget widget; | 320 Widget widget; |
218 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); | 321 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
219 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 322 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
220 params.bounds = gfx::Rect(0, 0, 650, 650); | 323 params.bounds = gfx::Rect(0, 0, 650, 650); |
221 widget.Init(params); | 324 widget.Init(params); |
222 | 325 |
223 internal::RootView* root_view = | 326 internal::RootView* root_view = |
224 static_cast<internal::RootView*>(widget.GetRootView()); | 327 static_cast<internal::RootView*>(widget.GetRootView()); |
225 ViewTargeter* view_targeter = new ViewTargeter(root_view); | 328 ViewTargeter* view_targeter = root_view->targeter(); |
226 root_view->SetEventTargeter(make_scoped_ptr(view_targeter)); | |
227 | 329 |
228 // The coordinates used for SetBounds() are in the parent coordinate space. | 330 // The coordinates used for SetBounds() are in the parent coordinate space. |
229 TestingView v2; | 331 TestingView v2; |
230 TestMaskedView v1, v3; | 332 TestMaskedView v1, v3; |
231 v1.SetBounds(0, 0, 200, 200); | 333 v1.SetBounds(0, 0, 200, 200); |
232 v2.SetBounds(300, 0, 300, 300); | 334 v2.SetBounds(300, 0, 300, 300); |
233 v3.SetBounds(0, 0, 100, 100); | 335 v3.SetBounds(0, 0, 100, 100); |
234 root_view->AddChildView(&v1); | 336 root_view->AddChildView(&v1); |
235 root_view->AddChildView(&v2); | 337 root_view->AddChildView(&v2); |
236 v2.AddChildView(&v3); | 338 v2.AddChildView(&v3); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin)); | 439 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin)); |
338 EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin)); | 440 EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin)); |
339 | 441 |
340 EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin)); | 442 EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin)); |
341 | 443 |
342 widget->CloseNow(); | 444 widget->CloseNow(); |
343 } | 445 } |
344 | 446 |
345 } // namespace test | 447 } // namespace test |
346 } // namespace views | 448 } // namespace views |
OLD | NEW |