diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-30 23:35:20 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-30 23:35:20 +0000 |
commit | 5025f86107dafec51f98c62dbdc996fbb703a361 (patch) | |
tree | a871aad5635c650c243b44b59d1802f79f590458 /views | |
parent | 5c9a1adb03e4e0059e25366a908f30dd28786790 (diff) | |
download | chromium_src-5025f86107dafec51f98c62dbdc996fbb703a361.zip chromium_src-5025f86107dafec51f98c62dbdc996fbb703a361.tar.gz chromium_src-5025f86107dafec51f98c62dbdc996fbb703a361.tar.bz2 |
views: Move view.h to ui/views/.
BUG=104039
R=ben@chromium.org
TBR=stevenjb@chromium.org
Review URL: http://codereview.chromium.org/8742030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112333 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/accessible_pane_view.h | 2 | ||||
-rw-r--r-- | views/background.cc | 2 | ||||
-rw-r--r-- | views/border.h | 2 | ||||
-rw-r--r-- | views/paint_lock.cc | 2 | ||||
-rw-r--r-- | views/run_all_unittests.cc | 2 | ||||
-rw-r--r-- | views/view.cc | 2061 | ||||
-rw-r--r-- | views/view.h | 1440 | ||||
-rw-r--r-- | views/view_aura.cc | 37 | ||||
-rw-r--r-- | views/view_gtk.cc | 39 | ||||
-rw-r--r-- | views/view_unittest.cc | 3068 | ||||
-rw-r--r-- | views/view_win.cc | 36 | ||||
-rw-r--r-- | views/views.gyp | 12 |
12 files changed, 11 insertions, 6692 deletions
diff --git a/views/accessible_pane_view.h b/views/accessible_pane_view.h index 655ebd9..104294e 100644 --- a/views/accessible_pane_view.h +++ b/views/accessible_pane_view.h @@ -11,7 +11,7 @@ #include "base/memory/weak_ptr.h" #include "ui/base/accelerators/accelerator.h" #include "ui/views/focus/focus_manager.h" -#include "views/view.h" +#include "ui/views/view.h" namespace views { class FocusSearch; diff --git a/views/background.cc b/views/background.cc index fa79793..717261d 100644 --- a/views/background.cc +++ b/views/background.cc @@ -9,8 +9,8 @@ #include "third_party/skia/include/core/SkPaint.h" #include "ui/gfx/canvas_skia.h" #include "ui/gfx/color_utils.h" +#include "ui/views/view.h" #include "views/painter.h" -#include "views/view.h" namespace views { diff --git a/views/border.h b/views/border.h index 27a46c6..fc7bdc4 100644 --- a/views/border.h +++ b/views/border.h @@ -8,7 +8,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/insets.h" -#include "views/view.h" +#include "ui/views/view.h" namespace gfx{ class Canvas; diff --git a/views/paint_lock.cc b/views/paint_lock.cc index 282c2c3..3b2ce1d 100644 --- a/views/paint_lock.cc +++ b/views/paint_lock.cc @@ -4,7 +4,7 @@ #include "views/paint_lock.h" -#include "views/view.h" +#include "ui/views/view.h" namespace views { diff --git a/views/run_all_unittests.cc b/views/run_all_unittests.cc index 083d4a8..e675291 100644 --- a/views/run_all_unittests.cc +++ b/views/run_all_unittests.cc @@ -7,7 +7,7 @@ #include "ui/base/ui_base_paths.h" #include "ui/gfx/compositor/test/compositor_test_support.h" #include "ui/gfx/test/gfx_test_utils.h" -#include "views/view.h" +#include "ui/views/view.h" class ViewTestSuite : public base::TestSuite { public: diff --git a/views/view.cc b/views/view.cc deleted file mode 100644 index 6a0db83..0000000 --- a/views/view.cc +++ /dev/null @@ -1,2061 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/view.h" - -#include <algorithm> - -#include "base/debug/trace_event.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop.h" -#include "base/stringprintf.h" -#include "base/utf_string_conversions.h" -#include "third_party/skia/include/core/SkRect.h" -#include "ui/base/accessibility/accessibility_types.h" -#include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/gfx/canvas_skia.h" -#include "ui/gfx/compositor/compositor.h" -#include "ui/gfx/compositor/layer.h" -#include "ui/gfx/compositor/layer_animator.h" -#include "ui/gfx/interpolated_transform.h" -#include "ui/gfx/path.h" -#include "ui/gfx/point3.h" -#include "ui/gfx/transform.h" -#include "ui/views/context_menu_controller.h" -#include "ui/views/drag_controller.h" -#include "ui/views/layout/layout_manager.h" -#include "ui/views/widget/native_widget_private.h" -#include "ui/views/widget/root_view.h" -#include "ui/views/widget/tooltip_manager.h" -#include "ui/views/widget/widget.h" -#include "views/background.h" -#include "views/views_delegate.h" - -#if defined(OS_WIN) -#include "base/win/scoped_gdi_object.h" -#include "ui/views/accessibility/native_view_accessibility_win.h" -#endif -#if defined(TOOLKIT_USES_GTK) -#include "ui/base/gtk/scoped_handle_gtk.h" -#endif - -namespace { - -// Whether to use accelerated compositing when necessary (e.g. when a view has a -// transformation). -#if defined(VIEWS_COMPOSITOR) -bool use_acceleration_when_possible = true; -#else -bool use_acceleration_when_possible = false; -#endif - -// Saves the drawing state, and restores the state when going out of scope. -class ScopedCanvas { - public: - explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) { - if (canvas_) - canvas_->Save(); - } - ~ScopedCanvas() { - if (canvas_) - canvas_->Restore(); - } - void SetCanvas(gfx::Canvas* canvas) { - if (canvas_) - canvas_->Restore(); - canvas_ = canvas; - canvas_->Save(); - } - - private: - gfx::Canvas* canvas_; - - DISALLOW_COPY_AND_ASSIGN(ScopedCanvas); -}; - -// Returns the top view in |view|'s hierarchy. -const views::View* GetHierarchyRoot(const views::View* view) { - const views::View* root = view; - while (root && root->parent()) - root = root->parent(); - return root; -} - -} // namespace - -namespace views { - -// static -ViewsDelegate* ViewsDelegate::views_delegate = NULL; - -// static -const char View::kViewClassName[] = "views/View"; - -//////////////////////////////////////////////////////////////////////////////// -// View, public: - -// TO BE MOVED ----------------------------------------------------------------- - -void View::SetHotTracked(bool flag) { -} - -bool View::IsHotTracked() const { - return false; -} - -// Creation and lifetime ------------------------------------------------------- - -View::View() - : parent_owned_(true), - id_(0), - group_(-1), - parent_(NULL), - visible_(true), - enabled_(true), - painting_enabled_(true), - registered_for_visible_bounds_notification_(false), - clip_x_(0.0), - clip_y_(0.0), - needs_layout_(true), - flip_canvas_on_paint_for_rtl_ui_(false), - paint_to_layer_(false), - accelerator_registration_delayed_(false), - accelerator_focus_manager_(NULL), - registered_accelerator_count_(0), - next_focusable_view_(NULL), - previous_focusable_view_(NULL), - focusable_(false), - accessibility_focusable_(false), - context_menu_controller_(NULL), - drag_controller_(NULL) { -} - -View::~View() { - if (parent_) - parent_->RemoveChildView(this); - - for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) { - (*i)->parent_ = NULL; - if ((*i)->parent_owned()) - delete *i; - } - -#if defined(OS_WIN) - if (native_view_accessibility_win_.get()) - native_view_accessibility_win_->set_view(NULL); -#endif -} - -// Tree operations ------------------------------------------------------------- - -const Widget* View::GetWidget() const { - // The root view holds a reference to this view hierarchy's Widget. - return parent_ ? parent_->GetWidget() : NULL; -} - -Widget* View::GetWidget() { - return const_cast<Widget*>(const_cast<const View*>(this)->GetWidget()); -} - -void View::AddChildView(View* view) { - AddChildViewAt(view, child_count()); -} - -void View::AddChildViewAt(View* view, int index) { - CHECK_NE(view, this) << "You cannot add a view as its own child"; - - // If |view| has a parent, remove it from its parent. - View* parent = view->parent_; - if (parent) - parent->RemoveChildView(view); - - // Sets the prev/next focus views. - InitFocusSiblings(view, index); - - // Let's insert the view. - view->parent_ = this; - children_.insert(children_.begin() + index, view); - - for (View* v = this; v; v = v->parent_) - v->ViewHierarchyChangedImpl(false, true, this, view); - - view->PropagateAddNotifications(this, view); - UpdateTooltip(); - if (GetWidget()) - RegisterChildrenForVisibleBoundsNotification(view); - - if (layout_manager_.get()) - layout_manager_->ViewAdded(this, view); - - if (use_acceleration_when_possible) - ReorderLayers(); - - // Make sure the visibility of the child layers are correct. - // If any of the parent View is hidden, then the layers of the subtree - // rooted at |this| should be hidden. Otherwise, all the child layers should - // inherit the visibility of the owner View. - UpdateLayerVisibility(); -} - -void View::ReorderChildView(View* view, int index) { - DCHECK_EQ(view->parent_, this); - if (index < 0) - index = child_count() - 1; - else if (index >= child_count()) - return; - if (children_[index] == view) - return; - - const Views::iterator i(std::find(children_.begin(), children_.end(), view)); - DCHECK(i != children_.end()); - children_.erase(i); - - // Unlink the view first - View* next_focusable = view->next_focusable_view_; - View* prev_focusable = view->previous_focusable_view_; - if (prev_focusable) - prev_focusable->next_focusable_view_ = next_focusable; - if (next_focusable) - next_focusable->previous_focusable_view_ = prev_focusable; - - // Add it in the specified index now. - InitFocusSiblings(view, index); - children_.insert(children_.begin() + index, view); - - if (use_acceleration_when_possible) - ReorderLayers(); -} - -void View::RemoveChildView(View* view) { - DoRemoveChildView(view, true, true, false); -} - -void View::RemoveAllChildViews(bool delete_children) { - while (!children_.empty()) - DoRemoveChildView(children_.front(), false, false, delete_children); - UpdateTooltip(); -} - -bool View::Contains(const View* view) const { - for (const View* v = view; v; v = v->parent_) { - if (v == this) - return true; - } - return false; -} - -int View::GetIndexOf(const View* view) const { - Views::const_iterator i(std::find(children_.begin(), children_.end(), view)); - return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1; -} - -// Size and disposition -------------------------------------------------------- - -void View::SetBounds(int x, int y, int width, int height) { - SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height))); -} - -void View::SetBoundsRect(const gfx::Rect& bounds) { - if (bounds == bounds_) { - if (needs_layout_) { - needs_layout_ = false; - Layout(); - SchedulePaint(); - } - return; - } - - if (IsVisible()) { - // Paint where the view is currently. - SchedulePaintBoundsChanged( - bounds_.size() == bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : - SCHEDULE_PAINT_SIZE_CHANGED); - } - - gfx::Rect prev = bounds_; - bounds_ = bounds; - BoundsChanged(prev); -} - -void View::SetSize(const gfx::Size& size) { - SetBounds(x(), y(), size.width(), size.height()); -} - -void View::SetPosition(const gfx::Point& position) { - SetBounds(position.x(), position.y(), width(), height()); -} - -void View::SetX(int x) { - SetBounds(x, y(), width(), height()); -} - -void View::SetY(int y) { - SetBounds(x(), y, width(), height()); -} - -gfx::Rect View::GetContentsBounds() const { - gfx::Rect contents_bounds(GetLocalBounds()); - if (border_.get()) { - gfx::Insets insets; - border_->GetInsets(&insets); - contents_bounds.Inset(insets); - } - return contents_bounds; -} - -gfx::Rect View::GetLocalBounds() const { - return gfx::Rect(gfx::Point(), size()); -} - -gfx::Insets View::GetInsets() const { - gfx::Insets insets; - if (border_.get()) - border_->GetInsets(&insets); - return insets; -} - -gfx::Rect View::GetVisibleBounds() const { - if (!IsVisibleInRootView()) - return gfx::Rect(); - gfx::Rect vis_bounds(0, 0, width(), height()); - gfx::Rect ancestor_bounds; - const View* view = this; - ui::Transform transform; - - while (view != NULL && !vis_bounds.IsEmpty()) { - transform.ConcatTransform(view->GetTransform()); - transform.ConcatTranslate(static_cast<float>(view->GetMirroredX()), - static_cast<float>(view->y())); - - vis_bounds = view->ConvertRectToParent(vis_bounds); - const View* ancestor = view->parent_; - if (ancestor != NULL) { - ancestor_bounds.SetRect(0, 0, ancestor->width(), ancestor->height()); - vis_bounds = vis_bounds.Intersect(ancestor_bounds); - } else if (!view->GetWidget()) { - // If the view has no Widget, we're not visible. Return an empty rect. - return gfx::Rect(); - } - view = ancestor; - } - if (vis_bounds.IsEmpty()) - return vis_bounds; - // Convert back to this views coordinate system. - transform.TransformRectReverse(&vis_bounds); - return vis_bounds; -} - -gfx::Rect View::GetScreenBounds() const { - gfx::Point origin; - View::ConvertPointToScreen(this, &origin); - return gfx::Rect(origin, size()); -} - -gfx::Size View::GetPreferredSize() { - if (layout_manager_.get()) - return layout_manager_->GetPreferredSize(this); - return gfx::Size(); -} - -int View::GetBaseline() const { - return -1; -} - -void View::SizeToPreferredSize() { - gfx::Size prefsize = GetPreferredSize(); - if ((prefsize.width() != width()) || (prefsize.height() != height())) - SetBounds(x(), y(), prefsize.width(), prefsize.height()); -} - -gfx::Size View::GetMinimumSize() { - return GetPreferredSize(); -} - -int View::GetHeightForWidth(int w) { - if (layout_manager_.get()) - return layout_manager_->GetPreferredHeightForWidth(this, w); - return GetPreferredSize().height(); -} - -void View::SetVisible(bool visible) { - if (visible != visible_) { - // If the View is currently visible, schedule paint to refresh parent. - // TODO(beng): not sure we should be doing this if we have a layer. - if (visible_) - SchedulePaint(); - - visible_ = visible; - - // This notifies all sub-views recursively. - PropagateVisibilityNotifications(this, visible_); - UpdateLayerVisibility(); - - // If we are newly visible, schedule paint. - if (visible_) - SchedulePaint(); - } -} - -bool View::IsVisible() const { - return visible_; -} - -bool View::IsVisibleInRootView() const { - return IsVisible() && parent_ ? parent_->IsVisibleInRootView() : false; -} - -void View::SetEnabled(bool enabled) { - if (enabled != enabled_) { - enabled_ = enabled; - OnEnabledChanged(); - } -} - -bool View::IsEnabled() const { - return enabled_; -} - -void View::OnEnabledChanged() { - SchedulePaint(); -} - -// Transformations ------------------------------------------------------------- - -const ui::Transform& View::GetTransform() const { - static const ui::Transform* no_op = new ui::Transform; - return layer() ? layer()->transform() : *no_op; -} - -void View::SetTransform(const ui::Transform& transform) { - if (!transform.HasChange()) { - if (layer()) { - layer()->SetTransform(transform); - if (!paint_to_layer_) - DestroyLayer(); - } else { - // Nothing. - } - } else { - if (!layer()) - CreateLayer(); - layer()->SetTransform(transform); - layer()->ScheduleDraw(); - } -} - -void View::SetPaintToLayer(bool paint_to_layer) { - paint_to_layer_ = paint_to_layer; - if (paint_to_layer_ && !layer()) { - CreateLayer(); - } else if (!paint_to_layer_ && layer()) { - DestroyLayer(); - } -} - -// RTL positioning ------------------------------------------------------------- - -gfx::Rect View::GetMirroredBounds() const { - gfx::Rect bounds(bounds_); - bounds.set_x(GetMirroredX()); - return bounds; -} - -gfx::Point View::GetMirroredPosition() const { - return gfx::Point(GetMirroredX(), y()); -} - -int View::GetMirroredX() const { - return parent_ ? parent_->GetMirroredXForRect(bounds_) : x(); -} - -int View::GetMirroredXForRect(const gfx::Rect& bounds) const { - return base::i18n::IsRTL() ? - (width() - bounds.x() - bounds.width()) : bounds.x(); -} - -int View::GetMirroredXInView(int x) const { - return base::i18n::IsRTL() ? width() - x : x; -} - -int View::GetMirroredXWithWidthInView(int x, int w) const { - return base::i18n::IsRTL() ? width() - x - w : x; -} - -// Layout ---------------------------------------------------------------------- - -void View::Layout() { - needs_layout_ = false; - - // If we have a layout manager, let it handle the layout for us. - if (layout_manager_.get()) - layout_manager_->Layout(this); - - // Make sure to propagate the Layout() call to any children that haven't - // received it yet through the layout manager and need to be laid out. This - // is needed for the case when the child requires a layout but its bounds - // weren't changed by the layout manager. If there is no layout manager, we - // just propagate the Layout() call down the hierarchy, so whoever receives - // the call can take appropriate action. - for (int i = 0, count = child_count(); i < count; ++i) { - View* child = child_at(i); - if (child->needs_layout_ || !layout_manager_.get()) { - child->needs_layout_ = false; - child->Layout(); - } - } -} - -void View::InvalidateLayout() { - // Always invalidate up. This is needed to handle the case of us already being - // valid, but not our parent. - needs_layout_ = true; - if (parent_) - parent_->InvalidateLayout(); -} - -LayoutManager* View::GetLayoutManager() const { - return layout_manager_.get(); -} - -void View::SetLayoutManager(LayoutManager* layout_manager) { - if (layout_manager_.get()) - layout_manager_->Uninstalled(this); - - layout_manager_.reset(layout_manager); - if (layout_manager_.get()) - layout_manager_->Installed(this); -} - -// Attributes ------------------------------------------------------------------ - -std::string View::GetClassName() const { - return kViewClassName; -} - -View* View::GetAncestorWithClassName(const std::string& name) { - for (View* view = this; view; view = view->parent_) { - if (view->GetClassName() == name) - return view; - } - return NULL; -} - -const View* View::GetViewByID(int id) const { - if (id == id_) - return const_cast<View*>(this); - - for (int i = 0, count = child_count(); i < count; ++i) { - const View* view = child_at(i)->GetViewByID(id); - if (view) - return view; - } - return NULL; -} - -View* View::GetViewByID(int id) { - return const_cast<View*>(const_cast<const View*>(this)->GetViewByID(id)); -} - -void View::SetGroup(int gid) { - // Don't change the group id once it's set. - DCHECK(group_ == -1 || group_ == gid); - group_ = gid; -} - -int View::GetGroup() const { - return group_; -} - -bool View::IsGroupFocusTraversable() const { - return true; -} - -void View::GetViewsInGroup(int group, Views* views) { - if (group_ == group) - views->push_back(this); - - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->GetViewsInGroup(group, views); -} - -View* View::GetSelectedViewForGroup(int group) { - Views views; - GetWidget()->GetRootView()->GetViewsInGroup(group, &views); - return views.empty() ? NULL : views[0]; -} - -// Coordinate conversion ------------------------------------------------------- - -// static -void View::ConvertPointToView(const View* source, - const View* target, - gfx::Point* point) { - if (source == target) - return; - - // |source| can be NULL. - const View* root = GetHierarchyRoot(target); - if (source) { - CHECK_EQ(GetHierarchyRoot(source), root); - - if (source != root) - source->ConvertPointForAncestor(root, point); - } - - if (target != root) - target->ConvertPointFromAncestor(root, point); - - // API defines NULL |source| as returning the point in screen coordinates. - if (!source) { - *point = point->Subtract( - root->GetWidget()->GetClientAreaScreenBounds().origin()); - } -} - -// static -void View::ConvertPointToWidget(const View* src, gfx::Point* p) { - DCHECK(src); - DCHECK(p); - - src->ConvertPointForAncestor(NULL, p); -} - -// static -void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { - DCHECK(dest); - DCHECK(p); - - dest->ConvertPointFromAncestor(NULL, p); -} - -// static -void View::ConvertPointToScreen(const View* src, gfx::Point* p) { - DCHECK(src); - DCHECK(p); - - // If the view is not connected to a tree, there's nothing we can do. - const Widget* widget = src->GetWidget(); - if (widget) { - ConvertPointToWidget(src, p); - gfx::Rect r = widget->GetClientAreaScreenBounds(); - p->SetPoint(p->x() + r.x(), p->y() + r.y()); - } -} - -gfx::Rect View::ConvertRectToParent(const gfx::Rect& rect) const { - gfx::Rect x_rect = rect; - GetTransform().TransformRect(&x_rect); - x_rect.Offset(GetMirroredPosition()); - return x_rect; -} - -gfx::Rect View::ConvertRectToWidget(const gfx::Rect& rect) const { - gfx::Rect x_rect = rect; - for (const View* v = this; v; v = v->parent_) - x_rect = v->ConvertRectToParent(x_rect); - return x_rect; -} - -// Painting -------------------------------------------------------------------- - -void View::SchedulePaint() { - SchedulePaintInRect(GetLocalBounds()); -} - -void View::SchedulePaintInRect(const gfx::Rect& rect) { - if (!IsVisible() || !painting_enabled_) - return; - - if (layer()) { - layer()->SchedulePaint(rect); - } else if (parent_) { - // Translate the requested paint rect to the parent's coordinate system - // then pass this notification up to the parent. - parent_->SchedulePaintInRect(ConvertRectToParent(rect)); - } -} - -void View::Paint(gfx::Canvas* canvas) { - TRACE_EVENT0("views", "View::Paint"); - - ScopedCanvas scoped_canvas(canvas); - - // Paint this View and its children, setting the clip rect to the bounds - // of this View and translating the origin to the local bounds' top left - // point. - // - // Note that the X (or left) position we pass to ClipRectInt takes into - // consideration whether or not the view uses a right-to-left layout so that - // we paint our view in its mirrored position if need be. - if (!canvas->ClipRect(gfx::Rect(GetMirroredX(), y(), - width() - static_cast<int>(clip_x_), - height() - static_cast<int>(clip_y_)))) { - return; - } - // Non-empty clip, translate the graphics such that 0,0 corresponds to - // where this view is located (related to its parent). - canvas->Translate(GetMirroredPosition()); - canvas->Transform(GetTransform()); - - PaintCommon(canvas); -} - -ThemeProvider* View::GetThemeProvider() const { - const Widget* widget = GetWidget(); - return widget ? widget->GetThemeProvider() : NULL; -} - -// Accelerated Painting -------------------------------------------------------- - -// static -void View::set_use_acceleration_when_possible(bool use) { - use_acceleration_when_possible = use; -} - -// static -bool View::get_use_acceleration_when_possible() { - return use_acceleration_when_possible; -} - -// Input ----------------------------------------------------------------------- - -View* View::GetEventHandlerForPoint(const gfx::Point& point) { - // Walk the child Views recursively looking for the View that most - // tightly encloses the specified point. - for (int i = child_count() - 1; i >= 0; --i) { - View* child = child_at(i); - if (!child->IsVisible()) - continue; - - gfx::Point point_in_child_coords(point); - View::ConvertPointToView(this, child, &point_in_child_coords); - if (child->HitTest(point_in_child_coords)) - return child->GetEventHandlerForPoint(point_in_child_coords); - } - return this; -} - -gfx::NativeCursor View::GetCursor(const MouseEvent& event) { -#if defined(OS_WIN) && !defined(USE_AURA) - static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW); - return arrow; -#else - return gfx::kNullCursor; -#endif -} - -bool View::HitTest(const gfx::Point& l) const { - if (GetLocalBounds().Contains(l)) { - if (HasHitTestMask()) { - gfx::Path mask; - GetHitTestMask(&mask); -#if defined(USE_AURA) - // TODO: should we use this every where? - SkRegion clip_region; - clip_region.setRect(0, 0, width(), height()); - SkRegion mask_region; - return mask_region.setPath(mask, clip_region) && - mask_region.contains(l.x(), l.y()); -#elif defined(OS_WIN) - base::win::ScopedRegion rgn(mask.CreateNativeRegion()); - return !!PtInRegion(rgn, l.x(), l.y()); -#elif defined(TOOLKIT_USES_GTK) - ui::ScopedRegion rgn(mask.CreateNativeRegion()); - return gdk_region_point_in(rgn.Get(), l.x(), l.y()); -#endif - } - // No mask, but inside our bounds. - return true; - } - // Outside our bounds. - return false; -} - -bool View::OnMousePressed(const MouseEvent& event) { - return false; -} - -bool View::OnMouseDragged(const MouseEvent& event) { - return false; -} - -void View::OnMouseReleased(const MouseEvent& event) { -} - -void View::OnMouseCaptureLost() { -} - -void View::OnMouseMoved(const MouseEvent& event) { -} - -void View::OnMouseEntered(const MouseEvent& event) { -} - -void View::OnMouseExited(const MouseEvent& event) { -} - -ui::TouchStatus View::OnTouchEvent(const TouchEvent& event) { - DVLOG(1) << "visited the OnTouchEvent"; - return ui::TOUCH_STATUS_UNKNOWN; -} - -void View::SetMouseHandler(View *new_mouse_handler) { - // It is valid for new_mouse_handler to be NULL - if (parent_) - parent_->SetMouseHandler(new_mouse_handler); -} - -bool View::OnKeyPressed(const KeyEvent& event) { - return false; -} - -bool View::OnKeyReleased(const KeyEvent& event) { - return false; -} - -bool View::OnMouseWheel(const MouseWheelEvent& event) { - return false; -} - -ui::TextInputClient* View::GetTextInputClient() { - return NULL; -} - -InputMethod* View::GetInputMethod() { - Widget* widget = GetWidget(); - return widget ? widget->GetInputMethod() : NULL; -} - -// Accelerators ---------------------------------------------------------------- - -void View::AddAccelerator(const ui::Accelerator& accelerator) { - if (!accelerators_.get()) - accelerators_.reset(new std::vector<ui::Accelerator>()); - - DCHECK(std::find(accelerators_->begin(), accelerators_->end(), accelerator) == - accelerators_->end()) - << "Registering the same accelerator multiple times"; - - accelerators_->push_back(accelerator); - RegisterPendingAccelerators(); -} - -void View::RemoveAccelerator(const ui::Accelerator& accelerator) { - if (!accelerators_.get()) { - NOTREACHED() << "Removing non-existing accelerator"; - return; - } - - std::vector<ui::Accelerator>::iterator i( - std::find(accelerators_->begin(), accelerators_->end(), accelerator)); - if (i == accelerators_->end()) { - NOTREACHED() << "Removing non-existing accelerator"; - return; - } - - size_t index = i - accelerators_->begin(); - accelerators_->erase(i); - if (index >= registered_accelerator_count_) { - // The accelerator is not registered to FocusManager. - return; - } - --registered_accelerator_count_; - - // Providing we are attached to a Widget and registered with a focus manager, - // we should de-register from that focus manager now. - if (GetWidget() && accelerator_focus_manager_) - accelerator_focus_manager_->UnregisterAccelerator(accelerator, this); -} - -void View::ResetAccelerators() { - if (accelerators_.get()) - UnregisterAccelerators(false); -} - -bool View::AcceleratorPressed(const ui::Accelerator& accelerator) { - return false; -} - -// Focus ----------------------------------------------------------------------- - -bool View::HasFocus() const { - const FocusManager* focus_manager = GetFocusManager(); - return focus_manager && (focus_manager->GetFocusedView() == this); -} - -View* View::GetNextFocusableView() { - return next_focusable_view_; -} - -const View* View::GetNextFocusableView() const { - return next_focusable_view_; -} - -View* View::GetPreviousFocusableView() { - return previous_focusable_view_; -} - -void View::SetNextFocusableView(View* view) { - view->previous_focusable_view_ = this; - next_focusable_view_ = view; -} - -bool View::IsFocusableInRootView() const { - return IsFocusable() && IsVisibleInRootView(); -} - -bool View::IsAccessibilityFocusableInRootView() const { - return (focusable_ || accessibility_focusable_) && IsEnabled() && - IsVisibleInRootView(); -} - -FocusManager* View::GetFocusManager() { - Widget* widget = GetWidget(); - return widget ? widget->GetFocusManager() : NULL; -} - -const FocusManager* View::GetFocusManager() const { - const Widget* widget = GetWidget(); - return widget ? widget->GetFocusManager() : NULL; -} - -void View::RequestFocus() { - FocusManager* focus_manager = GetFocusManager(); - if (focus_manager && IsFocusableInRootView()) - focus_manager->SetFocusedView(this); -} - -bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) { - return false; -} - -FocusTraversable* View::GetFocusTraversable() { - return NULL; -} - -FocusTraversable* View::GetPaneFocusTraversable() { - return NULL; -} - -// Tooltips -------------------------------------------------------------------- - -bool View::GetTooltipText(const gfx::Point& p, string16* tooltip) const { - return false; -} - -bool View::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const { - return false; -} - -// Context menus --------------------------------------------------------------- - -void View::ShowContextMenu(const gfx::Point& p, bool is_mouse_gesture) { - if (!context_menu_controller_) - return; - - context_menu_controller_->ShowContextMenuForView(this, p, is_mouse_gesture); -} - -// Drag and drop --------------------------------------------------------------- - -bool View::GetDropFormats( - int* formats, - std::set<OSExchangeData::CustomFormat>* custom_formats) { - return false; -} - -bool View::AreDropTypesRequired() { - return false; -} - -bool View::CanDrop(const OSExchangeData& data) { - // TODO(sky): when I finish up migration, this should default to true. - return false; -} - -void View::OnDragEntered(const DropTargetEvent& event) { -} - -int View::OnDragUpdated(const DropTargetEvent& event) { - return ui::DragDropTypes::DRAG_NONE; -} - -void View::OnDragExited() { -} - -int View::OnPerformDrop(const DropTargetEvent& event) { - return ui::DragDropTypes::DRAG_NONE; -} - -void View::OnDragDone() { -} - -// static -bool View::ExceededDragThreshold(int delta_x, int delta_y) { - return (abs(delta_x) > GetHorizontalDragThreshold() || - abs(delta_y) > GetVerticalDragThreshold()); -} - -// Scrolling ------------------------------------------------------------------- - -void View::ScrollRectToVisible(const gfx::Rect& rect) { - // We must take RTL UI mirroring into account when adjusting the position of - // the region. - if (parent_) { - gfx::Rect scroll_rect(rect); - scroll_rect.Offset(GetMirroredX(), y()); - parent_->ScrollRectToVisible(scroll_rect); - } -} - -int View::GetPageScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive) { - return 0; -} - -int View::GetLineScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive) { - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// View, protected: - -// Size and disposition -------------------------------------------------------- - -void View::OnBoundsChanged(const gfx::Rect& previous_bounds) { -} - -void View::PreferredSizeChanged() { - InvalidateLayout(); - if (parent_) - parent_->ChildPreferredSizeChanged(this); -} - -bool View::NeedsNotificationWhenVisibleBoundsChange() const { - return false; -} - -void View::OnVisibleBoundsChanged() { -} - -// Tree operations ------------------------------------------------------------- - -void View::ViewHierarchyChanged(bool is_add, View* parent, View* child) { -} - -void View::VisibilityChanged(View* starting_from, bool is_visible) { -} - -void View::NativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - internal::RootView* root_view) { - FocusManager* focus_manager = GetFocusManager(); - if (!accelerator_registration_delayed_ && - accelerator_focus_manager_ && - accelerator_focus_manager_ != focus_manager) { - UnregisterAccelerators(true); - accelerator_registration_delayed_ = true; - } - if (accelerator_registration_delayed_ && attached) { - if (focus_manager) { - RegisterPendingAccelerators(); - accelerator_registration_delayed_ = false; - } - } -} - -// Painting -------------------------------------------------------------------- - -void View::PaintChildren(gfx::Canvas* canvas) { - TRACE_EVENT0("views", "View::PaintChildren"); - for (int i = 0, count = child_count(); i < count; ++i) - if (!child_at(i)->layer()) - child_at(i)->Paint(canvas); -} - -void View::OnPaint(gfx::Canvas* canvas) { - TRACE_EVENT0("views", "View::OnPaint"); - OnPaintBackground(canvas); - OnPaintFocusBorder(canvas); - OnPaintBorder(canvas); -} - -void View::OnPaintBackground(gfx::Canvas* canvas) { - if (background_.get()) { - TRACE_EVENT2("views", "View::OnPaintBackground", - "width", canvas->GetSkCanvas()->getDevice()->width(), - "height", canvas->GetSkCanvas()->getDevice()->height()); - background_->Paint(canvas, this); - } -} - -void View::OnPaintBorder(gfx::Canvas* canvas) { - if (border_.get()) { - TRACE_EVENT2("views", "View::OnPaintBorder", - "width", canvas->GetSkCanvas()->getDevice()->width(), - "height", canvas->GetSkCanvas()->getDevice()->height()); - border_->Paint(*this, canvas); - } -} - -void View::OnPaintFocusBorder(gfx::Canvas* canvas) { - if ((IsFocusable() || IsAccessibilityFocusableInRootView()) && HasFocus()) { - TRACE_EVENT2("views", "views::OnPaintFocusBorder", - "width", canvas->GetSkCanvas()->getDevice()->width(), - "height", canvas->GetSkCanvas()->getDevice()->height()); - canvas->DrawFocusRect(GetLocalBounds()); - } -} - -// Accelerated Painting -------------------------------------------------------- - -void View::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { - // This method should not have the side-effect of creating the layer. - if (layer()) - layer()->SetFillsBoundsOpaquely(fills_bounds_opaquely); -} - -bool View::SetExternalTexture(ui::Texture* texture) { - DCHECK(texture); - SetPaintToLayer(true); - - layer()->SetExternalTexture(texture); - - // Child views must not paint into the external texture. So make sure each - // child view has its own layer to paint into. - for (Views::iterator i = children_.begin(); i != children_.end(); ++i) - (*i)->SetPaintToLayer(true); - - SchedulePaintInRect(GetLocalBounds()); - return true; -} - -void View::CalculateOffsetToAncestorWithLayer(gfx::Point* offset, - ui::Layer** layer_parent) { - if (layer()) { - if (layer_parent) - *layer_parent = layer(); - return; - } - if (!parent_) - return; - - offset->Offset(x(), y()); - parent_->CalculateOffsetToAncestorWithLayer(offset, layer_parent); -} - -void View::MoveLayerToParent(ui::Layer* parent_layer, - const gfx::Point& point) { - gfx::Point local_point(point); - if (parent_layer != layer()) - local_point.Offset(x(), y()); - if (layer() && parent_layer != layer()) { - parent_layer->Add(layer()); - layer()->SetBounds(gfx::Rect(local_point.x(), local_point.y(), - width(), height())); - } else { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->MoveLayerToParent(parent_layer, local_point); - } -} - -void View::UpdateLayerVisibility() { - if (!use_acceleration_when_possible) - return; - bool visible = IsVisible(); - for (const View* v = parent_; visible && v && !v->layer(); v = v->parent_) - visible = v->IsVisible(); - - UpdateChildLayerVisibility(visible); -} - -void View::UpdateChildLayerVisibility(bool ancestor_visible) { - if (layer()) { - layer()->SetVisible(ancestor_visible && IsVisible()); - } else { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->UpdateChildLayerVisibility(ancestor_visible && IsVisible()); - } -} - -void View::UpdateChildLayerBounds(const gfx::Point& offset) { - if (layer()) { - layer()->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height())); - } else { - for (int i = 0, count = child_count(); i < count; ++i) { - gfx::Point new_offset(offset.x() + child_at(i)->x(), - offset.y() + child_at(i)->y()); - child_at(i)->UpdateChildLayerBounds(new_offset); - } - } -} - -void View::OnPaintLayer(gfx::Canvas* canvas) { - if (!layer() || !layer()->fills_bounds_opaquely()) - canvas->GetSkCanvas()->drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); - PaintCommon(canvas); -} - -void View::ReorderLayers() { - View* v = this; - while (v && !v->layer()) - v = v->parent(); - - // Forward to widget in case we're in a NativeWidgetView. - if (!v) { - if (GetWidget()) - GetWidget()->ReorderLayers(); - } else { - for (Views::const_iterator i(v->children_.begin()); - i != v->children_.end(); - ++i) - (*i)->ReorderChildLayers(v->layer()); - } -} - -void View::ReorderChildLayers(ui::Layer* parent_layer) { - if (layer()) { - DCHECK_EQ(parent_layer, layer()->parent()); - parent_layer->StackAtTop(layer()); - } else { - for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) - (*i)->ReorderChildLayers(parent_layer); - } -} - -// Input ----------------------------------------------------------------------- - -bool View::HasHitTestMask() const { - return false; -} - -void View::GetHitTestMask(gfx::Path* mask) const { - DCHECK(mask); -} - -// Focus ----------------------------------------------------------------------- - -bool View::IsFocusable() const { - return focusable_ && IsEnabled() && IsVisible(); -} - -void View::OnFocus() { - // TODO(beng): Investigate whether it's possible for us to move this to - // Focus(). - // By default, we clear the native focus. This ensures that no visible native - // view as the focus and that we still receive keyboard inputs. - FocusManager* focus_manager = GetFocusManager(); - if (focus_manager) - focus_manager->ClearNativeFocus(); - - // TODO(beng): Investigate whether it's possible for us to move this to - // Focus(). - // Notify assistive technologies of the focus change. - GetWidget()->NotifyAccessibilityEvent( - this, ui::AccessibilityTypes::EVENT_FOCUS, true); -} - -void View::OnBlur() { -} - -void View::Focus() { - SchedulePaint(); - OnFocus(); -} - -void View::Blur() { - SchedulePaint(); - OnBlur(); -} - -// Tooltips -------------------------------------------------------------------- - -void View::TooltipTextChanged() { - Widget* widget = GetWidget(); - // TooltipManager may be null if there is a problem creating it. - if (widget && widget->native_widget_private()->GetTooltipManager()) { - widget->native_widget_private()->GetTooltipManager()-> - TooltipTextChanged(this); - } -} - -// Context menus --------------------------------------------------------------- - -gfx::Point View::GetKeyboardContextMenuLocation() { - gfx::Rect vis_bounds = GetVisibleBounds(); - gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2, - vis_bounds.y() + vis_bounds.height() / 2); - ConvertPointToScreen(this, &screen_point); - return screen_point; -} - -// Drag and drop --------------------------------------------------------------- - -int View::GetDragOperations(const gfx::Point& press_pt) { - return drag_controller_ ? - drag_controller_->GetDragOperationsForView(this, press_pt) : - ui::DragDropTypes::DRAG_NONE; -} - -void View::WriteDragData(const gfx::Point& press_pt, OSExchangeData* data) { - DCHECK(drag_controller_); - drag_controller_->WriteDragDataForView(this, press_pt, data); -} - -bool View::InDrag() { - Widget* widget = GetWidget(); - return widget ? widget->dragged_view() == this : false; -} - -// Debugging ------------------------------------------------------------------- - -#if !defined(NDEBUG) - -std::string View::PrintViewGraph(bool first) { - return DoPrintViewGraph(first, this); -} - -std::string View::DoPrintViewGraph(bool first, View* view_with_children) { - // 64-bit pointer = 16 bytes of hex + "0x" + '\0' = 19. - const size_t kMaxPointerStringLength = 19; - - std::string result; - - if (first) - result.append("digraph {\n"); - - // Node characteristics. - char p[kMaxPointerStringLength]; - - size_t baseNameIndex = GetClassName().find_last_of('/'); - if (baseNameIndex == std::string::npos) - baseNameIndex = 0; - else - baseNameIndex++; - - char bounds_buffer[512]; - - // Information about current node. - base::snprintf(p, arraysize(bounds_buffer), "%p", view_with_children); - result.append(" N"); - result.append(p+2); - result.append(" [label=\""); - - result.append(GetClassName().substr(baseNameIndex).c_str()); - - base::snprintf(bounds_buffer, - arraysize(bounds_buffer), - "\\n bounds: (%d, %d), (%dx%d)", - this->bounds().x(), - this->bounds().y(), - this->bounds().width(), - this->bounds().height()); - result.append(bounds_buffer); - - if (layer() && !layer()->hole_rect().IsEmpty()) { - base::snprintf(bounds_buffer, - arraysize(bounds_buffer), - "\\n hole bounds: (%d, %d), (%dx%d)", - layer()->hole_rect().x(), - layer()->hole_rect().y(), - layer()->hole_rect().width(), - layer()->hole_rect().height()); - result.append(bounds_buffer); - } - - if (GetTransform().HasChange()) { - gfx::Point translation; - float rotation; - gfx::Point3f scale; - if (ui::InterpolatedTransform::FactorTRS(GetTransform(), - &translation, - &rotation, - &scale)) { - if (translation != gfx::Point(0, 0)) { - base::snprintf(bounds_buffer, - arraysize(bounds_buffer), - "\\n translation: (%d, %d)", - translation.x(), - translation.y()); - result.append(bounds_buffer); - } - - if (fabs(rotation) > 1e-5) { - base::snprintf(bounds_buffer, - arraysize(bounds_buffer), - "\\n rotation: %3.2f", rotation); - result.append(bounds_buffer); - } - - if (scale.AsPoint() != gfx::Point(0, 0)) { - base::snprintf(bounds_buffer, - arraysize(bounds_buffer), - "\\n scale: (%2.4f, %2.4f)", - scale.x(), - scale.y()); - result.append(bounds_buffer); - } - } - } - - result.append("\""); - if (!parent_) - result.append(", shape=box"); - if (layer()) { - if (layer()->texture()) - result.append(", color=green"); - else - result.append(", color=red"); - - if (layer()->fills_bounds_opaquely()) - result.append(", style=filled"); - } - result.append("]\n"); - - // Link to parent. - if (parent_) { - char pp[kMaxPointerStringLength]; - - base::snprintf(pp, kMaxPointerStringLength, "%p", parent_); - result.append(" N"); - result.append(pp+2); - result.append(" -> N"); - result.append(p+2); - result.append("\n"); - } - - // Children. - for (int i = 0, count = view_with_children->child_count(); i < count; ++i) - result.append(view_with_children->child_at(i)->PrintViewGraph(false)); - - if (first) - result.append("}\n"); - - return result; -} - -#endif - -//////////////////////////////////////////////////////////////////////////////// -// View, private: - -// DropInfo -------------------------------------------------------------------- - -void View::DragInfo::Reset() { - possible_drag = false; - start_pt = gfx::Point(); -} - -void View::DragInfo::PossibleDrag(const gfx::Point& p) { - possible_drag = true; - start_pt = p; -} - -// Painting -------------------------------------------------------------------- - -void View::SchedulePaintBoundsChanged(SchedulePaintType type) { - // If we have a layer and the View's size did not change, we do not need to - // schedule any paints since the layer will be redrawn at its new location - // during the next Draw() cycle in the compositor. - if (!layer() || type == SCHEDULE_PAINT_SIZE_CHANGED) { - // Otherwise, if the size changes or we don't have a layer then we need to - // use SchedulePaint to invalidate the area occupied by the View. - SchedulePaint(); - } else if (parent_ && type == SCHEDULE_PAINT_SIZE_SAME) { - // The compositor doesn't Draw() until something on screen changes, so - // if our position changes but nothing is being animated on screen, then - // tell the compositor to redraw the scene. We know layer() exists due to - // the above if clause. - layer()->ScheduleDraw(); - } -} - -void View::PaintCommon(gfx::Canvas* canvas) { - if (!IsVisible() || !painting_enabled_) - return; - - { - // If the View we are about to paint requested the canvas to be flipped, we - // should change the transform appropriately. - // The canvas mirroring is undone once the View is done painting so that we - // don't pass the canvas with the mirrored transform to Views that didn't - // request the canvas to be flipped. - ScopedCanvas scoped(canvas); - if (FlipCanvasOnPaintForRTLUI()) { - canvas->Translate(gfx::Point(width(), 0)); - canvas->Scale(-1, 1); - } - - OnPaint(canvas); - } - - PaintChildren(canvas); -} - -// Tree operations ------------------------------------------------------------- - -void View::DoRemoveChildView(View* view, - bool update_focus_cycle, - bool update_tool_tip, - bool delete_removed_view) { - DCHECK(view); - const Views::iterator i(std::find(children_.begin(), children_.end(), view)); - scoped_ptr<View> view_to_be_deleted; - if (i != children_.end()) { - if (update_focus_cycle) { - // Let's remove the view from the focus traversal. - View* next_focusable = view->next_focusable_view_; - View* prev_focusable = view->previous_focusable_view_; - if (prev_focusable) - prev_focusable->next_focusable_view_ = next_focusable; - if (next_focusable) - next_focusable->previous_focusable_view_ = prev_focusable; - } - - if (GetWidget()) - UnregisterChildrenForVisibleBoundsNotification(view); - view->PropagateRemoveNotifications(this); - view->parent_ = NULL; - view->UpdateLayerVisibility(); - - if (delete_removed_view && view->parent_owned()) - view_to_be_deleted.reset(view); - - children_.erase(i); - } - - if (update_tool_tip) - UpdateTooltip(); - - if (layout_manager_.get()) - layout_manager_->ViewRemoved(this, view); -} - -void View::PropagateRemoveNotifications(View* parent) { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->PropagateRemoveNotifications(parent); - - for (View* v = this; v; v = v->parent_) - v->ViewHierarchyChangedImpl(true, false, parent, this); -} - -void View::PropagateAddNotifications(View* parent, View* child) { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->PropagateAddNotifications(parent, child); - ViewHierarchyChangedImpl(true, true, parent, child); -} - -void View::PropagateNativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - internal::RootView* root_view) { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->PropagateNativeViewHierarchyChanged(attached, - native_view, - root_view); - NativeViewHierarchyChanged(attached, native_view, root_view); -} - -void View::ViewHierarchyChangedImpl(bool register_accelerators, - bool is_add, - View* parent, - View* child) { - if (register_accelerators) { - if (is_add) { - // If you get this registration, you are part of a subtree that has been - // added to the view hierarchy. - if (GetFocusManager()) { - RegisterPendingAccelerators(); - } else { - // Delay accelerator registration until visible as we do not have - // focus manager until then. - accelerator_registration_delayed_ = true; - } - } else { - if (child == this) - UnregisterAccelerators(true); - } - } - - if (is_add && layer() && !layer()->parent()) { - UpdateParentLayer(); - } else if (!is_add && child == this) { - // Make sure the layers beloning to the subtree rooted at |child| get - // removed from layers that do not belong in the same subtree. - OrphanLayers(); - } - - ViewHierarchyChanged(is_add, parent, child); - parent->needs_layout_ = true; -} - -// Size and disposition -------------------------------------------------------- - -void View::PropagateVisibilityNotifications(View* start, bool is_visible) { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->PropagateVisibilityNotifications(start, is_visible); - VisibilityChangedImpl(start, is_visible); -} - -void View::VisibilityChangedImpl(View* starting_from, bool is_visible) { - if (is_visible) - RegisterPendingAccelerators(); - else - UnregisterAccelerators(true); - VisibilityChanged(starting_from, is_visible); -} - -void View::BoundsChanged(const gfx::Rect& previous_bounds) { - if (IsVisible()) { - // Paint the new bounds. - SchedulePaintBoundsChanged( - bounds_.size() == previous_bounds.size() ? SCHEDULE_PAINT_SIZE_SAME : - SCHEDULE_PAINT_SIZE_CHANGED); - } - - if (use_acceleration_when_possible) { - if (layer()) { - if (parent_) { - gfx::Point offset; - parent_->CalculateOffsetToAncestorWithLayer(&offset, NULL); - offset.Offset(x(), y()); - layer()->SetBounds(gfx::Rect(offset, size())); - } else { - layer()->SetBounds(bounds_); - } - // TODO(beng): this seems redundant with the SchedulePaint at the top of - // this function. explore collapsing. - if (previous_bounds.size() != bounds_.size() && - !layer()->layer_updated_externally()) { - // If our bounds have changed then we need to update the complete - // texture. - layer()->SchedulePaint(GetLocalBounds()); - } - } else { - // If our bounds have changed, then any descendant layer bounds may - // have changed. Update them accordingly. - gfx::Point offset; - CalculateOffsetToAncestorWithLayer(&offset, NULL); - UpdateChildLayerBounds(offset); - } - } - - OnBoundsChanged(previous_bounds); - - if (previous_bounds.size() != size()) { - needs_layout_ = false; - Layout(); - } - - if (NeedsNotificationWhenVisibleBoundsChange()) - OnVisibleBoundsChanged(); - - // Notify interested Views that visible bounds within the root view may have - // changed. - if (descendants_to_notify_.get()) { - for (Views::iterator i(descendants_to_notify_->begin()); - i != descendants_to_notify_->end(); ++i) { - (*i)->OnVisibleBoundsChanged(); - } - } -} - -// static -void View::RegisterChildrenForVisibleBoundsNotification(View* view) { - if (view->NeedsNotificationWhenVisibleBoundsChange()) - view->RegisterForVisibleBoundsNotification(); - for (int i = 0; i < view->child_count(); ++i) - RegisterChildrenForVisibleBoundsNotification(view->child_at(i)); -} - -// static -void View::UnregisterChildrenForVisibleBoundsNotification(View* view) { - if (view->NeedsNotificationWhenVisibleBoundsChange()) - view->UnregisterForVisibleBoundsNotification(); - for (int i = 0; i < view->child_count(); ++i) - UnregisterChildrenForVisibleBoundsNotification(view->child_at(i)); -} - -void View::RegisterForVisibleBoundsNotification() { - if (registered_for_visible_bounds_notification_) - return; - - registered_for_visible_bounds_notification_ = true; - for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) - ancestor->AddDescendantToNotify(this); -} - -void View::UnregisterForVisibleBoundsNotification() { - if (!registered_for_visible_bounds_notification_) - return; - - registered_for_visible_bounds_notification_ = false; - for (View* ancestor = parent_; ancestor; ancestor = ancestor->parent_) - ancestor->RemoveDescendantToNotify(this); -} - -void View::AddDescendantToNotify(View* view) { - DCHECK(view); - if (!descendants_to_notify_.get()) - descendants_to_notify_.reset(new Views); - descendants_to_notify_->push_back(view); -} - -void View::RemoveDescendantToNotify(View* view) { - DCHECK(view && descendants_to_notify_.get()); - Views::iterator i(std::find( - descendants_to_notify_->begin(), descendants_to_notify_->end(), view)); - DCHECK(i != descendants_to_notify_->end()); - descendants_to_notify_->erase(i); - if (descendants_to_notify_->empty()) - descendants_to_notify_.reset(); -} - -// Transformations ------------------------------------------------------------- - -bool View::GetTransformRelativeTo(const View* ancestor, - ui::Transform* transform) const { - const View* p = this; - - while (p && p != ancestor) { - transform->ConcatTransform(p->GetTransform()); - transform->ConcatTranslate(static_cast<float>(p->GetMirroredX()), - static_cast<float>(p->y())); - - p = p->parent_; - } - - return p == ancestor; -} - -// Coordinate conversion ------------------------------------------------------- - -bool View::ConvertPointForAncestor(const View* ancestor, - gfx::Point* point) const { - ui::Transform trans; - // TODO(sad): Have some way of caching the transformation results. - bool result = GetTransformRelativeTo(ancestor, &trans); - gfx::Point3f p(*point); - trans.TransformPoint(p); - *point = p.AsPoint(); - return result; -} - -bool View::ConvertPointFromAncestor(const View* ancestor, - gfx::Point* point) const { - ui::Transform trans; - bool result = GetTransformRelativeTo(ancestor, &trans); - gfx::Point3f p(*point); - trans.TransformPointReverse(p); - *point = p.AsPoint(); - return result; -} - -// Accelerated painting -------------------------------------------------------- - -void View::CreateLayer() { - // A new layer is being created for the view. So all the layers of the - // sub-tree can inherit the visibility of the corresponding view. - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->UpdateChildLayerVisibility(true); - - layer_.reset(new ui::Layer()); - layer_->set_delegate(this); -#if !defined(NDEBUG) - layer_->set_name(GetClassName()); -#endif - - UpdateParentLayers(); - UpdateLayerVisibility(); - - // The new layer needs to be ordered in the layer tree according - // to the view tree. Children of this layer were added in order - // in UpdateParentLayers(). - if (parent()) - parent()->ReorderLayers(); -} - -void View::UpdateParentLayers() { - // Attach all top-level un-parented layers. - if (layer() && !layer()->parent()) { - UpdateParentLayer(); - } else { - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->UpdateParentLayers(); - } -} - -void View::UpdateParentLayer() { - if (!layer()) - return; - - ui::Layer* parent_layer = NULL; - gfx::Point offset(x(), y()); - - // TODO(sad): The NULL check here for parent_ essentially is to check if this - // is the RootView. Instead of doing this, this function should be made - // virtual and overridden from the RootView. - if (parent_) - parent_->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer); - else if (!parent_ && GetWidget()) - GetWidget()->CalculateOffsetToAncestorWithLayer(&offset, &parent_layer); - - ReparentLayer(offset, parent_layer); -} - -void View::OrphanLayers() { - if (layer()) { - if (layer()->parent()) - layer()->parent()->Remove(layer()); - - // The layer belonging to this View has already been orphaned. It is not - // necessary to orphan the child layers. - return; - } - for (int i = 0, count = child_count(); i < count; ++i) - child_at(i)->OrphanLayers(); -} - -void View::ReparentLayer(const gfx::Point& offset, ui::Layer* parent_layer) { - layer_->SetBounds(gfx::Rect(offset.x(), offset.y(), width(), height())); - DCHECK_NE(layer(), parent_layer); - if (parent_layer) - parent_layer->Add(layer()); - layer_->SchedulePaint(GetLocalBounds()); - MoveLayerToParent(layer(), gfx::Point()); -} - -void View::DestroyLayer() { - ui::Layer* new_parent = layer()->parent(); - std::vector<ui::Layer*> children = layer()->children(); - for (size_t i = 0; i < children.size(); ++i) { - layer()->Remove(children[i]); - if (new_parent) - new_parent->Add(children[i]); - } - - layer_.reset(); - - if (new_parent) - ReorderLayers(); - - gfx::Point offset; - CalculateOffsetToAncestorWithLayer(&offset, NULL); - UpdateChildLayerBounds(offset); - - SchedulePaint(); -} - -// Input ----------------------------------------------------------------------- - -bool View::ProcessMousePressed(const MouseEvent& event, DragInfo* drag_info) { - const bool enabled = IsEnabled(); - int drag_operations = - (enabled && event.IsOnlyLeftMouseButton() && HitTest(event.location())) ? - GetDragOperations(event.location()) : 0; - ContextMenuController* context_menu_controller = event.IsRightMouseButton() ? - context_menu_controller_ : 0; - - const bool result = OnMousePressed(event); - // WARNING: we may have been deleted, don't use any View variables. - - if (!enabled) - return result; - - if (drag_operations != ui::DragDropTypes::DRAG_NONE) { - drag_info->PossibleDrag(event.location()); - return true; - } - return !!context_menu_controller || result; -} - -bool View::ProcessMouseDragged(const MouseEvent& event, DragInfo* drag_info) { - // Copy the field, that way if we're deleted after drag and drop no harm is - // done. - ContextMenuController* context_menu_controller = context_menu_controller_; - const bool possible_drag = drag_info->possible_drag; - if (possible_drag && ExceededDragThreshold( - drag_info->start_pt.x() - event.x(), - drag_info->start_pt.y() - event.y())) { - if (!drag_controller_ || - drag_controller_->CanStartDragForView( - this, drag_info->start_pt, event.location())) - DoDrag(event, drag_info->start_pt); - } else { - if (OnMouseDragged(event)) - return true; - // Fall through to return value based on context menu controller. - } - // WARNING: we may have been deleted. - return (context_menu_controller != NULL) || possible_drag; -} - -void View::ProcessMouseReleased(const MouseEvent& event) { - if (context_menu_controller_ && event.IsOnlyRightMouseButton()) { - // Assume that if there is a context menu controller we won't be deleted - // from mouse released. - gfx::Point location(event.location()); - OnMouseReleased(event); - if (HitTest(location)) { - ConvertPointToScreen(this, &location); - ShowContextMenu(location, true); - } - } else { - OnMouseReleased(event); - } - // WARNING: we may have been deleted. -} - -ui::TouchStatus View::ProcessTouchEvent(const TouchEvent& event) { - // TODO(rjkroege): Implement a grab scheme similar to as as is found in - // MousePressed. - return OnTouchEvent(event); -} - -// Accelerators ---------------------------------------------------------------- - -void View::RegisterPendingAccelerators() { - if (!accelerators_.get() || - registered_accelerator_count_ == accelerators_->size()) { - // No accelerators are waiting for registration. - return; - } - - if (!GetWidget()) { - // The view is not yet attached to a widget, defer registration until then. - return; - } - - accelerator_focus_manager_ = GetFocusManager(); - if (!accelerator_focus_manager_) { - // Some crash reports seem to show that we may get cases where we have no - // focus manager (see bug #1291225). This should never be the case, just - // making sure we don't crash. - - // TODO(jcampan): This fails for a view under NativeWidgetGtk with - // TYPE_CHILD. (see http://crbug.com/21335) reenable - // NOTREACHED assertion and verify accelerators works as - // expected. -#if defined(OS_WIN) - NOTREACHED(); -#endif - return; - } - // Only register accelerators if we are visible. - if (!IsVisibleInRootView() || !GetWidget()->IsVisible()) - return; - for (std::vector<ui::Accelerator>::const_iterator i( - accelerators_->begin() + registered_accelerator_count_); - i != accelerators_->end(); ++i) { - accelerator_focus_manager_->RegisterAccelerator(*i, this); - } - registered_accelerator_count_ = accelerators_->size(); -} - -void View::UnregisterAccelerators(bool leave_data_intact) { - if (!accelerators_.get()) - return; - - if (GetWidget()) { - if (accelerator_focus_manager_) { - // We may not have a FocusManager if the window containing us is being - // closed, in which case the FocusManager is being deleted so there is - // nothing to unregister. - accelerator_focus_manager_->UnregisterAccelerators(this); - accelerator_focus_manager_ = NULL; - } - if (!leave_data_intact) { - accelerators_->clear(); - accelerators_.reset(); - } - registered_accelerator_count_ = 0; - } -} - -// Focus ----------------------------------------------------------------------- - -void View::InitFocusSiblings(View* v, int index) { - int count = child_count(); - - if (count == 0) { - v->next_focusable_view_ = NULL; - v->previous_focusable_view_ = NULL; - } else { - if (index == count) { - // We are inserting at the end, but the end of the child list may not be - // the last focusable element. Let's try to find an element with no next - // focusable element to link to. - View* last_focusable_view = NULL; - for (Views::iterator i(children_.begin()); i != children_.end(); ++i) { - if (!(*i)->next_focusable_view_) { - last_focusable_view = *i; - break; - } - } - if (last_focusable_view == NULL) { - // Hum... there is a cycle in the focus list. Let's just insert ourself - // after the last child. - View* prev = children_[index - 1]; - v->previous_focusable_view_ = prev; - v->next_focusable_view_ = prev->next_focusable_view_; - prev->next_focusable_view_->previous_focusable_view_ = v; - prev->next_focusable_view_ = v; - } else { - last_focusable_view->next_focusable_view_ = v; - v->next_focusable_view_ = NULL; - v->previous_focusable_view_ = last_focusable_view; - } - } else { - View* prev = children_[index]->GetPreviousFocusableView(); - v->previous_focusable_view_ = prev; - v->next_focusable_view_ = children_[index]; - if (prev) - prev->next_focusable_view_ = v; - children_[index]->previous_focusable_view_ = v; - } - } -} - -// System events --------------------------------------------------------------- - -void View::PropagateThemeChanged() { - for (int i = child_count() - 1; i >= 0; --i) - child_at(i)->PropagateThemeChanged(); - OnThemeChanged(); -} - -void View::PropagateLocaleChanged() { - for (int i = child_count() - 1; i >= 0; --i) - child_at(i)->PropagateLocaleChanged(); - OnLocaleChanged(); -} - -// Tooltips -------------------------------------------------------------------- - -void View::UpdateTooltip() { - Widget* widget = GetWidget(); - // TODO(beng): The TooltipManager NULL check can be removed when we - // consolidate Init() methods and make views_unittests Init() all - // Widgets that it uses. - if (widget && widget->native_widget_private()->GetTooltipManager()) - widget->native_widget_private()->GetTooltipManager()->UpdateTooltip(); -} - -// Drag and drop --------------------------------------------------------------- - -void View::DoDrag(const MouseEvent& event, const gfx::Point& press_pt) { - int drag_operations = GetDragOperations(press_pt); - if (drag_operations == ui::DragDropTypes::DRAG_NONE) - return; - - OSExchangeData data; - WriteDragData(press_pt, &data); - - // Message the RootView to do the drag and drop. That way if we're removed - // the RootView can detect it and avoid calling us back. - GetWidget()->RunShellDrag(this, data, drag_operations); -} - -} // namespace views diff --git a/views/view.h b/views/view.h deleted file mode 100644 index e93a125..0000000 --- a/views/view.h +++ /dev/null @@ -1,1440 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef VIEWS_VIEW_H_ -#define VIEWS_VIEW_H_ -#pragma once - -#include <algorithm> -#include <map> -#include <set> -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/i18n/rtl.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "build/build_config.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/dragdrop/os_exchange_data.h" -#include "ui/gfx/compositor/layer_delegate.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/rect.h" -#include "ui/views/events/event.h" -#include "views/background.h" -#include "views/border.h" - -#if defined(OS_WIN) -#include "base/win/scoped_comptr.h" -#endif - -using ui::OSExchangeData; - -namespace gfx { -class Canvas; -class Insets; -class Path; -} - -namespace ui { -struct AccessibleViewState; -class Compositor; -class Layer; -class TextInputClient; -class Texture; -class ThemeProvider; -class Transform; -enum TouchStatus; -} - -#if defined(OS_WIN) -class __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) -NativeViewAccessibilityWin; -#endif - -namespace views { - -class Background; -class Border; -class ContextMenuController; -class DragController; -class FocusManager; -class FocusTraversable; -class InputMethod; -class LayoutManager; -class ScrollView; -class Widget; - -namespace internal { -class NativeWidgetView; -class RootView; -} - -///////////////////////////////////////////////////////////////////////////// -// -// View class -// -// A View is a rectangle within the views View hierarchy. It is the base -// class for all Views. -// -// A View is a container of other Views (there is no such thing as a Leaf -// View - makes code simpler, reduces type conversion headaches, design -// mistakes etc) -// -// The View contains basic properties for sizing (bounds), layout (flex, -// orientation, etc), painting of children and event dispatch. -// -// The View also uses a simple Box Layout Manager similar to XUL's -// SprocketLayout system. Alternative Layout Managers implementing the -// LayoutManager interface can be used to lay out children if required. -// -// It is up to the subclass to implement Painting and storage of subclass - -// specific properties and functionality. -// -// Unless otherwise documented, views is not thread safe and should only be -// accessed from the main thread. -// -///////////////////////////////////////////////////////////////////////////// -class VIEWS_EXPORT View : public ui::LayerDelegate, - public ui::AcceleratorTarget { - public: - typedef std::vector<View*> Views; - - // TO BE MOVED --------------------------------------------------------------- - // TODO(beng): These methods are to be moved to other files/classes. - - // TODO(beng): delete - // Set whether this view is hottracked. A disabled view cannot be hottracked. - // If flag differs from the current value, SchedulePaint is invoked. - virtual void SetHotTracked(bool flag); - - // TODO(beng): delete - // Returns whether the view is hot-tracked. - virtual bool IsHotTracked() const; - - // Creation and lifetime ----------------------------------------------------- - - View(); - virtual ~View(); - - // By default a View is owned by its parent unless specified otherwise here. - bool parent_owned() const { return parent_owned_; } - void set_parent_owned(bool parent_owned) { parent_owned_ = parent_owned; } - - // Tree operations ----------------------------------------------------------- - - // Get the Widget that hosts this View, if any. - virtual const Widget* GetWidget() const; - virtual Widget* GetWidget(); - - // Adds |view| as a child of this view, optionally at |index|. - void AddChildView(View* view); - void AddChildViewAt(View* view, int index); - - // Moves |view| to the specified |index|. A negative value for |index| moves - // the view at the end. - void ReorderChildView(View* view, int index); - - // Removes |view| from this view. The view's parent will change to NULL. - void RemoveChildView(View* view); - - // Removes all the children from this view. If |delete_children| is true, - // the views are deleted, unless marked as not parent owned. - void RemoveAllChildViews(bool delete_children); - - // STL-style accessors. - Views::const_iterator children_begin() { return children_.begin(); } - Views::const_iterator children_end() { return children_.end(); } - Views::const_reverse_iterator children_rbegin() { return children_.rbegin(); } - Views::const_reverse_iterator children_rend() { return children_.rend(); } - int child_count() const { return static_cast<int>(children_.size()); } - bool has_children() const { return !children_.empty(); } - - // Returns the child view at |index|. - const View* child_at(int index) const { - DCHECK_GE(index, 0); - DCHECK_LT(index, child_count()); - return children_[index]; - } - View* child_at(int index) { - return const_cast<View*>(const_cast<const View*>(this)->child_at(index)); - } - - // Returns the parent view. - const View* parent() const { return parent_; } - View* parent() { return parent_; } - - // Returns true if |view| is contained within this View's hierarchy, even as - // an indirect descendant. Will return true if child is also this view. - bool Contains(const View* view) const; - - // Returns the index of |view|, or -1 if |view| is not a child of this view. - int GetIndexOf(const View* view) const; - - // Size and disposition ------------------------------------------------------ - // Methods for obtaining and modifying the position and size of the view. - // Position is in the coordinate system of the view's parent. - // Position is NOT flipped for RTL. See "RTL positioning" for RTL-sensitive - // position accessors. - // Transformations are not applied on the size/position. For example, if - // bounds is (0, 0, 100, 100) and it is scaled by 0.5 along the X axis, the - // width will still be 100 (although when painted, it will be 50x50, painted - // at location (0, 0)). - - void SetBounds(int x, int y, int width, int height); - void SetBoundsRect(const gfx::Rect& bounds); - void SetSize(const gfx::Size& size); - void SetPosition(const gfx::Point& position); - void SetX(int x); - void SetY(int y); - - // No transformation is applied on the size or the locations. - const gfx::Rect& bounds() const { return bounds_; } - int x() const { return bounds_.x(); } - int y() const { return bounds_.y(); } - int width() const { return bounds_.width(); } - int height() const { return bounds_.height(); } - const gfx::Size& size() const { return bounds_.size(); } - - // Returns the bounds of the content area of the view, i.e. the rectangle - // enclosed by the view's border. - gfx::Rect GetContentsBounds() const; - - // Returns the bounds of the view in its own coordinates (i.e. position is - // 0, 0). - gfx::Rect GetLocalBounds() const; - - // Returns the insets of the current border. If there is no border an empty - // insets is returned. - virtual gfx::Insets GetInsets() const; - - // Returns the visible bounds of the receiver in the receivers coordinate - // system. - // - // When traversing the View hierarchy in order to compute the bounds, the - // function takes into account the mirroring setting and transformation for - // each View and therefore it will return the mirrored and transformed version - // of the visible bounds if need be. - gfx::Rect GetVisibleBounds() const; - - // Return the bounds of the View in screen coordinate system. - gfx::Rect GetScreenBounds() const; - - // Returns the baseline of this view, or -1 if this view has no baseline. The - // return value is relative to the preferred height. - virtual int GetBaseline() const; - - // Get the size the View would like to be, if enough space were available. - virtual gfx::Size GetPreferredSize(); - - // Convenience method that sizes this view to its preferred size. - void SizeToPreferredSize(); - - // Gets the minimum size of the view. View's implementation invokes - // GetPreferredSize. - virtual gfx::Size GetMinimumSize(); - - // Return the height necessary to display this view with the provided width. - // View's implementation returns the value from getPreferredSize.cy. - // Override if your View's preferred height depends upon the width (such - // as with Labels). - virtual int GetHeightForWidth(int w); - - // Set whether the receiving view is visible. Painting is scheduled as needed - virtual void SetVisible(bool visible); - - // Return whether a view is visible - virtual bool IsVisible() const; - - // Return whether a view and its ancestors are visible. Returns true if the - // path from this view to the root view is visible. - virtual bool IsVisibleInRootView() const; - - // Set whether this view is enabled. A disabled view does not receive keyboard - // or mouse inputs. If flag differs from the current value, SchedulePaint is - // invoked. - void SetEnabled(bool enabled); - - // Returns whether the view is enabled. - virtual bool IsEnabled() const; - - // This indicates that the view completely fills its bounds in an opaque - // color. This doesn't affect compositing but is a hint to the compositor to - // optimize painting. - // Note that this method does not implicitly create a layer if one does not - // already exist for the View, but is a no-op in that case. - void SetFillsBoundsOpaquely(bool fills_bounds_opaquely); - - // Transformations ----------------------------------------------------------- - - // Methods for setting transformations for a view (e.g. rotation, scaling). - - const ui::Transform& GetTransform() const; - - // Clipping parameters. Clipping happens from the right and/or bottom. The - // clipping amount is in parent's coordinate system, as in, if the view is - // rotated, then the clipping will be applied after the rotation (and other - // transformations, if any). - void set_clip_x(float x) { clip_x_ = x; } - void set_clip_y(float y) { clip_y_ = y; } - void set_clip(float x, float y) { clip_x_ = x; clip_y_ = y; } - - // Sets the transform to the supplied transform. - void SetTransform(const ui::Transform& transform); - - // Sets whether this view paints to a layer. A view paints to a layer if - // either of the following are true: - // . the view has a non-identity transform. - // . SetPaintToLayer(true) has been invoked. - // View creates the Layer only when it exists in a Widget with a non-NULL - // Compositor. - void SetPaintToLayer(bool paint_to_layer); - - const ui::Layer* layer() const { return layer_.get(); } - ui::Layer* layer() { return layer_.get(); } - - // RTL positioning ----------------------------------------------------------- - - // Methods for accessing the bounds and position of the view, relative to its - // parent. The position returned is mirrored if the parent view is using a RTL - // layout. - // - // NOTE: in the vast majority of the cases, the mirroring implementation is - // transparent to the View subclasses and therefore you should use the - // bounds() accessor instead. - gfx::Rect GetMirroredBounds() const; - gfx::Point GetMirroredPosition() const; - int GetMirroredX() const; - - // Given a rectangle specified in this View's coordinate system, the function - // computes the 'left' value for the mirrored rectangle within this View. If - // the View's UI layout is not right-to-left, then bounds.x() is returned. - // - // UI mirroring is transparent to most View subclasses and therefore there is - // no need to call this routine from anywhere within your subclass - // implementation. - int GetMirroredXForRect(const gfx::Rect& rect) const; - - // Given the X coordinate of a point inside the View, this function returns - // the mirrored X coordinate of the point if the View's UI layout is - // right-to-left. If the layout is left-to-right, the same X coordinate is - // returned. - // - // Following are a few examples of the values returned by this function for - // a View with the bounds {0, 0, 100, 100} and a right-to-left layout: - // - // GetMirroredXCoordinateInView(0) -> 100 - // GetMirroredXCoordinateInView(20) -> 80 - // GetMirroredXCoordinateInView(99) -> 1 - int GetMirroredXInView(int x) const; - - // Given a X coordinate and a width inside the View, this function returns - // the mirrored X coordinate if the View's UI layout is right-to-left. If the - // layout is left-to-right, the same X coordinate is returned. - // - // Following are a few examples of the values returned by this function for - // a View with the bounds {0, 0, 100, 100} and a right-to-left layout: - // - // GetMirroredXCoordinateInView(0, 10) -> 90 - // GetMirroredXCoordinateInView(20, 20) -> 60 - int GetMirroredXWithWidthInView(int x, int w) const; - - // Layout -------------------------------------------------------------------- - - // Lay out the child Views (set their bounds based on sizing heuristics - // specific to the current Layout Manager) - virtual void Layout(); - - // TODO(beng): I think we should remove this. - // Mark this view and all parents to require a relayout. This ensures the - // next call to Layout() will propagate to this view, even if the bounds of - // parent views do not change. - void InvalidateLayout(); - - // Gets/Sets the Layout Manager used by this view to size and place its - // children. - // The LayoutManager is owned by the View and is deleted when the view is - // deleted, or when a new LayoutManager is installed. - LayoutManager* GetLayoutManager() const; - void SetLayoutManager(LayoutManager* layout); - - // Attributes ---------------------------------------------------------------- - - // The view class name. - static const char kViewClassName[]; - - // Return the receiving view's class name. A view class is a string which - // uniquely identifies the view class. It is intended to be used as a way to - // find out during run time if a view can be safely casted to a specific view - // subclass. The default implementation returns kViewClassName. - virtual std::string GetClassName() const; - - // Returns the first ancestor, starting at this, whose class name is |name|. - // Returns null if no ancestor has the class name |name|. - View* GetAncestorWithClassName(const std::string& name); - - // Recursively descends the view tree starting at this view, and returns - // the first child that it encounters that has the given ID. - // Returns NULL if no matching child view is found. - virtual const View* GetViewByID(int id) const; - virtual View* GetViewByID(int id); - - // Gets and sets the ID for this view. ID should be unique within the subtree - // that you intend to search for it. 0 is the default ID for views. - int id() const { return id_; } - void set_id(int id) { id_ = id; } - - // A group id is used to tag views which are part of the same logical group. - // Focus can be moved between views with the same group using the arrow keys. - // Groups are currently used to implement radio button mutual exclusion. - // The group id is immutable once it's set. - void SetGroup(int gid); - // Returns the group id of the view, or -1 if the id is not set yet. - int GetGroup() const; - - // If this returns true, the views from the same group can each be focused - // when moving focus with the Tab/Shift-Tab key. If this returns false, - // only the selected view from the group (obtained with - // GetSelectedViewForGroup()) is focused. - virtual bool IsGroupFocusTraversable() const; - - // Fills |views| with all the available views which belong to the provided - // |group|. - void GetViewsInGroup(int group, Views* views); - - // Returns the View that is currently selected in |group|. - // The default implementation simply returns the first View found for that - // group. - virtual View* GetSelectedViewForGroup(int group); - - // Coordinate conversion ----------------------------------------------------- - - // Note that the utility coordinate conversions functions always operate on - // the mirrored position of the child Views if the parent View uses a - // right-to-left UI layout. - - // Convert a point from the coordinate system of one View to another. - // - // |source| and |target| must be in the same widget, but doesn't need to be in - // the same view hierarchy. - // |source| can be NULL in which case it means the screen coordinate system. - static void ConvertPointToView(const View* source, - const View* target, - gfx::Point* point); - - // Convert a point from a View's coordinate system to that of its Widget. - static void ConvertPointToWidget(const View* src, gfx::Point* point); - - // Convert a point from the coordinate system of a View's Widget to that - // View's coordinate system. - static void ConvertPointFromWidget(const View* dest, gfx::Point* p); - - // Convert a point from a View's coordinate system to that of the screen. - static void ConvertPointToScreen(const View* src, gfx::Point* point); - - // Applies transformation on the rectangle, which is in the view's coordinate - // system, to convert it into the parent's coordinate system. - gfx::Rect ConvertRectToParent(const gfx::Rect& rect) const; - - // Converts a rectangle from this views coordinate system to its widget - // coordinate system. - gfx::Rect ConvertRectToWidget(const gfx::Rect& rect) const; - - // Painting ------------------------------------------------------------------ - - // Mark all or part of the View's bounds as dirty (needing repaint). - // |r| is in the View's coordinates. - // Rectangle |r| should be in the view's coordinate system. The - // transformations are applied to it to convert it into the parent coordinate - // system before propagating SchedulePaint up the view hierarchy. - // TODO(beng): Make protected. - virtual void SchedulePaint(); - virtual void SchedulePaintInRect(const gfx::Rect& r); - - // Called by the framework to paint a View. Performs translation and clipping - // for View coordinates and language direction as required, allows the View - // to paint itself via the various OnPaint*() event handlers and then paints - // the hierarchy beneath it. - virtual void Paint(gfx::Canvas* canvas); - - // The background object is owned by this object and may be NULL. - void set_background(Background* b) { background_.reset(b); } - const Background* background() const { return background_.get(); } - Background* background() { return background_.get(); } - - // The border object is owned by this object and may be NULL. - void set_border(Border* b) { border_.reset(b); } - const Border* border() const { return border_.get(); } - Border* border() { return border_.get(); } - - // Get the theme provider from the parent widget. - virtual ui::ThemeProvider* GetThemeProvider() const; - - // RTL painting -------------------------------------------------------------- - - // This method determines whether the gfx::Canvas object passed to - // View::Paint() needs to be transformed such that anything drawn on the - // canvas object during View::Paint() is flipped horizontally. - // - // By default, this function returns false (which is the initial value of - // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on - // a flipped gfx::Canvas when the UI layout is right-to-left need to call - // EnableCanvasFlippingForRTLUI(). - bool FlipCanvasOnPaintForRTLUI() const { - return flip_canvas_on_paint_for_rtl_ui_ ? base::i18n::IsRTL() : false; - } - - // Enables or disables flipping of the gfx::Canvas during View::Paint(). - // Note that if canvas flipping is enabled, the canvas will be flipped only - // if the UI layout is right-to-left; that is, the canvas will be flipped - // only if base::i18n::IsRTL() returns true. - // - // Enabling canvas flipping is useful for leaf views that draw a bitmap that - // needs to be flipped horizontally when the UI layout is right-to-left - // (views::Button, for example). This method is helpful for such classes - // because their drawing logic stays the same and they can become agnostic to - // the UI directionality. - void EnableCanvasFlippingForRTLUI(bool enable) { - flip_canvas_on_paint_for_rtl_ui_ = enable; - } - - // Accelerated painting ------------------------------------------------------ - - // Enable/Disable accelerated compositing. - static void set_use_acceleration_when_possible(bool use); - static bool get_use_acceleration_when_possible(); - - // Input --------------------------------------------------------------------- - // The points (and mouse locations) in the following functions are in the - // view's coordinates, except for a RootView. - - // Returns the deepest visible descendant that contains the specified point. - virtual View* GetEventHandlerForPoint(const gfx::Point& point); - - // Return the cursor that should be used for this view or the default cursor. - // The event location is in the receiver's coordinate system. The caller is - // responsible for managing the lifetime of the returned object, though that - // lifetime may vary from platform to platform. On Windows, the cursor is a - // shared resource, but Gtk destroys the returned cursor after setting it. - virtual gfx::NativeCursor GetCursor(const MouseEvent& event); - - // Convenience to test whether a point is within this view's bounds - virtual bool HitTest(const gfx::Point& l) const; - - // This method is invoked when the user clicks on this view. - // The provided event is in the receiver's coordinate system. - // - // Return true if you processed the event and want to receive subsequent - // MouseDraggged and MouseReleased events. This also stops the event from - // bubbling. If you return false, the event will bubble through parent - // views. - // - // If you remove yourself from the tree while processing this, event bubbling - // stops as if you returned true, but you will not receive future events. - // The return value is ignored in this case. - // - // Default implementation returns true if a ContextMenuController has been - // set, false otherwise. Override as needed. - // - virtual bool OnMousePressed(const MouseEvent& event); - - // This method is invoked when the user clicked on this control. - // and is still moving the mouse with a button pressed. - // The provided event is in the receiver's coordinate system. - // - // Return true if you processed the event and want to receive - // subsequent MouseDragged and MouseReleased events. - // - // Default implementation returns true if a ContextMenuController has been - // set, false otherwise. Override as needed. - // - virtual bool OnMouseDragged(const MouseEvent& event); - - // This method is invoked when the user releases the mouse - // button. The event is in the receiver's coordinate system. - // - // Default implementation notifies the ContextMenuController is appropriate. - // Subclasses that wish to honor the ContextMenuController should invoke - // super. - virtual void OnMouseReleased(const MouseEvent& event); - - // This method is invoked when the mouse press/drag was canceled by a - // system/user gesture. - virtual void OnMouseCaptureLost(); - - // This method is invoked when the mouse is above this control - // The event is in the receiver's coordinate system. - // - // Default implementation does nothing. Override as needed. - virtual void OnMouseMoved(const MouseEvent& event); - - // This method is invoked when the mouse enters this control. - // - // Default implementation does nothing. Override as needed. - virtual void OnMouseEntered(const MouseEvent& event); - - // This method is invoked when the mouse exits this control - // The provided event location is always (0, 0) - // Default implementation does nothing. Override as needed. - virtual void OnMouseExited(const MouseEvent& event); - - // This method is invoked for each touch event. Default implementation - // does nothing. Override as needed. - virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event); - - // Set the MouseHandler for a drag session. - // - // A drag session is a stream of mouse events starting - // with a MousePressed event, followed by several MouseDragged - // events and finishing with a MouseReleased event. - // - // This method should be only invoked while processing a - // MouseDragged or MousePressed event. - // - // All further mouse dragged and mouse up events will be sent - // the MouseHandler, even if it is reparented to another window. - // - // The MouseHandler is automatically cleared when the control - // comes back from processing the MouseReleased event. - // - // Note: if the mouse handler is no longer connected to a - // view hierarchy, events won't be sent. - // - virtual void SetMouseHandler(View* new_mouse_handler); - - // Invoked when a key is pressed or released. - // Subclasser should return true if the event has been processed and false - // otherwise. If the event has not been processed, the parent will be given a - // chance. - virtual bool OnKeyPressed(const KeyEvent& event); - virtual bool OnKeyReleased(const KeyEvent& event); - - // Invoked when the user uses the mousewheel. Implementors should return true - // if the event has been processed and false otherwise. This message is sent - // if the view is focused. If the event has not been processed, the parent - // will be given a chance. - virtual bool OnMouseWheel(const MouseWheelEvent& event); - - // Returns the View's TextInputClient instance or NULL if the View doesn't - // support text input. - virtual ui::TextInputClient* GetTextInputClient(); - - // Convenience method to retrieve the InputMethod associated with the - // Widget that contains this view. Returns NULL if this view is not part of a - // view hierarchy with a Widget. - virtual InputMethod* GetInputMethod(); - - // Accelerators -------------------------------------------------------------- - - // Sets a keyboard accelerator for that view. When the user presses the - // accelerator key combination, the AcceleratorPressed method is invoked. - // Note that you can set multiple accelerators for a view by invoking this - // method several times. - virtual void AddAccelerator(const ui::Accelerator& accelerator); - - // Removes the specified accelerator for this view. - virtual void RemoveAccelerator(const ui::Accelerator& accelerator); - - // Removes all the keyboard accelerators for this view. - virtual void ResetAccelerators(); - - // Overridden from AcceleratorTarget: - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; - - // Focus --------------------------------------------------------------------- - - // Returns whether this view currently has the focus. - virtual bool HasFocus() const; - - // Returns the view that should be selected next when pressing Tab. - View* GetNextFocusableView(); - const View* GetNextFocusableView() const; - - // Returns the view that should be selected next when pressing Shift-Tab. - View* GetPreviousFocusableView(); - - // Sets the component that should be selected next when pressing Tab, and - // makes the current view the precedent view of the specified one. - // Note that by default views are linked in the order they have been added to - // their container. Use this method if you want to modify the order. - // IMPORTANT NOTE: loops in the focus hierarchy are not supported. - void SetNextFocusableView(View* view); - - // Sets whether this view can accept the focus. - // Note that this is false by default so that a view used as a container does - // not get the focus. - void set_focusable(bool focusable) { focusable_ = focusable; } - - // Returns true if the view is focusable (IsFocusable) and visible in the root - // view. See also IsFocusable. - bool IsFocusableInRootView() const; - - // Return whether this view is focusable when the user requires full keyboard - // access, even though it may not be normally focusable. - bool IsAccessibilityFocusableInRootView() const; - - // Set whether this view can be made focusable if the user requires - // full keyboard access, even though it's not normally focusable. - // Note that this is false by default. - void set_accessibility_focusable(bool accessibility_focusable) { - accessibility_focusable_ = accessibility_focusable; - } - - // Convenience method to retrieve the FocusManager associated with the - // Widget that contains this view. This can return NULL if this view is not - // part of a view hierarchy with a Widget. - virtual FocusManager* GetFocusManager(); - virtual const FocusManager* GetFocusManager() const; - - // Request the keyboard focus. The receiving view will become the - // focused view. - virtual void RequestFocus(); - - // Invoked when a view is about to be requested for focus due to the focus - // traversal. Reverse is this request was generated going backward - // (Shift-Tab). - virtual void AboutToRequestFocusFromTabTraversal(bool reverse) { } - - // Invoked when a key is pressed before the key event is processed (and - // potentially eaten) by the focus manager for tab traversal, accelerators and - // other focus related actions. - // The default implementation returns false, ensuring that tab traversal and - // accelerators processing is performed. - // Subclasses should return true if they want to process the key event and not - // have it processed as an accelerator (if any) or as a tab traversal (if the - // key event is for the TAB key). In that case, OnKeyPressed will - // subsequently be invoked for that event. - virtual bool SkipDefaultKeyEventProcessing(const KeyEvent& event); - - // Subclasses that contain traversable children that are not directly - // accessible through the children hierarchy should return the associated - // FocusTraversable for the focus traversal to work properly. - virtual FocusTraversable* GetFocusTraversable(); - - // Subclasses that can act as a "pane" must implement their own - // FocusTraversable to keep the focus trapped within the pane. - // If this method returns an object, any view that's a direct or - // indirect child of this view will always use this FocusTraversable - // rather than the one from the widget. - virtual FocusTraversable* GetPaneFocusTraversable(); - - // Tooltips ------------------------------------------------------------------ - - // Gets the tooltip for this View. If the View does not have a tooltip, - // return false. If the View does have a tooltip, copy the tooltip into - // the supplied string and return true. - // Any time the tooltip text that a View is displaying changes, it must - // invoke TooltipTextChanged. - // |p| provides the coordinates of the mouse (relative to this view). - virtual bool GetTooltipText(const gfx::Point& p, string16* tooltip) const; - - // Returns the location (relative to this View) for the text on the tooltip - // to display. If false is returned (the default), the tooltip is placed at - // a default position. - virtual bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* loc) const; - - // Context menus ------------------------------------------------------------- - - // Sets the ContextMenuController. Setting this to non-null makes the View - // process mouse events. - ContextMenuController* context_menu_controller() { - return context_menu_controller_; - } - void set_context_menu_controller(ContextMenuController* menu_controller) { - context_menu_controller_ = menu_controller; - } - - // Provides default implementation for context menu handling. The default - // implementation calls the ShowContextMenu of the current - // ContextMenuController (if it is not NULL). Overridden in subclassed views - // to provide right-click menu display triggerd by the keyboard (i.e. for the - // Chrome toolbar Back and Forward buttons). No source needs to be specified, - // as it is always equal to the current View. - virtual void ShowContextMenu(const gfx::Point& p, - bool is_mouse_gesture); - - // Drag and drop ------------------------------------------------------------- - - DragController* drag_controller() { return drag_controller_; } - void set_drag_controller(DragController* drag_controller) { - drag_controller_ = drag_controller; - } - - // During a drag and drop session when the mouse moves the view under the - // mouse is queried for the drop types it supports by way of the - // GetDropFormats methods. If the view returns true and the drag site can - // provide data in one of the formats, the view is asked if the drop data - // is required before any other drop events are sent. Once the - // data is available the view is asked if it supports the drop (by way of - // the CanDrop method). If a view returns true from CanDrop, - // OnDragEntered is sent to the view when the mouse first enters the view, - // as the mouse moves around within the view OnDragUpdated is invoked. - // If the user releases the mouse over the view and OnDragUpdated returns a - // valid drop, then OnPerformDrop is invoked. If the mouse moves outside the - // view or over another view that wants the drag, OnDragExited is invoked. - // - // Similar to mouse events, the deepest view under the mouse is first checked - // if it supports the drop (Drop). If the deepest view under - // the mouse does not support the drop, the ancestors are walked until one - // is found that supports the drop. - - // Override and return the set of formats that can be dropped on this view. - // |formats| is a bitmask of the formats defined bye OSExchangeData::Format. - // The default implementation returns false, which means the view doesn't - // support dropping. - virtual bool GetDropFormats( - int* formats, - std::set<OSExchangeData::CustomFormat>* custom_formats); - - // Override and return true if the data must be available before any drop - // methods should be invoked. The default is false. - virtual bool AreDropTypesRequired(); - - // A view that supports drag and drop must override this and return true if - // data contains a type that may be dropped on this view. - virtual bool CanDrop(const OSExchangeData& data); - - // OnDragEntered is invoked when the mouse enters this view during a drag and - // drop session and CanDrop returns true. This is immediately - // followed by an invocation of OnDragUpdated, and eventually one of - // OnDragExited or OnPerformDrop. - virtual void OnDragEntered(const DropTargetEvent& event); - - // Invoked during a drag and drop session while the mouse is over the view. - // This should return a bitmask of the DragDropTypes::DragOperation supported - // based on the location of the event. Return 0 to indicate the drop should - // not be accepted. - virtual int OnDragUpdated(const DropTargetEvent& event); - - // Invoked during a drag and drop session when the mouse exits the views, or - // when the drag session was canceled and the mouse was over the view. - virtual void OnDragExited(); - - // Invoked during a drag and drop session when OnDragUpdated returns a valid - // operation and the user release the mouse. - virtual int OnPerformDrop(const DropTargetEvent& event); - - // Invoked from DoDrag after the drag completes. This implementation does - // nothing, and is intended for subclasses to do cleanup. - virtual void OnDragDone(); - - // Returns true if the mouse was dragged enough to start a drag operation. - // delta_x and y are the distance the mouse was dragged. - static bool ExceededDragThreshold(int delta_x, int delta_y); - - // Accessibility ------------------------------------------------------------- - - // Modifies |state| to reflect the current accessible state of this view. - virtual void GetAccessibleState(ui::AccessibleViewState* state) { } - - // Returns an instance of the native accessibility interface for this view. - virtual gfx::NativeViewAccessible GetNativeViewAccessible(); - - // Scrolling ----------------------------------------------------------------- - // TODO(beng): Figure out if this can live somewhere other than View, i.e. - // closer to ScrollView. - - // Scrolls the specified region, in this View's coordinate system, to be - // visible. View's implementation passes the call onto the parent View (after - // adjusting the coordinates). It is up to views that only show a portion of - // the child view, such as Viewport, to override appropriately. - virtual void ScrollRectToVisible(const gfx::Rect& rect); - - // The following methods are used by ScrollView to determine the amount - // to scroll relative to the visible bounds of the view. For example, a - // return value of 10 indicates the scrollview should scroll 10 pixels in - // the appropriate direction. - // - // Each method takes the following parameters: - // - // is_horizontal: if true, scrolling is along the horizontal axis, otherwise - // the vertical axis. - // is_positive: if true, scrolling is by a positive amount. Along the - // vertical axis scrolling by a positive amount equates to - // scrolling down. - // - // The return value should always be positive and gives the number of pixels - // to scroll. ScrollView interprets a return value of 0 (or negative) - // to scroll by a default amount. - // - // See VariableRowHeightScrollHelper and FixedRowHeightScrollHelper for - // implementations of common cases. - virtual int GetPageScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive); - virtual int GetLineScrollIncrement(ScrollView* scroll_view, - bool is_horizontal, bool is_positive); - - protected: - // Size and disposition ------------------------------------------------------ - - // Override to be notified when the bounds of the view have changed. - virtual void OnBoundsChanged(const gfx::Rect& previous_bounds); - - // Called when the preferred size of a child view changed. This gives the - // parent an opportunity to do a fresh layout if that makes sense. - virtual void ChildPreferredSizeChanged(View* child) {} - - // Invalidates the layout and calls ChildPreferredSizeChanged on the parent - // if there is one. Be sure to call View::PreferredSizeChanged when - // overriding such that the layout is properly invalidated. - virtual void PreferredSizeChanged(); - - // 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(); - - // Override to be notified when the enabled state of this View has - // changed. The default implementation calls SchedulePaint() on this View. - virtual void OnEnabledChanged(); - - // Tree operations ----------------------------------------------------------- - - // This method is invoked when the tree changes. - // - // When a view is removed, it is invoked for all children and grand - // children. For each of these views, a notification is sent to the - // view and all parents. - // - // When a view is added, a notification is sent to the view, all its - // parents, and all its children (and grand children) - // - // Default implementation does nothing. Override to perform operations - // required when a view is added or removed from a view hierarchy - // - // parent is the new or old parent. Child is the view being added or - // removed. - // - virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); - - // When SetVisible() changes the visibility of a view, this method is - // invoked for that view as well as all the children recursively. - virtual void VisibilityChanged(View* starting_from, bool is_visible); - - // Called when the native view hierarchy changed. - // |attached| is true if that view has been attached to a new NativeView - // hierarchy, false if it has been detached. - // |native_view| is the NativeView this view was attached/detached from, and - // |root_view| is the root view associated with the NativeView. - // Views created without a native view parent don't have a focus manager. - // When this function is called they could do the processing that requires - // it - like registering accelerators, for example. - virtual void NativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - internal::RootView* root_view); - - // Painting ------------------------------------------------------------------ - - // Responsible for calling Paint() on child Views. Override to control the - // order child Views are painted. - virtual void PaintChildren(gfx::Canvas* canvas); - - // Override to provide rendering in any part of the View's bounds. Typically - // this is the "contents" of the view. If you override this method you will - // have to call the subsequent OnPaint*() methods manually. - virtual void OnPaint(gfx::Canvas* canvas); - - // Override to paint a background before any content is drawn. Typically this - // is done if you are satisfied with a default OnPaint handler but wish to - // supply a different background. - virtual void OnPaintBackground(gfx::Canvas* canvas); - - // Override to paint a border not specified by SetBorder(). - virtual void OnPaintBorder(gfx::Canvas* canvas); - - // Override to paint a focus border (usually a dotted rectangle) around - // relevant contents. - virtual void OnPaintFocusBorder(gfx::Canvas* canvas); - - // Accelerated painting ------------------------------------------------------ - - // This creates a layer for the view, if one does not exist. It then - // passes the texture to a layer associated with the view. While an external - // texture is set, the view will not update the layer contents. - // - // |texture| cannot be NULL. - // - // Returns false if it cannot create a layer to which to assign the texture. - bool SetExternalTexture(ui::Texture* texture); - - // Returns the offset from this view to the nearest ancestor with a layer. - // If |ancestor| is non-NULL it is set to the nearest ancestor with a layer. - virtual void CalculateOffsetToAncestorWithLayer( - gfx::Point* offset, - ui::Layer** layer_parent); - - // If this view has a layer, the layer is reparented to |parent_layer| and its - // bounds is set based on |point|. If this view does not have a layer, then - // recurses through all children. This is used when adding a layer to an - // existing view to make sure all descendants that have layers are parented to - // the right layer. - virtual void MoveLayerToParent(ui::Layer* parent_layer, - const gfx::Point& point); - - // Called to update the bounds of any child layers within this View's - // hierarchy when something happens to the hierarchy. - virtual void UpdateChildLayerBounds(const gfx::Point& offset); - - // Overridden from ui::LayerDelegate: - virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE; - - // Finds the layer that this view paints to (it may belong to an ancestor - // view), then reorders the immediate children of that layer to match the - // order of the view tree. - virtual void ReorderLayers(); - - // This reorders the immediate children of |*parent_layer| to match the - // order of the view tree. - virtual void ReorderChildLayers(ui::Layer* parent_layer); - - // Input --------------------------------------------------------------------- - - // 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; - - // Focus --------------------------------------------------------------------- - - // Returns whether this view can accept focus. - // A view can accept focus if it's enabled, focusable and visible. - // This method is intended for views to use when calculating preferred size. - // The FocusManager and other places use IsFocusableInRootView. - virtual bool IsFocusable() const; - - // Override to be notified when focus has changed either to or from this View. - virtual void OnFocus(); - virtual void OnBlur(); - - // Handle view focus/blur events for this view. - void Focus(); - void Blur(); - - // System events ------------------------------------------------------------- - - // Called when the UI theme has changed, overriding allows individual Views to - // do special cleanup and processing (such as dropping resource caches). - // To dispatch a theme changed notification, call Widget::ThemeChanged(). - virtual void OnThemeChanged() {} - - // Called when the locale has changed, overriding allows individual Views to - // update locale-dependent strings. - // To dispatch a locale changed notification, call Widget::LocaleChanged(). - virtual void OnLocaleChanged() {} - - // Tooltips ------------------------------------------------------------------ - - // Views must invoke this when the tooltip text they are to display changes. - void TooltipTextChanged(); - - // Context menus ------------------------------------------------------------- - - // Returns the location, in screen coordinates, to show the context menu at - // when the context menu is shown from the keyboard. This implementation - // returns the middle of the visible region of this view. - // - // This method is invoked when the context menu is shown by way of the - // keyboard. - virtual gfx::Point GetKeyboardContextMenuLocation(); - - // Drag and drop ------------------------------------------------------------- - - // These are cover methods that invoke the method of the same name on - // the DragController. Subclasses may wish to override rather than install - // a DragController. - // See DragController for a description of these methods. - virtual int GetDragOperations(const gfx::Point& press_pt); - virtual void WriteDragData(const gfx::Point& press_pt, OSExchangeData* data); - - // Returns whether we're in the middle of a drag session that was initiated - // by us. - bool InDrag(); - - // Returns how much the mouse needs to move in one direction to start a - // drag. These methods cache in a platform-appropriate way. These values are - // used by the public static method ExceededDragThreshold(). - static int GetHorizontalDragThreshold(); - static int GetVerticalDragThreshold(); - - // Debugging ----------------------------------------------------------------- - -#if !defined(NDEBUG) - // Returns string containing a graph of the views hierarchy in graphViz DOT - // language (http://graphviz.org/). Can be called within debugger and save - // to a file to compile/view. - // Note: Assumes initial call made with first = true. - virtual std::string PrintViewGraph(bool first); - - // Some classes may own an object which contains the children to displayed in - // the views hierarchy. The above function gives the class the flexibility to - // decide which object should be used to obtain the children, but this - // function makes the decision explicit. - std::string DoPrintViewGraph(bool first, View* view_with_children); -#endif - - private: - friend class internal::NativeWidgetView; - friend class internal::RootView; - friend class FocusManager; - friend class ViewStorage; - friend class Widget; - friend class PaintLock; - - // Used to track a drag. RootView passes this into - // ProcessMousePressed/Dragged. - struct DragInfo { - // Sets possible_drag to false and start_x/y to 0. This is invoked by - // RootView prior to invoke ProcessMousePressed. - void Reset(); - - // Sets possible_drag to true and start_pt to the specified point. - // This is invoked by the target view if it detects the press may generate - // a drag. - void PossibleDrag(const gfx::Point& p); - - // Whether the press may generate a drag. - bool possible_drag; - - // Coordinates of the mouse press. - gfx::Point start_pt; - }; - - // Painting ----------------------------------------------------------------- - - enum SchedulePaintType { - // Indicates the size is the same (only the origin changed). - SCHEDULE_PAINT_SIZE_SAME, - - // Indicates the size changed (and possibly the origin). - SCHEDULE_PAINT_SIZE_CHANGED - }; - - // Invoked before and after the bounds change to schedule painting the old and - // new bounds. - void SchedulePaintBoundsChanged(SchedulePaintType type); - - // Common Paint() code shared by accelerated and non-accelerated code paths to - // invoke OnPaint() on the View. - void PaintCommon(gfx::Canvas* canvas); - - // Tree operations ----------------------------------------------------------- - - // Removes |view| from the hierarchy tree. If |update_focus_cycle| is true, - // the next and previous focusable views of views pointing to this view are - // updated. If |update_tool_tip| is true, the tooltip is updated. If - // |delete_removed_view| is true, the view is also deleted (if it is parent - // owned). - void DoRemoveChildView(View* view, - bool update_focus_cycle, - bool update_tool_tip, - bool delete_removed_view); - - // Call ViewHierarchyChanged for all child views on all parents - void PropagateRemoveNotifications(View* parent); - - // Call ViewHierarchyChanged for all children - void PropagateAddNotifications(View* parent, View* child); - - // Propagates NativeViewHierarchyChanged() notification through all the - // children. - void PropagateNativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - internal::RootView* root_view); - - // Takes care of registering/unregistering accelerators if - // |register_accelerators| true and calls ViewHierarchyChanged(). - void ViewHierarchyChangedImpl(bool register_accelerators, - bool is_add, - View* parent, - View* child); - - // Size and disposition ------------------------------------------------------ - - // Call VisibilityChanged() recursively for all children. - void PropagateVisibilityNotifications(View* from, bool is_visible); - - // Registers/unregisters accelerators as necessary and calls - // VisibilityChanged(). - void VisibilityChangedImpl(View* starting_from, bool is_visible); - - // Responsible for propagating bounds change notifications to relevant - // views. - void BoundsChanged(const gfx::Rect& previous_bounds); - - // 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. - void AddDescendantToNotify(View* view); - void RemoveDescendantToNotify(View* view); - - // Transformations ----------------------------------------------------------- - - // Returns in |transform| the transform to get from coordinates of |ancestor| - // to this. Returns true if |ancestor| is found. If |ancestor| is not found, - // or NULL, |transform| is set to convert from root view coordinates to this. - bool GetTransformRelativeTo(const View* ancestor, - ui::Transform* transform) const; - - // Coordinate conversion ----------------------------------------------------- - - // Convert a point in the view's coordinate to an ancestor view's coordinate - // system using necessary transformations. Returns whether the point was - // successfully converted to the ancestor's coordinate system. - bool ConvertPointForAncestor(const View* ancestor, gfx::Point* point) const; - - // Convert a point in the ancestor's coordinate system to the view's - // coordinate system using necessary transformations. Returns whether the - // point was successfully from the ancestor's coordinate system to the view's - // coordinate system. - bool ConvertPointFromAncestor(const View* ancestor, gfx::Point* point) const; - - // Accelerated painting ------------------------------------------------------ - - // Disables painting during time critical operations. Used by PaintLock. - // TODO(vollick) Ideally, the widget would not dispatch paints into the - // hierarchy during time critical operations and this would not be needed. - void set_painting_enabled(bool enabled) { painting_enabled_ = enabled; } - - // Creates the layer and related fields for this view. - void CreateLayer(); - - // Parents all un-parented layers within this view's hierarchy to this view's - // layer. - void UpdateParentLayers(); - - // Updates the view's layer's parent. Called when a view is added to a view - // hierarchy, responsible for parenting the view's layer to the enclosing - // layer in the hierarchy. - void UpdateParentLayer(); - - // Parents this view's layer to |parent_layer|, and sets its bounds and other - // properties in accordance to |offset|, the view's offset from the - // |parent_layer|. - void ReparentLayer(const gfx::Point& offset, ui::Layer* parent_layer); - - // Called to update the layer visibility. The layer will be visible if the - // View itself, and all its parent Views are visible. This also updates - // visibility of the child layers. - void UpdateLayerVisibility(); - void UpdateChildLayerVisibility(bool visible); - - // Orphans the layers in this subtree that are parented to layers outside of - // this subtree. - void OrphanLayers(); - - // Destroys the layer associated with this view, and reparents any descendants - // to the destroyed layer's parent. - void DestroyLayer(); - - // Input --------------------------------------------------------------------- - - // RootView invokes these. These in turn invoke the appropriate OnMouseXXX - // method. If a drag is detected, DoDrag is invoked. - bool ProcessMousePressed(const MouseEvent& event, DragInfo* drop_info); - bool ProcessMouseDragged(const MouseEvent& event, DragInfo* drop_info); - void ProcessMouseReleased(const MouseEvent& event); - - // RootView will invoke this with incoming TouchEvents. Returns the - // the result of OnTouchEvent. - ui::TouchStatus ProcessTouchEvent(const TouchEvent& event); - - // Accelerators -------------------------------------------------------------- - - // Registers this view's keyboard accelerators that are not registered to - // FocusManager yet, if possible. - void RegisterPendingAccelerators(); - - // Unregisters all the keyboard accelerators associated with this view. - // |leave_data_intact| if true does not remove data from accelerators_ array, - // so it could be re-registered with other focus manager - void UnregisterAccelerators(bool leave_data_intact); - - // Focus --------------------------------------------------------------------- - - // Initialize the previous/next focusable views of the specified view relative - // to the view at the specified index. - void InitFocusSiblings(View* view, int index); - - // System events ------------------------------------------------------------- - - // Used to propagate theme changed notifications from the root view to all - // views in the hierarchy. - virtual void PropagateThemeChanged(); - - // Used to propagate locale changed notifications from the root view to all - // views in the hierarchy. - virtual void PropagateLocaleChanged(); - - // Tooltips ------------------------------------------------------------------ - - // Propagates UpdateTooltip() to the TooltipManager for the Widget. - // This must be invoked any time the View hierarchy changes in such a way - // the view under the mouse differs. For example, if the bounds of a View is - // changed, this is invoked. Similarly, as Views are added/removed, this - // is invoked. - void UpdateTooltip(); - - // Drag and drop ------------------------------------------------------------- - - // Starts a drag and drop operation originating from this view. This invokes - // WriteDragData to write the data and GetDragOperations to determine the - // supported drag operations. When done, OnDragDone is invoked. - void DoDrag(const MouseEvent& event, const gfx::Point& press_pt); - - ////////////////////////////////////////////////////////////////////////////// - - // Creation and lifetime ----------------------------------------------------- - - // True if the hierarchy (i.e. the parent View) is responsible for deleting - // this View. Default is true. - bool parent_owned_; - - // Attributes ---------------------------------------------------------------- - - // The id of this View. Used to find this View. - int id_; - - // The group of this view. Some view subclasses use this id to find other - // views of the same group. For example radio button uses this information - // to find other radio buttons. - int group_; - - // Tree operations ----------------------------------------------------------- - - // This view's parent. - View* parent_; - - // This view's children. - Views children_; - - // Size and disposition ------------------------------------------------------ - - // This View's bounds in the parent coordinate system. - gfx::Rect bounds_; - - // Whether this view is visible. - bool visible_; - - // Whether this view is enabled. - bool enabled_; - - // Whether this view is painting. - bool painting_enabled_; - - // Whether or not RegisterViewForVisibleBoundsNotification on the RootView - // has been invoked. - bool registered_for_visible_bounds_notification_; - - // List of descendants wanting notification when their visible bounds change. - scoped_ptr<Views> descendants_to_notify_; - - // Transformations ----------------------------------------------------------- - - // Clipping parameters. skia transformation matrix does not give us clipping. - // So we do it ourselves. - float clip_x_; - float clip_y_; - - // Layout -------------------------------------------------------------------- - - // Whether the view needs to be laid out. - bool needs_layout_; - - // The View's LayoutManager defines the sizing heuristics applied to child - // Views. The default is absolute positioning according to bounds_. - scoped_ptr<LayoutManager> layout_manager_; - - // Painting ------------------------------------------------------------------ - - // Background - scoped_ptr<Background> background_; - - // Border. - scoped_ptr<Border> border_; - - // RTL painting -------------------------------------------------------------- - - // Indicates whether or not the gfx::Canvas object passed to View::Paint() - // is going to be flipped horizontally (using the appropriate transform) on - // right-to-left locales for this View. - bool flip_canvas_on_paint_for_rtl_ui_; - - // Accelerated painting ------------------------------------------------------ - - bool paint_to_layer_; - scoped_ptr<ui::Layer> layer_; - - // Accelerators -------------------------------------------------------------- - - // true if when we were added to hierarchy we were without focus manager - // attempt addition when ancestor chain changed. - bool accelerator_registration_delayed_; - - // Focus manager accelerators registered on. - FocusManager* accelerator_focus_manager_; - - // The list of accelerators. List elements in the range - // [0, registered_accelerator_count_) are already registered to FocusManager, - // and the rest are not yet. - scoped_ptr<std::vector<ui::Accelerator> > accelerators_; - size_t registered_accelerator_count_; - - // Focus --------------------------------------------------------------------- - - // Next view to be focused when the Tab key is pressed. - View* next_focusable_view_; - - // Next view to be focused when the Shift-Tab key combination is pressed. - View* previous_focusable_view_; - - // Whether this view can be focused. - bool focusable_; - - // Whether this view is focusable if the user requires full keyboard access, - // even though it may not be normally focusable. - bool accessibility_focusable_; - - // Context menus ------------------------------------------------------------- - - // The menu controller. - ContextMenuController* context_menu_controller_; - - // Drag and drop ------------------------------------------------------------- - - DragController* drag_controller_; - - // Accessibility ------------------------------------------------------------- - - // The Windows-specific accessibility implementation for this view. -#if defined(OS_WIN) - base::win::ScopedComPtr<NativeViewAccessibilityWin> - native_view_accessibility_win_; -#endif - - DISALLOW_COPY_AND_ASSIGN(View); -}; - -} // namespace views - -#endif // VIEWS_VIEW_H_ diff --git a/views/view_aura.cc b/views/view_aura.cc deleted file mode 100644 index 0f5911d..0000000 --- a/views/view_aura.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/view.h" - -namespace { - -// Default horizontal drag threshold in pixels. -// Same as what gtk uses. -const int kDefaultHorizontalDragThreshold = 8; - -// Default vertical drag threshold in pixels. -// Same as what gtk uses. -const int kDefaultVerticalDragThreshold = 8; - -} // namespace - -namespace views { - -gfx::NativeViewAccessible View::GetNativeViewAccessible() { - return NULL; -} - -int View::GetHorizontalDragThreshold() { - // TODO(jennyz): This value may need to be adjusted for different platforms - // and for different display density. - return kDefaultHorizontalDragThreshold; -} - -int View::GetVerticalDragThreshold() { - // TODO(jennyz): This value may need to be adjusted for different platforms - // and for different display density. - return kDefaultVerticalDragThreshold; -} - -} // namespace views diff --git a/views/view_gtk.cc b/views/view_gtk.cc deleted file mode 100644 index af62f1e..0000000 --- a/views/view_gtk.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/view.h" - -#include <gtk/gtk.h> - -#include "base/logging.h" - -namespace views { - -gfx::NativeViewAccessible View::GetNativeViewAccessible() { - NOTIMPLEMENTED(); - return NULL; -} - -int View::GetHorizontalDragThreshold() { - static bool determined_threshold = false; - static int drag_threshold = 8; - if (determined_threshold) - return drag_threshold; - determined_threshold = true; - GtkSettings* settings = gtk_settings_get_default(); - if (!settings) - return drag_threshold; - int value = 0; - g_object_get(G_OBJECT(settings), "gtk-dnd-drag-threshold", &value, NULL); - if (value) - drag_threshold = value; - return drag_threshold; -} - -int View::GetVerticalDragThreshold() { - // Vertical and horizontal drag threshold are the same in Gtk. - return GetHorizontalDragThreshold(); -} - -} // namespace views diff --git a/views/view_unittest.cc b/views/view_unittest.cc deleted file mode 100644 index baee824..0000000 --- a/views/view_unittest.cc +++ /dev/null @@ -1,3068 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <map> - -#include "base/memory/scoped_ptr.h" -#include "base/rand_util.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/clipboard/clipboard.h" -#include "ui/base/keycodes/keyboard_codes.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/gfx/canvas_skia.h" -#include "ui/gfx/compositor/compositor.h" -#include "ui/gfx/compositor/layer.h" -#include "ui/gfx/compositor/layer_animator.h" -#include "ui/gfx/compositor/test/test_compositor.h" -#include "ui/gfx/compositor/test/test_texture.h" -#include "ui/gfx/path.h" -#include "ui/gfx/transform.h" -#include "ui/views/controls/button/button_dropdown.h" -#include "ui/views/controls/button/checkbox.h" -#include "ui/views/controls/native/native_view_host.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/textfield/textfield.h" -#include "ui/views/events/event.h" -#include "ui/views/focus/accelerator_handler.h" -#include "ui/views/focus/view_storage.h" -#include "ui/views/test/views_test_base.h" -#include "ui/views/touchui/gesture_manager.h" -#include "ui/views/widget/native_widget.h" -#include "ui/views/widget/root_view.h" -#include "ui/views/window/dialog_delegate.h" -#include "views/background.h" -#include "views/view.h" -#include "views/views_delegate.h" - -#if defined(OS_WIN) -#include "ui/views/test/test_views_delegate.h" -#endif -#if defined(USE_AURA) -#include "ui/aura/desktop.h" -#endif - -using ::testing::_; - -namespace { - -// Returns true if |ancestor| is an ancestor of |layer|. -bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) { - while (layer && layer != ancestor) - layer = layer->parent(); - return layer == ancestor; -} - -// Convenience functions for walking a View tree. -const views::View* FirstView(const views::View* view) { - const views::View* v = view; - while (v->has_children()) - v = v->child_at(0); - return v; -} - -const views::View* NextView(const views::View* view) { - const views::View* v = view; - const views::View* parent = v->parent(); - if (!parent) - return NULL; - int next = parent->GetIndexOf(v) + 1; - if (next != parent->child_count()) - return FirstView(parent->child_at(next)); - return parent; -} - -// Convenience functions for walking a Layer tree. -const ui::Layer* FirstLayer(const ui::Layer* layer) { - const ui::Layer* l = layer; - while (l->children().size() > 0) - l = l->children()[0]; - return l; -} - -const ui::Layer* NextLayer(const ui::Layer* layer) { - const ui::Layer* parent = layer->parent(); - if (!parent) - return NULL; - const std::vector<ui::Layer*> children = parent->children(); - size_t index; - for (index = 0; index < children.size(); index++) { - if (children[index] == layer) - break; - } - size_t next = index + 1; - if (next < children.size()) - return FirstLayer(children[next]); - return parent; -} - -// Given the root nodes of a View tree and a Layer tree, makes sure the two -// trees are in sync. -bool ViewAndLayerTreeAreConsistent(const views::View* view, - const ui::Layer* layer) { - const views::View* v = FirstView(view); - const ui::Layer* l = FirstLayer(layer); - while (v && l) { - // Find the view with a layer. - while (v && !v->layer()) - v = NextView(v); - EXPECT_TRUE(v); - if (!v) - return false; - - // Check if the View tree and the Layer tree are in sync. - EXPECT_EQ(l, v->layer()); - if (v->layer() != l) - return false; - - // Check if the visibility states of the View and the Layer are in sync. - EXPECT_EQ(l->IsDrawn(), v->IsVisibleInRootView()); - if (v->IsVisibleInRootView() != l->IsDrawn()) { - for (const views::View* vv = v; vv; vv = vv->parent()) - LOG(ERROR) << "V: " << vv << " " << vv->IsVisible() << " " - << vv->IsVisibleInRootView() << " " << vv->layer(); - for (const ui::Layer* ll = l; ll; ll = ll->parent()) - LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn(); - return false; - } - - // Check if the size of the View and the Layer are in sync. - EXPECT_EQ(l->bounds(), v->bounds()); - if (v->bounds() != l->bounds()) - return false; - - if (v == view || l == layer) - return v == view && l == layer; - - v = NextView(v); - l = NextLayer(l); - } - - return false; -} - -// Constructs a View tree with the specified depth. -void ConstructTree(views::View* view, int depth) { - if (depth == 0) - return; - int count = base::RandInt(1, 5); - for (int i = 0; i < count; i++) { - views::View* v = new views::View; - view->AddChildView(v); - if (base::RandDouble() > 0.5) - v->SetPaintToLayer(true); - if (base::RandDouble() < 0.2) - v->SetVisible(false); - - ConstructTree(v, depth - 1); - } -} - -void ScrambleTree(views::View* view) { - int count = view->child_count(); - if (count == 0) - return; - for (int i = 0; i < count; i++) { - ScrambleTree(view->child_at(i)); - } - - if (count > 1) { - int a = base::RandInt(0, count - 1); - int b = base::RandInt(0, count - 1); - - views::View* view_a = view->child_at(a); - views::View* view_b = view->child_at(b); - view->ReorderChildView(view_a, b); - view->ReorderChildView(view_b, a); - } - - if (!view->layer() && base::RandDouble() < 0.1) - view->SetPaintToLayer(true); - - if (base::RandDouble() < 0.1) - view->SetVisible(!view->IsVisible()); -} - -} - -namespace views { - -typedef ViewsTestBase ViewTest; - -// A derived class for testing purpose. -class TestView : public View { - public: - TestView() : View(), in_touch_sequence_(false) {} - virtual ~TestView() {} - - // Reset all test state - void Reset() { - did_change_bounds_ = false; - last_mouse_event_type_ = 0; - location_.SetPoint(0, 0); - last_touch_event_type_ = 0; - last_touch_event_was_handled_ = false; - last_clip_.setEmpty(); - accelerator_count_map_.clear(); - } - - virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; - virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE; - virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE; - virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE; - virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event) OVERRIDE; - virtual void Paint(gfx::Canvas* canvas) OVERRIDE; - virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE; - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; - - // OnBoundsChanged. - bool did_change_bounds_; - gfx::Rect new_bounds_; - - // MouseEvent. - int last_mouse_event_type_; - gfx::Point location_; - - // Painting. - std::vector<gfx::Rect> scheduled_paint_rects_; - - // TouchEvent. - int last_touch_event_type_; - bool last_touch_event_was_handled_; - bool in_touch_sequence_; - - // Painting. - SkRect last_clip_; - - // Accelerators. - std::map<ui::Accelerator, int> accelerator_count_map_; -}; - -// Mock instance of the GestureManager for testing. -class MockGestureManager : public GestureManager { - public: - // Reset all test state. - void Reset() { - last_touch_event_ = 0; - last_view_ = NULL; - previously_handled_flag_ = false; - dispatched_synthetic_event_ = false; - } - - bool ProcessTouchEventForGesture(const TouchEvent& event, - View* source, - ui::TouchStatus status); - MockGestureManager(); - - bool previously_handled_flag_; - int last_touch_event_; - View *last_view_; - bool dispatched_synthetic_event_; - - DISALLOW_COPY_AND_ASSIGN(MockGestureManager); -}; - -// A view subclass that ignores all touch events for testing purposes. -class TestViewIgnoreTouch : public TestView { - public: - TestViewIgnoreTouch() : TestView() {} - virtual ~TestViewIgnoreTouch() {} - - private: - virtual ui::TouchStatus OnTouchEvent(const TouchEvent& event) OVERRIDE; -}; - -//////////////////////////////////////////////////////////////////////////////// -// OnBoundsChanged -//////////////////////////////////////////////////////////////////////////////// - -void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - did_change_bounds_ = true; - new_bounds_ = bounds(); -} - -TEST_F(ViewTest, OnBoundsChanged) { - TestView v; - - gfx::Rect prev_rect(0, 0, 200, 200); - gfx::Rect new_rect(100, 100, 250, 250); - - v.SetBoundsRect(prev_rect); - v.Reset(); - v.SetBoundsRect(new_rect); - - EXPECT_EQ(v.did_change_bounds_, true); - EXPECT_EQ(v.new_bounds_, new_rect); - EXPECT_EQ(v.bounds(), new_rect); -} - -//////////////////////////////////////////////////////////////////////////////// -// MouseEvent -//////////////////////////////////////////////////////////////////////////////// - -bool TestView::OnMousePressed(const MouseEvent& event) { - last_mouse_event_type_ = event.type(); - location_.SetPoint(event.x(), event.y()); - return true; -} - -bool TestView::OnMouseDragged(const MouseEvent& event) { - last_mouse_event_type_ = event.type(); - location_.SetPoint(event.x(), event.y()); - return true; -} - -void TestView::OnMouseReleased(const MouseEvent& event) { - last_mouse_event_type_ = event.type(); - location_.SetPoint(event.x(), event.y()); -} - -TEST_F(ViewTest, MouseEvent) { - TestView* v1 = new TestView(); - v1->SetBounds(0, 0, 300, 300); - - TestView* v2 = new TestView(); - v2->SetBounds(100, 100, 100, 100); - - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(50, 50, 650, 650); - widget->Init(params); - View* root = widget->GetRootView(); - - root->AddChildView(v1); - v1->AddChildView(v2); - - v1->Reset(); - v2->Reset(); - - MouseEvent pressed(ui::ET_MOUSE_PRESSED, - 110, - 120, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMousePressed(pressed); - EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED); - EXPECT_EQ(v2->location_.x(), 10); - EXPECT_EQ(v2->location_.y(), 20); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_mouse_event_type_, 0); - - // Drag event out of bounds. Should still go to v2 - v1->Reset(); - v2->Reset(); - MouseEvent dragged(ui::ET_MOUSE_DRAGGED, - 50, - 40, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMouseDragged(dragged); - EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED); - EXPECT_EQ(v2->location_.x(), -50); - EXPECT_EQ(v2->location_.y(), -60); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_mouse_event_type_, 0); - - // Releasted event out of bounds. Should still go to v2 - v1->Reset(); - v2->Reset(); - MouseEvent released(ui::ET_MOUSE_RELEASED, 0, 0, 0); - root->OnMouseDragged(released); - EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED); - EXPECT_EQ(v2->location_.x(), -100); - EXPECT_EQ(v2->location_.y(), -100); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_mouse_event_type_, 0); - - widget->CloseNow(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TouchEvent -//////////////////////////////////////////////////////////////////////////////// -bool MockGestureManager::ProcessTouchEventForGesture( - const TouchEvent& event, - View* source, - ui::TouchStatus status) { - if (status != ui::TOUCH_STATUS_UNKNOWN) { - dispatched_synthetic_event_ = false; - return false; - } - last_touch_event_ = event.type(); - last_view_ = source; - previously_handled_flag_ = status != ui::TOUCH_STATUS_UNKNOWN; - dispatched_synthetic_event_ = true; - return true; -} - -MockGestureManager::MockGestureManager() { -} - -ui::TouchStatus TestView::OnTouchEvent(const TouchEvent& event) { - last_touch_event_type_ = event.type(); - location_.SetPoint(event.x(), event.y()); - if (!in_touch_sequence_) { - if (event.type() == ui::ET_TOUCH_PRESSED) { - in_touch_sequence_ = true; - return ui::TOUCH_STATUS_START; - } - } else { - if (event.type() == ui::ET_TOUCH_RELEASED) { - in_touch_sequence_ = false; - return ui::TOUCH_STATUS_END; - } - return ui::TOUCH_STATUS_CONTINUE; - } - return last_touch_event_was_handled_ ? ui::TOUCH_STATUS_CONTINUE : - ui::TOUCH_STATUS_UNKNOWN; -} - -ui::TouchStatus TestViewIgnoreTouch::OnTouchEvent(const TouchEvent& event) { - return ui::TOUCH_STATUS_UNKNOWN; -} - -TEST_F(ViewTest, TouchEvent) { - MockGestureManager gm; - - TestView* v1 = new TestView(); - v1->SetBounds(0, 0, 300, 300); - - TestView* v2 = new TestView(); - v2->SetBounds(100, 100, 100, 100); - - TestView* v3 = new TestViewIgnoreTouch(); - v3->SetBounds(0, 0, 100, 100); - - scoped_ptr<Widget> widget(new Widget()); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(50, 50, 650, 650); - widget->Init(params); - View* root = widget->GetRootView(); - - root->AddChildView(v1); - static_cast<internal::RootView*>(root)->SetGestureManagerForTesting(&gm); - v1->AddChildView(v2); - v2->AddChildView(v3); - - // |v3| completely obscures |v2|, but all the touch events on |v3| should - // reach |v2| because |v3| doesn't process any touch events. - - // Make sure if none of the views handle the touch event, the gesture manager - // does. - v1->Reset(); - v2->Reset(); - gm.Reset(); - - TouchEvent unhandled(ui::ET_TOUCH_MOVED, - 400, - 400, - 0, /* no flags */ - 0, /* first finger touch */ - 1.0, 0.0, 1.0, 0.0); - root->OnTouchEvent(unhandled); - - EXPECT_EQ(v1->last_touch_event_type_, 0); - EXPECT_EQ(v2->last_touch_event_type_, 0); - - EXPECT_EQ(gm.previously_handled_flag_, false); - EXPECT_EQ(gm.last_touch_event_, ui::ET_TOUCH_MOVED); - EXPECT_EQ(gm.last_view_, root); - EXPECT_EQ(gm.dispatched_synthetic_event_, true); - - // Test press, drag, release touch sequence. - v1->Reset(); - v2->Reset(); - gm.Reset(); - - TouchEvent pressed(ui::ET_TOUCH_PRESSED, - 110, - 120, - 0, /* no flags */ - 0, /* first finger touch */ - 1.0, 0.0, 1.0, 0.0); - v2->last_touch_event_was_handled_ = true; - root->OnTouchEvent(pressed); - - EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_PRESSED); - EXPECT_EQ(v2->location_.x(), 10); - EXPECT_EQ(v2->location_.y(), 20); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_touch_event_type_, 0); - - // Since v2 handled the touch-event, the gesture manager should not handle it. - EXPECT_EQ(gm.last_touch_event_, 0); - EXPECT_EQ(NULL, gm.last_view_); - EXPECT_EQ(gm.previously_handled_flag_, false); - - // Drag event out of bounds. Should still go to v2 - v1->Reset(); - v2->Reset(); - TouchEvent dragged(ui::ET_TOUCH_MOVED, - 50, - 40, - 0, /* no flags */ - 0, /* first finger touch */ - 1.0, 0.0, 1.0, 0.0); - - root->OnTouchEvent(dragged); - EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_MOVED); - EXPECT_EQ(v2->location_.x(), -50); - EXPECT_EQ(v2->location_.y(), -60); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_touch_event_type_, 0); - - EXPECT_EQ(gm.last_touch_event_, 0); - EXPECT_EQ(NULL, gm.last_view_); - EXPECT_EQ(gm.previously_handled_flag_, false); - - // Released event out of bounds. Should still go to v2 - v1->Reset(); - v2->Reset(); - TouchEvent released(ui::ET_TOUCH_RELEASED, 0, 0, 0, 0 /* first finger */, - 1.0, 0.0, 1.0, 0.0); - v2->last_touch_event_was_handled_ = true; - root->OnTouchEvent(released); - EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_RELEASED); - EXPECT_EQ(v2->location_.x(), -100); - EXPECT_EQ(v2->location_.y(), -100); - // Make sure v1 did not receive the event - EXPECT_EQ(v1->last_touch_event_type_, 0); - - EXPECT_EQ(gm.last_touch_event_, 0); - EXPECT_EQ(NULL, gm.last_view_); - EXPECT_EQ(gm.previously_handled_flag_, false); - - widget->CloseNow(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Painting -//////////////////////////////////////////////////////////////////////////////// - -void TestView::Paint(gfx::Canvas* canvas) { - canvas->GetSkCanvas()->getClipBounds(&last_clip_); -} - -void TestView::SchedulePaintInRect(const gfx::Rect& rect) { - scheduled_paint_rects_.push_back(rect); - View::SchedulePaintInRect(rect); -} - -void CheckRect(const SkRect& check_rect, const SkRect& target_rect) { - EXPECT_EQ(target_rect.fLeft, check_rect.fLeft); - EXPECT_EQ(target_rect.fRight, check_rect.fRight); - EXPECT_EQ(target_rect.fTop, check_rect.fTop); - EXPECT_EQ(target_rect.fBottom, check_rect.fBottom); -} - -/* This test is disabled because it is flakey on some systems. -TEST_F(ViewTest, DISABLED_Painting) { - // Determine if InvalidateRect generates an empty paint rectangle. - EmptyWindow paint_window(CRect(50, 50, 650, 650)); - paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL, - RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); - bool empty_paint = paint_window.empty_paint(); - - NativeWidgetWin window; - window.set_delete_on_destroy(false); - window.set_window_style(WS_OVERLAPPEDWINDOW); - window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL); - View* root = window.GetRootView(); - - TestView* v1 = new TestView(); - v1->SetBounds(0, 0, 650, 650); - root->AddChildView(v1); - - TestView* v2 = new TestView(); - v2->SetBounds(10, 10, 80, 80); - v1->AddChildView(v2); - - TestView* v3 = new TestView(); - v3->SetBounds(10, 10, 60, 60); - v2->AddChildView(v3); - - TestView* v4 = new TestView(); - v4->SetBounds(10, 200, 100, 100); - v1->AddChildView(v4); - - // Make sure to paint current rects - PaintRootView(root, empty_paint); - - - v1->Reset(); - v2->Reset(); - v3->Reset(); - v4->Reset(); - v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10)); - PaintRootView(root, empty_paint); - - SkRect tmp_rect; - - tmp_rect.set(SkIntToScalar(10), - SkIntToScalar(10), - SkIntToScalar(20), - SkIntToScalar(20)); - CheckRect(v3->last_clip_, tmp_rect); - - tmp_rect.set(SkIntToScalar(20), - SkIntToScalar(20), - SkIntToScalar(30), - SkIntToScalar(30)); - CheckRect(v2->last_clip_, tmp_rect); - - tmp_rect.set(SkIntToScalar(30), - SkIntToScalar(30), - SkIntToScalar(40), - SkIntToScalar(40)); - CheckRect(v1->last_clip_, tmp_rect); - - // Make sure v4 was not painted - tmp_rect.setEmpty(); - CheckRect(v4->last_clip_, tmp_rect); - - window.DestroyWindow(); -} -*/ - -#if defined(OS_WIN) -TEST_F(ViewTest, RemoveNotification) { -#else -// TODO(beng): stopped working with widget hierarchy split, -// http://crbug.com/82364 -TEST_F(ViewTest, DISABLED_RemoveNotification) { -#endif - ViewStorage* vs = ViewStorage::GetInstance(); - Widget* widget = new Widget; - widget->Init(Widget::InitParams(Widget::InitParams::TYPE_POPUP)); - View* root_view = widget->GetRootView(); - - View* v1 = new View; - int s1 = vs->CreateStorageID(); - vs->StoreView(s1, v1); - root_view->AddChildView(v1); - View* v11 = new View; - int s11 = vs->CreateStorageID(); - vs->StoreView(s11, v11); - v1->AddChildView(v11); - View* v111 = new View; - int s111 = vs->CreateStorageID(); - vs->StoreView(s111, v111); - v11->AddChildView(v111); - View* v112 = new View; - int s112 = vs->CreateStorageID(); - vs->StoreView(s112, v112); - v11->AddChildView(v112); - View* v113 = new View; - int s113 = vs->CreateStorageID(); - vs->StoreView(s113, v113); - v11->AddChildView(v113); - View* v1131 = new View; - int s1131 = vs->CreateStorageID(); - vs->StoreView(s1131, v1131); - v113->AddChildView(v1131); - View* v12 = new View; - int s12 = vs->CreateStorageID(); - vs->StoreView(s12, v12); - v1->AddChildView(v12); - - View* v2 = new View; - int s2 = vs->CreateStorageID(); - vs->StoreView(s2, v2); - root_view->AddChildView(v2); - View* v21 = new View; - int s21 = vs->CreateStorageID(); - vs->StoreView(s21, v21); - v2->AddChildView(v21); - View* v211 = new View; - int s211 = vs->CreateStorageID(); - vs->StoreView(s211, v211); - v21->AddChildView(v211); - - size_t stored_views = vs->view_count(); - - // Try removing a leaf view. - v21->RemoveChildView(v211); - EXPECT_EQ(stored_views - 1, vs->view_count()); - EXPECT_EQ(NULL, vs->RetrieveView(s211)); - delete v211; // We won't use this one anymore. - - // Now try removing a view with a hierarchy of depth 1. - v11->RemoveChildView(v113); - EXPECT_EQ(stored_views - 3, vs->view_count()); - EXPECT_EQ(NULL, vs->RetrieveView(s113)); - EXPECT_EQ(NULL, vs->RetrieveView(s1131)); - delete v113; // We won't use this one anymore. - - // Now remove even more. - root_view->RemoveChildView(v1); - EXPECT_EQ(NULL, vs->RetrieveView(s1)); - EXPECT_EQ(NULL, vs->RetrieveView(s11)); - EXPECT_EQ(NULL, vs->RetrieveView(s12)); - EXPECT_EQ(NULL, vs->RetrieveView(s111)); - EXPECT_EQ(NULL, vs->RetrieveView(s112)); - - // Put v1 back for more tests. - root_view->AddChildView(v1); - vs->StoreView(s1, v1); - - // Synchronously closing the window deletes the view hierarchy, which should - // remove all its views from ViewStorage. - widget->CloseNow(); - EXPECT_EQ(stored_views - 10, vs->view_count()); - EXPECT_EQ(NULL, vs->RetrieveView(s1)); - EXPECT_EQ(NULL, vs->RetrieveView(s12)); - EXPECT_EQ(NULL, vs->RetrieveView(s11)); - EXPECT_EQ(NULL, vs->RetrieveView(s12)); - EXPECT_EQ(NULL, vs->RetrieveView(s21)); - EXPECT_EQ(NULL, vs->RetrieveView(s111)); - EXPECT_EQ(NULL, vs->RetrieveView(s112)); -} - -namespace { -class HitTestView : public View { - public: - explicit HitTestView(bool has_hittest_mask) - : has_hittest_mask_(has_hittest_mask) { - } - virtual ~HitTestView() {} - - protected: - // Overridden from 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(width()); - SkScalar h = SkIntToScalar(height()); - - // 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); -}; - -gfx::Point ConvertPointToView(View* view, const gfx::Point& p) { - gfx::Point tmp(p); - View::ConvertPointToView(view->GetWidget()->GetRootView(), view, &tmp); - return tmp; -} - -void RotateCounterclockwise(ui::Transform& transform) { - transform.matrix().set3x3(0, -1, 0, - 1, 0, 0, - 0, 0, 1); -} - -void RotateClockwise(ui::Transform& transform) { - transform.matrix().set3x3( 0, 1, 0, - -1, 0, 0, - 0, 0, 1); -} - -} // namespace - -TEST_F(ViewTest, HitTestMasks) { - Widget* widget = new Widget; - widget->Init(Widget::InitParams(Widget::InitParams::TYPE_POPUP)); - View* root_view = widget->GetRootView(); - root_view->SetBounds(0, 0, 500, 500); - - gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100); - HitTestView* v1 = new HitTestView(false); - v1->SetBoundsRect(v1_bounds); - root_view->AddChildView(v1); - - gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100); - HitTestView* v2 = new HitTestView(true); - v2->SetBoundsRect(v2_bounds); - root_view->AddChildView(v2); - - gfx::Point v1_centerpoint = v1_bounds.CenterPoint(); - gfx::Point v2_centerpoint = v2_bounds.CenterPoint(); - gfx::Point v1_origin = v1_bounds.origin(); - gfx::Point v2_origin = v2_bounds.origin(); - - // Test HitTest - EXPECT_TRUE(v1->HitTest(ConvertPointToView(v1, v1_centerpoint))); - EXPECT_TRUE(v2->HitTest(ConvertPointToView(v2, v2_centerpoint))); - - EXPECT_TRUE(v1->HitTest(ConvertPointToView(v1, v1_origin))); - EXPECT_FALSE(v2->HitTest(ConvertPointToView(v2, v2_origin))); - - // Test GetEventHandlerForPoint - EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint)); - EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint)); - EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin)); - EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin)); - - widget->CloseNow(); -} - -TEST_F(ViewTest, Textfield) { - const string16 kText = ASCIIToUTF16("Reality is that which, when you stop " - "believing it, doesn't go away."); - const string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!"); - const string16 kEmptyString; - - ui::Clipboard clipboard; - - Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(0, 0, 100, 100); - widget->Init(params); - View* root_view = widget->GetRootView(); - - Textfield* textfield = new Textfield(); - root_view->AddChildView(textfield); - - // Test setting, appending text. - textfield->SetText(kText); - EXPECT_EQ(kText, textfield->text()); - textfield->AppendText(kExtraText); - EXPECT_EQ(kText + kExtraText, textfield->text()); - textfield->SetText(string16()); - EXPECT_EQ(kEmptyString, textfield->text()); - - // Test selection related methods. - textfield->SetText(kText); - EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); - textfield->SelectAll(); - EXPECT_EQ(kText, textfield->text()); - textfield->ClearSelection(); - EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); - - widget->CloseNow(); -} - -#if defined(OS_WIN) && !defined(USE_AURA) - -// Tests that the Textfield view respond appropiately to cut/copy/paste. -TEST_F(ViewTest, TextfieldCutCopyPaste) { - const string16 kNormalText = ASCIIToUTF16("Normal"); - const string16 kReadOnlyText = ASCIIToUTF16("Read only"); - const string16 kPasswordText = ASCIIToUTF16("Password! ** Secret stuff **"); - - ui::Clipboard clipboard; - - Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(0, 0, 100, 100); - widget->Init(params); - View* root_view = widget->GetRootView(); - - Textfield* normal = new Textfield(); - Textfield* read_only = new Textfield(); - read_only->SetReadOnly(true); - Textfield* password = new Textfield(Textfield::STYLE_PASSWORD); - - root_view->AddChildView(normal); - root_view->AddChildView(read_only); - root_view->AddChildView(password); - - normal->SetText(kNormalText); - read_only->SetText(kReadOnlyText); - password->SetText(kPasswordText); - - // - // Test cut. - // - ASSERT_TRUE(normal->GetTestingHandle()); - normal->SelectAll(); - ::SendMessage(normal->GetTestingHandle(), WM_CUT, 0, 0); - - string16 result; - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - EXPECT_EQ(kNormalText, result); - normal->SetText(kNormalText); // Let's revert to the original content. - - ASSERT_TRUE(read_only->GetTestingHandle()); - read_only->SelectAll(); - ::SendMessage(read_only->GetTestingHandle(), WM_CUT, 0, 0); - result.clear(); - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - // Cut should have failed, so the clipboard content should not have changed. - EXPECT_EQ(kNormalText, result); - - ASSERT_TRUE(password->GetTestingHandle()); - password->SelectAll(); - ::SendMessage(password->GetTestingHandle(), WM_CUT, 0, 0); - result.clear(); - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - // Cut should have failed, so the clipboard content should not have changed. - EXPECT_EQ(kNormalText, result); - - // - // Test copy. - // - - // Let's start with read_only as the clipboard already contains the content - // of normal. - read_only->SelectAll(); - ::SendMessage(read_only->GetTestingHandle(), WM_COPY, 0, 0); - result.clear(); - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - EXPECT_EQ(kReadOnlyText, result); - - normal->SelectAll(); - ::SendMessage(normal->GetTestingHandle(), WM_COPY, 0, 0); - result.clear(); - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - EXPECT_EQ(kNormalText, result); - - password->SelectAll(); - ::SendMessage(password->GetTestingHandle(), WM_COPY, 0, 0); - result.clear(); - clipboard.ReadText(ui::Clipboard::BUFFER_STANDARD, &result); - // We don't let you copy from a password field, clipboard should not have - // changed. - EXPECT_EQ(kNormalText, result); - - // - // Test Paste. - // - // Note that we use GetWindowText instead of Textfield::GetText below as the - // text in the Textfield class is synced to the text of the HWND on - // WM_KEYDOWN messages that we are not simulating here. - - // Attempting to copy kNormalText in a read-only text-field should fail. - read_only->SelectAll(); - ::SendMessage(read_only->GetTestingHandle(), WM_KEYDOWN, 0, 0); - wchar_t buffer[1024] = { 0 }; - ::GetWindowText(read_only->GetTestingHandle(), buffer, 1024); - EXPECT_EQ(kReadOnlyText, string16(buffer)); - - password->SelectAll(); - ::SendMessage(password->GetTestingHandle(), WM_PASTE, 0, 0); - ::GetWindowText(password->GetTestingHandle(), buffer, 1024); - EXPECT_EQ(kNormalText, string16(buffer)); - - // Copy from read_only so the string we are pasting is not the same as the - // current one. - read_only->SelectAll(); - ::SendMessage(read_only->GetTestingHandle(), WM_COPY, 0, 0); - normal->SelectAll(); - ::SendMessage(normal->GetTestingHandle(), WM_PASTE, 0, 0); - ::GetWindowText(normal->GetTestingHandle(), buffer, 1024); - EXPECT_EQ(kReadOnlyText, string16(buffer)); - widget->CloseNow(); -} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Accelerators -//////////////////////////////////////////////////////////////////////////////// -bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) { - accelerator_count_map_[accelerator]++; - return true; -} - -#if defined(OS_WIN) && !defined(USE_AURA) -TEST_F(ViewTest, ActivateAccelerator) { - // Register a keyboard accelerator before the view is added to a window. - ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false); - TestView* view = new TestView(); - view->Reset(); - view->AddAccelerator(return_accelerator); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); - - // Create a window and add the view as its child. - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(0, 0, 100, 100); - widget->Init(params); - View* root = widget->GetRootView(); - root->AddChildView(view); - widget->Show(); - - // Get the focus manager. - FocusManager* focus_manager = widget->GetFocusManager(); - ASSERT_TRUE(focus_manager); - - // Hit the return key and see if it takes effect. - EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); - - // Hit the escape key. Nothing should happen. - ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, false, false, false); - EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0); - - // Now register the escape key and hit it again. - view->AddAccelerator(escape_accelerator); - EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); - - // Remove the return key accelerator. - view->RemoveAccelerator(return_accelerator); - EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); - - // Add it again. Hit the return key and the escape key. - view->AddAccelerator(return_accelerator); - EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); - EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); - - // Remove all the accelerators. - view->ResetAccelerators(); - EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); - EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); - EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); - - widget->CloseNow(); -} -#endif - -#if defined(OS_WIN) && !defined(USE_AURA) -TEST_F(ViewTest, HiddenViewWithAccelerator) { - ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false); - TestView* view = new TestView(); - view->Reset(); - view->AddAccelerator(return_accelerator); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); - - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(0, 0, 100, 100); - widget->Init(params); - View* root = widget->GetRootView(); - root->AddChildView(view); - widget->Show(); - - FocusManager* focus_manager = widget->GetFocusManager(); - ASSERT_TRUE(focus_manager); - - view->SetVisible(false); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - - view->SetVisible(true); - EXPECT_EQ(view, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - - widget->CloseNow(); -} -#endif - -#if defined(OS_WIN) && !defined(USE_AURA) -TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) { - ui::Accelerator return_accelerator(ui::VKEY_RETURN, false, false, false); - TestView* view = new TestView(); - view->Reset(); - view->AddAccelerator(return_accelerator); - EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); - - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(0, 0, 100, 100); - widget->Init(params); - View* root = widget->GetRootView(); - root->AddChildView(view); - - FocusManager* focus_manager = widget->GetFocusManager(); - ASSERT_TRUE(focus_manager); - - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - - widget->Show(); - EXPECT_EQ(view, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - - widget->Hide(); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - - widget->CloseNow(); -} -#endif - -#if defined(OS_WIN) && !defined(USE_AURA) -//////////////////////////////////////////////////////////////////////////////// -// Mouse-wheel message rerouting -//////////////////////////////////////////////////////////////////////////////// -class ScrollableTestView : public View { - public: - ScrollableTestView() { } - - virtual gfx::Size GetPreferredSize() { - return gfx::Size(100, 10000); - } - - virtual void Layout() { - SizeToPreferredSize(); - } -}; - -class TestViewWithControls : public View { - public: - TestViewWithControls() { - text_field_ = new Textfield(); - AddChildView(text_field_); - } - - Textfield* text_field_; -}; - -class SimpleWidgetDelegate : public WidgetDelegate { - public: - explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { } - - virtual void DeleteDelegate() { delete this; } - - virtual View* GetContentsView() { return contents_; } - - virtual Widget* GetWidget() { return contents_->GetWidget(); } - virtual const Widget* GetWidget() const { return contents_->GetWidget(); } - - private: - View* contents_; -}; - -// Tests that the mouse-wheel messages are correctly rerouted to the window -// under the mouse. -// TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build -// bot. -// Note that this fails for a variety of reasons: -// - focused view is apparently reset across window activations and never -// properly restored -// - this test depends on you not having any other window visible open under the -// area that it opens the test windows. --beng -TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) { - TestViewWithControls* view_with_controls = new TestViewWithControls(); - Widget* window1 = Widget::CreateWindowWithBounds( - new SimpleWidgetDelegate(view_with_controls), - gfx::Rect(0, 0, 100, 100)); - window1->Show(); - ScrollView* scroll_view = new ScrollView(); - scroll_view->SetContents(new ScrollableTestView()); - Widget* window2 = Widget::CreateWindowWithBounds( - new SimpleWidgetDelegate(scroll_view), - gfx::Rect(200, 200, 100, 100)); - window2->Show(); - EXPECT_EQ(0, scroll_view->GetVisibleRect().y()); - - // Make the window1 active, as this is what it would be in real-world. - window1->Activate(); - - // Let's send a mouse-wheel message to the different controls and check that - // it is rerouted to the window under the mouse (effectively scrolling the - // scroll-view). - - // First to the Window's HWND. - ::SendMessage(view_with_controls->GetWidget()->GetNativeView(), - WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250)); - EXPECT_EQ(20, scroll_view->GetVisibleRect().y()); - - // Then the text-field. - ::SendMessage(view_with_controls->text_field_->GetTestingHandle(), - WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250)); - EXPECT_EQ(80, scroll_view->GetVisibleRect().y()); - - // Ensure we don't scroll when the mouse is not over that window. - ::SendMessage(view_with_controls->text_field_->GetTestingHandle(), - WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50)); - EXPECT_EQ(80, scroll_view->GetVisibleRect().y()); - - window1->CloseNow(); - window2->CloseNow(); -} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Dialogs' default button -//////////////////////////////////////////////////////////////////////////////// - -class MockMenuModel : public ui::MenuModel { - public: - MOCK_CONST_METHOD0(HasIcons, bool()); - MOCK_CONST_METHOD1(GetFirstItemIndex, int(gfx::NativeMenu native_menu)); - MOCK_CONST_METHOD0(GetItemCount, int()); - MOCK_CONST_METHOD1(GetTypeAt, ItemType(int index)); - MOCK_CONST_METHOD1(GetCommandIdAt, int(int index)); - MOCK_CONST_METHOD1(GetLabelAt, string16(int index)); - MOCK_CONST_METHOD1(IsItemDynamicAt, bool(int index)); - MOCK_CONST_METHOD1(GetLabelFontAt, const gfx::Font* (int index)); - MOCK_CONST_METHOD2(GetAcceleratorAt, bool(int index, - ui::Accelerator* accelerator)); - MOCK_CONST_METHOD1(IsItemCheckedAt, bool(int index)); - MOCK_CONST_METHOD1(GetGroupIdAt, int(int index)); - MOCK_METHOD2(GetIconAt, bool(int index, SkBitmap* icon)); - MOCK_CONST_METHOD1(GetButtonMenuItemAt, ui::ButtonMenuItemModel*(int index)); - MOCK_CONST_METHOD1(IsEnabledAt, bool(int index)); - MOCK_CONST_METHOD1(IsVisibleAt, bool(int index)); - MOCK_CONST_METHOD1(GetSubmenuModelAt, MenuModel*(int index)); - MOCK_METHOD1(HighlightChangedTo, void(int index)); - MOCK_METHOD1(ActivatedAt, void(int index)); - MOCK_METHOD2(ActivatedAt, void(int index, int disposition)); - MOCK_METHOD0(MenuWillShow, void()); - MOCK_METHOD0(MenuClosed, void()); - MOCK_METHOD1(SetMenuModelDelegate, void(ui::MenuModelDelegate* delegate)); - MOCK_METHOD3(GetModelAndIndexForCommandId, bool(int command_id, - MenuModel** model, int* index)); -}; - -class TestDialog : public DialogDelegate, public ButtonListener { - public: - explicit TestDialog(MockMenuModel* mock_menu_model) - : contents_(NULL), - button1_(NULL), - button2_(NULL), - checkbox_(NULL), - button_drop_(NULL), - last_pressed_button_(NULL), - mock_menu_model_(mock_menu_model), - canceled_(false), - oked_(false), - closeable_(false), - widget_(NULL) { - } - - void TearDown() { - // Now we can close safely. - closeable_ = true; - widget_->Close(); - widget_ = NULL; - // delegate has to be alive while shutting down. - MessageLoop::current()->DeleteSoon(FROM_HERE, this); - } - - // DialogDelegate implementation: - virtual int GetDefaultDialogButton() const OVERRIDE { - return ui::DIALOG_BUTTON_OK; - } - - virtual View* GetContentsView() OVERRIDE { - if (!contents_) { - contents_ = new View; - button1_ = new NativeTextButton(this, ASCIIToUTF16("Button1")); - button2_ = new NativeTextButton(this, ASCIIToUTF16("Button2")); - checkbox_ = new Checkbox(ASCIIToUTF16("My checkbox")); - button_drop_ = new ButtonDropDown(this, mock_menu_model_); - contents_->AddChildView(button1_); - contents_->AddChildView(button2_); - contents_->AddChildView(checkbox_); - contents_->AddChildView(button_drop_); - } - return contents_; - } - - // Prevent the dialog from really closing (so we can click the OK/Cancel - // buttons to our heart's content). - virtual bool Cancel() OVERRIDE { - canceled_ = true; - return closeable_; - } - virtual bool Accept() OVERRIDE { - oked_ = true; - return closeable_; - } - - virtual Widget* GetWidget() OVERRIDE { - return widget_; - } - virtual const Widget* GetWidget() const OVERRIDE { - return widget_; - } - - // ButtonListener implementation. - virtual void ButtonPressed(Button* sender, const Event& event) OVERRIDE { - last_pressed_button_ = sender; - } - - void ResetStates() { - oked_ = false; - canceled_ = false; - last_pressed_button_ = NULL; - } - - // Set up expectations for methods that are called when an (empty) menu is - // shown from a drop down button. - void ExpectShowDropMenu() { - if (mock_menu_model_) { - EXPECT_CALL(*mock_menu_model_, HasIcons()); - EXPECT_CALL(*mock_menu_model_, GetFirstItemIndex(_)); - EXPECT_CALL(*mock_menu_model_, GetItemCount()); - EXPECT_CALL(*mock_menu_model_, MenuClosed()); - } - } - - View* contents_; - NativeTextButton* button1_; - NativeTextButton* button2_; - Checkbox* checkbox_; - ButtonDropDown* button_drop_; - Button* last_pressed_button_; - MockMenuModel* mock_menu_model_; - - bool canceled_; - bool oked_; - bool closeable_; - Widget* widget_; -}; - -class DefaultButtonTest : public ViewTest { - public: - enum ButtonID { - OK, - CANCEL, - BUTTON1, - BUTTON2 - }; - - DefaultButtonTest() - : focus_manager_(NULL), - test_dialog_(NULL), - client_view_(NULL), - ok_button_(NULL), - cancel_button_(NULL) { - } - - virtual void SetUp() OVERRIDE { - ViewTest::SetUp(); - test_dialog_ = new TestDialog(NULL); - Widget* window = - Widget::CreateWindowWithBounds(test_dialog_, gfx::Rect(0, 0, 100, 100)); - test_dialog_->widget_ = window; - window->Show(); - focus_manager_ = test_dialog_->contents_->GetFocusManager(); - ASSERT_TRUE(focus_manager_ != NULL); - client_view_ = - static_cast<DialogClientView*>(window->client_view()); - ok_button_ = client_view_->ok_button(); - cancel_button_ = client_view_->cancel_button(); - } - - virtual void TearDown() OVERRIDE { - test_dialog_->TearDown(); - ViewTest::TearDown(); - } - - void SimulatePressingEnterAndCheckDefaultButton(ButtonID button_id) { - KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0); - focus_manager_->OnKeyEvent(event); - switch (button_id) { - case OK: - EXPECT_TRUE(test_dialog_->oked_); - EXPECT_FALSE(test_dialog_->canceled_); - EXPECT_FALSE(test_dialog_->last_pressed_button_); - break; - case CANCEL: - EXPECT_FALSE(test_dialog_->oked_); - EXPECT_TRUE(test_dialog_->canceled_); - EXPECT_FALSE(test_dialog_->last_pressed_button_); - break; - case BUTTON1: - EXPECT_FALSE(test_dialog_->oked_); - EXPECT_FALSE(test_dialog_->canceled_); - EXPECT_TRUE(test_dialog_->last_pressed_button_ == - test_dialog_->button1_); - break; - case BUTTON2: - EXPECT_FALSE(test_dialog_->oked_); - EXPECT_FALSE(test_dialog_->canceled_); - EXPECT_TRUE(test_dialog_->last_pressed_button_ == - test_dialog_->button2_); - break; - } - test_dialog_->ResetStates(); - } - - FocusManager* focus_manager_; - TestDialog* test_dialog_; - DialogClientView* client_view_; - NativeTextButton* ok_button_; - NativeTextButton* cancel_button_; -}; - -TEST_F(DefaultButtonTest, DialogDefaultButtonTest) { - // Window has just been shown, we expect the default button specified in the - // DialogDelegate. - EXPECT_TRUE(ok_button_->is_default()); - - // Simulate pressing enter, that should trigger the OK button. - SimulatePressingEnterAndCheckDefaultButton(OK); - - // Simulate focusing another button, it should become the default button. - client_view_->OnWillChangeFocus(ok_button_, test_dialog_->button1_); - EXPECT_FALSE(ok_button_->is_default()); - EXPECT_TRUE(test_dialog_->button1_->is_default()); - // Simulate pressing enter, that should trigger button1. - SimulatePressingEnterAndCheckDefaultButton(BUTTON1); - - // Now select something that is not a button, the OK should become the default - // button again. - client_view_->OnWillChangeFocus(test_dialog_->button1_, - test_dialog_->checkbox_); - EXPECT_TRUE(ok_button_->is_default()); - EXPECT_FALSE(test_dialog_->button1_->is_default()); - SimulatePressingEnterAndCheckDefaultButton(OK); - - // Select yet another button. - client_view_->OnWillChangeFocus(test_dialog_->checkbox_, - test_dialog_->button2_); - EXPECT_FALSE(ok_button_->is_default()); - EXPECT_FALSE(test_dialog_->button1_->is_default()); - EXPECT_TRUE(test_dialog_->button2_->is_default()); - SimulatePressingEnterAndCheckDefaultButton(BUTTON2); - - // Focus nothing. - client_view_->OnWillChangeFocus(test_dialog_->button2_, NULL); - EXPECT_TRUE(ok_button_->is_default()); - EXPECT_FALSE(test_dialog_->button1_->is_default()); - EXPECT_FALSE(test_dialog_->button2_->is_default()); - SimulatePressingEnterAndCheckDefaultButton(OK); - - // Focus the cancel button. - client_view_->OnWillChangeFocus(NULL, cancel_button_); - EXPECT_FALSE(ok_button_->is_default()); - EXPECT_TRUE(cancel_button_->is_default()); - EXPECT_FALSE(test_dialog_->button1_->is_default()); - EXPECT_FALSE(test_dialog_->button2_->is_default()); - SimulatePressingEnterAndCheckDefaultButton(CANCEL); -} - -class ButtonDropDownTest : public ViewTest { - public: - ButtonDropDownTest() - : test_dialog_(NULL), - button_as_view_(NULL) { - } - - virtual void SetUp() OVERRIDE { - ViewTest::SetUp(); - test_dialog_ = new TestDialog(&mock_menu_model_); - Widget* window = - Widget::CreateWindowWithBounds(test_dialog_, gfx::Rect(0, 0, 100, 100)); - test_dialog_->widget_ = window; - window->Show(); - test_dialog_->button_drop_->SetBounds(0, 0, 100, 100); - // We have to cast the button back into a View in order to invoke it's - // OnMouseReleased method. - button_as_view_ = static_cast<View*>(test_dialog_->button_drop_); - } - - virtual void TearDown() OVERRIDE { - test_dialog_->TearDown(); - ViewTest::TearDown(); - } - - TestDialog* test_dialog_; - MockMenuModel mock_menu_model_; - // This is owned by test_dialog_. - View* button_as_view_; - - private: - DISALLOW_COPY_AND_ASSIGN(ButtonDropDownTest); -}; - -// Ensure that regular clicks on the drop down button still work. (i.e. - the -// click events are processed and the listener gets the click) -TEST_F(ButtonDropDownTest, RegularClickTest) { - MouseEvent press_event(ui::ET_MOUSE_PRESSED, 1, 1, ui::EF_LEFT_BUTTON_DOWN); - MouseEvent release_event(ui::ET_MOUSE_RELEASED, 1, 1, - ui::EF_LEFT_BUTTON_DOWN); - button_as_view_->OnMousePressed(press_event); - button_as_view_->OnMouseReleased(release_event); - EXPECT_EQ(test_dialog_->last_pressed_button_, test_dialog_->button_drop_); -} - -//////////////////////////////////////////////////////////////////////////////// -// View hierarchy / Visibility changes -//////////////////////////////////////////////////////////////////////////////// -/* -TEST_F(ViewTest, ChangeVisibility) { -#if defined(OS_LINUX) - // Make CRITICAL messages fatal - // TODO(oshima): we probably should enable this for entire tests on linux. - g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); -#endif - scoped_ptr<Widget> window(CreateWidget()); - window->Init(NULL, gfx::Rect(0, 0, 500, 300)); - View* root_view = window->GetRootView(); - NativeTextButton* native = new NativeTextButton(NULL, ASCIIToUTF16("Native")); - - root_view->SetContentsView(native); - native->SetVisible(true); - - root_view->RemoveChildView(native); - native->SetVisible(false); - // Change visibility to true with no widget. - native->SetVisible(true); - - root_view->SetContentsView(native); - native->SetVisible(true); -} -*/ - -//////////////////////////////////////////////////////////////////////////////// -// Native view hierachy -//////////////////////////////////////////////////////////////////////////////// -class TestNativeViewHierarchy : public View { - public: - TestNativeViewHierarchy() { - } - - virtual void NativeViewHierarchyChanged(bool attached, - gfx::NativeView native_view, - internal::RootView* root_view) { - NotificationInfo info; - info.attached = attached; - info.native_view = native_view; - info.root_view = root_view; - notifications_.push_back(info); - }; - struct NotificationInfo { - bool attached; - gfx::NativeView native_view; - internal::RootView* root_view; - }; - static const size_t kTotalViews = 2; - std::vector<NotificationInfo> notifications_; -}; - -class TestChangeNativeViewHierarchy { - public: - explicit TestChangeNativeViewHierarchy(ViewTest *view_test) { - view_test_ = view_test; - native_host_ = new NativeViewHost(); - host_ = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(0, 0, 500, 300); - host_->Init(params); - host_->GetRootView()->AddChildView(native_host_); - for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { - windows_[i] = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); - params.parent = host_->GetNativeView(); - params.bounds = gfx::Rect(0, 0, 500, 300); - windows_[i]->Init(params); - root_views_[i] = windows_[i]->GetRootView(); - test_views_[i] = new TestNativeViewHierarchy; - root_views_[i]->AddChildView(test_views_[i]); - } - } - - ~TestChangeNativeViewHierarchy() { - for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { - windows_[i]->Close(); - } - host_->Close(); - // Will close and self-delete widgets - no need to manually delete them. - view_test_->RunPendingMessages(); - } - - void CheckEnumeratingNativeWidgets() { - if (!host_->GetTopLevelWidget()) - return; - Widget::Widgets widgets; - Widget::GetAllChildWidgets(host_->GetNativeView(), &widgets); - EXPECT_EQ(TestNativeViewHierarchy::kTotalViews + 1, widgets.size()); - // Unfortunately there is no guarantee the sequence of views here so always - // go through all of them. - for (Widget::Widgets::iterator i = widgets.begin(); - i != widgets.end(); ++i) { - View* root_view = (*i)->GetRootView(); - if (host_->GetRootView() == root_view) - continue; - size_t j; - for (j = 0; j < TestNativeViewHierarchy::kTotalViews; ++j) - if (root_views_[j] == root_view) - break; - // EXPECT_LT/GT/GE() fails to compile with class-defined constants - // with gcc, with error - // "error: undefined reference to 'TestNativeViewHierarchy::kTotalViews'" - // so I forced to use EXPECT_TRUE() instead. - EXPECT_TRUE(TestNativeViewHierarchy::kTotalViews > j); - } - } - - void CheckChangingHierarhy() { - size_t i; - for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { - // TODO(georgey): use actual hierarchy changes to send notifications. - static_cast<internal::RootView*>(root_views_[i])-> - NotifyNativeViewHierarchyChanged(false, host_->GetNativeView()); - static_cast<internal::RootView*>(root_views_[i])-> - NotifyNativeViewHierarchyChanged(true, host_->GetNativeView()); - } - for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { - ASSERT_EQ(static_cast<size_t>(2), test_views_[i]->notifications_.size()); - EXPECT_FALSE(test_views_[i]->notifications_[0].attached); - EXPECT_EQ(host_->GetNativeView(), - test_views_[i]->notifications_[0].native_view); - EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[0].root_view); - EXPECT_TRUE(test_views_[i]->notifications_[1].attached); - EXPECT_EQ(host_->GetNativeView(), - test_views_[i]->notifications_[1].native_view); - EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[1].root_view); - } - } - - NativeViewHost* native_host_; - Widget* host_; - Widget* windows_[TestNativeViewHierarchy::kTotalViews]; - View* root_views_[TestNativeViewHierarchy::kTotalViews]; - TestNativeViewHierarchy* test_views_[TestNativeViewHierarchy::kTotalViews]; - ViewTest* view_test_; -}; - -TEST_F(ViewTest, ChangeNativeViewHierarchyFindRoots) { - // TODO(georgey): Fix the test for Linux -#if defined(OS_WIN) - TestChangeNativeViewHierarchy test(this); - test.CheckEnumeratingNativeWidgets(); -#endif -} - -TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) { - // TODO(georgey): Fix the test for Linux -#if defined(OS_WIN) - TestChangeNativeViewHierarchy test(this); - test.CheckChangingHierarhy(); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// Transformations -//////////////////////////////////////////////////////////////////////////////// - -class TransformPaintView : public TestView { - public: - TransformPaintView() {} - virtual ~TransformPaintView() {} - - void ClearScheduledPaintRect() { - scheduled_paint_rect_ = gfx::Rect(); - } - - gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; } - - // Overridden from View: - virtual void SchedulePaintInRect(const gfx::Rect& rect) { - gfx::Rect xrect = ConvertRectToParent(rect); - scheduled_paint_rect_ = scheduled_paint_rect_.Union(xrect); - } - - private: - gfx::Rect scheduled_paint_rect_; - - DISALLOW_COPY_AND_ASSIGN(TransformPaintView); -}; - -TEST_F(ViewTest, TransformPaint) { - TransformPaintView* v1 = new TransformPaintView(); - v1->SetBounds(0, 0, 500, 300); - - TestView* v2 = new TestView(); - v2->SetBounds(100, 100, 200, 100); - - Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(50, 50, 650, 650); - widget->Init(params); - widget->Show(); - View* root = widget->GetRootView(); - - root->AddChildView(v1); - v1->AddChildView(v2); - - // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. - v1->ClearScheduledPaintRect(); - v2->SchedulePaint(); - - EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect()); - - // Rotate |v1| counter-clockwise. - ui::Transform transform; - RotateCounterclockwise(transform); - transform.SetTranslateY(500.0f); - v1->SetTransform(transform); - - // |v2| now occupies (100, 200) to (200, 400) in |root|. - - v1->ClearScheduledPaintRect(); - v2->SchedulePaint(); - - EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect()); - - widget->CloseNow(); -} - -TEST_F(ViewTest, TransformEvent) { - TestView* v1 = new TestView(); - v1->SetBounds(0, 0, 500, 300); - - TestView* v2 = new TestView(); - v2->SetBounds(100, 100, 200, 100); - - Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(50, 50, 650, 650); - widget->Init(params); - View* root = widget->GetRootView(); - - root->AddChildView(v1); - v1->AddChildView(v2); - - // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. - - // Rotate |v1| counter-clockwise. - ui::Transform transform(v1->GetTransform()); - RotateCounterclockwise(transform); - transform.SetTranslateY(500.0f); - v1->SetTransform(transform); - - // |v2| now occupies (100, 200) to (200, 400) in |root|. - v1->Reset(); - v2->Reset(); - - MouseEvent pressed(ui::ET_MOUSE_PRESSED, - 110, 210, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMousePressed(pressed); - EXPECT_EQ(0, v1->last_mouse_event_type_); - EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); - EXPECT_EQ(190, v2->location_.x()); - EXPECT_EQ(10, v2->location_.y()); - - MouseEvent released(ui::ET_MOUSE_RELEASED, 0, 0, 0); - root->OnMouseReleased(released); - - // Now rotate |v2| inside |v1| clockwise. - transform = v2->GetTransform(); - RotateClockwise(transform); - transform.SetTranslateX(100.0f); - v2->SetTransform(transform); - - // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to - // (300, 400) in |root|. - - v1->Reset(); - v2->Reset(); - - MouseEvent p2(ui::ET_MOUSE_PRESSED, - 110, 320, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMousePressed(p2); - EXPECT_EQ(0, v1->last_mouse_event_type_); - EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); - EXPECT_EQ(10, v2->location_.x()); - EXPECT_EQ(20, v2->location_.y()); - - root->OnMouseReleased(released); - - v1->SetTransform(ui::Transform()); - v2->SetTransform(ui::Transform()); - - TestView* v3 = new TestView(); - v3->SetBounds(10, 10, 20, 30); - v2->AddChildView(v3); - - // Rotate |v3| clockwise with respect to |v2|. - transform = v1->GetTransform(); - RotateClockwise(transform); - transform.SetTranslateX(30.0f); - v3->SetTransform(transform); - - // Scale |v2| with respect to |v1| along both axis. - transform = v2->GetTransform(); - transform.SetScale(0.8f, 0.5f); - v2->SetTransform(transform); - - // |v3| occupies (108, 105) to (132, 115) in |root|. - - v1->Reset(); - v2->Reset(); - v3->Reset(); - - MouseEvent p3(ui::ET_MOUSE_PRESSED, - 112, 110, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMousePressed(p3); - - EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); - EXPECT_EQ(10, v3->location_.x()); - EXPECT_EQ(25, v3->location_.y()); - - root->OnMouseReleased(released); - - v1->SetTransform(ui::Transform()); - v2->SetTransform(ui::Transform()); - v3->SetTransform(ui::Transform()); - - v1->Reset(); - v2->Reset(); - v3->Reset(); - - // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis. - transform = v3->GetTransform(); - RotateClockwise(transform); - transform.SetTranslateX(30.0f); - // Rotation sets some scaling transformation. Using SetScale would overwrite - // that and pollute the rotation. So combine the scaling with the existing - // transforamtion. - transform.ConcatScale(0.8f, 0.5f); - v3->SetTransform(transform); - - // Translate |v2| with respect to |v1|. - transform = v2->GetTransform(); - transform.SetTranslate(10, 10); - v2->SetTransform(transform); - - // |v3| now occupies (120, 120) to (144, 130) in |root|. - - MouseEvent p4(ui::ET_MOUSE_PRESSED, - 124, 125, - ui::EF_LEFT_BUTTON_DOWN); - root->OnMousePressed(p4); - - EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); - EXPECT_EQ(10, v3->location_.x()); - EXPECT_EQ(25, v3->location_.y()); - - root->OnMouseReleased(released); - - widget->CloseNow(); -} - -TEST_F(ViewTest, TransformVisibleBound) { - gfx::Rect viewport_bounds(0, 0, 100, 100); - - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = viewport_bounds; - widget->Init(params); - widget->GetRootView()->SetBoundsRect(viewport_bounds); - - View* viewport = new View; - widget->SetContentsView(viewport); - View* contents = new View; - viewport->AddChildView(contents); - viewport->SetBoundsRect(viewport_bounds); - contents->SetBounds(0, 0, 100, 200); - - View* child = new View; - contents->AddChildView(child); - child->SetBounds(10, 90, 50, 50); - EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds()); - - // Rotate |child| counter-clockwise - ui::Transform transform; - RotateCounterclockwise(transform); - transform.SetTranslateY(50.0f); - child->SetTransform(transform); - EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds()); - - 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); -}; - -TEST_F(ViewTest, OnVisibleBoundsChanged) { - gfx::Rect viewport_bounds(0, 0, 100, 100); - - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = viewport_bounds; - widget->Init(params); - widget->GetRootView()->SetBoundsRect(viewport_bounds); - - View* viewport = new View; - widget->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(); -} - -//////////////////////////////////////////////////////////////////////////////// -// BoundsChanged() - -TEST_F(ViewTest, SetBoundsPaint) { - TestView top_view; - TestView* child_view = new TestView; - - top_view.SetBounds(0, 0, 100, 100); - top_view.scheduled_paint_rects_.clear(); - child_view->SetBounds(10, 10, 20, 20); - top_view.AddChildView(child_view); - - top_view.scheduled_paint_rects_.clear(); - child_view->SetBounds(30, 30, 20, 20); - EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size()); - - // There should be 2 rects, spanning from (10, 10) to (50, 50). - gfx::Rect paint_rect = - top_view.scheduled_paint_rects_[0].Union( - top_view.scheduled_paint_rects_[1]); - EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect); -} - -// Tests conversion methods with a transform. -TEST_F(ViewTest, ConvertPointToViewWithTransform) { - TestView top_view; - TestView* child = new TestView; - TestView* child_child = new TestView; - - top_view.AddChildView(child); - child->AddChildView(child_child); - - top_view.SetBounds(0, 0, 1000, 1000); - - child->SetBounds(7, 19, 500, 500); - ui::Transform transform; - transform.SetScale(3.0f, 4.0f); - child->SetTransform(transform); - - child_child->SetBounds(17, 13, 100, 100); - transform = ui::Transform(); - transform.SetScale(5.0f, 7.0f); - child_child->SetTransform(transform); - - // Sanity check to make sure basic transforms act as expected. - { - ui::Transform transform; - transform.ConcatTranslate(1, 1); - transform.ConcatScale(100, 55); - transform.ConcatTranslate(110, -110); - - // convert to a 3x3 matrix. - const SkMatrix& matrix = transform.matrix(); - - EXPECT_EQ(210, matrix.getTranslateX()); - EXPECT_EQ(-55, matrix.getTranslateY()); - EXPECT_EQ(100, matrix.getScaleX()); - EXPECT_EQ(55, matrix.getScaleY()); - EXPECT_EQ(0, matrix.getSkewX()); - EXPECT_EQ(0, matrix.getSkewY()); - } - - { - ui::Transform transform; - transform.SetTranslate(1, 1); - ui::Transform t2; - t2.SetScale(100, 55); - ui::Transform t3; - t3.SetTranslate(110, -110); - transform.ConcatTransform(t2); - transform.ConcatTransform(t3); - - // convert to a 3x3 matrix - const SkMatrix& matrix = transform.matrix(); - - EXPECT_EQ(210, matrix.getTranslateX()); - EXPECT_EQ(-55, matrix.getTranslateY()); - EXPECT_EQ(100, matrix.getScaleX()); - EXPECT_EQ(55, matrix.getScaleY()); - EXPECT_EQ(0, matrix.getSkewX()); - EXPECT_EQ(0, matrix.getSkewY()); - } - - // Conversions from child->top and top->child. - { - gfx::Point point(5, 5); - View::ConvertPointToView(child, &top_view, &point); - EXPECT_EQ(22, point.x()); - EXPECT_EQ(39, point.y()); - - point.SetPoint(22, 39); - View::ConvertPointToView(&top_view, child, &point); - EXPECT_EQ(5, point.x()); - EXPECT_EQ(5, point.y()); - } - - // Conversions from child_child->top and top->child_child. - { - gfx::Point point(5, 5); - View::ConvertPointToView(child_child, &top_view, &point); - EXPECT_EQ(133, point.x()); - EXPECT_EQ(211, point.y()); - - point.SetPoint(133, 211); - View::ConvertPointToView(&top_view, child_child, &point); - EXPECT_EQ(5, point.x()); - EXPECT_EQ(5, point.y()); - } - - // Conversions from child_child->child and child->child_child - { - gfx::Point point(5, 5); - View::ConvertPointToView(child_child, child, &point); - EXPECT_EQ(42, point.x()); - EXPECT_EQ(48, point.y()); - - point.SetPoint(42, 48); - View::ConvertPointToView(child, child_child, &point); - EXPECT_EQ(5, point.x()); - EXPECT_EQ(5, point.y()); - } - - // Conversions from top_view to child with a value that should be negative. - // This ensures we don't round up with negative numbers. - { - gfx::Point point(6, 18); - View::ConvertPointToView(&top_view, child, &point); - EXPECT_EQ(-1, point.x()); - EXPECT_EQ(-1, point.y()); - } -} - -// Tests conversion methods for rectangles. -TEST_F(ViewTest, ConvertRectWithTransform) { - scoped_ptr<Widget> widget(new Widget); - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(50, 50, 650, 650); - widget->Init(params); - View* root = widget->GetRootView(); - - TestView* v1 = new TestView; - TestView* v2 = new TestView; - root->AddChildView(v1); - v1->AddChildView(v2); - - v1->SetBounds(10, 10, 500, 500); - v2->SetBounds(20, 20, 100, 200); - - // |v2| now occupies (30, 30) to (130, 230) in |widget| - gfx::Rect rect(5, 5, 15, 40); - EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect)); - EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect)); - - // Rotate |v2| - ui::Transform t2; - RotateCounterclockwise(t2); - t2.SetTranslateY(100.0f); - v2->SetTransform(t2); - - // |v2| now occupies (30, 30) to (230, 130) in |widget| - EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); - EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect)); - - // Scale down |v1| - ui::Transform t1; - t1.SetScale(0.5, 0.5); - v1->SetTransform(t1); - - // The rectangle should remain the same for |v1|. - EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); - - // |v2| now occupies (20, 20) to (120, 70) in |widget| - // There are some rounding of floating values here. These values may change if - // floating operations are improved/changed. - EXPECT_EQ(gfx::Rect(22, 60, 20, 7), v2->ConvertRectToWidget(rect)); - - widget->CloseNow(); -} - -class ObserverView : public View { - public: - ObserverView(); - virtual ~ObserverView(); - - void ResetTestState(); - - bool child_added() const { return child_added_; } - bool child_removed() const { return child_removed_; } - const View* parent_view() const { return parent_view_; } - const View* child_view() const { return child_view_; } - - private: - // View: - virtual void ViewHierarchyChanged(bool is_add, - View* parent, - View* child) OVERRIDE; - - bool child_added_; - bool child_removed_; - View* parent_view_; - View* child_view_; - - DISALLOW_COPY_AND_ASSIGN(ObserverView); -}; - -ObserverView::ObserverView() - : child_added_(false), - child_removed_(false), - parent_view_(NULL), - child_view_(NULL) { -} - -ObserverView::~ObserverView() {} - -void ObserverView::ResetTestState() { - child_added_ = false; - child_removed_ = false; - parent_view_ = NULL; - child_view_ = NULL; -} - -void ObserverView::ViewHierarchyChanged(bool is_add, - View* parent, - View* child) { - if (is_add) - child_added_ = true; - else - child_removed_ = true; - - parent_view_ = parent; - child_view_ = child; -} - -// Verifies that the ViewHierarchyChanged() notification is sent correctly when -// a child view is added or removed to all the views in the hierarchy (up and -// down). -// The tree looks like this: -// v1 -// +-- v2 -// +-- v3 -TEST_F(ViewTest, ViewHierarchyChanged) { - ObserverView v1; - - ObserverView* v3 = new ObserverView(); - - // Add |v3| to |v2|. - scoped_ptr<ObserverView> v2(new ObserverView()); - v2->AddChildView(v3); - - // Make sure both |v2| and |v3| receive the ViewHierarchyChanged() - // notification. - EXPECT_TRUE(v2->child_added()); - EXPECT_FALSE(v2->child_removed()); - EXPECT_EQ(v2.get(), v2->parent_view()); - EXPECT_EQ(v3, v2->child_view()); - - EXPECT_TRUE(v3->child_added()); - EXPECT_FALSE(v3->child_removed()); - EXPECT_EQ(v2.get(), v3->parent_view()); - EXPECT_EQ(v3, v3->child_view()); - - // Reset everything to the initial state. - v2->ResetTestState(); - v3->ResetTestState(); - - // Add |v2| to v1. - v1.AddChildView(v2.get()); - - // Verifies that |v2| is the child view *added* and the parent view is |v1|. - // Make sure all the views (v1, v2, v3) received _that_ information. - EXPECT_TRUE(v1.child_added()); - EXPECT_FALSE(v1.child_removed()); - EXPECT_EQ(&v1, v1.parent_view()); - EXPECT_EQ(v2.get(), v1.child_view()); - - EXPECT_TRUE(v2->child_added()); - EXPECT_FALSE(v2->child_removed()); - EXPECT_EQ(&v1, v2->parent_view()); - EXPECT_EQ(v2.get(), v2->child_view()); - - EXPECT_TRUE(v3->child_added()); - EXPECT_FALSE(v3->child_removed()); - EXPECT_EQ(&v1, v3->parent_view()); - EXPECT_EQ(v2.get(), v3->child_view()); - - // Reset everything to the initial state. - v1.ResetTestState(); - v2->ResetTestState(); - v3->ResetTestState(); - - // Remove |v2| from |v1|. - v1.RemoveChildView(v2.get()); - - // Verifies that |v2| is the child view *removed* and the parent view is |v1|. - // Make sure all the views (v1, v2, v3) received _that_ information. - EXPECT_FALSE(v1.child_added()); - EXPECT_TRUE(v1.child_removed()); - EXPECT_EQ(&v1, v1.parent_view()); - EXPECT_EQ(v2.get(), v1.child_view()); - - EXPECT_FALSE(v2->child_added()); - EXPECT_TRUE(v2->child_removed()); - EXPECT_EQ(&v1, v2->parent_view()); - EXPECT_EQ(v2.get(), v2->child_view()); - - EXPECT_FALSE(v3->child_added()); - EXPECT_TRUE(v3->child_removed()); - EXPECT_EQ(&v1, v3->parent_view()); - EXPECT_EQ(v3, v3->child_view()); -} - -// Verifies if the child views added under the root are all deleted when calling -// RemoveAllChildViews. -// The tree looks like this: -// root -// +-- child1 -// +-- foo -// +-- bar0 -// +-- bar1 -// +-- bar2 -// +-- child2 -// +-- child3 -TEST_F(ViewTest, RemoveAllChildViews) { - View root; - - View* child1 = new View; - root.AddChildView(child1); - - for (int i = 0; i < 2; ++i) - root.AddChildView(new View); - - View* foo = new View; - child1->AddChildView(foo); - - // Add some nodes to |foo|. - for (int i = 0; i < 3; ++i) - foo->AddChildView(new View); - - EXPECT_EQ(3, root.child_count()); - EXPECT_EQ(1, child1->child_count()); - EXPECT_EQ(3, foo->child_count()); - - // Now remove all child views from root. - root.RemoveAllChildViews(true); - - EXPECT_EQ(0, root.child_count()); - EXPECT_FALSE(root.has_children()); -} - -TEST_F(ViewTest, Contains) { - View v1; - View* v2 = new View; - View* v3 = new View; - - v1.AddChildView(v2); - v2->AddChildView(v3); - - EXPECT_FALSE(v1.Contains(NULL)); - EXPECT_TRUE(v1.Contains(&v1)); - EXPECT_TRUE(v1.Contains(v2)); - EXPECT_TRUE(v1.Contains(v3)); - - EXPECT_FALSE(v2->Contains(NULL)); - EXPECT_TRUE(v2->Contains(v2)); - EXPECT_FALSE(v2->Contains(&v1)); - EXPECT_TRUE(v2->Contains(v3)); - - EXPECT_FALSE(v3->Contains(NULL)); - EXPECT_TRUE(v3->Contains(v3)); - EXPECT_FALSE(v3->Contains(&v1)); - EXPECT_FALSE(v3->Contains(v2)); -} - -// Verifies if GetIndexOf() returns the correct index for the specified child -// view. -// The tree looks like this: -// root -// +-- child1 -// +-- foo1 -// +-- child2 -TEST_F(ViewTest, GetIndexOf) { - View root; - - View* child1 = new View; - root.AddChildView(child1); - - View* child2 = new View; - root.AddChildView(child2); - - View* foo1 = new View; - child1->AddChildView(foo1); - - EXPECT_EQ(-1, root.GetIndexOf(NULL)); - EXPECT_EQ(-1, root.GetIndexOf(&root)); - EXPECT_EQ(0, root.GetIndexOf(child1)); - EXPECT_EQ(1, root.GetIndexOf(child2)); - EXPECT_EQ(-1, root.GetIndexOf(foo1)); - - EXPECT_EQ(-1, child1->GetIndexOf(NULL)); - EXPECT_EQ(-1, child1->GetIndexOf(&root)); - EXPECT_EQ(-1, child1->GetIndexOf(child1)); - EXPECT_EQ(-1, child1->GetIndexOf(child2)); - EXPECT_EQ(0, child1->GetIndexOf(foo1)); - - EXPECT_EQ(-1, child2->GetIndexOf(NULL)); - EXPECT_EQ(-1, child2->GetIndexOf(&root)); - EXPECT_EQ(-1, child2->GetIndexOf(child2)); - EXPECT_EQ(-1, child2->GetIndexOf(child1)); - EXPECT_EQ(-1, child2->GetIndexOf(foo1)); -} - -// Verifies that the child views can be reordered correctly. -TEST_F(ViewTest, ReorderChildren) { - View root; - - View* child = new View(); - root.AddChildView(child); - - View* foo1 = new View(); - child->AddChildView(foo1); - View* foo2 = new View(); - child->AddChildView(foo2); - View* foo3 = new View(); - child->AddChildView(foo3); - foo1->set_focusable(true); - foo2->set_focusable(true); - foo3->set_focusable(true); - - ASSERT_EQ(0, child->GetIndexOf(foo1)); - ASSERT_EQ(1, child->GetIndexOf(foo2)); - ASSERT_EQ(2, child->GetIndexOf(foo3)); - ASSERT_EQ(foo2, foo1->GetNextFocusableView()); - ASSERT_EQ(foo3, foo2->GetNextFocusableView()); - ASSERT_EQ(NULL, foo3->GetNextFocusableView()); - - // Move |foo2| at the end. - child->ReorderChildView(foo2, -1); - ASSERT_EQ(0, child->GetIndexOf(foo1)); - ASSERT_EQ(1, child->GetIndexOf(foo3)); - ASSERT_EQ(2, child->GetIndexOf(foo2)); - ASSERT_EQ(foo3, foo1->GetNextFocusableView()); - ASSERT_EQ(foo2, foo3->GetNextFocusableView()); - ASSERT_EQ(NULL, foo2->GetNextFocusableView()); - - // Move |foo1| at the end. - child->ReorderChildView(foo1, -1); - ASSERT_EQ(0, child->GetIndexOf(foo3)); - ASSERT_EQ(1, child->GetIndexOf(foo2)); - ASSERT_EQ(2, child->GetIndexOf(foo1)); - ASSERT_EQ(NULL, foo1->GetNextFocusableView()); - ASSERT_EQ(foo2, foo1->GetPreviousFocusableView()); - ASSERT_EQ(foo2, foo3->GetNextFocusableView()); - ASSERT_EQ(foo1, foo2->GetNextFocusableView()); - - // Move |foo2| to the front. - child->ReorderChildView(foo2, 0); - ASSERT_EQ(0, child->GetIndexOf(foo2)); - ASSERT_EQ(1, child->GetIndexOf(foo3)); - ASSERT_EQ(2, child->GetIndexOf(foo1)); - ASSERT_EQ(NULL, foo1->GetNextFocusableView()); - ASSERT_EQ(foo3, foo1->GetPreviousFocusableView()); - ASSERT_EQ(foo3, foo2->GetNextFocusableView()); - ASSERT_EQ(foo1, foo3->GetNextFocusableView()); -} - -// Verifies that GetViewByID returns the correctly child view from the specified -// ID. -// The tree looks like this: -// v1 -// +-- v2 -// +-- v3 -// +-- v4 -TEST_F(ViewTest, GetViewByID) { - View v1; - const int kV1ID = 1; - v1.set_id(kV1ID); - - View v2; - const int kV2ID = 2; - v2.set_id(kV2ID); - - View v3; - const int kV3ID = 3; - v3.set_id(kV3ID); - - View v4; - const int kV4ID = 4; - v4.set_id(kV4ID); - - const int kV5ID = 5; - - v1.AddChildView(&v2); - v2.AddChildView(&v3); - v2.AddChildView(&v4); - - EXPECT_EQ(&v1, v1.GetViewByID(kV1ID)); - EXPECT_EQ(&v2, v1.GetViewByID(kV2ID)); - EXPECT_EQ(&v4, v1.GetViewByID(kV4ID)); - - EXPECT_EQ(NULL, v1.GetViewByID(kV5ID)); // No V5 exists. - EXPECT_EQ(NULL, v2.GetViewByID(kV1ID)); // It can get only from child views. - - const int kGroup = 1; - v3.SetGroup(kGroup); - v4.SetGroup(kGroup); - - View::Views views; - v1.GetViewsInGroup(kGroup, &views); - EXPECT_EQ(2U, views.size()); - - View::Views::const_iterator i(std::find(views.begin(), views.end(), &v3)); - EXPECT_NE(views.end(), i); - - i = std::find(views.begin(), views.end(), &v4); - EXPECT_NE(views.end(), i); -} - -//////////////////////////////////////////////////////////////////////////////// -// Layers -//////////////////////////////////////////////////////////////////////////////// - -#if defined(VIEWS_COMPOSITOR) - -namespace { - -// Test implementation of LayerAnimator. -class TestLayerAnimator : public ui::LayerAnimator { - public: - TestLayerAnimator(); - - const gfx::Rect& last_bounds() const { return last_bounds_; } - - // LayerAnimator. - virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; - - private: - gfx::Rect last_bounds_; - - DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator); -}; - -TestLayerAnimator::TestLayerAnimator() - : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) { -} - -void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) { - last_bounds_ = bounds; -} - -} // namespace - -class ViewLayerTest : public ViewsTestBase { - public: - ViewLayerTest() : widget_(NULL), old_use_acceleration_(false) {} - - virtual ~ViewLayerTest() { - } - - // Returns the Layer used by the RootView. - ui::Layer* GetRootLayer() { -#if defined(USE_AURA) - ui::Layer* root_layer = NULL; - gfx::Point origin; - widget()->CalculateOffsetToAncestorWithLayer(&origin, &root_layer); - return root_layer; -#else - return widget()->GetRootView()->layer(); -#endif - } - - virtual void SetUp() OVERRIDE { - ViewTest::SetUp(); - old_use_acceleration_ = View::get_use_acceleration_when_possible(); - View::set_use_acceleration_when_possible(true); - - ui::TestTexture::reset_live_count(); - - widget_ = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_POPUP); - params.bounds = gfx::Rect(50, 50, 200, 200); - widget_->Init(params); - widget_->Show(); - widget_->GetRootView()->SetBounds(0, 0, 200, 200); - } - - virtual void TearDown() OVERRIDE { - View::set_use_acceleration_when_possible(old_use_acceleration_); - widget_->CloseNow(); - Widget::SetPureViews(false); - ViewsTestBase::TearDown(); - } - - Widget* widget() { return widget_; } - - private: - Widget* widget_; - bool old_use_acceleration_; -}; - -#if !defined(USE_AURA) -// This test assumes a particular layer hierarchy that isn't valid for aura. -// Ensures the RootView has a layer and its set up correctly. -TEST_F(ViewLayerTest, RootState) { - ui::Layer* layer = widget()->GetRootView()->layer(); - ASSERT_TRUE(layer); - EXPECT_FALSE(layer->parent()); - EXPECT_EQ(0u, layer->children().size()); - EXPECT_FALSE(layer->transform().HasChange()); - EXPECT_EQ(widget()->GetRootView()->bounds(), layer->bounds()); - EXPECT_TRUE(layer->GetCompositor() != NULL); -} - -// Verifies that the complete bounds of a texture are updated if the texture -// needs to be refreshed and paint with a clip is invoked. -// This test invokes OnNativeWidgetPaintAccelerated, which is not used by aura. -TEST_F(ViewLayerTest, PaintAll) { - View* view = widget()->GetRootView(); - ui::Layer* layer = GetRootLayer(); - view->SetBounds(0, 0, 200, 200); - widget()->OnNativeWidgetPaintAccelerated(gfx::Rect(0, 0, 1, 1)); - ASSERT_TRUE(layer != NULL); - const ui::TestTexture* texture = - static_cast<const ui::TestTexture*>(layer->texture()); - ASSERT_TRUE(texture != NULL); - EXPECT_EQ(view->GetLocalBounds(), texture->bounds_of_last_paint()); -} -#endif - -TEST_F(ViewLayerTest, LayerToggling) { - // Because we lazily create textures the calls to DrawTree are necessary to - // ensure we trigger creation of textures. -#if defined(USE_AURA) - ui::Layer* root_layer = NULL; - gfx::Point origin; - widget()->CalculateOffsetToAncestorWithLayer(&origin, &root_layer); -#else - ui::Layer* root_layer = widget()->GetRootView()->layer(); -#endif - View* content_view = new View; - widget()->SetContentsView(content_view); - -#if !defined(USE_WEBKIT_COMPOSITOR) - // TODO(piman): with the webkit compositor, we don't create Textures on - // Layers. We're not supposed to be calling Layer::DrawTree. This test needs - // refactoring to fully work in that case. - root_layer->DrawTree(); - ui::TestTexture::reset_live_count(); -#endif - - // Create v1, give it a bounds and verify everything is set up correctly. - View* v1 = new View; - v1->SetPaintToLayer(true); -#if !defined(USE_WEBKIT_COMPOSITOR) - root_layer->DrawTree(); - EXPECT_EQ(0, ui::TestTexture::live_count()); -#endif - EXPECT_TRUE(v1->layer() != NULL); - v1->SetBounds(20, 30, 140, 150); - content_view->AddChildView(v1); -#if !defined(USE_WEBKIT_COMPOSITOR) - root_layer->DrawTree(); - EXPECT_EQ(1, ui::TestTexture::live_count()); -#endif - ASSERT_TRUE(v1->layer() != NULL); - EXPECT_EQ(root_layer, v1->layer()->parent()); - EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds()); - - // Create v2 as a child of v1 and do basic assertion testing. - View* v2 = new View; - v1->AddChildView(v2); - EXPECT_TRUE(v2->layer() == NULL); - v2->SetBounds(10, 20, 30, 40); - v2->SetPaintToLayer(true); -#if !defined(USE_WEBKIT_COMPOSITOR) - root_layer->DrawTree(); - EXPECT_EQ(2, ui::TestTexture::live_count()); -#endif - ASSERT_TRUE(v2->layer() != NULL); - EXPECT_EQ(v1->layer(), v2->layer()->parent()); - EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); - - // Turn off v1s layer. v2 should still have a layer but its parent should have - // changed. - v1->SetPaintToLayer(false); -#if !defined(USE_WEBKIT_COMPOSITOR) - root_layer->DrawTree(); - EXPECT_EQ(1, ui::TestTexture::live_count()); -#endif - EXPECT_TRUE(v1->layer() == NULL); - EXPECT_TRUE(v2->layer() != NULL); - EXPECT_EQ(root_layer, v2->layer()->parent()); - ASSERT_EQ(1u, root_layer->children().size()); - EXPECT_EQ(root_layer->children()[0], v2->layer()); - // The bounds of the layer should have changed to be relative to the root view - // now. - EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds()); - - // Make v1 have a layer again and verify v2s layer is wired up correctly. - ui::Transform transform; - transform.SetScale(2.0f, 2.0f); - v1->SetTransform(transform); -#if !defined(USE_WEBKIT_COMPOSITOR) - root_layer->DrawTree(); - EXPECT_EQ(2, ui::TestTexture::live_count()); -#endif - EXPECT_TRUE(v1->layer() != NULL); - EXPECT_TRUE(v2->layer() != NULL); - EXPECT_EQ(root_layer, v1->layer()->parent()); - EXPECT_EQ(v1->layer(), v2->layer()->parent()); - ASSERT_EQ(1u, root_layer->children().size()); - EXPECT_EQ(root_layer->children()[0], v1->layer()); - ASSERT_EQ(1u, v1->layer()->children().size()); - EXPECT_EQ(v1->layer()->children()[0], v2->layer()); - EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); -} - -// Verifies turning on a layer wires up children correctly. -TEST_F(ViewLayerTest, NestedLayerToggling) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - // Create v1, give it a bounds and verify everything is set up correctly. - View* v1 = new View; - content_view->AddChildView(v1); - v1->SetBounds(20, 30, 140, 150); - - View* v2 = new View; - v1->AddChildView(v2); - - View* v3 = new View; - v3->SetPaintToLayer(true); - v2->AddChildView(v3); - ASSERT_TRUE(v3->layer() != NULL); - - // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't. - - v1->SetPaintToLayer(true); - EXPECT_EQ(v1->layer(), v3->layer()->parent()); -} - -TEST_F(ViewLayerTest, LayerAnimator) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* v1 = new View; - content_view->AddChildView(v1); - v1->SetPaintToLayer(true); - EXPECT_TRUE(v1->layer() != NULL); - - TestLayerAnimator* animator = new TestLayerAnimator(); - v1->layer()->SetAnimator(animator); - - gfx::Rect bounds(1, 2, 3, 4); - v1->SetBoundsRect(bounds); - EXPECT_EQ(bounds, animator->last_bounds()); - // TestLayerAnimator doesn't update the layer. - EXPECT_NE(bounds, v1->layer()->bounds()); -} - -// Verifies the bounds of a layer are updated if the bounds of ancestor that -// doesn't have a layer change. -TEST_F(ViewLayerTest, BoundsChangeWithLayer) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* v1 = new View; - content_view->AddChildView(v1); - v1->SetBounds(20, 30, 140, 150); - - View* v2 = new View; - v2->SetBounds(10, 11, 40, 50); - v1->AddChildView(v2); - v2->SetPaintToLayer(true); - ASSERT_TRUE(v2->layer() != NULL); - EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds()); - - v1->SetPosition(gfx::Point(25, 36)); - EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds()); - - v2->SetPosition(gfx::Point(11, 12)); - EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds()); - - // Bounds of the layer should change even if the view is not invisible. - v1->SetVisible(false); - v1->SetPosition(gfx::Point(20, 30)); - EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds()); - - v2->SetVisible(false); - v2->SetBounds(10, 11, 20, 30); - EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds()); -} - -// Makes sure a transform persists after toggling the visibility. -TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) { - View* view = new View; - ui::Transform transform; - transform.SetScale(2.0f, 2.0f); - view->SetTransform(transform); - widget()->SetContentsView(view); - EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); - - view->SetVisible(false); - EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); - - view->SetVisible(true); - EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); -} - -// Verifies a transform persists after removing/adding a view with a transform. -TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) { - View* view = new View; - ui::Transform transform; - transform.SetScale(2.0f, 2.0f); - view->SetTransform(transform); - widget()->SetContentsView(view); - EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); - ASSERT_TRUE(view->layer() != NULL); - EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); - - View* parent = view->parent(); - parent->RemoveChildView(view); - parent->AddChildView(view); - - EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); - ASSERT_TRUE(view->layer() != NULL); - EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); -} - -// Makes sure that layer visibility is correct after toggling View visibility. -TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - // The view isn't attached to a widget or a parent view yet. But it should - // still have a layer, but the layer should not be attached to the root - // layer. - View* v1 = new View; - v1->SetPaintToLayer(true); - EXPECT_TRUE(v1->layer()); - EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), - v1->layer())); - - // Once the view is attached to a widget, its layer should be attached to the - // root layer and visible. - content_view->AddChildView(v1); - EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), - v1->layer())); - EXPECT_TRUE(v1->layer()->IsDrawn()); - - v1->SetVisible(false); - EXPECT_FALSE(v1->layer()->IsDrawn()); - - v1->SetVisible(true); - EXPECT_TRUE(v1->layer()->IsDrawn()); - - widget()->Hide(); - EXPECT_FALSE(v1->layer()->IsDrawn()); - - widget()->Show(); - EXPECT_TRUE(v1->layer()->IsDrawn()); -} - -// Test that a hole in a layer is correctly created regardless of whether -// the opacity attribute is set before or after the layer is created. -TEST_F(ViewLayerTest, ToggleOpacityWithLayer) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* parent_view = new View; - content_view->AddChildView(parent_view); - parent_view->SetPaintToLayer(true); - parent_view->SetBounds(0, 0, 400, 400); - - View* child_view = new View; - child_view->SetBounds(50, 50, 100, 100); - parent_view->AddChildView(child_view); - - widget()->GetCompositor()->Draw(false); - - ASSERT_TRUE(child_view->layer() == NULL); - child_view->SetPaintToLayer(true); - child_view->SetFillsBoundsOpaquely(true); - widget()->GetCompositor()->Draw(false); - ASSERT_TRUE(child_view->layer()); - EXPECT_EQ( - gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); - - child_view->SetFillsBoundsOpaquely(false); - widget()->GetCompositor()->Draw(false); - EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty()); -} - -// Test that a hole in a layer always corresponds to the bounds of opaque -// layers. -TEST_F(ViewLayerTest, MultipleOpaqueLayers) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* parent_view = new View; - parent_view->SetPaintToLayer(true); - parent_view->SetBounds(0, 0, 400, 400); - content_view->AddChildView(parent_view); - - View* child_view1 = new View; - child_view1->SetPaintToLayer(true); - child_view1->SetFillsBoundsOpaquely(true); - child_view1->SetBounds(50, 50, 100, 100); - parent_view->AddChildView(child_view1); - - View* child_view2 = new View; - child_view2->SetPaintToLayer(true); - child_view2->SetFillsBoundsOpaquely(false); - child_view2->SetBounds(150, 150, 200, 200); - parent_view->AddChildView(child_view2); - - widget()->GetCompositor()->Draw(false); - - // Only child_view1 is opaque - EXPECT_EQ( - gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); - - // Both child views are opaque - child_view2->SetFillsBoundsOpaquely(true); - widget()->GetCompositor()->Draw(false); - EXPECT_TRUE( - gfx::Rect(50, 50, 100, 100) == parent_view->layer()->hole_rect() || - gfx::Rect(150, 150, 200, 200) == parent_view->layer()->hole_rect()); - - // Only child_view2 is opaque - delete child_view1; - EXPECT_EQ( - gfx::Rect(150, 150, 200, 200), parent_view->layer()->hole_rect()); -} - -// Makes sure that opacity of layer persists after toggling visibilty. -TEST_F(ViewLayerTest, ToggleVisibilityWithOpaqueLayer) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* parent_view = new View; - parent_view->SetPaintToLayer(true); - parent_view->SetBounds(0, 0, 400, 400); - content_view->AddChildView(parent_view); - - parent_view->SetPaintToLayer(true); - parent_view->SetBounds(0, 0, 400, 400); - - View* child_view = new View; - child_view->SetBounds(50, 50, 100, 100); - child_view->SetPaintToLayer(true); - child_view->SetFillsBoundsOpaquely(true); - parent_view->AddChildView(child_view); - widget()->GetCompositor()->Draw(false); - EXPECT_EQ( - gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); - - child_view->SetVisible(false); - widget()->GetCompositor()->Draw(false); - EXPECT_TRUE(parent_view->layer()->hole_rect().IsEmpty()); - - child_view->SetVisible(true); - widget()->GetCompositor()->Draw(false); - EXPECT_EQ( - gfx::Rect(50, 50, 100, 100), parent_view->layer()->hole_rect()); -} - -// Tests that the layers in the subtree are orphaned after a View is removed -// from the parent. -TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) { - View* content_view = new View; - widget()->SetContentsView(content_view); - - View* v1 = new View; - content_view->AddChildView(v1); - - View* v2 = new View; - v1->AddChildView(v2); - v2->SetPaintToLayer(true); - EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), - v2->layer())); - EXPECT_TRUE(v2->layer()->IsDrawn()); - - content_view->RemoveChildView(v1); - EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), - v2->layer())); - - // Reparent |v2|. - content_view->AddChildView(v2); - EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), - v2->layer())); - EXPECT_TRUE(v2->layer()->IsDrawn()); -} - -class PaintTrackingView : public View { - public: - PaintTrackingView() : painted_(false) { - } - - bool painted() const { return painted_; } - void set_painted(bool value) { painted_ = value; } - - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { - painted_ = true; - } - - private: - bool painted_; - - DISALLOW_COPY_AND_ASSIGN(PaintTrackingView); -}; - -#if !defined(USE_WEBKIT_COMPOSITOR) -// TODO(piman): this test relies on the way the non-webkit compositor works. -// Layer::DrawTree should not be called with the webkit compositor. In the -// WebKit case, it needs to go through the "real" compositor (not the test one) -// to do the paints on the layer/views. - -// Makes sure child views with layers aren't painted when paint starts at an -// ancestor. -TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) { - PaintTrackingView* content_view = new PaintTrackingView; - widget()->SetContentsView(content_view); - content_view->SetPaintToLayer(true); - GetRootLayer()->DrawTree(); - GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); - content_view->set_painted(false); - // content_view no longer has a dirty rect. Paint from the root and make sure - // PaintTrackingView isn't painted. - GetRootLayer()->DrawTree(); - EXPECT_FALSE(content_view->painted()); - - // Make content_view have a dirty rect, paint the layers and make sure - // PaintTrackingView is painted. - content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); - GetRootLayer()->DrawTree(); - EXPECT_TRUE(content_view->painted()); -} -#endif - -// Tests that the visibility of child layers are updated correctly when a View's -// visibility changes. -TEST_F(ViewLayerTest, VisibilityChildLayers) { - View* v1 = new View; - v1->SetPaintToLayer(true); - widget()->SetContentsView(v1); - - View* v2 = new View; - v1->AddChildView(v2); - - View* v3 = new View; - v2->AddChildView(v3); - v3->SetVisible(false); - - View* v4 = new View; - v4->SetPaintToLayer(true); - v3->AddChildView(v4); - - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_FALSE(v4->layer()->IsDrawn()); - - v2->SetVisible(false); - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_FALSE(v4->layer()->IsDrawn()); - - v2->SetVisible(true); - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_FALSE(v4->layer()->IsDrawn()); - - v2->SetVisible(false); - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_FALSE(v4->layer()->IsDrawn()); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); - - v3->SetVisible(true); - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_FALSE(v4->layer()->IsDrawn()); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); - - // Reparent |v3| to |v1|. - v1->AddChildView(v3); - EXPECT_TRUE(v1->layer()->IsDrawn()); - EXPECT_TRUE(v4->layer()->IsDrawn()); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); -} - -// This test creates a random View tree, and then randomly reorders child views, -// reparents views etc. Unrelated changes can appear to break this test. So -// marking this as FLAKY. -TEST_F(ViewLayerTest, FLAKY_ViewLayerTreesInSync) { - View* content = new View; - content->SetPaintToLayer(true); - widget()->SetContentsView(content); - widget()->Show(); - - ConstructTree(content, 5); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); - - ScrambleTree(content); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); - - ScrambleTree(content); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); - - ScrambleTree(content); - EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); -} - -#endif // VIEWS_COMPOSITOR - -} // namespace views diff --git a/views/view_win.cc b/views/view_win.cc deleted file mode 100644 index f8adb43..0000000 --- a/views/view_win.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/view.h" - -// Necessary to define oleacc GUID's. -#include <windows.h> -#include <initguid.h> -#include <oleacc.h> - -#include "ui/views/accessibility/native_view_accessibility_win.h" - -namespace views { - -gfx::NativeViewAccessible View::GetNativeViewAccessible() { - if (!native_view_accessibility_win_.get()) - native_view_accessibility_win_ = NativeViewAccessibilityWin::Create(this); - return native_view_accessibility_win_.get(); -} - -int View::GetHorizontalDragThreshold() { - static int threshold = -1; - if (threshold == -1) - threshold = GetSystemMetrics(SM_CXDRAG) / 2; - return threshold; -} - -int View::GetVerticalDragThreshold() { - static int threshold = -1; - if (threshold == -1) - threshold = GetSystemMetrics(SM_CYDRAG) / 2; - return threshold; -} - -} // namespace views diff --git a/views/views.gyp b/views/views.gyp index 889df74..63373b8 100644 --- a/views/views.gyp +++ b/views/views.gyp @@ -60,15 +60,10 @@ 'painter.h', 'repeat_controller.cc', 'repeat_controller.h', - 'view.cc', - 'view.h', - 'view_aura.cc', 'view_constants.cc', 'view_constants.h', - 'view_gtk.cc', 'view_text_utils.cc', 'view_text_utils.h', - 'view_win.cc', 'views_delegate.h', '../ui/views/accessibility/native_view_accessibility_win.cc', '../ui/views/accessibility/native_view_accessibility_win.h', @@ -325,6 +320,11 @@ '../ui/views/touchui/gesture_manager.h', '../ui/views/touchui/touch_selection_controller.cc', '../ui/views/touchui/touch_selection_controller.h', + '../ui/views/view.cc', + '../ui/views/view.h', + '../ui/views/view_aura.cc', + '../ui/views/view_gtk.cc', + '../ui/views/view_win.cc', '../ui/views/widget/aero_tooltip_manager.cc', '../ui/views/widget/aero_tooltip_manager.h', '../ui/views/widget/child_window_message_processor.cc', @@ -534,6 +534,7 @@ '../ui/views/test/test_views_delegate.h', '../ui/views/test/views_test_base.cc', '../ui/views/test/views_test_base.h', + '../ui/views/view_unittest.cc', '../ui/views/widget/native_widget_test_utils.h', '../ui/views/widget/native_widget_test_utils_aura.cc', '../ui/views/widget/native_widget_test_utils_gtk.cc', @@ -543,7 +544,6 @@ '../ui/views/widget/widget_unittest.cc', 'accessible_pane_view_unittest.cc', 'run_all_unittests.cc', - 'view_unittest.cc', '<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc', '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources.rc', |