Index: ui/views/widget/widget_unittest.cc |
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc |
index 6cc7d1aaeb0aea3220af87e5b745115e25b26a82..a31717daebe8e749272161e4e82136810d0a19a0 100644 |
--- a/ui/views/widget/widget_unittest.cc |
+++ b/ui/views/widget/widget_unittest.cc |
@@ -39,6 +39,19 @@ |
namespace views { |
namespace test { |
+namespace { |
+ |
+// TODO(tdanderson): This utility function is used in different unittest |
+// files. Move to a common location to avoid |
+// repeated code. |
+gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) { |
+ gfx::Point tmp(p); |
+ View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); |
+ return tmp; |
+} |
+ |
+} // namespace |
+ |
// A view that keeps track of the events it receives, optionally consuming them. |
class EventCountView : public View { |
public: |
@@ -2349,6 +2362,97 @@ TEST_F(WidgetTest, ScrollGestureEventDispatch) { |
widget->Close(); |
} |
+// A class used in WidgetTest.GestureEventLocationWhileBubbling to verify |
+// that when a gesture event bubbles up a View hierarchy, the location |
+// of a gesture event seen by each View is in the local coordinate space |
+// of that View. |
+class GestureLocationView : public EventCountView { |
+ public: |
+ GestureLocationView() {} |
+ virtual ~GestureLocationView() {} |
+ |
+ void set_expected_location(gfx::Point expected_location) { |
+ expected_location_ = expected_location; |
+ } |
+ |
+ // EventCountView: |
+ virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { |
+ EventCountView::OnGestureEvent(event); |
+ |
+ // Verify that the location of |event| is in the local coordinate |
+ // space of |this|. |
+ EXPECT_EQ(expected_location_, event->location()); |
+ } |
+ |
+ private: |
+ // The expected location of a gesture event dispatched to |this|. |
+ gfx::Point expected_location_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(GestureLocationView); |
+}; |
+ |
+// Verifies that the location of a gesture event is always in the local |
+// coordinate space of the View receiving the event while bubbling. |
+TEST_F(WidgetTest, GestureEventLocationWhileBubbling) { |
+ Widget* widget = CreateTopLevelNativeWidget(); |
+ widget->SetBounds(gfx::Rect(0, 0, 300, 300)); |
+ |
+ // Define a hierarchy of three views (coordinates shown below are in the |
+ // coordinate space of the root view, but the coordinates used for |
+ // SetBounds() are in their parent coordinate space). |
+ // v1 (50, 50, 150, 150) |
+ // v2 (100, 70, 50, 80) |
+ // v3 (120, 100, 10, 10) |
+ GestureLocationView* v1 = new GestureLocationView(); |
+ v1->SetBounds(50, 50, 150, 150); |
+ GestureLocationView* v2 = new GestureLocationView(); |
+ v2->SetBounds(50, 20, 50, 80); |
+ GestureLocationView* v3 = new GestureLocationView(); |
+ v3->SetBounds(20, 30, 10, 10); |
+ internal::RootView* root_view = |
+ static_cast<internal::RootView*>(widget->GetRootView()); |
+ root_view->AddChildView(v1); |
+ v1->AddChildView(v2); |
+ v2->AddChildView(v3); |
+ |
+ widget->Show(); |
+ |
+ // Define a GESTURE_TAP event located at (125, 105) in root view coordinates. |
+ // This event is contained within all of |v1|, |v2|, and |v3|. |
+ gfx::Point location_in_root(125, 105); |
+ GestureEventForTest tap( |
+ ui::ET_GESTURE_TAP, location_in_root.x(), location_in_root.y()); |
+ |
+ // Calculate the location of the event in the local coordinate spaces |
+ // of each of the views. |
+ gfx::Point location_in_v1(ConvertPointFromWidgetToView(v1, location_in_root)); |
+ EXPECT_EQ(gfx::Point(75, 55), location_in_v1); |
+ gfx::Point location_in_v2(ConvertPointFromWidgetToView(v2, location_in_root)); |
+ EXPECT_EQ(gfx::Point(25, 35), location_in_v2); |
+ gfx::Point location_in_v3(ConvertPointFromWidgetToView(v3, location_in_root)); |
+ EXPECT_EQ(gfx::Point(5, 5), location_in_v3); |
+ |
+ // Dispatch the event. When each view receives the event, its location should |
+ // be in the local coordinate space of that view (see the check made by |
+ // GestureLocationView). After dispatch is complete the event's location |
+ // should be in the root coordinate space. |
+ v1->set_expected_location(location_in_v1); |
+ v2->set_expected_location(location_in_v2); |
+ v3->set_expected_location(location_in_v3); |
+ widget->OnGestureEvent(&tap); |
+ EXPECT_EQ(location_in_root, tap.location()); |
+ |
+ // Verify that each view did in fact see the event. |
+ EventCountView* view1 = v1; |
+ EventCountView* view2 = v2; |
+ EventCountView* view3 = v3; |
+ EXPECT_EQ(1, view1->GetEventCount(ui::ET_GESTURE_TAP)); |
+ EXPECT_EQ(1, view2->GetEventCount(ui::ET_GESTURE_TAP)); |
+ EXPECT_EQ(1, view3->GetEventCount(ui::ET_GESTURE_TAP)); |
+ |
+ widget->Close(); |
+} |
+ |
// Verifies that disabled views are permitted to be set as the default gesture |
// handler in RootView. Also verifies that gesture events targeted to a disabled |
// view are not actually dispatched to the view, but are still marked as |