diff options
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 11 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.h | 4 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_strip.cc | 12 | ||||
-rw-r--r-- | chrome/views/view.cc | 41 | ||||
-rw-r--r-- | chrome/views/view.h | 12 | ||||
-rw-r--r-- | chrome/views/view_unittest.cc | 74 |
6 files changed, 125 insertions, 29 deletions
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc index bf5dc89..ec2ec29 100644 --- a/chrome/browser/views/tabs/tab.cc +++ b/chrome/browser/views/tabs/tab.cc @@ -126,11 +126,12 @@ bool Tab::IsSelected() const { /////////////////////////////////////////////////////////////////////////////// // Tab, ChromeViews::View overrides: -bool Tab::HitTest(const CPoint &l) const { - gfx::Path path; - MakePathForTab(&path); - ScopedHRGN rgn(path.CreateHRGN()); - return !!PtInRegion(rgn, l.x, l.y); +bool Tab::HasHitTestMask() const { + return true; +} + +void Tab::GetHitTestMask(gfx::Path* mask) const { + MakePathForTab(mask); } bool Tab::OnMousePressed(const ChromeViews::MouseEvent& event) { diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h index 753e1a9..369a39d 100644 --- a/chrome/browser/views/tabs/tab.h +++ b/chrome/browser/views/tabs/tab.h @@ -84,10 +84,10 @@ class Tab : public TabRenderer, // TabRenderer overrides: virtual bool IsSelected() const; - // ChromeViews::View overrides: - virtual bool HitTest(const CPoint &l) const; private: // ChromeViews::View overrides: + virtual bool HasHitTestMask() const; + virtual void GetHitTestMask(gfx::Path* mask) const; virtual bool OnMousePressed(const ChromeViews::MouseEvent& event); virtual bool OnMouseDragged(const ChromeViews::MouseEvent& event); virtual void OnMouseReleased(const ChromeViews::MouseEvent& event, diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index 748b9e7..6182e9b 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -67,15 +67,10 @@ class NewTabButton : public ChromeViews::Button { protected: // Overridden from ChromeViews::View: - virtual bool HitTest(const CPoint &l) const { - gfx::Path path; - MakePathForButton(&path); - ScopedHRGN rgn(path.CreateHRGN()); - return !!PtInRegion(rgn, l.x, l.y); + virtual bool HasHitTestMask() const { + return true; } - - private: - void MakePathForButton(gfx::Path* path) const { + virtual void GetHitTestMask(gfx::Path* path) const { DCHECK(path); SkScalar h = SkIntToScalar(GetHeight()); @@ -95,6 +90,7 @@ class NewTabButton : public ChromeViews::Button { path->close(); } + private: DISALLOW_COPY_AND_ASSIGN(NewTabButton); }; diff --git a/chrome/views/view.cc b/chrome/views/view.cc index 45543cc..18dfd65 100644 --- a/chrome/views/view.cc +++ b/chrome/views/view.cc @@ -12,9 +12,11 @@ #include "base/logging.h" #include "base/message_loop.h" +#include "base/scoped_handle.h" #include "base/string_util.h" #include "chrome/common/drag_drop_types.h" #include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/path.h" #include "chrome/common/l10n_util.h" #include "chrome/common/os_exchange_data.h" #include "chrome/views/accessibility/accessible_wrapper.h" @@ -712,6 +714,14 @@ bool View::IsProcessingPaint() const { } #endif +bool View::HasHitTestMask() const { + return false; +} + +void View::GetHitTestMask(gfx::Path* mask) const { + DCHECK(mask); +} + void View::ViewHierarchyChanged(bool is_add, View *parent, View *child) { } @@ -768,16 +778,13 @@ View* View::GetViewForPoint(const CPoint& point, bool can_create_floating) { // tightly encloses the specified point. for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) { View* child = GetChildViewAt(i); - if (!child->IsVisible()) { + if (!child->IsVisible()) continue; - } - CRect bounds; - child->GetBounds(&bounds, APPLY_MIRRORING_TRANSFORMATION); - if (bounds.PtInRect(point)) { - CPoint cl(point); - cl.Offset(-bounds.left, -bounds.top); - return child->GetViewForPoint(cl, true); - } + + CPoint point_in_child_coords(point); + View::ConvertPointToView(this, child, &point_in_child_coords); + if (child->HitTest(point_in_child_coords)) + return child->GetViewForPoint(point_in_child_coords, true); } // We haven't found a view for the point. Try to create floating views @@ -1437,13 +1444,19 @@ bool View::IsVisibleInRootView() const { return false; } -bool View::HitTest(const CPoint &l) const { - if (l.x >= 0 && l.x < static_cast<int>(GetWidth()) && - l.y >= 0 && l.y < static_cast<int>(GetHeight())) { +bool View::HitTest(const CPoint& l) const { + if (l.x >= 0 && l.x < GetWidth() && l.y >= 0 && l.y < GetHeight()) { + if (HasHitTestMask()) { + gfx::Path mask; + GetHitTestMask(&mask); + ScopedHRGN rgn(mask.CreateHRGN()); + return !!PtInRegion(rgn, l.x, l.y); + } + // No mask, but inside our bounds. return true; - } else { - return false; } + // Outside our bounds. + return false; } HCURSOR View::GetCursorForPoint(Event::EventType event_type, int x, int y) { diff --git a/chrome/views/view.h b/chrome/views/view.h index c758418..a4ae692 100644 --- a/chrome/views/view.h +++ b/chrome/views/view.h @@ -19,6 +19,7 @@ namespace gfx { class Insets; +class Path; } class AccessibleWrapper; @@ -973,6 +974,7 @@ class View : public AcceleratorTarget { bool is_horizontal, bool is_positive); protected: + // TODO(beng): these members should NOT be protected per style guide. // This View's bounds in the parent coordinate system. CRect bounds_; @@ -989,6 +991,16 @@ class View : public AcceleratorTarget { virtual bool IsProcessingPaint() const; #endif + // Called by HitTest to see if this View has a custom hit test mask. If the + // return value is true, GetHitTestMask will be called to obtain the mask. + // Default value is false, in which case the View will hit-test against its + // bounds. + virtual bool HasHitTestMask() const; + + // Called by HitTest to retrieve a mask for hit-testing against. Subclasses + // override to provide custom shaped hit test regions. + virtual void GetHitTestMask(gfx::Path* mask) const; + // This method is invoked when the tree changes. // // When a view is removed, it is invoked for all children and grand diff --git a/chrome/views/view_unittest.cc b/chrome/views/view_unittest.cc index a658132..e404102 100644 --- a/chrome/views/view_unittest.cc +++ b/chrome/views/view_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/path.h" #include "chrome/views/background.h" #include "chrome/views/event.h" #include "chrome/views/root_view.h" @@ -506,3 +507,76 @@ TEST_F(ViewTest, RemoveNotification) { NOTIFY_VIEW_REMOVED, NotificationService::AllSources()); } +namespace { +class HitTestView : public ChromeViews::View { + public: + explicit HitTestView(bool has_hittest_mask) + : has_hittest_mask_(has_hittest_mask) { + } + virtual ~HitTestView() {} + + protected: + // Overridden from ChromeViews::View: + virtual bool HasHitTestMask() const { + return has_hittest_mask_; + } + virtual void GetHitTestMask(gfx::Path* mask) const { + DCHECK(has_hittest_mask_); + DCHECK(mask); + + SkScalar w = SkIntToScalar(GetWidth()); + SkScalar h = SkIntToScalar(GetHeight()); + + // Create a triangular mask within the bounds of this View. + mask->moveTo(w / 2, 0); + mask->lineTo(w, h); + mask->lineTo(0, h); + mask->close(); + } + + private: + bool has_hittest_mask_; + + DISALLOW_COPY_AND_ASSIGN(HitTestView); +}; + +POINT ConvertPointToView(ChromeViews::View* view, const POINT& p) { + CPoint tmp = p; + ChromeViews::View::ConvertPointToView(view->GetRootView(), view, &tmp); + return tmp; +} +} + +TEST_F(ViewTest, HitTestMasks) { + ChromeViews::HWNDViewContainer* window = new ChromeViews::HWNDViewContainer; + ChromeViews::RootView* root_view = window->GetRootView(); + root_view->SetBounds(0, 0, 500, 500); + + gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100); + HitTestView* v1 = new HitTestView(false); + v1->SetBounds(v1_bounds.ToRECT()); + root_view->AddChildView(v1); + + gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100); + HitTestView* v2 = new HitTestView(true); + v2->SetBounds(v2_bounds.ToRECT()); + root_view->AddChildView(v2); + + POINT v1_centerpoint = v1_bounds.CenterPoint().ToPOINT(); + POINT v2_centerpoint = v2_bounds.CenterPoint().ToPOINT(); + POINT v1_origin = v1_bounds.origin().ToPOINT(); + POINT v2_origin = v2_bounds.origin().ToPOINT(); + + // Test HitTest + EXPECT_EQ(true, v1->HitTest(ConvertPointToView(v1, v1_centerpoint))); + EXPECT_EQ(true, v2->HitTest(ConvertPointToView(v2, v2_centerpoint))); + + EXPECT_EQ(true, v1->HitTest(ConvertPointToView(v1, v1_origin))); + EXPECT_EQ(false, v2->HitTest(ConvertPointToView(v2, v2_origin))); + + // Test GetViewForPoint + EXPECT_EQ(v1, root_view->GetViewForPoint(v1_centerpoint)); + EXPECT_EQ(v2, root_view->GetViewForPoint(v2_centerpoint)); + EXPECT_EQ(v1, root_view->GetViewForPoint(v1_origin)); + EXPECT_EQ(root_view, root_view->GetViewForPoint(v2_origin)); +} |