| 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 |