diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-16 21:28:01 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-16 21:28:01 +0000 |
commit | 6260f9e685ffa86d44750e61e1695bc57e9e122d (patch) | |
tree | 78250b5e4a4c2f66c64701d5edbe222e36845f05 /views | |
parent | d73d5f66e9c1d054e58b3966e9eaab7ab0020999 (diff) | |
download | chromium_src-6260f9e685ffa86d44750e61e1695bc57e9e122d.zip chromium_src-6260f9e685ffa86d44750e61e1695bc57e9e122d.tar.gz chromium_src-6260f9e685ffa86d44750e61e1695bc57e9e122d.tar.bz2 |
Remove "visible bounds in root changed" functions from RootView, move them to View.
Clean up the API a little. Adds a BoundsChanged() processing function to View that does default processing for bounds-changed events, including notifying the view via OnBoundsChanged() and potentially notifying of visible bounds changing. Adds a unit test for OnVisibleBoundsChanged.
http://crbug.com/72040
TEST=unit test
Review URL: http://codereview.chromium.org/6534001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/native/native_view_host.cc | 13 | ||||
-rw-r--r-- | views/controls/native/native_view_host.h | 3 | ||||
-rw-r--r-- | views/view.cc | 95 | ||||
-rw-r--r-- | views/view.h | 43 | ||||
-rw-r--r-- | views/view_unittest.cc | 76 | ||||
-rw-r--r-- | views/widget/root_view.cc | 38 | ||||
-rw-r--r-- | views/widget/root_view.h | 11 |
7 files changed, 160 insertions, 119 deletions
diff --git a/views/controls/native/native_view_host.cc b/views/controls/native/native_view_host.cc index 81f1f2f..4566b80 100644 --- a/views/controls/native/native_view_host.cc +++ b/views/controls/native/native_view_host.cc @@ -33,10 +33,6 @@ NativeViewHost::NativeViewHost() views_view_(NULL), fast_resize_(false), focus_view_(NULL) { - // The native widget is placed relative to the root. As such, we need to - // know when the position of any ancestor changes, or our visibility relative - // to other views changed as it'll effect our position relative to the root. - SetNotifyWhenVisibleBoundsInRootChanges(true); } NativeViewHost::~NativeViewHost() { @@ -156,7 +152,14 @@ void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) { Layout(); } -void NativeViewHost::VisibleBoundsInRootChanged() { +bool NativeViewHost::NeedsNotificationWhenVisibleBoundsChange() const { + // The native widget is placed relative to the root. As such, we need to + // know when the position of any ancestor changes, or our visibility relative + // to other views changed as it'll effect our position relative to the root. + return true; +} + +void NativeViewHost::OnVisibleBoundsChanged() { Layout(); } diff --git a/views/controls/native/native_view_host.h b/views/controls/native/native_view_host.h index da8e540..9c06f35 100644 --- a/views/controls/native/native_view_host.h +++ b/views/controls/native/native_view_host.h @@ -84,7 +84,8 @@ class NativeViewHost : public View { virtual bool ContainsNativeView(gfx::NativeView native_view) const; protected: - virtual void VisibleBoundsInRootChanged(); + virtual bool NeedsNotificationWhenVisibleBoundsChange() const; + virtual void OnVisibleBoundsChanged(); virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); virtual std::string GetClassName() const; diff --git a/views/view.cc b/views/view.cc index ab79197..4d75272 100644 --- a/views/view.cc +++ b/views/view.cc @@ -63,7 +63,6 @@ View::View() is_parent_owned_(true), parent_(NULL), is_visible_(true), - notify_when_visible_bounds_in_root_changes_(false), registered_for_visible_bounds_notification_(false), clip_x_(0), clip_y_(0), @@ -129,9 +128,8 @@ void View::AddChildViewAt(View* view, int index) { view->PropagateAddNotifications(this, view); UpdateTooltip(); - RootView* root = GetRootView(); - if (root) - RegisterChildrenForVisibleBoundsNotification(root, view); + if (GetWidget()) + RegisterChildrenForVisibleBoundsNotification(view); if (layout_manager_.get()) layout_manager_->ViewAdded(this, view); @@ -199,9 +197,6 @@ RootView* View::GetRootView() { return widget ? widget->GetRootView() : NULL; } -#ifndef NDEBUG -#endif - // Size and disposition -------------------------------------------------------- void View::SetBounds(int x, int y, int width, int height) { @@ -222,13 +217,8 @@ void View::SetBoundsRect(const gfx::Rect& bounds) { bool size_changed = prev.size() != bounds_.size(); bool position_changed = prev.origin() != bounds_.origin(); - if (size_changed || position_changed) { - OnBoundsChanged(); - - RootView* root = GetRootView(); - if (root) - root->ViewBoundsChanged(this, size_changed, position_changed); - } + if (size_changed || position_changed) + BoundsChanged(); } void View::SetSize(const gfx::Size& size) { @@ -1009,21 +999,11 @@ void View::PreferredSizeChanged() { parent_->ChildPreferredSizeChanged(this); } -void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) { - if (notify_when_visible_bounds_in_root_changes_ == value) - return; - notify_when_visible_bounds_in_root_changes_ = value; - RootView* root = GetRootView(); - if (root) { - if (value) - root->RegisterViewForVisibleBoundsNotification(this); - else - root->UnregisterViewForVisibleBoundsNotification(this); - } +bool View::NeedsNotificationWhenVisibleBoundsChange() const { + return false; } -bool View::GetNotifyWhenVisibleBoundsInRootChanges() { - return notify_when_visible_bounds_in_root_changes_; +void View::OnVisibleBoundsChanged() { } // Tree operations ------------------------------------------------------------- @@ -1198,9 +1178,8 @@ void View::DoRemoveChildView(View* view, next_focusable->previous_focusable_view_ = prev_focusable; } - RootView* root = GetRootView(); - if (root) - UnregisterChildrenForVisibleBoundsNotification(root, view); + if (GetWidget()) + UnregisterChildrenForVisibleBoundsNotification(view); view->PropagateRemoveNotifications(this); view->SetParent(NULL); @@ -1287,25 +1266,55 @@ void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { VisibilityChanged(starting_from, is_visible); } +void View::BoundsChanged() { + OnBoundsChanged(); + + // Notify interested Views that visible bounds within the root view may have + // changed. + if (descendants_to_notify_.get()) { + for (std::vector<View*>::iterator i = descendants_to_notify_->begin(); + i != descendants_to_notify_->end(); ++i) { + (*i)->OnVisibleBoundsChanged(); + } + } +} + // static -void View::RegisterChildrenForVisibleBoundsNotification( - RootView* root, View* view) { - DCHECK(root && view); - if (view->GetNotifyWhenVisibleBoundsInRootChanges()) - root->RegisterViewForVisibleBoundsNotification(view); +void View::RegisterChildrenForVisibleBoundsNotification(View* view) { + if (view->NeedsNotificationWhenVisibleBoundsChange()) + view->RegisterForVisibleBoundsNotification(); for (int i = 0; i < view->child_count(); ++i) - RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i)); + RegisterChildrenForVisibleBoundsNotification(view->GetChildViewAt(i)); } // static -void View::UnregisterChildrenForVisibleBoundsNotification( - RootView* root, View* view) { - DCHECK(root && view); - if (view->GetNotifyWhenVisibleBoundsInRootChanges()) - root->UnregisterViewForVisibleBoundsNotification(view); +void View::UnregisterChildrenForVisibleBoundsNotification(View* view) { + if (view->NeedsNotificationWhenVisibleBoundsChange()) + view->UnregisterForVisibleBoundsNotification(); for (int i = 0; i < view->child_count(); ++i) - UnregisterChildrenForVisibleBoundsNotification(root, - view->GetChildViewAt(i)); + UnregisterChildrenForVisibleBoundsNotification(view->GetChildViewAt(i)); +} + +void View::RegisterForVisibleBoundsNotification() { + if (registered_for_visible_bounds_notification_) + return; + registered_for_visible_bounds_notification_ = true; + View* ancestor = parent(); + while (ancestor) { + ancestor->AddDescendantToNotify(this); + ancestor = ancestor->parent(); + } +} + +void View::UnregisterForVisibleBoundsNotification() { + if (!registered_for_visible_bounds_notification_) + return; + registered_for_visible_bounds_notification_ = false; + View* ancestor = parent(); + while (ancestor) { + ancestor->RemoveDescendantToNotify(this); + ancestor = ancestor->parent(); + } } void View::AddDescendantToNotify(View* view) { diff --git a/views/view.h b/views/view.h index 4080070..6104ff1 100644 --- a/views/view.h +++ b/views/view.h @@ -986,17 +986,15 @@ class View : public AcceleratorTarget { // overriding such that the layout is properly invalidated. virtual void PreferredSizeChanged(); - // Sets whether this view wants notification when its visible bounds relative - // to the root view changes. If true, this view is notified any time the - // origin of one its ancestors changes, or the portion of the bounds not - // obscured by ancestors changes. The default is false. - void SetNotifyWhenVisibleBoundsInRootChanges(bool value); - bool GetNotifyWhenVisibleBoundsInRootChanges(); - - // Notification that this views visible bounds, relative to the RootView - // has changed. The visible bounds corresponds to the region of the - // view not obscured by other ancestors. - virtual void VisibleBoundsInRootChanged() {} + // Override returning true when the view needs to be notified when its visible + // bounds relative to the root view may have changed. Only used by + // NativeViewHost. + virtual bool NeedsNotificationWhenVisibleBoundsChange() const; + + // Notification that this View's visible bounds relative to the root view may + // have changed. The visible bounds are the region of the View not clipped by + // its ancestors. This is used for clipping NativeViewHost. + virtual void OnVisibleBoundsChanged(); // TODO(beng): eliminate in protected. // Whether this view is enabled. @@ -1233,13 +1231,19 @@ class View : public AcceleratorTarget { // VisibilityChanged(). void VisibilityChangedImpl(View* starting_from, bool is_visible); - // Recursively descends through all descendant views, - // registering/unregistering all views that want visible bounds in root - // view notification. - static void RegisterChildrenForVisibleBoundsNotification(RootView* root, - View* view); - static void UnregisterChildrenForVisibleBoundsNotification(RootView* root, - View* view); + // Responsible for propagating bounds change notifications to relevant + // views. + void BoundsChanged(); + + // Visible bounds notification registration. + // When a view is added to a hierarchy, it and all its children are asked if + // they need to be registered for "visible bounds within root" notifications + // (see comment on OnVisibleBoundsChanged()). If they do, they are registered + // with every ancestor between them and the root of the hierarchy. + static void RegisterChildrenForVisibleBoundsNotification(View* view); + static void UnregisterChildrenForVisibleBoundsNotification(View* view); + void RegisterForVisibleBoundsNotification(); + void UnregisterForVisibleBoundsNotification(); // Adds/removes view to the list of descendants that are notified any time // this views location and possibly size are changed. @@ -1347,9 +1351,6 @@ class View : public AcceleratorTarget { // Visible state bool is_visible_; - // See SetNotifyWhenVisibleBoundsInRootChanges. - bool notify_when_visible_bounds_in_root_changes_; - // Whether or not RegisterViewForVisibleBoundsNotification on the RootView // has been invoked. bool registered_for_visible_bounds_notification_; diff --git a/views/view_unittest.cc b/views/view_unittest.cc index 3b1dcfe..6ae69c5 100644 --- a/views/view_unittest.cc +++ b/views/view_unittest.cc @@ -1557,3 +1557,79 @@ TEST_F(ViewTest, TransformPaint) { widget->CloseNow(); } + +//////////////////////////////////////////////////////////////////////////////// +// OnVisibleBoundsChanged() + +class VisibleBoundsView : public View { + public: + VisibleBoundsView() : received_notification_(false) {} + virtual ~VisibleBoundsView() {} + + bool received_notification() const { return received_notification_; } + void set_received_notification(bool received) { + received_notification_ = received; + } + + private: + // Overridden from View: + virtual bool NeedsNotificationWhenVisibleBoundsChange() const { + return true; + } + virtual void OnVisibleBoundsChanged() { + received_notification_ = true; + } + + bool received_notification_; + + DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView); +}; + +#if defined(OS_WIN) +// TODO(beng): This can be cross platform when widget construction/init is. +TEST_F(ViewTest, OnVisibleBoundsChanged) { + gfx::Rect viewport_bounds(0, 0, 100, 100); + + scoped_ptr<Widget> widget(CreateWidget()); + WidgetWin* widget_win = static_cast<WidgetWin*>(widget.get()); + widget_win->set_delete_on_destroy(false); + widget_win->set_window_style(WS_OVERLAPPEDWINDOW); + widget_win->Init(NULL, viewport_bounds); + widget->GetRootView()->SetBoundsRect(viewport_bounds); + + View* viewport = new View; + widget->GetRootView()->SetContentsView(viewport); + View* contents = new View; + viewport->AddChildView(contents); + viewport->SetBoundsRect(viewport_bounds); + contents->SetBounds(0, 0, 100, 200); + + // Create a view that cares about visible bounds notifications, and position + // it just outside the visible bounds of the viewport. + VisibleBoundsView* child = new VisibleBoundsView; + contents->AddChildView(child); + child->SetBounds(10, 110, 50, 50); + + // The child bound should be fully clipped. + EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); + + // Now scroll the contents, but not enough to make the child visible. + contents->SetY(contents->y() - 1); + + // We should have received the notification since the visible bounds may have + // changed (even though they didn't). + EXPECT_TRUE(child->received_notification()); + EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); + child->set_received_notification(false); + + // Now scroll the contents, this time by enough to make the child visible by + // one pixel. + contents->SetY(contents->y() - 10); + EXPECT_TRUE(child->received_notification()); + EXPECT_EQ(1, child->GetVisibleBounds().height()); + child->set_received_notification(false); + + widget->CloseNow(); +} + +#endif diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc index 547e3ab..1de505e 100644 --- a/views/widget/root_view.cc +++ b/views/widget/root_view.cc @@ -702,44 +702,6 @@ void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { //////////////////////////////////////////////////////////////////////////////// // RootView, protected: -// Size and disposition -------------------------------------------------------- - -void RootView::ViewBoundsChanged(View* view, bool size_changed, - bool position_changed) { - DCHECK(view && (size_changed || position_changed)); - if (!view->descendants_to_notify_.get()) - return; - - for (std::vector<View*>::iterator i = view->descendants_to_notify_->begin(); - i != view->descendants_to_notify_->end(); ++i) { - (*i)->VisibleBoundsInRootChanged(); - } -} - -void RootView::RegisterViewForVisibleBoundsNotification(View* view) { - DCHECK(view); - if (view->registered_for_visible_bounds_notification_) - return; - view->registered_for_visible_bounds_notification_ = true; - View* ancestor = view->parent(); - while (ancestor) { - ancestor->AddDescendantToNotify(view); - ancestor = ancestor->parent(); - } -} - -void RootView::UnregisterViewForVisibleBoundsNotification(View* view) { - DCHECK(view); - if (!view->registered_for_visible_bounds_notification_) - return; - view->registered_for_visible_bounds_notification_ = false; - View* ancestor = view->parent(); - while (ancestor) { - ancestor->RemoveDescendantToNotify(view); - ancestor = ancestor->parent(); - } -} - // Coordinate conversion ------------------------------------------------------- bool RootView::ConvertPointToMouseHandler(const gfx::Point& l, diff --git a/views/widget/root_view.h b/views/widget/root_view.h index ba294a8..495b013 100644 --- a/views/widget/root_view.h +++ b/views/widget/root_view.h @@ -205,17 +205,6 @@ class RootView : public View, friend class GestureManager; #endif - // Size and disposition ------------------------------------------------------ - - // Notification that size and/or position of a view has changed. This - // notifies the appropriate views. - void ViewBoundsChanged(View* view, bool size_changed, bool position_changed); - - // Registers a view for notification when the visible bounds relative to the - // root of a view changes. - void RegisterViewForVisibleBoundsNotification(View* view); - void UnregisterViewForVisibleBoundsNotification(View* view); - // Coordinate conversion ----------------------------------------------------- // Convert a point to our current mouse handler. Returns false if the |