summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbeng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-16 00:37:56 +0000
committerbeng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-16 00:37:56 +0000
commit82739cfe200335e53c66b36e6b467c32294f7ef0 (patch)
tree32436525bb71a6ac93124da4e1dcc4b8c0bc48ed /chrome
parent0ae7d14ea97bdb4170948521144de57059eb4eeb (diff)
downloadchromium_src-82739cfe200335e53c66b36e6b467c32294f7ef0.zip
chromium_src-82739cfe200335e53c66b36e6b467c32294f7ef0.tar.gz
chromium_src-82739cfe200335e53c66b36e6b467c32294f7ef0.tar.bz2
Allow Views to support an optional hit-test mask. Make hittest use this.
Make GetViewForPoint call HitTest instead of rolling its own crude hit testing. Update custom-shaped views to use this framework instead of overriding hittest themselves. B=2273 Review URL: http://codereview.chromium.org/3051 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2255 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/views/tabs/tab.cc11
-rw-r--r--chrome/browser/views/tabs/tab.h4
-rw-r--r--chrome/browser/views/tabs/tab_strip.cc12
-rw-r--r--chrome/views/view.cc41
-rw-r--r--chrome/views/view.h12
-rw-r--r--chrome/views/view_unittest.cc74
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));
+}