Home | History | Annotate | Download | only in views
      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.
      4 
      5 #include "ui/views/view_targeter.h"
      6 
      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_targeter_delegate.h"
     11 #include "ui/views/test/views_test_base.h"
     12 #include "ui/views/view_targeter.h"
     13 #include "ui/views/view_targeter_delegate.h"
     14 #include "ui/views/widget/root_view.h"
     15 
     16 namespace views {
     17 
     18 // A derived class of View used for testing purposes.
     19 class TestingView : public View, public ViewTargeterDelegate {
     20  public:
     21   TestingView() : can_process_events_within_subtree_(true) {}
     22   virtual ~TestingView() {}
     23 
     24   // Reset all test state.
     25   void Reset() { can_process_events_within_subtree_ = true; }
     26 
     27   void set_can_process_events_within_subtree(bool can_process) {
     28     can_process_events_within_subtree_ = can_process;
     29   }
     30 
     31   // A call-through function to ViewTargeterDelegate::DoesIntersectRect().
     32   bool TestDoesIntersectRect(const View* target, const gfx::Rect& rect) const {
     33     return DoesIntersectRect(target, rect);
     34   }
     35 
     36   // View:
     37   virtual bool CanProcessEventsWithinSubtree() const OVERRIDE {
     38     return can_process_events_within_subtree_;
     39   }
     40 
     41  private:
     42   // Value to return from CanProcessEventsWithinSubtree().
     43   bool can_process_events_within_subtree_;
     44 
     45   DISALLOW_COPY_AND_ASSIGN(TestingView);
     46 };
     47 
     48 // A derived class of View having a triangular-shaped hit test mask.
     49 class TestMaskedView : public View, public MaskedTargeterDelegate {
     50  public:
     51   TestMaskedView() {}
     52   virtual ~TestMaskedView() {}
     53 
     54   // A call-through function to MaskedTargeterDelegate::DoesIntersectRect().
     55   bool TestDoesIntersectRect(const View* target, const gfx::Rect& rect) const {
     56     return DoesIntersectRect(target, rect);
     57   }
     58 
     59  private:
     60   // MaskedTargeterDelegate:
     61   virtual bool GetHitTestMask(gfx::Path* mask) const OVERRIDE {
     62     DCHECK(mask);
     63     SkScalar w = SkIntToScalar(width());
     64     SkScalar h = SkIntToScalar(height());
     65 
     66     // Create a triangular mask within the bounds of this View.
     67     mask->moveTo(w / 2, 0);
     68     mask->lineTo(w, h);
     69     mask->lineTo(0, h);
     70     mask->close();
     71     return true;
     72   }
     73 
     74   DISALLOW_COPY_AND_ASSIGN(TestMaskedView);
     75 };
     76 
     77 namespace test {
     78 
     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 SetGestureHandlerSetBeforeProcessing(internal::RootView* root_view,
     92                                             bool set) {
     93     root_view->gesture_handler_set_before_processing_ = set;
     94   }
     95 
     96  private:
     97   DISALLOW_COPY_AND_ASSIGN(ViewTargeterTest);
     98 };
     99 
    100 namespace {
    101 
    102 gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) {
    103   gfx::Point tmp(p);
    104   View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
    105   return tmp;
    106 }
    107 
    108 gfx::Rect ConvertRectFromWidgetToView(View* view, const gfx::Rect& r) {
    109   gfx::Rect tmp(r);
    110   tmp.set_origin(ConvertPointFromWidgetToView(view, r.origin()));
    111   return tmp;
    112 }
    113 
    114 }  // namespace
    115 
    116 // Verifies that the the functions ViewTargeter::FindTargetForEvent()
    117 // and ViewTargeter::FindNextBestTarget() are implemented correctly
    118 // for key events.
    119 TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) {
    120   Widget widget;
    121   Widget::InitParams init_params =
    122       CreateParams(Widget::InitParams::TYPE_POPUP);
    123   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    124   widget.Init(init_params);
    125 
    126   View* content = new View;
    127   View* child = new View;
    128   View* grandchild = new View;
    129 
    130   widget.SetContentsView(content);
    131   content->AddChildView(child);
    132   child->AddChildView(grandchild);
    133 
    134   grandchild->SetFocusable(true);
    135   grandchild->RequestFocus();
    136 
    137   internal::RootView* root_view =
    138       static_cast<internal::RootView*>(widget.GetRootView());
    139   ui::EventTargeter* targeter = root_view->targeter();
    140 
    141   ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE);
    142 
    143   // The focused view should be the initial target of the event.
    144   ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
    145                                                                  &key_event);
    146   EXPECT_EQ(grandchild, static_cast<View*>(current_target));
    147 
    148   // Verify that FindNextBestTarget() will return the parent view of the
    149   // argument (and NULL if the argument has no parent view).
    150   current_target = targeter->FindNextBestTarget(grandchild, &key_event);
    151   EXPECT_EQ(child, static_cast<View*>(current_target));
    152   current_target = targeter->FindNextBestTarget(child, &key_event);
    153   EXPECT_EQ(content, static_cast<View*>(current_target));
    154   current_target = targeter->FindNextBestTarget(content, &key_event);
    155   EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
    156   current_target = targeter->FindNextBestTarget(widget.GetRootView(),
    157                                                 &key_event);
    158   EXPECT_EQ(NULL, static_cast<View*>(current_target));
    159 }
    160 
    161 // Verifies that the the functions ViewTargeter::FindTargetForEvent()
    162 // and ViewTargeter::FindNextBestTarget() are implemented correctly
    163 // for scroll events.
    164 TEST_F(ViewTargeterTest, ViewTargeterForScrollEvents) {
    165   Widget widget;
    166   Widget::InitParams init_params =
    167       CreateParams(Widget::InitParams::TYPE_POPUP);
    168   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    169   init_params.bounds = gfx::Rect(0, 0, 200, 200);
    170   widget.Init(init_params);
    171 
    172   // The coordinates used for SetBounds() are in the parent coordinate space.
    173   View* content = new View;
    174   content->SetBounds(0, 0, 100, 100);
    175   View* child = new View;
    176   child->SetBounds(50, 50, 20, 20);
    177   View* grandchild = new View;
    178   grandchild->SetBounds(0, 0, 5, 5);
    179 
    180   widget.SetContentsView(content);
    181   content->AddChildView(child);
    182   child->AddChildView(grandchild);
    183 
    184   internal::RootView* root_view =
    185       static_cast<internal::RootView*>(widget.GetRootView());
    186   ui::EventTargeter* targeter = root_view->targeter();
    187 
    188   // The event falls within the bounds of |child| and |content| but not
    189   // |grandchild|, so |child| should be the initial target for the event.
    190   ui::ScrollEvent scroll(ui::ET_SCROLL,
    191                          gfx::Point(60, 60),
    192                          ui::EventTimeForNow(),
    193                          0,
    194                          0, 3,
    195                          0, 3,
    196                          2);
    197   ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
    198                                                                  &scroll);
    199   EXPECT_EQ(child, static_cast<View*>(current_target));
    200 
    201   // Verify that FindNextBestTarget() will return the parent view of the
    202   // argument (and NULL if the argument has no parent view).
    203   current_target = targeter->FindNextBestTarget(child, &scroll);
    204   EXPECT_EQ(content, static_cast<View*>(current_target));
    205   current_target = targeter->FindNextBestTarget(content, &scroll);
    206   EXPECT_EQ(widget.GetRootView(), static_cast<View*>(current_target));
    207   current_target = targeter->FindNextBestTarget(widget.GetRootView(),
    208                                                 &scroll);
    209   EXPECT_EQ(NULL, static_cast<View*>(current_target));
    210 
    211   // The event falls outside of the original specified bounds of |content|,
    212   // |child|, and |grandchild|. But since |content| is the contents view,
    213   // and contents views are resized to fill the entire area of the root
    214   // view, the event's initial target should still be |content|.
    215   scroll = ui::ScrollEvent(ui::ET_SCROLL,
    216                            gfx::Point(150, 150),
    217                            ui::EventTimeForNow(),
    218                            0,
    219                            0, 3,
    220                            0, 3,
    221                            2);
    222   current_target = targeter->FindTargetForEvent(root_view, &scroll);
    223   EXPECT_EQ(content, static_cast<View*>(current_target));
    224 }
    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)) {}
    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 some gesture events for testing.
    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);
    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);
    273   details.set_bounding_box(bounding_box);
    274   GestureEventForTest scroll_begin(details, center_point.x(), center_point.y());
    275   details = ui::GestureEventDetails(ui::ET_GESTURE_END);
    276   details.set_bounding_box(bounding_box);
    277   GestureEventForTest end(details, center_point.x(), center_point.y());
    278 
    279   // Assume that the view currently handling gestures has been set as
    280   // |grandchild| by a previous gesture event. Thus subsequent TAP and
    281   // SCROLL_BEGIN events should be initially targeted to |grandchild|, and
    282   // re-targeting should be prohibited for TAP but permitted for
    283   // GESTURE_SCROLL_BEGIN (which should be re-targeted to the parent of
    284   // |grandchild|).
    285   SetGestureHandlerSetBeforeProcessing(root_view, true);
    286   SetGestureHandler(root_view, grandchild);
    287   EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap));
    288   EXPECT_EQ(NULL, targeter->FindNextBestTarget(grandchild, &tap));
    289   EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin));
    290   EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin));
    291 
    292   // GESTURE_END events should be targeted to the existing gesture handler,
    293   // but re-targeting should be prohibited.
    294   EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &end));
    295   EXPECT_EQ(NULL, targeter->FindNextBestTarget(grandchild, &end));
    296 
    297   // Assume that the view currently handling gestures is still set as
    298   // |grandchild|, but this was not done by a previous gesture. Thus we are
    299   // in the process of finding the View to which subsequent gestures will be
    300   // dispatched, so TAP and SCROLL_BEGIN events should be re-targeted up
    301   // the ancestor chain.
    302   SetGestureHandlerSetBeforeProcessing(root_view, false);
    303   EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &tap));
    304   EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &scroll_begin));
    305 
    306   // GESTURE_END events are not permitted to be re-targeted up the ancestor
    307   // chain; they are only ever targeted in the case where the gesture handler
    308   // was established by a previous gesture.
    309   EXPECT_EQ(NULL, targeter->FindNextBestTarget(grandchild, &end));
    310 
    311   // Assume that the default gesture handler was set by the previous gesture,
    312   // but that this handler is currently NULL. No gesture events should be
    313   // re-targeted in this case (regardless of the view that is passed in to
    314   // FindNextBestTarget() as the previous target).
    315   SetGestureHandler(root_view, NULL);
    316   SetGestureHandlerSetBeforeProcessing(root_view, true);
    317   EXPECT_EQ(NULL, targeter->FindNextBestTarget(child, &tap));
    318   EXPECT_EQ(NULL, targeter->FindNextBestTarget(NULL, &tap));
    319   EXPECT_EQ(NULL, targeter->FindNextBestTarget(content, &scroll_begin));
    320   EXPECT_EQ(NULL, targeter->FindNextBestTarget(content, &end));
    321 
    322   // Reset the locations of the gesture events to be in the root view
    323   // coordinate space since we are about to call FindTargetForEvent()
    324   // again (calls to FindTargetForEvent() and FindNextBestTarget()
    325   // mutate the location of the gesture events to be in the coordinate
    326   // space of the returned view).
    327   details = ui::GestureEventDetails(ui::ET_GESTURE_TAP);
    328   details.set_bounding_box(bounding_box);
    329   tap = GestureEventForTest(details, center_point.x(), center_point.y());
    330   details = ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN);
    331   details.set_bounding_box(bounding_box);
    332   scroll_begin =
    333       GestureEventForTest(details, center_point.x(), center_point.y());
    334   details = ui::GestureEventDetails(ui::ET_GESTURE_END);
    335   details.set_bounding_box(bounding_box);
    336   end = GestureEventForTest(details, center_point.x(), center_point.y());
    337 
    338   // If no default gesture handler is currently set, targeting should be
    339   // performed using the location of the gesture event for a TAP and a
    340   // SCROLL_BEGIN.
    341   SetGestureHandlerSetBeforeProcessing(root_view, false);
    342   EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &tap));
    343   EXPECT_EQ(grandchild, targeter->FindTargetForEvent(root_view, &scroll_begin));
    344 
    345   // If no default gesture handler is currently set, GESTURE_END events
    346   // should never be targeted or re-targeted to any View.
    347   EXPECT_EQ(NULL, targeter->FindTargetForEvent(root_view, &end));
    348   EXPECT_EQ(NULL, targeter->FindNextBestTarget(NULL, &end));
    349   EXPECT_EQ(NULL, targeter->FindNextBestTarget(child, &end));
    350 }
    351 
    352 // Tests that calls to FindTargetForEvent() and FindNextBestTarget() change
    353 // the location of a gesture event to be in the correct coordinate space.
    354 TEST_F(ViewTargeterTest, GestureEventCoordinateConversion) {
    355   Widget widget;
    356   Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP);
    357   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    358   init_params.bounds = gfx::Rect(0, 0, 200, 200);
    359   widget.Init(init_params);
    360 
    361   // The coordinates used for SetBounds() are in the parent coordinate space.
    362   View* content = new View;
    363   content->SetBounds(0, 0, 100, 100);
    364   View* child = new View;
    365   child->SetBounds(50, 50, 20, 20);
    366   View* grandchild = new View;
    367   grandchild->SetBounds(5, 5, 10, 10);
    368   View* great_grandchild = new View;
    369   great_grandchild->SetBounds(3, 3, 4, 4);
    370 
    371   widget.SetContentsView(content);
    372   content->AddChildView(child);
    373   child->AddChildView(grandchild);
    374   grandchild->AddChildView(great_grandchild);
    375 
    376   internal::RootView* root_view =
    377       static_cast<internal::RootView*>(widget.GetRootView());
    378   ui::EventTargeter* targeter = root_view->targeter();
    379 
    380   // Define a GESTURE_TAP event with a bounding box centered at (60, 60)
    381   // in root view coordinates with width and height of 4.
    382   gfx::Rect bounding_box(gfx::Point(58, 58), gfx::Size(4, 4));
    383   gfx::Point center_point(bounding_box.CenterPoint());
    384   ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
    385   details.set_bounding_box(bounding_box);
    386   GestureEventForTest tap(details, center_point.x(), center_point.y());
    387 
    388   // Calculate the location of the gesture in each of the different
    389   // coordinate spaces.
    390   gfx::Point location_in_root(center_point);
    391   EXPECT_EQ(gfx::Point(60, 60), location_in_root);
    392   gfx::Point location_in_great_grandchild(
    393       ConvertPointFromWidgetToView(great_grandchild, location_in_root));
    394   EXPECT_EQ(gfx::Point(2, 2), location_in_great_grandchild);
    395   gfx::Point location_in_grandchild(
    396       ConvertPointFromWidgetToView(grandchild, location_in_root));
    397   EXPECT_EQ(gfx::Point(5, 5), location_in_grandchild);
    398   gfx::Point location_in_child(
    399       ConvertPointFromWidgetToView(child, location_in_root));
    400   EXPECT_EQ(gfx::Point(10, 10), location_in_child);
    401   gfx::Point location_in_content(
    402       ConvertPointFromWidgetToView(content, location_in_root));
    403   EXPECT_EQ(gfx::Point(60, 60), location_in_content);
    404 
    405   // Verify the location of |tap| is in screen coordinates.
    406   EXPECT_EQ(gfx::Point(60, 60), tap.location());
    407 
    408   // The initial target should be |great_grandchild| and the location of
    409   // the event should be changed into the coordinate space of the target.
    410   EXPECT_EQ(great_grandchild, targeter->FindTargetForEvent(root_view, &tap));
    411   EXPECT_EQ(location_in_great_grandchild, tap.location());
    412   SetGestureHandler(root_view, great_grandchild);
    413 
    414   // The next target should be |grandchild| and the location of
    415   // the event should be changed into the coordinate space of the target.
    416   EXPECT_EQ(grandchild, targeter->FindNextBestTarget(great_grandchild, &tap));
    417   EXPECT_EQ(location_in_grandchild, tap.location());
    418   SetGestureHandler(root_view, grandchild);
    419 
    420   // The next target should be |child| and the location of
    421   // the event should be changed into the coordinate space of the target.
    422   EXPECT_EQ(child, targeter->FindNextBestTarget(grandchild, &tap));
    423   EXPECT_EQ(location_in_child, tap.location());
    424   SetGestureHandler(root_view, child);
    425 
    426   // The next target should be |content| and the location of
    427   // the event should be changed into the coordinate space of the target.
    428   EXPECT_EQ(content, targeter->FindNextBestTarget(child, &tap));
    429   EXPECT_EQ(location_in_content, tap.location());
    430   SetGestureHandler(root_view, content);
    431 
    432   // The next target should be |root_view| and the location of
    433   // the event should be changed into the coordinate space of the target.
    434   EXPECT_EQ(widget.GetRootView(), targeter->FindNextBestTarget(content, &tap));
    435   EXPECT_EQ(location_in_root, tap.location());
    436   SetGestureHandler(root_view, widget.GetRootView());
    437 
    438   // The next target should be NULL and the location of the event should
    439   // remain unchanged.
    440   EXPECT_EQ(NULL, targeter->FindNextBestTarget(widget.GetRootView(), &tap));
    441   EXPECT_EQ(location_in_root, tap.location());
    442 }
    443 
    444 // Tests that the functions ViewTargeterDelegate::DoesIntersectRect()
    445 // and MaskedTargeterDelegate::DoesIntersectRect() work as intended when
    446 // called on views which are derived from ViewTargeterDelegate.
    447 // Also verifies that ViewTargeterDelegate::DoesIntersectRect() can
    448 // be called from the ViewTargeter installed on RootView.
    449 TEST_F(ViewTargeterTest, DoesIntersectRect) {
    450   Widget widget;
    451   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    452   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    453   params.bounds = gfx::Rect(0, 0, 650, 650);
    454   widget.Init(params);
    455 
    456   internal::RootView* root_view =
    457       static_cast<internal::RootView*>(widget.GetRootView());
    458   ViewTargeter* view_targeter = root_view->targeter();
    459 
    460   // The coordinates used for SetBounds() are in the parent coordinate space.
    461   TestingView v2;
    462   TestMaskedView v1, v3;
    463   v1.SetBounds(0, 0, 200, 200);
    464   v2.SetBounds(300, 0, 300, 300);
    465   v3.SetBounds(0, 0, 100, 100);
    466   root_view->AddChildView(&v1);
    467   root_view->AddChildView(&v2);
    468   v2.AddChildView(&v3);
    469 
    470   // The coordinates used below are in the local coordinate space of the
    471   // view that is passed in as an argument.
    472 
    473   // Hit tests against |v1|, which has a hit test mask.
    474   EXPECT_TRUE(v1.TestDoesIntersectRect(&v1, gfx::Rect(0, 0, 200, 200)));
    475   EXPECT_TRUE(v1.TestDoesIntersectRect(&v1, gfx::Rect(-10, -10, 110, 12)));
    476   EXPECT_TRUE(v1.TestDoesIntersectRect(&v1, gfx::Rect(112, 142, 1, 1)));
    477   EXPECT_FALSE(v1.TestDoesIntersectRect(&v1, gfx::Rect(0, 0, 20, 20)));
    478   EXPECT_FALSE(v1.TestDoesIntersectRect(&v1, gfx::Rect(-10, -10, 90, 12)));
    479   EXPECT_FALSE(v1.TestDoesIntersectRect(&v1, gfx::Rect(150, 49, 1, 1)));
    480 
    481   // Hit tests against |v2|, which does not have a hit test mask.
    482   EXPECT_TRUE(v2.TestDoesIntersectRect(&v2, gfx::Rect(0, 0, 200, 200)));
    483   EXPECT_TRUE(v2.TestDoesIntersectRect(&v2, gfx::Rect(-10, 250, 60, 60)));
    484   EXPECT_TRUE(v2.TestDoesIntersectRect(&v2, gfx::Rect(250, 250, 1, 1)));
    485   EXPECT_FALSE(v2.TestDoesIntersectRect(&v2, gfx::Rect(-10, 250, 7, 7)));
    486   EXPECT_FALSE(v2.TestDoesIntersectRect(&v2, gfx::Rect(-1, -1, 1, 1)));
    487 
    488   // Hit tests against |v3|, which has a hit test mask and is a child of |v2|.
    489   EXPECT_TRUE(v3.TestDoesIntersectRect(&v3, gfx::Rect(0, 0, 50, 50)));
    490   EXPECT_TRUE(v3.TestDoesIntersectRect(&v3, gfx::Rect(90, 90, 1, 1)));
    491   EXPECT_FALSE(v3.TestDoesIntersectRect(&v3, gfx::Rect(10, 125, 50, 50)));
    492   EXPECT_FALSE(v3.TestDoesIntersectRect(&v3, gfx::Rect(110, 110, 1, 1)));
    493 
    494   // Verify that hit-testing is performed correctly when using the
    495   // call-through function ViewTargeter::DoesIntersectRect().
    496   EXPECT_TRUE(view_targeter->DoesIntersectRect(root_view,
    497                                                gfx::Rect(0, 0, 50, 50)));
    498   EXPECT_FALSE(view_targeter->DoesIntersectRect(root_view,
    499                                                 gfx::Rect(-20, -20, 10, 10)));
    500 }
    501 
    502 // Tests that calls made directly on the hit-testing methods in View
    503 // (HitTestPoint(), HitTestRect(), etc.) return the correct values.
    504 TEST_F(ViewTargeterTest, HitTestCallsOnView) {
    505   // The coordinates in this test are in the coordinate space of the root view.
    506   Widget* widget = new Widget;
    507   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
    508   widget->Init(params);
    509   View* root_view = widget->GetRootView();
    510   root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
    511 
    512   // |v1| has no hit test mask. No ViewTargeter is installed on |v1|, which
    513   // means that View::HitTestRect() will call into the targeter installed on
    514   // the root view instead when we hit test against |v1|.
    515   gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100);
    516   TestingView* v1 = new TestingView();
    517   v1->SetBoundsRect(v1_bounds);
    518   root_view->AddChildView(v1);
    519 
    520   // |v2| has a triangular hit test mask. Install a ViewTargeter on |v2| which
    521   // will be called into by View::HitTestRect().
    522   gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100);
    523   TestMaskedView* v2 = new TestMaskedView();
    524   v2->SetBoundsRect(v2_bounds);
    525   root_view->AddChildView(v2);
    526   ViewTargeter* view_targeter = new ViewTargeter(v2);
    527   v2->SetEventTargeter(make_scoped_ptr(view_targeter));
    528 
    529   gfx::Point v1_centerpoint = v1_bounds.CenterPoint();
    530   gfx::Point v2_centerpoint = v2_bounds.CenterPoint();
    531   gfx::Point v1_origin = v1_bounds.origin();
    532   gfx::Point v2_origin = v2_bounds.origin();
    533   gfx::Rect r1(10, 10, 110, 15);
    534   gfx::Rect r2(106, 1, 98, 98);
    535   gfx::Rect r3(0, 0, 300, 300);
    536   gfx::Rect r4(115, 342, 200, 10);
    537 
    538   // Test calls into View::HitTestPoint().
    539   EXPECT_TRUE(
    540       v1->HitTestPoint(ConvertPointFromWidgetToView(v1, v1_centerpoint)));
    541   EXPECT_TRUE(
    542       v2->HitTestPoint(ConvertPointFromWidgetToView(v2, v2_centerpoint)));
    543 
    544   EXPECT_TRUE(v1->HitTestPoint(ConvertPointFromWidgetToView(v1, v1_origin)));
    545   EXPECT_FALSE(v2->HitTestPoint(ConvertPointFromWidgetToView(v2, v2_origin)));
    546 
    547   // Test calls into View::HitTestRect().
    548   EXPECT_TRUE(v1->HitTestRect(ConvertRectFromWidgetToView(v1, r1)));
    549   EXPECT_FALSE(v2->HitTestRect(ConvertRectFromWidgetToView(v2, r1)));
    550 
    551   EXPECT_FALSE(v1->HitTestRect(ConvertRectFromWidgetToView(v1, r2)));
    552   EXPECT_TRUE(v2->HitTestRect(ConvertRectFromWidgetToView(v2, r2)));
    553 
    554   EXPECT_TRUE(v1->HitTestRect(ConvertRectFromWidgetToView(v1, r3)));
    555   EXPECT_TRUE(v2->HitTestRect(ConvertRectFromWidgetToView(v2, r3)));
    556 
    557   EXPECT_FALSE(v1->HitTestRect(ConvertRectFromWidgetToView(v1, r4)));
    558   EXPECT_FALSE(v2->HitTestRect(ConvertRectFromWidgetToView(v2, r4)));
    559 
    560   // Test calls into View::GetEventHandlerForPoint().
    561   EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint));
    562   EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint));
    563 
    564   EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin));
    565   EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin));
    566 
    567   // Test calls into View::GetTooltipHandlerForPoint().
    568   EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_centerpoint));
    569   EXPECT_EQ(v2, root_view->GetTooltipHandlerForPoint(v2_centerpoint));
    570 
    571   EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin));
    572   EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin));
    573 
    574   EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin));
    575 
    576   widget->CloseNow();
    577 }
    578 
    579 }  // namespace test
    580 }  // namespace views
    581