diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-07-14 17:41:05 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-08-04 12:37:36 +0000 |
commit | 399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (patch) | |
tree | 6b06b60ff365abef0e13b3503d593a0df48d20e8 /chromium/ui/views | |
parent | 7366110654eec46f21b6824f302356426f48cd74 (diff) | |
download | qtwebengine-chromium-399c965b6064c440ddcf4015f5f8e9d131c7a0a6.tar.gz |
BASELINE: Update Chromium to 52.0.2743.76 and Ninja to 1.7.1
Change-Id: I382f51b959689505a60f8b707255ecb344f7d8b4
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/views')
346 files changed, 7989 insertions, 5237 deletions
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn index 5b85b89b3cf..d02ed9bd420 100644 --- a/chromium/ui/views/BUILD.gn +++ b/chromium/ui/views/BUILD.gn @@ -34,6 +34,7 @@ component("views") { "//skia", "//third_party/icu", "//ui/accessibility", + "//ui/display", "//ui/native_theme", "//ui/resources", "//ui/strings", @@ -104,6 +105,7 @@ component("views") { ] deps += [ "//ui/events/devices", + "//ui/events/devices/x11", "//ui/events/platform/x11", "//ui/gfx/x", ] @@ -138,8 +140,10 @@ component("views") { "//ui/events:dom_keycode_converter", ] libs = [ - # Required by bridged_native_widget.mm. - "QuartzCore.framework", + "AppKit.framework", + "CoreGraphics.framework", + "Foundation.framework", + "QuartzCore.framework", # Required by bridged_native_widget.mm. ] } } @@ -174,7 +178,10 @@ source_set("test_support_internal") { "//ui/gfx/geometry", ] - sources += [ "test/platform_test_helper.h" ] + sources += [ + "test/platform_test_helper.cc", + "test/platform_test_helper.h", + ] if (use_aura) { sources += gypi_values.views_test_support_aura_sources @@ -204,7 +211,6 @@ static_library("test_support") { ":test_support_internal", ] sources = [ - "test/default_platform_test_helper.cc", "test/native_widget_factory_desktop.cc", ] } @@ -240,10 +246,8 @@ test("views_unittests") { "//url", ] - # TODO(thakis): This should be a data_deps on //ui/resources:ui_test_pak, but - # that has no effect. (See similar TODOs elsewhere ui_test.pak is listed) - data = [ - "$root_out_dir/ui_test.pak", + data_deps = [ + "//ui/resources:ui_test_pak_data", ] if (is_win) { @@ -306,7 +310,9 @@ if (is_mac) { test("macviews_interactive_ui_tests") { sources = [ "cocoa/bridged_native_widget_interactive_uitest.mm", - "run_all_unittests.cc", + "run_all_unittests_main.cc", + "views_test_suite.cc", + "views_test_suite.h", "widget/native_widget_mac_interactive_uitest.mm", ] deps = [ diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc index 80122369c31..3e5184d777d 100644 --- a/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc +++ b/chromium/ui/views/accessibility/ax_aura_obj_cache_unittest.cc @@ -10,13 +10,13 @@ namespace test { namespace { -// This class can be used as a deleter for scoped_ptr<Widget> +// This class can be used as a deleter for std::unique_ptr<Widget> // to call function Widget::CloseNow automatically. struct WidgetCloser { inline void operator()(Widget* widget) const { widget->CloseNow(); } }; -using WidgetAutoclosePtr = scoped_ptr<Widget, WidgetCloser>; +using WidgetAutoclosePtr = std::unique_ptr<Widget, WidgetCloser>; } class AXAuraObjCacheTest : public WidgetTest { diff --git a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc index 705f3efc77f..a60b1cb6b95 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc @@ -48,9 +48,9 @@ class NativeViewAccessibilityTest : public ViewsTestBase { } protected: - scoped_ptr<TestButton> button_; + std::unique_ptr<TestButton> button_; NativeViewAccessibility* button_accessibility_; - scoped_ptr<Label> label_; + std::unique_ptr<Label> label_; NativeViewAccessibility* label_accessibility_; }; @@ -90,13 +90,13 @@ class TestNativeViewAccessibility : public NativeViewAccessibility { }; TEST_F(NativeViewAccessibilityTest, CrashOnWidgetDestroyed) { - scoped_ptr<Widget> parent_widget(new Widget); + std::unique_ptr<Widget> parent_widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); parent_widget->Init(params); - scoped_ptr<Widget> child_widget(new Widget); + std::unique_ptr<Widget> child_widget(new Widget); child_widget->Init(params); // Make sure that deleting the parent widget can't cause a crash diff --git a/chromium/ui/views/accessible_pane_view.h b/chromium/ui/views/accessible_pane_view.h index 36170a84c95..80d4e54bfcd 100644 --- a/chromium/ui/views/accessible_pane_view.h +++ b/chromium/ui/views/accessible_pane_view.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_ACCESSIBLE_PANE_VIEW_H_ #define UI_VIEWS_ACCESSIBLE_PANE_VIEW_H_ +#include <memory> + #include "base/containers/hash_tables.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/base/accelerators/accelerator.h" #include "ui/views/focus/focus_manager.h" @@ -106,7 +107,7 @@ class VIEWS_EXPORT AccessiblePaneView : public View, // Our custom focus search implementation that traps focus in this // pane and traverses all views that are focusable for accessibility, // not just those that are normally focusable. - scoped_ptr<FocusSearch> focus_search_; + std::unique_ptr<FocusSearch> focus_search_; // Registered accelerators ui::Accelerator home_key_; diff --git a/chromium/ui/views/accessible_pane_view_unittest.cc b/chromium/ui/views/accessible_pane_view_unittest.cc index 864481ff3ff..d3f5bd0d44b 100644 --- a/chromium/ui/views/accessible_pane_view_unittest.cc +++ b/chromium/ui/views/accessible_pane_view_unittest.cc @@ -38,10 +38,10 @@ class TestBarView : public AccessiblePaneView, private: void Init(); - scoped_ptr<LabelButton> child_button_; - scoped_ptr<LabelButton> second_child_button_; - scoped_ptr<LabelButton> third_child_button_; - scoped_ptr<LabelButton> not_child_button_; + std::unique_ptr<LabelButton> child_button_; + std::unique_ptr<LabelButton> second_child_button_; + std::unique_ptr<LabelButton> third_child_button_; + std::unique_ptr<LabelButton> not_child_button_; DISALLOW_COPY_AND_ASSIGN(TestBarView); }; @@ -74,7 +74,7 @@ View* TestBarView::GetDefaultFocusableChild() { TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus) { TestBarView* test_view = new TestBarView(); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -102,7 +102,7 @@ TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus) { TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) { View* test_view_main = new View(); - scoped_ptr<Widget> widget_main(new Widget()); + std::unique_ptr<Widget> widget_main(new Widget()); Widget::InitParams params_main = CreateParams(Widget::InitParams::TYPE_POPUP); params_main.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; // By default, TYPE_POPUP is not activatable. @@ -117,7 +117,7 @@ TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) { EXPECT_TRUE(test_view_main->HasFocus()); TestBarView* test_view_bar = new TestBarView(); - scoped_ptr<Widget> widget_bar(new Widget()); + std::unique_ptr<Widget> widget_bar(new Widget()); Widget::InitParams params_bar = CreateParams(Widget::InitParams::TYPE_POPUP); params_bar.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params_bar.activatable = Widget::InitParams::ACTIVATABLE_YES; @@ -157,7 +157,7 @@ TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) { TEST_F(AccessiblePaneViewTest, TwoSetPaneFocus) { TestBarView* test_view = new TestBarView(); TestBarView* test_view_2 = new TestBarView(); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -187,7 +187,7 @@ TEST_F(AccessiblePaneViewTest, TwoSetPaneFocus) { TEST_F(AccessiblePaneViewTest, PaneFocusTraversal) { TestBarView* test_view = new TestBarView(); TestBarView* original_test_view = new TestBarView(); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); diff --git a/chromium/ui/views/animation/bounds_animator.cc b/chromium/ui/views/animation/bounds_animator.cc index ba9412722e0..3f0e65fd0f0 100644 --- a/chromium/ui/views/animation/bounds_animator.cc +++ b/chromium/ui/views/animation/bounds_animator.cc @@ -4,7 +4,8 @@ #include "ui/views/animation/bounds_animator.h" -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/gfx/animation/animation_container.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/views/animation/bounds_animator_observer.h" @@ -89,14 +90,14 @@ void BoundsAnimator::SetAnimationForView(View* view, SlideAnimation* animation) { DCHECK(animation); - scoped_ptr<SlideAnimation> animation_wrapper(animation); + std::unique_ptr<SlideAnimation> animation_wrapper(animation); if (!IsAnimating(view)) return; // We delay deleting the animation until the end so that we don't prematurely // send out notification that we're done. - scoped_ptr<Animation> old_animation(ResetAnimationForView(view)); + std::unique_ptr<Animation> old_animation(ResetAnimationForView(view)); data_[view].animation = animation_wrapper.release(); animation_to_view_[animation] = view; @@ -112,7 +113,7 @@ const SlideAnimation* BoundsAnimator::GetAnimationForView(View* view) { void BoundsAnimator::SetAnimationDelegate( View* view, - scoped_ptr<AnimationDelegate> delegate) { + std::unique_ptr<AnimationDelegate> delegate) { DCHECK(IsAnimating(view)); data_[view].delegate = delegate.release(); diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h index 2840c3dcd73..7f4208985b2 100644 --- a/chromium/ui/views/animation/bounds_animator.h +++ b/chromium/ui/views/animation/bounds_animator.h @@ -6,11 +6,11 @@ #define UI_VIEWS_ANIMATION_BOUNDS_ANIMATOR_H_ #include <map> +#include <memory> #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "ui/gfx/animation/animation_container_observer.h" #include "ui/gfx/animation/animation_delegate.h" @@ -71,7 +71,7 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, // Sets the delegate for the animation for the specified view. void SetAnimationDelegate(View* view, - scoped_ptr<gfx::AnimationDelegate> delegate); + std::unique_ptr<gfx::AnimationDelegate> delegate); // Returns true if BoundsAnimator is animating the bounds of |view|. bool IsAnimating(View* view) const; diff --git a/chromium/ui/views/animation/bounds_animator_unittest.cc b/chromium/ui/views/animation/bounds_animator_unittest.cc index 7e09deba510..f8421ae6af5 100644 --- a/chromium/ui/views/animation/bounds_animator_unittest.cc +++ b/chromium/ui/views/animation/bounds_animator_unittest.cc @@ -114,7 +114,8 @@ TEST_F(BoundsAnimatorTest, AnimateViewTo) { gfx::Rect target_bounds(10, 10, 20, 20); animator()->AnimateViewTo(child(), target_bounds); animator()->SetAnimationDelegate( - child(), scoped_ptr<gfx::AnimationDelegate>(new TestAnimationDelegate())); + child(), + std::unique_ptr<gfx::AnimationDelegate>(new TestAnimationDelegate())); // The animator should be animating now. EXPECT_TRUE(animator()->IsAnimating()); @@ -136,7 +137,7 @@ TEST_F(BoundsAnimatorTest, AnimateViewTo) { TEST_F(BoundsAnimatorTest, DeleteDelegateOnCancel) { animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); animator()->SetAnimationDelegate( - child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); + child(), std::unique_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); animator()->Cancel(); @@ -153,7 +154,7 @@ TEST_F(BoundsAnimatorTest, DeleteDelegateOnCancel) { TEST_F(BoundsAnimatorTest, DeleteDelegateOnNewAnimate) { animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); animator()->SetAnimationDelegate( - child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); + child(), std::unique_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); @@ -164,11 +165,11 @@ TEST_F(BoundsAnimatorTest, DeleteDelegateOnNewAnimate) { // Makes sure StopAnimating works. TEST_F(BoundsAnimatorTest, StopAnimating) { - scoped_ptr<OwnedDelegate> delegate(new OwnedDelegate()); + std::unique_ptr<OwnedDelegate> delegate(new OwnedDelegate()); animator()->AnimateViewTo(child(), gfx::Rect(0, 0, 10, 10)); animator()->SetAnimationDelegate( - child(), scoped_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); + child(), std::unique_ptr<gfx::AnimationDelegate>(new OwnedDelegate())); animator()->StopAnimatingView(child()); diff --git a/chromium/ui/views/animation/button_ink_drop_delegate.cc b/chromium/ui/views/animation/button_ink_drop_delegate.cc index 73152d77bc5..3862e871b97 100644 --- a/chromium/ui/views/animation/button_ink_drop_delegate.cc +++ b/chromium/ui/views/animation/button_ink_drop_delegate.cc @@ -6,8 +6,8 @@ #include "ui/events/event.h" #include "ui/events/scoped_target_handler.h" -#include "ui/views/animation/ink_drop_animation_controller.h" -#include "ui/views/animation/ink_drop_animation_controller_factory.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_factory.h" #include "ui/views/animation/ink_drop_host.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/view.h" @@ -18,23 +18,25 @@ ButtonInkDropDelegate::ButtonInkDropDelegate(InkDropHost* ink_drop_host, View* view) : target_handler_(new ui::ScopedTargetHandler(view, this)), ink_drop_host_(ink_drop_host), - ink_drop_animation_controller_( - InkDropAnimationControllerFactory::CreateInkDropAnimationController( - ink_drop_host_)) {} + ink_drop_(InkDropFactory::CreateInkDrop(ink_drop_host_)) {} ButtonInkDropDelegate::~ButtonInkDropDelegate() { } void ButtonInkDropDelegate::OnAction(InkDropState state) { - ink_drop_animation_controller_->AnimateToState(state); + ink_drop_->AnimateToState(state); } void ButtonInkDropDelegate::SnapToActivated() { - ink_drop_animation_controller_->SnapToActivated(); + ink_drop_->SnapToActivated(); } void ButtonInkDropDelegate::SetHovered(bool is_hovered) { - ink_drop_animation_controller_->SetHovered(is_hovered); + ink_drop_->SetHovered(is_hovered); +} + +InkDropState ButtonInkDropDelegate::GetTargetInkDropState() const { + return ink_drop_->GetTargetInkDropState(); } //////////////////////////////////////////////////////////////////////////////// @@ -54,8 +56,7 @@ void ButtonInkDropDelegate::OnMouseEvent(ui::MouseEvent* event) { } void ButtonInkDropDelegate::OnGestureEvent(ui::GestureEvent* event) { - InkDropState current_ink_drop_state = - ink_drop_animation_controller_->GetTargetInkDropState(); + InkDropState current_ink_drop_state = ink_drop_->GetTargetInkDropState(); InkDropState ink_drop_state = InkDropState::HIDDEN; switch (event->type()) { @@ -93,7 +94,7 @@ void ButtonInkDropDelegate::OnGestureEvent(ui::GestureEvent* event) { // would prematurely pre-empt these animations. return; } - ink_drop_animation_controller_->AnimateToState(ink_drop_state); + ink_drop_->AnimateToState(ink_drop_state); } } // namespace views diff --git a/chromium/ui/views/animation/button_ink_drop_delegate.h b/chromium/ui/views/animation/button_ink_drop_delegate.h index f4c245ecdc1..aa9330d2948 100644 --- a/chromium/ui/views/animation/button_ink_drop_delegate.h +++ b/chromium/ui/views/animation/button_ink_drop_delegate.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_ANIMATION_BUTTON_INK_DROP_DELEGATE_H_ #define UI_VIEWS_ANIMATION_BUTTON_INK_DROP_DELEGATE_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/events/event_handler.h" #include "ui/gfx/geometry/point.h" #include "ui/views/animation/ink_drop_delegate.h" @@ -18,7 +19,7 @@ class ScopedTargetHandler; namespace views { -class InkDropAnimationController; +class InkDrop; class InkDropHost; class View; @@ -40,6 +41,7 @@ class VIEWS_EXPORT ButtonInkDropDelegate : public InkDropDelegate, void OnAction(InkDropState state) override; void SnapToActivated() override; void SetHovered(bool is_hovered) override; + InkDropState GetTargetInkDropState() const override; // ui::EventHandler: void OnMouseEvent(ui::MouseEvent* event) override; @@ -47,7 +49,7 @@ class VIEWS_EXPORT ButtonInkDropDelegate : public InkDropDelegate, private: // An instance of ScopedTargetHandler allowing |this| to handle events. - scoped_ptr<ui::ScopedTargetHandler> target_handler_; + std::unique_ptr<ui::ScopedTargetHandler> target_handler_; // Parent InkDropHost (typically a View) that hosts the ink ripple animations. InkDropHost* ink_drop_host_; @@ -57,7 +59,7 @@ class VIEWS_EXPORT ButtonInkDropDelegate : public InkDropDelegate, gfx::Point last_ink_drop_location_; // Animation controller for the ink drop ripple effect. - scoped_ptr<InkDropAnimationController> ink_drop_animation_controller_; + std::unique_ptr<InkDrop> ink_drop_; DISALLOW_COPY_AND_ASSIGN(ButtonInkDropDelegate); }; diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_animation.cc b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc index 6e177aaff37..f779066bf3a 100644 --- a/chromium/ui/views/animation/flood_fill_ink_drop_animation.cc +++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/animation/flood_fill_ink_drop_animation.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include <algorithm> @@ -96,9 +96,9 @@ int kAnimationDurationInMs[] = { // Returns the InkDropState sub animation duration for the given |state|. base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) { return base::TimeDelta::FromMilliseconds( - (views::InkDropAnimation::UseFastAnimations() + (views::InkDropRipple::UseFastAnimations() ? 1 - : views::InkDropAnimation::kSlowAnimationDurationFactor) * + : views::InkDropRipple::kSlowAnimationDurationFactor) * kAnimationDurationInMs[state]); } @@ -106,10 +106,9 @@ base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) { namespace views { -FloodFillInkDropAnimation::FloodFillInkDropAnimation( - const gfx::Rect& clip_bounds, - const gfx::Point& center_point, - SkColor color) +FloodFillInkDropRipple::FloodFillInkDropRipple(const gfx::Rect& clip_bounds, + const gfx::Point& center_point, + SkColor color) : clip_bounds_(clip_bounds), center_point_(center_point), root_layer_(ui::LAYER_NOT_DRAWN), @@ -117,7 +116,7 @@ FloodFillInkDropAnimation::FloodFillInkDropAnimation( color, std::max(clip_bounds_.width(), clip_bounds_.height()) / 2.f), ink_drop_state_(InkDropState::HIDDEN) { - root_layer_.set_name("FloodFillInkDropAnimation:ROOT_LAYER"); + root_layer_.set_name("FloodFillInkDropRipple:ROOT_LAYER"); root_layer_.SetMasksToBounds(true); root_layer_.SetBounds(clip_bounds); @@ -130,34 +129,34 @@ FloodFillInkDropAnimation::FloodFillInkDropAnimation( painted_layer_.SetVisible(true); painted_layer_.SetOpacity(1.0); painted_layer_.SetMasksToBounds(false); - painted_layer_.set_name("FloodFillInkDropAnimation:PAINTED_LAYER"); + painted_layer_.set_name("FloodFillInkDropRipple:PAINTED_LAYER"); root_layer_.Add(&painted_layer_); SetStateToHidden(); } -FloodFillInkDropAnimation::~FloodFillInkDropAnimation() { +FloodFillInkDropRipple::~FloodFillInkDropRipple() { // Explicitly aborting all the animations ensures all callbacks are invoked // while this instance still exists. AbortAllAnimations(); } -void FloodFillInkDropAnimation::SnapToActivated() { - InkDropAnimation::SnapToActivated(); +void FloodFillInkDropRipple::SnapToActivated() { + InkDropRipple::SnapToActivated(); SetOpacity(kVisibleOpacity); painted_layer_.SetTransform(GetMaxSizeTargetTransform()); } -ui::Layer* FloodFillInkDropAnimation::GetRootLayer() { +ui::Layer* FloodFillInkDropRipple::GetRootLayer() { return &root_layer_; } -bool FloodFillInkDropAnimation::IsVisible() const { +bool FloodFillInkDropRipple::IsVisible() const { return root_layer_.visible(); } -void FloodFillInkDropAnimation::AnimateStateChange( +void FloodFillInkDropRipple::AnimateStateChange( InkDropState old_ink_drop_state, InkDropState new_ink_drop_state, ui::LayerAnimationObserver* animation_observer) { @@ -245,18 +244,18 @@ void FloodFillInkDropAnimation::AnimateStateChange( } } -void FloodFillInkDropAnimation::SetStateToHidden() { +void FloodFillInkDropRipple::SetStateToHidden() { painted_layer_.SetTransform(CalculateTransform(kMinRadius)); - root_layer_.SetOpacity(InkDropAnimation::kHiddenOpacity); + root_layer_.SetOpacity(InkDropRipple::kHiddenOpacity); root_layer_.SetVisible(false); } -void FloodFillInkDropAnimation::AbortAllAnimations() { +void FloodFillInkDropRipple::AbortAllAnimations() { root_layer_.GetAnimator()->AbortAllAnimations(); painted_layer_.GetAnimator()->AbortAllAnimations(); } -void FloodFillInkDropAnimation::AnimateToTransform( +void FloodFillInkDropRipple::AnimateToTransform( const gfx::Transform& transform, base::TimeDelta duration, ui::LayerAnimator::PreemptionStrategy preemption_strategy, @@ -277,11 +276,11 @@ void FloodFillInkDropAnimation::AnimateToTransform( animator->StartAnimation(sequence); } -void FloodFillInkDropAnimation::SetOpacity(float opacity) { +void FloodFillInkDropRipple::SetOpacity(float opacity) { root_layer_.SetOpacity(opacity); } -void FloodFillInkDropAnimation::AnimateToOpacity( +void FloodFillInkDropRipple::AnimateToOpacity( float opacity, base::TimeDelta duration, ui::LayerAnimator::PreemptionStrategy preemption_strategy, @@ -302,7 +301,7 @@ void FloodFillInkDropAnimation::AnimateToOpacity( animator->StartAnimation(animation_sequence); } -gfx::Transform FloodFillInkDropAnimation::CalculateTransform( +gfx::Transform FloodFillInkDropRipple::CalculateTransform( float target_radius) const { const float target_scale = target_radius / circle_layer_delegate_.radius(); const gfx::Point drawn_center_point = @@ -317,7 +316,7 @@ gfx::Transform FloodFillInkDropAnimation::CalculateTransform( return transform; } -gfx::Transform FloodFillInkDropAnimation::GetMaxSizeTargetTransform() const { +gfx::Transform FloodFillInkDropRipple::GetMaxSizeTargetTransform() const { // TODO(estade): get rid of this 2, but make the fade out start before the // active/action transform is done. return CalculateTransform( diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_animation.h b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h index 2ddde9647af..795ffeb8ab1 100644 --- a/chromium/ui/views/animation/flood_fill_ink_drop_animation.h +++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h @@ -2,24 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_ANIMATION_H_ -#define UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_ANIMATION_H_ +#ifndef UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_RIPPLE_H_ +#define UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_RIPPLE_H_ +#include <memory> #include <string> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" #include "ui/gfx/animation/tween.h" #include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/transform.h" -#include "ui/views/animation/ink_drop_animation.h" #include "ui/views/animation/ink_drop_painted_layer_delegates.h" +#include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/views_export.h" @@ -31,10 +30,10 @@ namespace views { class CircleLayerDelegate; namespace test { -class FloodFillInkDropAnimationTestApi; +class FloodFillInkDropRippleTestApi; } // namespace test -// An ink drop animation that starts as a small circle and flood fills a +// An ink drop ripple that starts as a small circle and flood fills a // rectangle of the given size. The circle is clipped to the rectangles bounds. // // The valid InkDropState transitions are defined below: @@ -47,22 +46,22 @@ class FloodFillInkDropAnimationTestApi; // {All InkDropStates} => ACTIVATED // {All InkDropStates} => DEACTIVATED // -class VIEWS_EXPORT FloodFillInkDropAnimation : public InkDropAnimation { +class VIEWS_EXPORT FloodFillInkDropRipple : public InkDropRipple { public: - FloodFillInkDropAnimation(const gfx::Rect& clip_bounds, - const gfx::Point& center_point, - SkColor color); - ~FloodFillInkDropAnimation() override; + FloodFillInkDropRipple(const gfx::Rect& clip_bounds, + const gfx::Point& center_point, + SkColor color); + ~FloodFillInkDropRipple() override; - // InkDropAnimation: + // InkDropRipple: void SnapToActivated() override; ui::Layer* GetRootLayer() override; bool IsVisible() const override; private: - friend class test::FloodFillInkDropAnimationTestApi; + friend class test::FloodFillInkDropRippleTestApi; - // InkDropAnimation: + // InkDropRipple: void AnimateStateChange(InkDropState old_ink_drop_state, InkDropState new_ink_drop_state, ui::LayerAnimationObserver* observer) override; @@ -123,9 +122,9 @@ class VIEWS_EXPORT FloodFillInkDropAnimation : public InkDropAnimation { // The current ink drop state. InkDropState ink_drop_state_; - DISALLOW_COPY_AND_ASSIGN(FloodFillInkDropAnimation); + DISALLOW_COPY_AND_ASSIGN(FloodFillInkDropRipple); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_ANIMATION_H_ +#endif // UI_VIEWS_ANIMATION_FLOOD_FILL_INK_DROP_RIPPLE_H_ diff --git a/chromium/ui/views/animation/ink_drop_animation_controller.h b/chromium/ui/views/animation/ink_drop.h index ec511e21986..c79828ac567 100644 --- a/chromium/ui/views/animation/ink_drop_animation_controller.h +++ b/chromium/ui/views/animation/ink_drop.h @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_H_ +#ifndef UI_VIEWS_ANIMATION_INK_DROP_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_H_ + +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "ui/compositor/layer_tree_owner.h" #include "ui/events/event_handler.h" @@ -22,10 +23,10 @@ class Layer; namespace views { // Pure virtual base class that manages the lifetime and state of an ink drop -// animation as well as visual hover state feedback. -class VIEWS_EXPORT InkDropAnimationController { +// ripple as well as visual hover state feedback. +class VIEWS_EXPORT InkDrop { public: - virtual ~InkDropAnimationController() {} + virtual ~InkDrop() {} // Gets the target state of the ink drop. virtual InkDropState GetTargetInkDropState() const = 0; @@ -47,12 +48,12 @@ class VIEWS_EXPORT InkDropAnimationController { virtual void SetHovered(bool is_hovered) = 0; protected: - InkDropAnimationController() {} + InkDrop() {} private: - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationController); + DISALLOW_COPY_AND_ASSIGN(InkDrop); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_H_ +#endif // UI_VIEWS_ANIMATION_INK_DROP_H_ diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_factory.cc b/chromium/ui/views/animation/ink_drop_animation_controller_factory.cc deleted file mode 100644 index 19bae013b57..00000000000 --- a/chromium/ui/views/animation/ink_drop_animation_controller_factory.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2015 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 "ui/views/animation/ink_drop_animation_controller_factory.h" - -#include "base/macros.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/animation/ink_drop_animation_controller.h" -#include "ui/views/animation/ink_drop_animation_controller_impl.h" -#include "ui/views/views_export.h" - -namespace views { - -namespace { - -// A stub implementation of an InkDropAnimationController that can be used when -// material design is not enabled. -class InkDropAnimationControllerStub - : public InkDropAnimationController { - public: - explicit InkDropAnimationControllerStub(); - ~InkDropAnimationControllerStub() override; - - // InkDropAnimationController: - InkDropState GetTargetInkDropState() const override; - bool IsVisible() const override; - void AnimateToState(InkDropState state) override; - void SnapToActivated() override; - void SetHovered(bool is_hovered) override; - - private: - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerStub); -}; - -InkDropAnimationControllerStub::InkDropAnimationControllerStub() {} - -InkDropAnimationControllerStub::~InkDropAnimationControllerStub() {} - -InkDropState InkDropAnimationControllerStub::GetTargetInkDropState() const { - return InkDropState::HIDDEN; -} - -bool InkDropAnimationControllerStub::IsVisible() const { - return false; -} - -void InkDropAnimationControllerStub::AnimateToState(InkDropState state) {} - -void InkDropAnimationControllerStub::SnapToActivated() {} - -void InkDropAnimationControllerStub::SetHovered(bool is_hovered) {} - -} // namespace - -InkDropAnimationControllerFactory::InkDropAnimationControllerFactory() {} - -InkDropAnimationControllerFactory::~InkDropAnimationControllerFactory() {} - -scoped_ptr<InkDropAnimationController> -InkDropAnimationControllerFactory::CreateInkDropAnimationController( - InkDropHost* ink_drop_host) { - if (ui::MaterialDesignController::IsModeMaterial()) { - return scoped_ptr<InkDropAnimationController>( - new InkDropAnimationControllerImpl(ink_drop_host)); - } - - return scoped_ptr<InkDropAnimationController>( - new InkDropAnimationControllerStub()); -} - -} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_factory.h b/chromium/ui/views/animation/ink_drop_animation_controller_factory.h deleted file mode 100644 index 839631460f7..00000000000 --- a/chromium/ui/views/animation/ink_drop_animation_controller_factory.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 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 UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "ui/views/views_export.h" - -namespace views { -class InkDropAnimationController; -class InkDropHost; - -// A factory to create InkDropAnimationController. A different -// InkDropAnimationController type will be created based on whether or not -// material design is enabled. -class VIEWS_EXPORT InkDropAnimationControllerFactory { - public: - // Creates a new InkDropAnimationController that will add/remove an - // InkDropAnimation's ui::Layer to/from the |ink_drop_host| when the animation - // is active/inactive. - static scoped_ptr<InkDropAnimationController> - CreateInkDropAnimationController(InkDropHost* ink_drop_host); - - private: - InkDropAnimationControllerFactory(); - ~InkDropAnimationControllerFactory(); - - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerFactory); -}; - -} // namespace views - -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_H_ diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc b/chromium/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc deleted file mode 100644 index c75b2c23d7b..00000000000 --- a/chromium/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2015 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 "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "base/timer/timer.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/base/test/material_design_controller_test_api.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/views/animation/ink_drop_animation_controller.h" -#include "ui/views/animation/ink_drop_animation_controller_factory.h" -#include "ui/views/animation/ink_drop_animation_controller_impl.h" -#include "ui/views/animation/ink_drop_host.h" -#include "ui/views/animation/ink_drop_state.h" -#include "ui/views/animation/test/test_ink_drop_host.h" - -namespace views { - -class InkDropAnimationControllerFactoryTest - : public testing::TestWithParam< - testing::tuple<ui::MaterialDesignController::Mode>> { - public: - InkDropAnimationControllerFactoryTest(); - ~InkDropAnimationControllerFactoryTest(); - - protected: - // A dummy InkDropHost required to create an InkDropAnimationController. - TestInkDropHost test_ink_drop_host_; - - // The InkDropAnimationController returned by the - // InkDropAnimationControllerFactory test target. - scoped_ptr<InkDropAnimationController> ink_drop_animation_controller_; - - private: - // Extracts and returns the material design mode from the test parameters. - ui::MaterialDesignController::Mode GetMaterialMode() const; - - scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; - - // Required by base::Timer's. - scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; - - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerFactoryTest); -}; - -InkDropAnimationControllerFactoryTest::InkDropAnimationControllerFactoryTest() - : ink_drop_animation_controller_(nullptr) { - // Any call by a previous test to MaterialDesignController::GetMode() will - // initialize and cache the mode. This ensures that these tests will run from - // a non-initialized state. - ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); - ui::test::MaterialDesignControllerTestAPI::SetMode(GetMaterialMode()); - ink_drop_animation_controller_.reset( - InkDropAnimationControllerFactory::CreateInkDropAnimationController( - &test_ink_drop_host_) - .release()); - - zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); - - switch (GetMaterialMode()) { - case ui::MaterialDesignController::NON_MATERIAL: - break; - case ui::MaterialDesignController::MATERIAL_NORMAL: - case ui::MaterialDesignController::MATERIAL_HYBRID: - // The Timer's used by the InkDropAnimationControllerImpl class require a - // base::ThreadTaskRunnerHandle instance. - scoped_refptr<base::TestMockTimeTaskRunner> task_runner( - new base::TestMockTimeTaskRunner); - thread_task_runner_handle_.reset( - new base::ThreadTaskRunnerHandle(task_runner)); - break; - } -} - -InkDropAnimationControllerFactoryTest:: - ~InkDropAnimationControllerFactoryTest() { - ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); -} - -ui::MaterialDesignController::Mode -InkDropAnimationControllerFactoryTest::GetMaterialMode() const { - return testing::get<0>(GetParam()); -} - -// Note: First argument is optional and intentionally left blank. -// (it's a prefix for the generated test cases) -INSTANTIATE_TEST_CASE_P( - , - InkDropAnimationControllerFactoryTest, - testing::Values(ui::MaterialDesignController::NON_MATERIAL, - ui::MaterialDesignController::MATERIAL_NORMAL, - ui::MaterialDesignController::MATERIAL_HYBRID)); - -TEST_P(InkDropAnimationControllerFactoryTest, - VerifyInkDropLayersRemovedAfterDestructionWhenRippleIsActive) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_.reset(); - EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, - VerifyInkDropLayersRemovedAfterDestructionWhenHoverIsActive) { - test_ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_->SetHovered(true); - ink_drop_animation_controller_.reset(); - EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, StateIsHiddenInitially) { - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickAction) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_TRIGGERED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, CancelQuickAction) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::HIDDEN); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, TypicalSlowAction) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::ALTERNATE_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::ALTERNATE_ACTION_TRIGGERED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, CancelSlowAction) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::ALTERNATE_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::HIDDEN); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickActivated) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); - ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -TEST_P(InkDropAnimationControllerFactoryTest, TypicalSlowActivated) { - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::ALTERNATE_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); - ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetTargetInkDropState()); -} - -} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_impl.cc b/chromium/ui/views/animation/ink_drop_animation_controller_impl.cc deleted file mode 100644 index 62e953ba606..00000000000 --- a/chromium/ui/views/animation/ink_drop_animation_controller_impl.cc +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2015 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 "ui/views/animation/ink_drop_animation_controller_impl.h" - -#include "base/auto_reset.h" -#include "base/timer/timer.h" -#include "ui/compositor/layer.h" -#include "ui/views/animation/ink_drop_host.h" -#include "ui/views/animation/ink_drop_hover.h" -#include "ui/views/animation/square_ink_drop_animation.h" - -namespace views { - -namespace { - -// The duration, in milliseconds, of the hover state fade in animation when it -// is triggered by user input. -const int kHoverFadeInFromUserInputDurationInMs = 250; - -// The duration, in milliseconds, of the hover state fade out animation when it -// is triggered by user input. -const int kHoverFadeOutFromUserInputDurationInMs = 250; - -// The duration, in milliseconds, of the hover state fade in animation when it -// is triggered by an ink drop ripple animation ending. -const int kHoverFadeInAfterAnimationDurationInMs = 250; - -// The duration, in milliseconds, of the hover state fade out animation when it -// is triggered by an ink drop ripple animation starting. -const int kHoverFadeOutBeforeAnimationDurationInMs = 120; - -// The amount of time in milliseconds that |hover_| should delay after a ripple -// animation before fading in. -const int kHoverFadeInAfterAnimationDelayInMs = 1000; - -// Returns true if an ink drop with the given |ink_drop_state| should -// automatically transition to the InkDropState::HIDDEN state. -bool ShouldAnimateToHidden(InkDropState ink_drop_state) { - switch (ink_drop_state) { - case views::InkDropState::ACTION_TRIGGERED: - case views::InkDropState::ALTERNATE_ACTION_TRIGGERED: - case views::InkDropState::DEACTIVATED: - return true; - default: - return false; - } -} - -} // namespace - -InkDropAnimationControllerImpl::InkDropAnimationControllerImpl( - InkDropHost* ink_drop_host) - : ink_drop_host_(ink_drop_host), - root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), - root_layer_added_to_host_(false), - is_hovered_(false), - hover_after_animation_timer_(nullptr) { - root_layer_->set_name("InkDropAnimationControllerImpl:RootLayer"); -} - -InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() { - // Explicitly destroy the InkDropAnimation so that this still exists if - // views::InkDropAnimationObserver methods are called on this. - DestroyInkDropAnimation(); - DestroyInkDropHover(); -} - -InkDropState InkDropAnimationControllerImpl::GetTargetInkDropState() const { - if (!ink_drop_animation_) - return InkDropState::HIDDEN; - return ink_drop_animation_->target_ink_drop_state(); -} - -bool InkDropAnimationControllerImpl::IsVisible() const { - return ink_drop_animation_ && ink_drop_animation_->IsVisible(); -} - -void InkDropAnimationControllerImpl::AnimateToState( - InkDropState ink_drop_state) { - DestroyHiddenTargetedAnimations(); - if (!ink_drop_animation_) - CreateInkDropAnimation(); - - if (ink_drop_state != views::InkDropState::HIDDEN) { - SetHoveredInternal(false, base::TimeDelta::FromMilliseconds( - kHoverFadeOutBeforeAnimationDurationInMs), - true); - } - - ink_drop_animation_->AnimateToState(ink_drop_state); -} - -void InkDropAnimationControllerImpl::SnapToActivated() { - DestroyHiddenTargetedAnimations(); - if (!ink_drop_animation_) - CreateInkDropAnimation(); - - SetHoveredInternal(false, base::TimeDelta(), false); - - ink_drop_animation_->SnapToActivated(); -} - -void InkDropAnimationControllerImpl::SetHovered(bool is_hovered) { - is_hovered_ = is_hovered; - SetHoveredInternal(is_hovered, - is_hovered ? base::TimeDelta::FromMilliseconds( - kHoverFadeInFromUserInputDurationInMs) - : base::TimeDelta::FromMilliseconds( - kHoverFadeOutFromUserInputDurationInMs), - false); -} - -void InkDropAnimationControllerImpl::DestroyHiddenTargetedAnimations() { - if (ink_drop_animation_ && - (ink_drop_animation_->target_ink_drop_state() == InkDropState::HIDDEN || - ShouldAnimateToHidden(ink_drop_animation_->target_ink_drop_state()))) { - DestroyInkDropAnimation(); - } -} - -void InkDropAnimationControllerImpl::CreateInkDropAnimation() { - DestroyInkDropAnimation(); - ink_drop_animation_ = ink_drop_host_->CreateInkDropAnimation(); - ink_drop_animation_->set_observer(this); - root_layer_->Add(ink_drop_animation_->GetRootLayer()); - AddRootLayerToHostIfNeeded(); -} - -void InkDropAnimationControllerImpl::DestroyInkDropAnimation() { - if (!ink_drop_animation_) - return; - root_layer_->Remove(ink_drop_animation_->GetRootLayer()); - ink_drop_animation_.reset(); - RemoveRootLayerFromHostIfNeeded(); -} - -void InkDropAnimationControllerImpl::CreateInkDropHover() { - DestroyInkDropHover(); - - hover_ = ink_drop_host_->CreateInkDropHover(); - if (!hover_) - return; - hover_->set_observer(this); - root_layer_->Add(hover_->layer()); - AddRootLayerToHostIfNeeded(); -} - -void InkDropAnimationControllerImpl::DestroyInkDropHover() { - if (!hover_) - return; - root_layer_->Remove(hover_->layer()); - hover_->set_observer(nullptr); - hover_.reset(); - RemoveRootLayerFromHostIfNeeded(); -} - -void InkDropAnimationControllerImpl::AddRootLayerToHostIfNeeded() { - DCHECK(hover_ || ink_drop_animation_); - if (!root_layer_added_to_host_) { - root_layer_added_to_host_ = true; - ink_drop_host_->AddInkDropLayer(root_layer_.get()); - } -} - -void InkDropAnimationControllerImpl::RemoveRootLayerFromHostIfNeeded() { - if (root_layer_added_to_host_ && !hover_ && !ink_drop_animation_) { - root_layer_added_to_host_ = false; - ink_drop_host_->RemoveInkDropLayer(root_layer_.get()); - } -} - -bool InkDropAnimationControllerImpl::IsHoverFadingInOrVisible() const { - return hover_ && hover_->IsFadingInOrVisible(); -} - -// ----------------------------------------------------------------------------- -// views::InkDropAnimationObserver: - -void InkDropAnimationControllerImpl::AnimationStarted( - InkDropState ink_drop_state) {} - -void InkDropAnimationControllerImpl::AnimationEnded( - InkDropState ink_drop_state, - InkDropAnimationEndedReason reason) { - if (reason != InkDropAnimationEndedReason::SUCCESS) - return; - if (ShouldAnimateToHidden(ink_drop_state)) { - ink_drop_animation_->AnimateToState(views::InkDropState::HIDDEN); - } else if (ink_drop_state == views::InkDropState::HIDDEN) { - if (is_hovered_) - StartHoverAfterAnimationTimer(); - // TODO(bruthig): Investigate whether creating and destroying - // InkDropAnimations is expensive and consider creating an - // InkDropAnimationPool. See www.crbug.com/522175. - DestroyInkDropAnimation(); - } -} - -// ----------------------------------------------------------------------------- -// views::InkDropHoverObserver: - -void InkDropAnimationControllerImpl::AnimationStarted( - InkDropHover::AnimationType animation_type) {} - -void InkDropAnimationControllerImpl::AnimationEnded( - InkDropHover::AnimationType animation_type, - InkDropAnimationEndedReason reason) { - if (animation_type == InkDropHover::FADE_OUT && - reason == InkDropAnimationEndedReason::SUCCESS) { - DestroyInkDropHover(); - } -} - -void InkDropAnimationControllerImpl::SetHoveredInternal( - bool is_hovered, - base::TimeDelta animation_duration, - bool explode) { - StopHoverAfterAnimationTimer(); - - if (IsHoverFadingInOrVisible() == is_hovered) - return; - - if (is_hovered) { - CreateInkDropHover(); - if (hover_ && !IsVisible()) - hover_->FadeIn(animation_duration); - } else { - hover_->FadeOut(animation_duration, explode); - } -} - -void InkDropAnimationControllerImpl::StartHoverAfterAnimationTimer() { - StopHoverAfterAnimationTimer(); - - if (!hover_after_animation_timer_) - hover_after_animation_timer_.reset(new base::OneShotTimer); - - hover_after_animation_timer_->Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kHoverFadeInAfterAnimationDelayInMs), - base::Bind(&InkDropAnimationControllerImpl::HoverAfterAnimationTimerFired, - base::Unretained(this))); -} - -void InkDropAnimationControllerImpl::StopHoverAfterAnimationTimer() { - if (hover_after_animation_timer_) - hover_after_animation_timer_.reset(); -} - -void InkDropAnimationControllerImpl::HoverAfterAnimationTimerFired() { - SetHoveredInternal(true, base::TimeDelta::FromMilliseconds( - kHoverFadeInAfterAnimationDurationInMs), - true); - hover_after_animation_timer_.reset(); -} - -} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_animation_ended_reason.h b/chromium/ui/views/animation/ink_drop_animation_ended_reason.h index fc2f359cef2..0761f102e04 100644 --- a/chromium/ui/views/animation/ink_drop_animation_ended_reason.h +++ b/chromium/ui/views/animation/ink_drop_animation_ended_reason.h @@ -5,8 +5,11 @@ #ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_ENDED_REASON_H_ #define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_ENDED_REASON_H_ +#include <iosfwd> #include <string> +#include "ui/views/views_export.h" + namespace views { // Enumeration of the different reasons why an ink drop animation has finished. @@ -18,7 +21,12 @@ enum class InkDropAnimationEndedReason { }; // Returns a human readable string for |reason|. Useful for logging. -std::string ToString(InkDropAnimationEndedReason reason); +VIEWS_EXPORT std::string ToString(InkDropAnimationEndedReason reason); + +// This is declared here for use in gtest-based unit tests but is defined in +// the views_test_support target. Depend on that to use this in your unit test. +// This should not be used in production code - call ToString() instead. +void PrintTo(InkDropAnimationEndedReason reason, ::std::ostream* os); } // namespace views diff --git a/chromium/ui/views/animation/ink_drop_animation_unittest.cc b/chromium/ui/views/animation/ink_drop_animation_unittest.cc deleted file mode 100644 index e1ff62c456c..00000000000 --- a/chromium/ui/views/animation/ink_drop_animation_unittest.cc +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2015 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 UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ - -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/animation/flood_fill_ink_drop_animation.h" -#include "ui/views/animation/ink_drop_animation.h" -#include "ui/views/animation/ink_drop_animation_observer.h" -#include "ui/views/animation/ink_drop_state.h" -#include "ui/views/animation/square_ink_drop_animation.h" -#include "ui/views/animation/test/flood_fill_ink_drop_animation_test_api.h" -#include "ui/views/animation/test/ink_drop_animation_test_api.h" -#include "ui/views/animation/test/square_ink_drop_animation_test_api.h" -#include "ui/views/animation/test/test_ink_drop_animation_observer.h" - -namespace views { -namespace test { - -// Represents all the derivatives of the InkDropAnimation class. To be used with -// the InkDropAnimationTest fixture to test all derviatives. -enum InkDropAnimationTestTypes { - SQUARE_INK_DROP_ANIMATION, - FLOOD_FILL_INK_DROP_ANIMATION -}; - -// Test fixture for all InkDropAnimation class derivatives. -// -// To add a new derivative: -// 1. Add a value to the InkDropAnimationTestTypes enum. -// 2. Implement set up and tear down code for the new enum value in -// InkDropAnimationTest() and -// ~InkDropAnimationTest(). -// 3. Add the new enum value to the INSTANTIATE_TEST_CASE_P) Values list. -class InkDropAnimationTest - : public testing::TestWithParam<InkDropAnimationTestTypes> { - public: - InkDropAnimationTest(); - ~InkDropAnimationTest() override; - - protected: - TestInkDropAnimationObserver observer_; - - scoped_ptr<InkDropAnimation> ink_drop_animation_; - - scoped_ptr<InkDropAnimationTestApi> test_api_; - - private: - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationTest); -}; - -InkDropAnimationTest::InkDropAnimationTest() { - switch (GetParam()) { - case SQUARE_INK_DROP_ANIMATION: { - SquareInkDropAnimation* square_ink_drop_animation = - new SquareInkDropAnimation(gfx::Size(10, 10), 2, gfx::Size(8, 8), 1, - gfx::Point(), SK_ColorBLACK); - ink_drop_animation_.reset(square_ink_drop_animation); - test_api_.reset( - new SquareInkDropAnimationTestApi(square_ink_drop_animation)); - break; - } - case FLOOD_FILL_INK_DROP_ANIMATION: { - FloodFillInkDropAnimation* flood_fill_ink_drop_animation = - new FloodFillInkDropAnimation(gfx::Rect(0, 0, 10, 10), gfx::Point(), - SK_ColorBLACK); - ink_drop_animation_.reset(flood_fill_ink_drop_animation); - test_api_.reset( - new FloodFillInkDropAnimationTestApi(flood_fill_ink_drop_animation)); - break; - } - } - ink_drop_animation_->set_observer(&observer_); - observer_.set_ink_drop_animation(ink_drop_animation_.get()); - test_api_->SetDisableAnimationTimers(true); -} - -InkDropAnimationTest::~InkDropAnimationTest() {} - -// Note: First argument is optional and intentionally left blank. -// (it's a prefix for the generated test cases) -INSTANTIATE_TEST_CASE_P(, - InkDropAnimationTest, - testing::Values(SQUARE_INK_DROP_ANIMATION, - FLOOD_FILL_INK_DROP_ANIMATION)); - -TEST_P(InkDropAnimationTest, InitialStateAfterConstruction) { - EXPECT_EQ(views::InkDropState::HIDDEN, - ink_drop_animation_->target_ink_drop_state()); -} - -// Verify no animations are used when animating from HIDDEN to HIDDEN. -TEST_P(InkDropAnimationTest, AnimateToHiddenFromInvisibleState) { - EXPECT_EQ(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); - - ink_drop_animation_->AnimateToState(InkDropState::HIDDEN); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); - EXPECT_FALSE(ink_drop_animation_->IsVisible()); -} - -TEST_P(InkDropAnimationTest, AnimateToHiddenFromVisibleState) { - ink_drop_animation_->AnimateToState(InkDropState::ACTION_PENDING); - test_api_->CompleteAnimations(); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - - EXPECT_NE(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); - - ink_drop_animation_->AnimateToState(InkDropState::HIDDEN); - test_api_->CompleteAnimations(); - - EXPECT_EQ(3, observer_.last_animation_started_ordinal()); - EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, ActionPendingOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, QuickActionOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_TRIGGERED); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, SlowActionPendingOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState( - views::InkDropState::ALTERNATE_ACTION_PENDING); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, SlowActionOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState( - views::InkDropState::ALTERNATE_ACTION_PENDING); - ink_drop_animation_->AnimateToState( - views::InkDropState::ALTERNATE_ACTION_TRIGGERED); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, ActivatedOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTIVATED); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); -} - -TEST_P(InkDropAnimationTest, DeactivatedOpacity) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTIVATED); - ink_drop_animation_->AnimateToState(views::InkDropState::DEACTIVATED); - test_api_->CompleteAnimations(); - - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); -} - -// Verify animations are aborted during deletion and the -// InkDropAnimationObservers are notified. -TEST_P(InkDropAnimationTest, AnimationsAbortedDuringDeletion) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_.reset(); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(views::InkDropState::ACTION_PENDING, - observer_.last_animation_ended_context()); - EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, - observer_.last_animation_ended_reason()); -} - -TEST_P(InkDropAnimationTest, VerifyObserversAreNotified) { - ink_drop_animation_->AnimateToState(InkDropState::ACTION_PENDING); - - EXPECT_TRUE(test_api_->HasActiveAnimations()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_TRUE(observer_.AnimationHasNotEnded()); - EXPECT_EQ(InkDropState::ACTION_PENDING, - observer_.last_animation_started_context()); - - test_api_->CompleteAnimations(); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropState::ACTION_PENDING, - observer_.last_animation_ended_context()); -} - -TEST_P(InkDropAnimationTest, VerifyObserversAreNotifiedOfSuccessfulAnimations) { - ink_drop_animation_->AnimateToState(InkDropState::ACTION_PENDING); - test_api_->CompleteAnimations(); - - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropAnimationEndedReason::SUCCESS, - observer_.last_animation_ended_reason()); -} - -TEST_P(InkDropAnimationTest, VerifyObserversAreNotifiedOfPreemptedAnimations) { - ink_drop_animation_->AnimateToState(InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING); - - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, - observer_.last_animation_ended_reason()); -} - -TEST_P(InkDropAnimationTest, InkDropStatesPersistWhenCallingAnimateToState) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState(views::InkDropState::ACTIVATED); - EXPECT_EQ(views::InkDropState::ACTIVATED, - ink_drop_animation_->target_ink_drop_state()); -} - -TEST_P(InkDropAnimationTest, HideImmediatelyWithoutActiveAnimations) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - test_api_->CompleteAnimations(); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_NE(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); - - ink_drop_animation_->HideImmediately(); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_EQ(views::InkDropState::HIDDEN, - ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); - EXPECT_FALSE(ink_drop_animation_->IsVisible()); -} - -// Verifies all active animations are aborted and the InkDropState is set to -// HIDDEN after invoking HideImmediately(). -TEST_P(InkDropAnimationTest, HideImmediatelyWithActiveAnimations) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - EXPECT_TRUE(test_api_->HasActiveAnimations()); - EXPECT_NE(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - - ink_drop_animation_->HideImmediately(); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_EQ(views::InkDropState::HIDDEN, - ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropState::ACTION_PENDING, - observer_.last_animation_ended_context()); - EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, - observer_.last_animation_ended_reason()); - - EXPECT_EQ(InkDropAnimation::kHiddenOpacity, test_api_->GetCurrentOpacity()); - EXPECT_FALSE(ink_drop_animation_->IsVisible()); -} - -TEST_P(InkDropAnimationTest, SnapToActivatedWithoutActiveAnimations) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - test_api_->CompleteAnimations(); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_NE(InkDropState::ACTIVATED, - ink_drop_animation_->target_ink_drop_state()); - - ink_drop_animation_->SnapToActivated(); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_EQ(views::InkDropState::ACTIVATED, - ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(3, observer_.last_animation_started_ordinal()); - EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); - - EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); - EXPECT_TRUE(ink_drop_animation_->IsVisible()); -} - -// Verifies all active animations are aborted and the InkDropState is set to -// ACTIVATED after invoking SnapToActivated(). -TEST_P(InkDropAnimationTest, SnapToActivatedWithActiveAnimations) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - EXPECT_TRUE(test_api_->HasActiveAnimations()); - EXPECT_NE(InkDropState::ACTIVATED, - ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - - ink_drop_animation_->SnapToActivated(); - - EXPECT_FALSE(test_api_->HasActiveAnimations()); - EXPECT_EQ(views::InkDropState::ACTIVATED, - ink_drop_animation_->target_ink_drop_state()); - EXPECT_EQ(3, observer_.last_animation_started_ordinal()); - EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(InkDropState::ACTIVATED, observer_.last_animation_ended_context()); - EXPECT_EQ(InkDropAnimationEndedReason::SUCCESS, - observer_.last_animation_ended_reason()); - - EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); - EXPECT_TRUE(ink_drop_animation_->IsVisible()); -} - -TEST_P(InkDropAnimationTest, AnimateToVisibleFromHidden) { - EXPECT_EQ(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - EXPECT_TRUE(ink_drop_animation_->IsVisible()); -} - -// Verifies that the value of InkDropAnimation::target_ink_drop_state() returns -// the most recent value passed to AnimateToState() when notifying observers -// that an animation has started within the AnimateToState() function call. -TEST_P(InkDropAnimationTest, TargetInkDropStateOnAnimationStarted) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState(views::InkDropState::HIDDEN); - - EXPECT_EQ(3, observer_.last_animation_started_ordinal()); - EXPECT_EQ(views::InkDropState::HIDDEN, - observer_.target_state_at_last_animation_started()); -} - -// Verifies that the value of InkDropAnimation::target_ink_drop_state() returns -// the most recent value passed to AnimateToState() when notifying observers -// that an animation has ended within the AnimateToState() function call. -TEST_P(InkDropAnimationTest, TargetInkDropStateOnAnimationEnded) { - ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); - ink_drop_animation_->AnimateToState(views::InkDropState::HIDDEN); - - EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); - EXPECT_EQ(views::InkDropState::HIDDEN, - observer_.target_state_at_last_animation_ended()); -} - -} // namespace test -} // namespace views - -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ diff --git a/chromium/ui/views/animation/ink_drop_delegate.h b/chromium/ui/views/animation/ink_drop_delegate.h index 61235241f92..545f5be0e3a 100644 --- a/chromium/ui/views/animation/ink_drop_delegate.h +++ b/chromium/ui/views/animation/ink_drop_delegate.h @@ -35,6 +35,9 @@ class VIEWS_EXPORT InkDropDelegate { // Enables or disables the hover state. virtual void SetHovered(bool is_hovered) = 0; + // Returns the current InkDropState + virtual InkDropState GetTargetInkDropState() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(InkDropDelegate); }; diff --git a/chromium/ui/views/animation/ink_drop_factory.cc b/chromium/ui/views/animation/ink_drop_factory.cc new file mode 100644 index 00000000000..f67f6b68cd1 --- /dev/null +++ b/chromium/ui/views/animation/ink_drop_factory.cc @@ -0,0 +1,71 @@ +// Copyright 2015 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 "ui/views/animation/ink_drop_factory.h" + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "ui/base/material_design/material_design_controller.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/views_export.h" + +namespace views { + +namespace { + +// A stub implementation of an InkDrop that can be used when material design is +// not enabled. +class InkDropStub : public InkDrop { + public: + explicit InkDropStub(); + ~InkDropStub() override; + + // InkDrop: + InkDropState GetTargetInkDropState() const override; + bool IsVisible() const override; + void AnimateToState(InkDropState state) override; + void SnapToActivated() override; + void SetHovered(bool is_hovered) override; + + private: + DISALLOW_COPY_AND_ASSIGN(InkDropStub); +}; + +InkDropStub::InkDropStub() {} + +InkDropStub::~InkDropStub() {} + +InkDropState InkDropStub::GetTargetInkDropState() const { + return InkDropState::HIDDEN; +} + +bool InkDropStub::IsVisible() const { + return false; +} + +void InkDropStub::AnimateToState(InkDropState state) {} + +void InkDropStub::SnapToActivated() {} + +void InkDropStub::SetHovered(bool is_hovered) {} + +} // namespace + +InkDropFactory::InkDropFactory() {} + +InkDropFactory::~InkDropFactory() {} + +std::unique_ptr<InkDrop> InkDropFactory::CreateInkDrop( + InkDropHost* ink_drop_host) { + if (ui::MaterialDesignController::IsModeMaterial()) { + return base::WrapUnique(new InkDropImpl(ink_drop_host)); + } + + return base::WrapUnique(new InkDropStub()); +} + +} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_factory.h b/chromium/ui/views/animation/ink_drop_factory.h new file mode 100644 index 00000000000..0fc57d82d54 --- /dev/null +++ b/chromium/ui/views/animation/ink_drop_factory.h @@ -0,0 +1,34 @@ +// Copyright 2015 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 UI_VIEWS_ANIMATION_INK_DROP_FACTORY_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_FACTORY_H_ + +#include <memory> + +#include "base/macros.h" +#include "ui/views/views_export.h" + +namespace views { +class InkDrop; +class InkDropHost; + +// A factory to create an InkDrop. A different InkDrop type will be created +// based on whether or not material design is enabled. +class VIEWS_EXPORT InkDropFactory { + public: + // Creates a new InkDrop that will add/remove an InkDropRipple's ui::Layer + // to/from the |ink_drop_host| when the animation is active/inactive. + static std::unique_ptr<InkDrop> CreateInkDrop(InkDropHost* ink_drop_host); + + private: + InkDropFactory(); + ~InkDropFactory(); + + DISALLOW_COPY_AND_ASSIGN(InkDropFactory); +}; + +} // namespace views + +#endif // UI_VIEWS_ANIMATION_INK_DROP_FACTORY_H_ diff --git a/chromium/ui/views/animation/ink_drop_factory_unittest.cc b/chromium/ui/views/animation/ink_drop_factory_unittest.cc new file mode 100644 index 00000000000..3afc90393e7 --- /dev/null +++ b/chromium/ui/views/animation/ink_drop_factory_unittest.cc @@ -0,0 +1,158 @@ +// Copyright 2015 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 "ui/views/animation/ink_drop_factory.h" + +#include <memory> + +#include "base/macros.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/timer/timer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/material_design/material_design_controller.h" +#include "ui/base/test/material_design_controller_test_api.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_host.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_state.h" +#include "ui/views/animation/test/test_ink_drop_host.h" + +namespace views { + +class InkDropFactoryTest + : public testing::TestWithParam< + testing::tuple<ui::MaterialDesignController::Mode>> { + public: + InkDropFactoryTest(); + ~InkDropFactoryTest(); + + protected: + // A dummy InkDropHost required to create an InkDrop. + TestInkDropHost test_ink_drop_host_; + + // The InkDrop returned by the InkDropFactory test target. + std::unique_ptr<InkDrop> ink_drop_; + + private: + // Extracts and returns the material design mode from the test parameters. + ui::MaterialDesignController::Mode GetMaterialMode() const; + + std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + + // Required by base::Timer's. + std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; + + std::unique_ptr<ui::test::MaterialDesignControllerTestAPI> + material_design_state_; + + DISALLOW_COPY_AND_ASSIGN(InkDropFactoryTest); +}; + +InkDropFactoryTest::InkDropFactoryTest() : ink_drop_(nullptr) { + // Any call by a previous test to MaterialDesignController::GetMode() will + // initialize and cache the mode. This ensures that these tests will run from + // a non-initialized state. + material_design_state_.reset( + new ui::test::MaterialDesignControllerTestAPI(GetMaterialMode())); + ink_drop_.reset( + InkDropFactory::CreateInkDrop(&test_ink_drop_host_).release()); + + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); + + switch (GetMaterialMode()) { + case ui::MaterialDesignController::NON_MATERIAL: + break; + case ui::MaterialDesignController::MATERIAL_NORMAL: + case ui::MaterialDesignController::MATERIAL_HYBRID: + // The Timer's used by the InkDropImpl class require a + // base::ThreadTaskRunnerHandle instance. + scoped_refptr<base::TestMockTimeTaskRunner> task_runner( + new base::TestMockTimeTaskRunner); + thread_task_runner_handle_.reset( + new base::ThreadTaskRunnerHandle(task_runner)); + break; + } +} + +InkDropFactoryTest::~InkDropFactoryTest() { + material_design_state_.reset(); +} + +ui::MaterialDesignController::Mode InkDropFactoryTest::GetMaterialMode() const { + return testing::get<0>(GetParam()); +} + +// Note: First argument is optional and intentionally left blank. +// (it's a prefix for the generated test cases) +INSTANTIATE_TEST_CASE_P( + , + InkDropFactoryTest, + testing::Values(ui::MaterialDesignController::NON_MATERIAL, + ui::MaterialDesignController::MATERIAL_NORMAL, + ui::MaterialDesignController::MATERIAL_HYBRID)); + +TEST_P(InkDropFactoryTest, + VerifyInkDropLayersRemovedAfterDestructionWhenRippleIsActive) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_.reset(); + EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); +} + +TEST_P(InkDropFactoryTest, + VerifyInkDropLayersRemovedAfterDestructionWhenHoverIsActive) { + test_ink_drop_host_.set_should_show_hover(true); + ink_drop_->SetHovered(true); + ink_drop_.reset(); + EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); +} + +TEST_P(InkDropFactoryTest, StateIsHiddenInitially) { + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, TypicalQuickAction) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ACTION_TRIGGERED); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, CancelQuickAction) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::HIDDEN); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, TypicalSlowAction) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ALTERNATE_ACTION_TRIGGERED); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, CancelSlowAction) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::HIDDEN); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, TypicalQuickActivated) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ACTIVATED); + ink_drop_->AnimateToState(InkDropState::DEACTIVATED); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +TEST_P(InkDropFactoryTest, TypicalSlowActivated) { + ink_drop_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING); + ink_drop_->AnimateToState(InkDropState::ACTIVATED); + ink_drop_->AnimateToState(InkDropState::DEACTIVATED); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_->GetTargetInkDropState()); +} + +} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_host.h b/chromium/ui/views/animation/ink_drop_host.h index 570f2710b49..aa13504e49a 100644 --- a/chromium/ui/views/animation/ink_drop_host.h +++ b/chromium/ui/views/animation/ink_drop_host.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_ANIMATION_INK_DROP_HOST_H_ #define UI_VIEWS_ANIMATION_INK_DROP_HOST_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/geometry/point.h" #include "ui/views/views_export.h" @@ -16,12 +17,12 @@ class Layer; namespace views { -class InkDropAnimation; +class InkDropRipple; class InkDropHover; -// Used by the InkDropAnimationController to add and remove the ink drop layers -// from a host's layer tree. Typically the ink drop layer is added to a View's -// layer but it can also be added to a View's ancestor layer. +// Used by the InkDrop to add and remove the ink drop layers from a host's layer +// tree. Typically the ink drop layer is added to a View's layer but it can also +// be added to a View's ancestor layer. // // Note: Some Views do not own a Layer, but you can use // View::SetLayer(new ui::Layer(ui::LAYER_NOT_DRAWN)) to force the View to have @@ -38,10 +39,10 @@ class VIEWS_EXPORT InkDropHost { virtual void RemoveInkDropLayer(ui::Layer* ink_drop_layer) = 0; // Creates and returns the effect used for press. - virtual scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const = 0; + virtual std::unique_ptr<InkDropRipple> CreateInkDropRipple() const = 0; // Creates and returns the effect used for hover. - virtual scoped_ptr<InkDropHover> CreateInkDropHover() const = 0; + virtual std::unique_ptr<InkDropHover> CreateInkDropHover() const = 0; private: DISALLOW_COPY_AND_ASSIGN(InkDropHost); diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc index 317645e6118..faf32b07d81 100644 --- a/chromium/ui/views/animation/ink_drop_host_view.cc +++ b/chromium/ui/views/animation/ink_drop_host_view.cc @@ -7,7 +7,7 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/views/animation/ink_drop_hover.h" -#include "ui/views/animation/square_ink_drop_animation.h" +#include "ui/views/animation/square_ink_drop_ripple.h" namespace views { @@ -46,16 +46,16 @@ void InkDropHostView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { SetPaintToLayer(false); } -scoped_ptr<InkDropAnimation> InkDropHostView::CreateInkDropAnimation() const { - scoped_ptr<InkDropAnimation> animation(new SquareInkDropAnimation( +std::unique_ptr<InkDropRipple> InkDropHostView::CreateInkDropRipple() const { + std::unique_ptr<InkDropRipple> ripple(new SquareInkDropRipple( CalculateLargeInkDropSize(ink_drop_size_), kInkDropLargeCornerRadius, ink_drop_size_, kInkDropSmallCornerRadius, GetInkDropCenter(), GetInkDropBaseColor())); - return animation; + return ripple; } -scoped_ptr<InkDropHover> InkDropHostView::CreateInkDropHover() const { - scoped_ptr<InkDropHover> hover( +std::unique_ptr<InkDropHover> InkDropHostView::CreateInkDropHover() const { + std::unique_ptr<InkDropHover> hover( new InkDropHover(ink_drop_size_, kInkDropSmallCornerRadius, GetInkDropCenter(), GetInkDropBaseColor())); hover->set_explode_size(CalculateLargeInkDropSize(ink_drop_size_)); diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h index 3a3efa6b6ed..e4ebe6d3b6d 100644 --- a/chromium/ui/views/animation/ink_drop_host_view.h +++ b/chromium/ui/views/animation/ink_drop_host_view.h @@ -5,7 +5,8 @@ #ifndef UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_ #define UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/size.h" #include "ui/views/animation/ink_drop_host.h" @@ -13,7 +14,7 @@ namespace views { -class InkDropAnimation; +class InkDropRipple; class InkDropHover; // A view that provides InkDropHost functionality. @@ -25,8 +26,8 @@ class VIEWS_EXPORT InkDropHostView : public views::View, public InkDropHost { // Overridden from views::InkDropHost: void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; - scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const override; - scoped_ptr<InkDropHover> CreateInkDropHover() const override; + std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<InkDropHover> CreateInkDropHover() const override; void set_ink_drop_size(const gfx::Size& size) { ink_drop_size_ = size; } @@ -43,6 +44,6 @@ class VIEWS_EXPORT InkDropHostView : public views::View, public InkDropHost { DISALLOW_COPY_AND_ASSIGN(InkDropHostView); }; -} +} // namespace views #endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_ diff --git a/chromium/ui/views/animation/ink_drop_hover.cc b/chromium/ui/views/animation/ink_drop_hover.cc index af98e614f59..24ad3844eb1 100644 --- a/chromium/ui/views/animation/ink_drop_hover.cc +++ b/chromium/ui/views/animation/ink_drop_hover.cc @@ -24,6 +24,18 @@ const float kHiddenOpacity = 0.0f; } // namespace +std::string ToString(InkDropHover::AnimationType animation_type) { + switch (animation_type) { + case InkDropHover::FADE_IN: + return std::string("FADE_IN"); + case InkDropHover::FADE_OUT: + return std::string("FADE_OUT"); + } + NOTREACHED() + << "Should never be reached but is necessary for some compilers."; + return std::string("UNKNOWN"); +} + InkDropHover::InkDropHover(const gfx::Size& size, int corner_radius, const gfx::Point& center_point, diff --git a/chromium/ui/views/animation/ink_drop_hover.h b/chromium/ui/views/animation/ink_drop_hover.h index e1cd2d42e5e..4c18b1d1889 100644 --- a/chromium/ui/views/animation/ink_drop_hover.h +++ b/chromium/ui/views/animation/ink_drop_hover.h @@ -5,8 +5,10 @@ #ifndef UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_ #define UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_ +#include <iosfwd> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/point.h" @@ -102,16 +104,24 @@ class VIEWS_EXPORT InkDropHover { bool last_animation_initiated_was_fade_in_; // The LayerDelegate that paints the hover |layer_|. - scoped_ptr<RoundedRectangleLayerDelegate> layer_delegate_; + std::unique_ptr<RoundedRectangleLayerDelegate> layer_delegate_; // The visual hover layer that is painted by |layer_delegate_|. - scoped_ptr<ui::Layer> layer_; + std::unique_ptr<ui::Layer> layer_; InkDropHoverObserver* observer_; DISALLOW_COPY_AND_ASSIGN(InkDropHover); }; +// Returns a human readable string for |animation_type|. Useful for logging. +VIEWS_EXPORT std::string ToString(InkDropHover::AnimationType animation_type); + +// This is declared here for use in gtest-based unit tests but is defined in +// the views_test_support target. Depend on that to use this in your unit test. +// This should not be used in production code - call ToString() instead. +void PrintTo(InkDropHover::AnimationType animation_type, ::std::ostream* os); + } // namespace views #endif // UI_VIEWS_ANIMATION_INK_DROP_HOVER_H_ diff --git a/chromium/ui/views/animation/ink_drop_hover_unittest.cc b/chromium/ui/views/animation/ink_drop_hover_unittest.cc index 5d02ab7f1ed..eefe5a639f0 100644 --- a/chromium/ui/views/animation/ink_drop_hover_unittest.cc +++ b/chromium/ui/views/animation/ink_drop_hover_unittest.cc @@ -4,8 +4,10 @@ #include "ui/views/animation/ink_drop_hover.h" +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" @@ -23,7 +25,7 @@ class InkDropHoverTest : public testing::Test { protected: // The test target. - scoped_ptr<InkDropHover> ink_drop_hover_; + std::unique_ptr<InkDropHover> ink_drop_hover_; // Allows privileged access to the the |ink_drop_hover_|. InkDropHoverTestApi test_api_; diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc new file mode 100644 index 00000000000..cce475b58b5 --- /dev/null +++ b/chromium/ui/views/animation/ink_drop_impl.cc @@ -0,0 +1,253 @@ +// Copyright 2015 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 "ui/views/animation/ink_drop_impl.h" + +#include "base/auto_reset.h" +#include "base/timer/timer.h" +#include "ui/compositor/layer.h" +#include "ui/views/animation/ink_drop_host.h" +#include "ui/views/animation/ink_drop_hover.h" +#include "ui/views/animation/square_ink_drop_ripple.h" + +namespace views { + +namespace { + +// The duration, in milliseconds, of the hover state fade in animation when it +// is triggered by user input. +const int kHoverFadeInFromUserInputDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade out animation when it +// is triggered by user input. +const int kHoverFadeOutFromUserInputDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade in animation when it +// is triggered by an ink drop ripple animation ending. +const int kHoverFadeInAfterRippleDurationInMs = 250; + +// The duration, in milliseconds, of the hover state fade out animation when it +// is triggered by an ink drop ripple animation starting. +const int kHoverFadeOutBeforeRippleDurationInMs = 120; + +// The amount of time in milliseconds that |hover_| should delay after a ripple +// animation before fading in. +const int kHoverFadeInAfterRippleDelayInMs = 1000; + +// Returns true if an ink drop with the given |ink_drop_state| should +// automatically transition to the InkDropState::HIDDEN state. +bool ShouldAnimateToHidden(InkDropState ink_drop_state) { + switch (ink_drop_state) { + case views::InkDropState::ACTION_TRIGGERED: + case views::InkDropState::ALTERNATE_ACTION_TRIGGERED: + case views::InkDropState::DEACTIVATED: + return true; + default: + return false; + } +} + +} // namespace + +InkDropImpl::InkDropImpl(InkDropHost* ink_drop_host) + : ink_drop_host_(ink_drop_host), + root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), + root_layer_added_to_host_(false), + is_hovered_(false), + hover_after_ripple_timer_(nullptr) { + root_layer_->set_name("InkDropImpl:RootLayer"); +} + +InkDropImpl::~InkDropImpl() { + // Explicitly destroy the InkDropRipple so that this still exists if + // views::InkDropRippleObserver methods are called on this. + DestroyInkDropRipple(); + DestroyInkDropHover(); +} + +InkDropState InkDropImpl::GetTargetInkDropState() const { + if (!ink_drop_ripple_) + return InkDropState::HIDDEN; + return ink_drop_ripple_->target_ink_drop_state(); +} + +bool InkDropImpl::IsVisible() const { + return ink_drop_ripple_ && ink_drop_ripple_->IsVisible(); +} + +void InkDropImpl::AnimateToState(InkDropState ink_drop_state) { + DestroyHiddenTargetedAnimations(); + if (!ink_drop_ripple_) + CreateInkDropRipple(); + + if (ink_drop_state != views::InkDropState::HIDDEN) { + SetHoveredInternal(false, base::TimeDelta::FromMilliseconds( + kHoverFadeOutBeforeRippleDurationInMs), + true); + } + + ink_drop_ripple_->AnimateToState(ink_drop_state); +} + +void InkDropImpl::SnapToActivated() { + DestroyHiddenTargetedAnimations(); + if (!ink_drop_ripple_) + CreateInkDropRipple(); + + SetHoveredInternal(false, base::TimeDelta(), false); + + ink_drop_ripple_->SnapToActivated(); +} + +void InkDropImpl::SetHovered(bool is_hovered) { + is_hovered_ = is_hovered; + SetHoveredInternal(is_hovered, + is_hovered ? base::TimeDelta::FromMilliseconds( + kHoverFadeInFromUserInputDurationInMs) + : base::TimeDelta::FromMilliseconds( + kHoverFadeOutFromUserInputDurationInMs), + false); +} + +void InkDropImpl::DestroyHiddenTargetedAnimations() { + if (ink_drop_ripple_ && + (ink_drop_ripple_->target_ink_drop_state() == InkDropState::HIDDEN || + ShouldAnimateToHidden(ink_drop_ripple_->target_ink_drop_state()))) { + DestroyInkDropRipple(); + } +} + +void InkDropImpl::CreateInkDropRipple() { + DestroyInkDropRipple(); + ink_drop_ripple_ = ink_drop_host_->CreateInkDropRipple(); + ink_drop_ripple_->set_observer(this); + root_layer_->Add(ink_drop_ripple_->GetRootLayer()); + AddRootLayerToHostIfNeeded(); +} + +void InkDropImpl::DestroyInkDropRipple() { + if (!ink_drop_ripple_) + return; + root_layer_->Remove(ink_drop_ripple_->GetRootLayer()); + ink_drop_ripple_.reset(); + RemoveRootLayerFromHostIfNeeded(); +} + +void InkDropImpl::CreateInkDropHover() { + DestroyInkDropHover(); + + hover_ = ink_drop_host_->CreateInkDropHover(); + if (!hover_) + return; + hover_->set_observer(this); + root_layer_->Add(hover_->layer()); + AddRootLayerToHostIfNeeded(); +} + +void InkDropImpl::DestroyInkDropHover() { + if (!hover_) + return; + root_layer_->Remove(hover_->layer()); + hover_->set_observer(nullptr); + hover_.reset(); + RemoveRootLayerFromHostIfNeeded(); +} + +void InkDropImpl::AddRootLayerToHostIfNeeded() { + DCHECK(hover_ || ink_drop_ripple_); + if (!root_layer_added_to_host_) { + root_layer_added_to_host_ = true; + ink_drop_host_->AddInkDropLayer(root_layer_.get()); + } +} + +void InkDropImpl::RemoveRootLayerFromHostIfNeeded() { + if (root_layer_added_to_host_ && !hover_ && !ink_drop_ripple_) { + root_layer_added_to_host_ = false; + ink_drop_host_->RemoveInkDropLayer(root_layer_.get()); + } +} + +bool InkDropImpl::IsHoverFadingInOrVisible() const { + return hover_ && hover_->IsFadingInOrVisible(); +} + +// ----------------------------------------------------------------------------- +// views::InkDropRippleObserver: + +void InkDropImpl::AnimationStarted(InkDropState ink_drop_state) {} + +void InkDropImpl::AnimationEnded(InkDropState ink_drop_state, + InkDropAnimationEndedReason reason) { + if (reason != InkDropAnimationEndedReason::SUCCESS) + return; + if (ShouldAnimateToHidden(ink_drop_state)) { + ink_drop_ripple_->AnimateToState(views::InkDropState::HIDDEN); + } else if (ink_drop_state == views::InkDropState::HIDDEN) { + if (is_hovered_) + StartHoverAfterRippleTimer(); + // TODO(bruthig): Investigate whether creating and destroying + // InkDropRipples is expensive and consider creating an + // InkDropRipplePool. See www.crbug.com/522175. + DestroyInkDropRipple(); + } +} + +// ----------------------------------------------------------------------------- +// views::InkDropHoverObserver: + +void InkDropImpl::AnimationStarted(InkDropHover::AnimationType animation_type) { +} + +void InkDropImpl::AnimationEnded(InkDropHover::AnimationType animation_type, + InkDropAnimationEndedReason reason) { + if (animation_type == InkDropHover::FADE_OUT && + reason == InkDropAnimationEndedReason::SUCCESS) { + DestroyInkDropHover(); + } +} + +void InkDropImpl::SetHoveredInternal(bool is_hovered, + base::TimeDelta animation_duration, + bool explode) { + StopHoverAfterRippleTimer(); + + if (IsHoverFadingInOrVisible() == is_hovered) + return; + + if (is_hovered) { + CreateInkDropHover(); + if (hover_ && !IsVisible()) + hover_->FadeIn(animation_duration); + } else { + hover_->FadeOut(animation_duration, explode); + } +} + +void InkDropImpl::StartHoverAfterRippleTimer() { + StopHoverAfterRippleTimer(); + + if (!hover_after_ripple_timer_) + hover_after_ripple_timer_.reset(new base::OneShotTimer); + + hover_after_ripple_timer_->Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kHoverFadeInAfterRippleDelayInMs), + base::Bind(&InkDropImpl::HoverAfterRippleTimerFired, + base::Unretained(this))); +} + +void InkDropImpl::StopHoverAfterRippleTimer() { + if (hover_after_ripple_timer_) + hover_after_ripple_timer_.reset(); +} + +void InkDropImpl::HoverAfterRippleTimerFired() { + SetHoveredInternal(true, base::TimeDelta::FromMilliseconds( + kHoverFadeInAfterRippleDurationInMs), + true); + hover_after_ripple_timer_.reset(); +} + +} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_impl.h b/chromium/ui/views/animation/ink_drop_impl.h index f39e4b9dd8a..dec07a9a981 100644 --- a/chromium/ui/views/animation/ink_drop_animation_controller_impl.h +++ b/chromium/ui/views/animation/ink_drop_impl.h @@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_IMPL_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_IMPL_H_ +#ifndef UI_VIEWS_ANIMATION_INK_DROP_IMPL_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_IMPL_H_ + +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -#include "ui/views/animation/ink_drop_animation_controller.h" -#include "ui/views/animation/ink_drop_animation_observer.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_hover_observer.h" +#include "ui/views/animation/ink_drop_ripple_observer.h" #include "ui/views/views_export.h" namespace base { @@ -20,26 +21,25 @@ class Timer; namespace views { namespace test { -class InkDropAnimationControllerImplTestApi; +class InkDropImplTestApi; } // namespace test -class InkDropAnimation; +class InkDropRipple; class InkDropHost; class InkDropHover; -class InkDropAnimationControllerFactoryTest; +class InkDropFactoryTest; -// A functional implementation of an InkDropAnimationController. -class VIEWS_EXPORT InkDropAnimationControllerImpl - : public InkDropAnimationController, - public InkDropAnimationObserver, - public InkDropHoverObserver { +// A functional implementation of an InkDrop. +class VIEWS_EXPORT InkDropImpl : public InkDrop, + public InkDropRippleObserver, + public InkDropHoverObserver { public: - // Constructs an ink drop controller that will attach the ink drop to the - // given |ink_drop_host|. - explicit InkDropAnimationControllerImpl(InkDropHost* ink_drop_host); - ~InkDropAnimationControllerImpl() override; + // Constructs an ink drop that will attach the ink drop to the given + // |ink_drop_host|. + explicit InkDropImpl(InkDropHost* ink_drop_host); + ~InkDropImpl() override; - // InkDropAnimationController: + // InkDrop: InkDropState GetTargetInkDropState() const override; bool IsVisible() const override; void AnimateToState(InkDropState ink_drop_state) override; @@ -47,18 +47,18 @@ class VIEWS_EXPORT InkDropAnimationControllerImpl void SetHovered(bool is_hovered) override; private: - friend class test::InkDropAnimationControllerImplTestApi; + friend class test::InkDropImplTestApi; - // Destroys |ink_drop_animation_| if it's targeted to the HIDDEN state. + // Destroys |ink_drop_ripple_| if it's targeted to the HIDDEN state. void DestroyHiddenTargetedAnimations(); - // Creates a new InkDropAnimation and sets it to |ink_drop_animation_|. If - // |ink_drop_animation_| wasn't null then it will be destroyed using - // DestroyInkDropAnimation(). - void CreateInkDropAnimation(); + // Creates a new InkDropRipple and sets it to |ink_drop_ripple_|. If + // |ink_drop_ripple_| wasn't null then it will be destroyed using + // DestroyInkDropRipple(). + void CreateInkDropRipple(); - // Destroys the current |ink_drop_animation_|. - void DestroyInkDropAnimation(); + // Destroys the current |ink_drop_ripple_|. + void DestroyInkDropRipple(); // Creates a new InkDropHover and sets it to |hover_|. If |hover_| wasn't null // then it will be destroyed using DestroyInkDropHover(). @@ -79,7 +79,7 @@ class VIEWS_EXPORT InkDropAnimationControllerImpl // is visible. bool IsHoverFadingInOrVisible() const; - // views::InkDropAnimationObserver: + // views::InkDropRippleObserver: void AnimationStarted(InkDropState ink_drop_state) override; void AnimationEnded(InkDropState ink_drop_state, InkDropAnimationEndedReason reason) override; @@ -97,45 +97,45 @@ class VIEWS_EXPORT InkDropAnimationControllerImpl base::TimeDelta animation_duration, bool explode); - // Starts the |hover_after_animation_timer_| timer. This will stop the current - // |hover_after_animation_timer_| instance if it exists. - void StartHoverAfterAnimationTimer(); + // Starts the |hover_after_ripple_timer_| timer. This will stop the current + // |hover_after_ripple_timer_| instance if it exists. + void StartHoverAfterRippleTimer(); - // Stops and destroys the current |hover_after_animation_timer_| instance. - void StopHoverAfterAnimationTimer(); + // Stops and destroys the current |hover_after_ripple_timer_| instance. + void StopHoverAfterRippleTimer(); - // Callback for when the |hover_after_animation_timer_| fires. - void HoverAfterAnimationTimerFired(); + // Callback for when the |hover_after_ripple_timer_| fires. + void HoverAfterRippleTimerFired(); // The host of the ink drop. Used to poll for information such as whether the // hover should be shown or not. InkDropHost* ink_drop_host_; - // The root Layer that parents the InkDropAnimation layers and the - // InkDropHover layers. The |root_layer_| is the one that is added and removed - // from the InkDropHost. - scoped_ptr<ui::Layer> root_layer_; + // The root Layer that parents the InkDropRipple layers and the InkDropHover + // layers. The |root_layer_| is the one that is added and removed from the + // InkDropHost. + std::unique_ptr<ui::Layer> root_layer_; // True when the |root_layer_| has been added to the |ink_drop_host_|. bool root_layer_added_to_host_; // The current InkDropHover. Lazily created using CreateInkDropHover(); - scoped_ptr<InkDropHover> hover_; + std::unique_ptr<InkDropHover> hover_; // Tracks the logical hovered state of |this| as manipulated by the public // SetHovered() function. bool is_hovered_; - // The current InkDropAnimation. Created on demand using - // CreateInkDropAnimation(). - scoped_ptr<InkDropAnimation> ink_drop_animation_; + // The current InkDropRipple. Created on demand using CreateInkDropRipple(). + std::unique_ptr<InkDropRipple> ink_drop_ripple_; - // The timer used to delay the hover fade in after an ink drop animation. - scoped_ptr<base::Timer> hover_after_animation_timer_; + // The timer used to delay the hover fade in after an ink drop ripple + // animation. + std::unique_ptr<base::Timer> hover_after_ripple_timer_; - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImpl); + DISALLOW_COPY_AND_ASSIGN(InkDropImpl); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_IMPL_H_ +#endif // UI_VIEWS_ANIMATION_INK_DROP_IMPL_H_ diff --git a/chromium/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc b/chromium/ui/views/animation/ink_drop_impl_unittest.cc index 75e1d4cea76..ef480e051c7 100644 --- a/chromium/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc +++ b/chromium/ui/views/animation/ink_drop_impl_unittest.cc @@ -2,84 +2,80 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/animation/ink_drop_animation_controller_impl.h" +#include "ui/views/animation/ink_drop_impl.h" #include "base/macros.h" #include "base/test/test_simple_task_runner.h" -#include "base/thread_task_runner_handle.h" +#include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/animation/ink_drop_animation.h" -#include "ui/views/animation/test/ink_drop_animation_controller_impl_test_api.h" +#include "ui/views/animation/ink_drop_ripple.h" +#include "ui/views/animation/test/ink_drop_impl_test_api.h" #include "ui/views/animation/test/test_ink_drop_host.h" namespace views { -// NOTE: The InkDropAnimationControllerImpl class is also tested by the -// InkDropAnimationControllerFactoryTest tests. -class InkDropAnimationControllerImplTest : public testing::Test { +// NOTE: The InkDropImpl class is also tested by the InkDropFactoryTest tests. +class InkDropImplTest : public testing::Test { public: - InkDropAnimationControllerImplTest(); - ~InkDropAnimationControllerImplTest() override; + InkDropImplTest(); + ~InkDropImplTest() override; protected: TestInkDropHost ink_drop_host_; // The test target. - InkDropAnimationControllerImpl ink_drop_animation_controller_; + InkDropImpl ink_drop_; // Allows privileged access to the the |ink_drop_hover_|. - test::InkDropAnimationControllerImplTestApi test_api_; + test::InkDropImplTestApi test_api_; - // Used to control the tasks scheduled by the InkDropAnimationControllerImpl's - // Timer. + // Used to control the tasks scheduled by the InkDropImpl's Timer. scoped_refptr<base::TestSimpleTaskRunner> task_runner_; // Required by base::Timer's. - scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; + std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; private: - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerImplTest); + DISALLOW_COPY_AND_ASSIGN(InkDropImplTest); }; -InkDropAnimationControllerImplTest::InkDropAnimationControllerImplTest() - : ink_drop_animation_controller_(&ink_drop_host_), - test_api_(&ink_drop_animation_controller_), +InkDropImplTest::InkDropImplTest() + : ink_drop_(&ink_drop_host_), + test_api_(&ink_drop_), task_runner_(new base::TestSimpleTaskRunner), thread_task_runner_handle_( new base::ThreadTaskRunnerHandle(task_runner_)) { ink_drop_host_.set_disable_timers_for_test(true); } -InkDropAnimationControllerImplTest::~InkDropAnimationControllerImplTest() {} +InkDropImplTest::~InkDropImplTest() {} -TEST_F(InkDropAnimationControllerImplTest, SetHoveredIsFadingInOrVisible) { +TEST_F(InkDropImplTest, SetHoveredIsFadingInOrVisible) { ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible()); test_api_.CompleteAnimations(); - ink_drop_animation_controller_.SetHovered(false); + ink_drop_.SetHovered(false); EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible()); } -TEST_F(InkDropAnimationControllerImplTest, - HoverDoesntFadeInAfterAnimationIfHoverNotSet) { +TEST_F(InkDropImplTest, HoverDoesntFadeInAfterAnimationIfHoverNotSet) { ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_.SetHovered(false); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED); + ink_drop_.SetHovered(false); + ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED); test_api_.CompleteAnimations(); EXPECT_FALSE(task_runner_->HasPendingTask()); EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible()); } -TEST_F(InkDropAnimationControllerImplTest, - HoverFadesInAfterAnimationWhenHostIsHovered) { +TEST_F(InkDropImplTest, HoverFadesInAfterAnimationWhenHostIsHovered) { ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_.SetHovered(true); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED); + ink_drop_.SetHovered(true); + ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED); test_api_.CompleteAnimations(); EXPECT_TRUE(task_runner_->HasPendingTask()); @@ -89,11 +85,10 @@ TEST_F(InkDropAnimationControllerImplTest, EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible()); } -TEST_F(InkDropAnimationControllerImplTest, - HoverDoesntFadeInAfterAnimationWhenHostIsNotHovered) { +TEST_F(InkDropImplTest, HoverDoesntFadeInAfterAnimationWhenHostIsNotHovered) { ink_drop_host_.set_should_show_hover(false); - ink_drop_animation_controller_.SetHovered(true); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED); + ink_drop_.SetHovered(true); + ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED); test_api_.CompleteAnimations(); EXPECT_TRUE(task_runner_->HasPendingTask()); @@ -103,86 +98,83 @@ TEST_F(InkDropAnimationControllerImplTest, EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible()); } -TEST_F(InkDropAnimationControllerImplTest, - HoveredStateNotVisibleOrFadingInAfterAnimateToState) { +TEST_F(InkDropImplTest, HoveredStateNotVisibleOrFadingInAfterAnimateToState) { ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); test_api_.CompleteAnimations(); EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible()); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_TRIGGERED); + ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED); EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible()); } // Verifies that there is not a crash when setting hovered state and the host // returns null for the hover. -TEST_F(InkDropAnimationControllerImplTest, - SetHoveredFalseWorksWhenNoInkDropHoverExists) { +TEST_F(InkDropImplTest, SetHoveredFalseWorksWhenNoInkDropHoverExists) { ink_drop_host_.set_should_show_hover(false); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_FALSE(test_api_.hover()); - ink_drop_animation_controller_.SetHovered(false); + ink_drop_.SetHovered(false); EXPECT_FALSE(test_api_.hover()); } -TEST_F(InkDropAnimationControllerImplTest, HoverFadesOutOnSnapToActivated) { +TEST_F(InkDropImplTest, HoverFadesOutOnSnapToActivated) { ink_drop_host_.set_should_show_hover(true); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); test_api_.CompleteAnimations(); EXPECT_TRUE(test_api_.IsHoverFadingInOrVisible()); - ink_drop_animation_controller_.SnapToActivated(); + ink_drop_.SnapToActivated(); EXPECT_FALSE(test_api_.IsHoverFadingInOrVisible()); } -TEST_F(InkDropAnimationControllerImplTest, LayersRemovedFromHostAfterHover) { +TEST_F(InkDropImplTest, LayersRemovedFromHostAfterHover) { ink_drop_host_.set_should_show_hover(true); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); test_api_.CompleteAnimations(); - ink_drop_animation_controller_.SetHovered(false); + ink_drop_.SetHovered(false); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); test_api_.CompleteAnimations(); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); } -TEST_F(InkDropAnimationControllerImplTest, LayersRemovedFromHostAfterInkDrop) { +TEST_F(InkDropImplTest, LayersRemovedFromHostAfterInkDrop) { ink_drop_host_.set_should_show_hover(true); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_.AnimateToState(InkDropState::ACTION_PENDING); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::HIDDEN); + ink_drop_.AnimateToState(InkDropState::HIDDEN); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); test_api_.CompleteAnimations(); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); } -TEST_F(InkDropAnimationControllerImplTest, - LayersAddedToHostWhenHoverOrInkDropVisible) { +TEST_F(InkDropImplTest, LayersAddedToHostWhenHoverOrInkDropVisible) { ink_drop_host_.set_should_show_hover(true); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_.AnimateToState(InkDropState::ACTION_PENDING); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::HIDDEN); + ink_drop_.AnimateToState(InkDropState::HIDDEN); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); test_api_.CompleteAnimations(); @@ -196,19 +188,18 @@ TEST_F(InkDropAnimationControllerImplTest, EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); } -TEST_F(InkDropAnimationControllerImplTest, - LayersNotAddedToHostWhenHoverTimeFires) { +TEST_F(InkDropImplTest, LayersNotAddedToHostWhenHoverTimeFires) { ink_drop_host_.set_should_show_hover(true); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_.AnimateToState(InkDropState::ACTION_PENDING); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.AnimateToState(InkDropState::HIDDEN); + ink_drop_.AnimateToState(InkDropState::HIDDEN); test_api_.CompleteAnimations(); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); @@ -220,21 +211,20 @@ TEST_F(InkDropAnimationControllerImplTest, EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); } -TEST_F(InkDropAnimationControllerImplTest, - LayersArentRemovedWhenPreemptingFadeOut) { +TEST_F(InkDropImplTest, LayersArentRemovedWhenPreemptingFadeOut) { ink_drop_host_.set_should_show_hover(true); EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); test_api_.CompleteAnimations(); - ink_drop_animation_controller_.SetHovered(false); + ink_drop_.SetHovered(false); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); - ink_drop_animation_controller_.SetHovered(true); + ink_drop_.SetHovered(true); EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers()); } diff --git a/chromium/ui/views/animation/ink_drop_animation.cc b/chromium/ui/views/animation/ink_drop_ripple.cc index 214716da23a..006e2f81259 100644 --- a/chromium/ui/views/animation/ink_drop_animation.cc +++ b/chromium/ui/views/animation/ink_drop_ripple.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/animation/ink_drop_animation.h" +#include "ui/views/animation/ink_drop_ripple.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -13,9 +13,9 @@ namespace views { -const double InkDropAnimation::kSlowAnimationDurationFactor = 3.0; +const double InkDropRipple::kSlowAnimationDurationFactor = 3.0; -bool InkDropAnimation::UseFastAnimations() { +bool InkDropRipple::UseFastAnimations() { static bool fast = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( (::switches::kMaterialDesignInkDropAnimationSpeed)) != @@ -23,15 +23,15 @@ bool InkDropAnimation::UseFastAnimations() { return fast; } -const float InkDropAnimation::kHiddenOpacity = 0.f; -const float InkDropAnimation::kVisibleOpacity = 0.175f; +const float InkDropRipple::kHiddenOpacity = 0.f; +const float InkDropRipple::kVisibleOpacity = 0.175f; -InkDropAnimation::InkDropAnimation() +InkDropRipple::InkDropRipple() : target_ink_drop_state_(InkDropState::HIDDEN), observer_(nullptr) {} -InkDropAnimation::~InkDropAnimation() {} +InkDropRipple::~InkDropRipple() {} -void InkDropAnimation::AnimateToState(InkDropState ink_drop_state) { +void InkDropRipple::AnimateToState(InkDropState ink_drop_state) { // Does not return early if |target_ink_drop_state_| == |ink_drop_state| for // two reasons. // 1. The attached observers must be notified of all animations started and @@ -45,9 +45,9 @@ void InkDropAnimation::AnimateToState(InkDropState ink_drop_state) { // |animation_observer|. ui::CallbackLayerAnimationObserver* animation_observer = new ui::CallbackLayerAnimationObserver( - base::Bind(&InkDropAnimation::AnimationStartedCallback, + base::Bind(&InkDropRipple::AnimationStartedCallback, base::Unretained(this), ink_drop_state), - base::Bind(&InkDropAnimation::AnimationEndedCallback, + base::Bind(&InkDropRipple::AnimationEndedCallback, base::Unretained(this), ink_drop_state)); InkDropState old_ink_drop_state = target_ink_drop_state_; @@ -68,7 +68,7 @@ void InkDropAnimation::AnimateToState(InkDropState ink_drop_state) { // AnimationEndedCallback which can delete |this|. } -void InkDropAnimation::SnapToActivated() { +void InkDropRipple::SnapToActivated() { AbortAllAnimations(); // |animation_observer| will be deleted when AnimationEndedCallback() returns // true. @@ -76,32 +76,32 @@ void InkDropAnimation::SnapToActivated() { // |animation_observer|. ui::CallbackLayerAnimationObserver* animation_observer = new ui::CallbackLayerAnimationObserver( - base::Bind(&InkDropAnimation::AnimationStartedCallback, + base::Bind(&InkDropRipple::AnimationStartedCallback, base::Unretained(this), InkDropState::ACTIVATED), - base::Bind(&InkDropAnimation::AnimationEndedCallback, + base::Bind(&InkDropRipple::AnimationEndedCallback, base::Unretained(this), InkDropState::ACTIVATED)); GetRootLayer()->SetVisible(true); target_ink_drop_state_ = InkDropState::ACTIVATED; animation_observer->SetActive(); } -void InkDropAnimation::HideImmediately() { +void InkDropRipple::HideImmediately() { AbortAllAnimations(); SetStateToHidden(); target_ink_drop_state_ = InkDropState::HIDDEN; } -test::InkDropAnimationTestApi* InkDropAnimation::GetTestApi() { +test::InkDropRippleTestApi* InkDropRipple::GetTestApi() { return nullptr; } -void InkDropAnimation::AnimationStartedCallback( +void InkDropRipple::AnimationStartedCallback( InkDropState ink_drop_state, const ui::CallbackLayerAnimationObserver& observer) { observer_->AnimationStarted(ink_drop_state); } -bool InkDropAnimation::AnimationEndedCallback( +bool InkDropRipple::AnimationEndedCallback( InkDropState ink_drop_state, const ui::CallbackLayerAnimationObserver& observer) { if (ink_drop_state == InkDropState::HIDDEN) diff --git a/chromium/ui/views/animation/ink_drop_animation.h b/chromium/ui/views/animation/ink_drop_ripple.h index b00be7db26f..738bb9ba252 100644 --- a/chromium/ui/views/animation/ink_drop_animation.h +++ b/chromium/ui/views/animation/ink_drop_ripple.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_H_ +#ifndef UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_H_ #include "base/macros.h" #include "ui/gfx/geometry/point.h" -#include "ui/views/animation/ink_drop_animation_observer.h" +#include "ui/views/animation/ink_drop_ripple_observer.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/views_export.h" @@ -20,15 +20,15 @@ class LayerAnimationObserver; namespace views { namespace test { -class InkDropAnimationTestApi; +class InkDropRippleTestApi; } // namespace test // Simple base class for animations that provide visual feedback for View state. -// Manages the attached InkDropAnimationObservers. +// Manages the attached InkDropRippleObservers. // // TODO(bruthig): Document the ink drop ripple on chromium.org and add a link to // the doc here. -class VIEWS_EXPORT InkDropAnimation { +class VIEWS_EXPORT InkDropRipple { public: // TODO(bruthig): Remove UseFastAnimations() and kSlowAnimationDurationFactor. // See http://crbug.com/584681 @@ -47,16 +47,14 @@ class VIEWS_EXPORT InkDropAnimation { // The opacity of the ink drop when it is visible. static const float kVisibleOpacity; - InkDropAnimation(); - virtual ~InkDropAnimation(); + InkDropRipple(); + virtual ~InkDropRipple(); // In the event that an animation is in progress for ink drop state 's1' and // an animation to a new state 's2' is triggered, then // AnimationEnded(s1, PRE_EMPTED) will be called before // AnimationStarted(s2). - void set_observer(InkDropAnimationObserver* observer) { - observer_ = observer; - } + void set_observer(InkDropRippleObserver* observer) { observer_ = observer; } // Animates from the current InkDropState to the new |ink_drop_state|. // @@ -68,8 +66,8 @@ class VIEWS_EXPORT InkDropAnimation { // Immediately aborts all in-progress animations and hides the ink drop. // - // NOTE: This will NOT raise InkDropAnimation(Started|Ended) events for the - // state transition to HIDDEN! + // NOTE: This will NOT raise Animation(Started|Ended) events for the state + // transition to HIDDEN! void HideImmediately(); // Immediately snaps the ink drop to the ACTIVATED target state. All pending @@ -88,7 +86,7 @@ class VIEWS_EXPORT InkDropAnimation { // Returns a test api to access internals of this. Default implmentations // should return nullptr and test specific subclasses can override to return // an instance. - virtual test::InkDropAnimationTestApi* GetTestApi(); + virtual test::InkDropRippleTestApi* GetTestApi(); protected: // Animates the ripple from the |old_ink_drop_state| to the @@ -121,11 +119,11 @@ class VIEWS_EXPORT InkDropAnimation { // The target InkDropState. InkDropState target_ink_drop_state_; - InkDropAnimationObserver* observer_; + InkDropRippleObserver* observer_; - DISALLOW_COPY_AND_ASSIGN(InkDropAnimation); + DISALLOW_COPY_AND_ASSIGN(InkDropRipple); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_H_ +#endif // UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_H_ diff --git a/chromium/ui/views/animation/ink_drop_animation_observer.h b/chromium/ui/views/animation/ink_drop_ripple_observer.h index 831a6be06b3..b294b3ae95c 100644 --- a/chromium/ui/views/animation/ink_drop_animation_observer.h +++ b/chromium/ui/views/animation/ink_drop_ripple_observer.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_OBSERVER_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_OBSERVER_H_ +#ifndef UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_OBSERVER_H_ +#define UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_OBSERVER_H_ #include <string> @@ -14,8 +14,8 @@ namespace views { -// Observer to attach to an InkDropAnimation. -class VIEWS_EXPORT InkDropAnimationObserver { +// Observer to attach to an InkDropRipple. +class VIEWS_EXPORT InkDropRippleObserver { public: // An animation for the given |ink_drop_state| has started. virtual void AnimationStarted(InkDropState ink_drop_state) = 0; @@ -29,13 +29,13 @@ class VIEWS_EXPORT InkDropAnimationObserver { InkDropAnimationEndedReason reason) = 0; protected: - InkDropAnimationObserver() = default; - virtual ~InkDropAnimationObserver() = default; + InkDropRippleObserver() = default; + virtual ~InkDropRippleObserver() = default; private: - DISALLOW_COPY_AND_ASSIGN(InkDropAnimationObserver); + DISALLOW_COPY_AND_ASSIGN(InkDropRippleObserver); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_OBSERVER_H_ +#endif // UI_VIEWS_ANIMATION_INK_DROP_RIPPLE_OBSERVER_H_ diff --git a/chromium/ui/views/animation/ink_drop_ripple_unittest.cc b/chromium/ui/views/animation/ink_drop_ripple_unittest.cc new file mode 100644 index 00000000000..2925af02b56 --- /dev/null +++ b/chromium/ui/views/animation/ink_drop_ripple_unittest.cc @@ -0,0 +1,348 @@ +// Copyright 2015 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 "ui/views/animation/ink_drop_ripple.h" + +#include <memory> + +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_ripple_observer.h" +#include "ui/views/animation/ink_drop_state.h" +#include "ui/views/animation/square_ink_drop_ripple.h" +#include "ui/views/animation/test/flood_fill_ink_drop_ripple_test_api.h" +#include "ui/views/animation/test/ink_drop_ripple_test_api.h" +#include "ui/views/animation/test/square_ink_drop_ripple_test_api.h" +#include "ui/views/animation/test/test_ink_drop_ripple_observer.h" + +namespace views { +namespace test { + +// Represents all the derivatives of the InkDropRipple class. To be used with +// the InkDropRippleTest fixture to test all derviatives. +enum InkDropRippleTestTypes { + SQUARE_INK_DROP_RIPPLE, + FLOOD_FILL_INK_DROP_RIPPLE +}; + +// Test fixture for all InkDropRipple class derivatives. +// +// To add a new derivative: +// 1. Add a value to the InkDropRippleTestTypes enum. +// 2. Implement set up and tear down code for the new enum value in +// InkDropRippleTest() and +// ~InkDropRippleTest(). +// 3. Add the new enum value to the INSTANTIATE_TEST_CASE_P) Values list. +class InkDropRippleTest + : public testing::TestWithParam<InkDropRippleTestTypes> { + public: + InkDropRippleTest(); + ~InkDropRippleTest() override; + + protected: + TestInkDropRippleObserver observer_; + + std::unique_ptr<InkDropRipple> ink_drop_ripple_; + + std::unique_ptr<InkDropRippleTestApi> test_api_; + + private: + DISALLOW_COPY_AND_ASSIGN(InkDropRippleTest); +}; + +InkDropRippleTest::InkDropRippleTest() { + switch (GetParam()) { + case SQUARE_INK_DROP_RIPPLE: { + SquareInkDropRipple* square_ink_drop_ripple = + new SquareInkDropRipple(gfx::Size(10, 10), 2, gfx::Size(8, 8), 1, + gfx::Point(), SK_ColorBLACK); + ink_drop_ripple_.reset(square_ink_drop_ripple); + test_api_.reset(new SquareInkDropRippleTestApi(square_ink_drop_ripple)); + break; + } + case FLOOD_FILL_INK_DROP_RIPPLE: { + FloodFillInkDropRipple* flood_fill_ink_drop_ripple = + new FloodFillInkDropRipple(gfx::Rect(0, 0, 10, 10), gfx::Point(), + SK_ColorBLACK); + ink_drop_ripple_.reset(flood_fill_ink_drop_ripple); + test_api_.reset( + new FloodFillInkDropRippleTestApi(flood_fill_ink_drop_ripple)); + break; + } + } + ink_drop_ripple_->set_observer(&observer_); + observer_.set_ink_drop_ripple(ink_drop_ripple_.get()); + test_api_->SetDisableAnimationTimers(true); +} + +InkDropRippleTest::~InkDropRippleTest() {} + +// Note: First argument is optional and intentionally left blank. +// (it's a prefix for the generated test cases) +INSTANTIATE_TEST_CASE_P(, + InkDropRippleTest, + testing::Values(SQUARE_INK_DROP_RIPPLE, + FLOOD_FILL_INK_DROP_RIPPLE)); + +TEST_P(InkDropRippleTest, InitialStateAfterConstruction) { + EXPECT_EQ(views::InkDropState::HIDDEN, + ink_drop_ripple_->target_ink_drop_state()); +} + +// Verify no animations are used when animating from HIDDEN to HIDDEN. +TEST_P(InkDropRippleTest, AnimateToHiddenFromInvisibleState) { + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); + + ink_drop_ripple_->AnimateToState(InkDropState::HIDDEN); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); + EXPECT_FALSE(ink_drop_ripple_->IsVisible()); +} + +TEST_P(InkDropRippleTest, AnimateToHiddenFromVisibleState) { + ink_drop_ripple_->AnimateToState(InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + + EXPECT_NE(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); + + ink_drop_ripple_->AnimateToState(InkDropState::HIDDEN); + test_api_->CompleteAnimations(); + + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, ActionPendingOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kVisibleOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, QuickActionOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_TRIGGERED); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, SlowActionPendingOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState( + views::InkDropState::ALTERNATE_ACTION_PENDING); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kVisibleOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, SlowActionOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState( + views::InkDropState::ALTERNATE_ACTION_PENDING); + ink_drop_ripple_->AnimateToState( + views::InkDropState::ALTERNATE_ACTION_TRIGGERED); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, ActivatedOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTIVATED); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kVisibleOpacity, test_api_->GetCurrentOpacity()); +} + +TEST_P(InkDropRippleTest, DeactivatedOpacity) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTIVATED); + ink_drop_ripple_->AnimateToState(views::InkDropState::DEACTIVATED); + test_api_->CompleteAnimations(); + + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); +} + +// Verify animations are aborted during deletion and the +// InkDropRippleObservers are notified. +TEST_P(InkDropRippleTest, AnimationsAbortedDuringDeletion) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_.reset(); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(views::InkDropState::ACTION_PENDING, + observer_.last_animation_ended_context()); + EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, + observer_.last_animation_ended_reason()); +} + +TEST_P(InkDropRippleTest, VerifyObserversAreNotified) { + ink_drop_ripple_->AnimateToState(InkDropState::ACTION_PENDING); + + EXPECT_TRUE(test_api_->HasActiveAnimations()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_TRUE(observer_.AnimationHasNotEnded()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + observer_.last_animation_started_context()); + + test_api_->CompleteAnimations(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + observer_.last_animation_ended_context()); +} + +TEST_P(InkDropRippleTest, VerifyObserversAreNotifiedOfSuccessfulAnimations) { + ink_drop_ripple_->AnimateToState(InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropAnimationEndedReason::SUCCESS, + observer_.last_animation_ended_reason()); +} + +TEST_P(InkDropRippleTest, VerifyObserversAreNotifiedOfPreemptedAnimations) { + ink_drop_ripple_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState(InkDropState::ALTERNATE_ACTION_PENDING); + + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, + observer_.last_animation_ended_reason()); +} + +TEST_P(InkDropRippleTest, InkDropStatesPersistWhenCallingAnimateToState) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTIVATED); + EXPECT_EQ(views::InkDropState::ACTIVATED, + ink_drop_ripple_->target_ink_drop_state()); +} + +TEST_P(InkDropRippleTest, HideImmediatelyWithoutActiveAnimations) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); + + ink_drop_ripple_->HideImmediately(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::HIDDEN, + ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); + EXPECT_FALSE(ink_drop_ripple_->IsVisible()); +} + +// Verifies all active animations are aborted and the InkDropState is set to +// HIDDEN after invoking HideImmediately(). +TEST_P(InkDropRippleTest, HideImmediatelyWithActiveAnimations) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + EXPECT_TRUE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + + ink_drop_ripple_->HideImmediately(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::HIDDEN, + ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + observer_.last_animation_ended_context()); + EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED, + observer_.last_animation_ended_reason()); + + EXPECT_EQ(InkDropRipple::kHiddenOpacity, test_api_->GetCurrentOpacity()); + EXPECT_FALSE(ink_drop_ripple_->IsVisible()); +} + +TEST_P(InkDropRippleTest, SnapToActivatedWithoutActiveAnimations) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::ACTIVATED, ink_drop_ripple_->target_ink_drop_state()); + + ink_drop_ripple_->SnapToActivated(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::ACTIVATED, + ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); + + EXPECT_EQ(InkDropRipple::kVisibleOpacity, test_api_->GetCurrentOpacity()); + EXPECT_TRUE(ink_drop_ripple_->IsVisible()); +} + +// Verifies all active animations are aborted and the InkDropState is set to +// ACTIVATED after invoking SnapToActivated(). +TEST_P(InkDropRippleTest, SnapToActivatedWithActiveAnimations) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + EXPECT_TRUE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::ACTIVATED, ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + + ink_drop_ripple_->SnapToActivated(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::ACTIVATED, + ink_drop_ripple_->target_ink_drop_state()); + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropState::ACTIVATED, observer_.last_animation_ended_context()); + EXPECT_EQ(InkDropAnimationEndedReason::SUCCESS, + observer_.last_animation_ended_reason()); + + EXPECT_EQ(InkDropRipple::kVisibleOpacity, test_api_->GetCurrentOpacity()); + EXPECT_TRUE(ink_drop_ripple_->IsVisible()); +} + +TEST_P(InkDropRippleTest, AnimateToVisibleFromHidden) { + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + EXPECT_TRUE(ink_drop_ripple_->IsVisible()); +} + +// Verifies that the value of InkDropRipple::target_ink_drop_state() returns +// the most recent value passed to AnimateToState() when notifying observers +// that an animation has started within the AnimateToState() function call. +TEST_P(InkDropRippleTest, TargetInkDropStateOnAnimationStarted) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState(views::InkDropState::HIDDEN); + + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(views::InkDropState::HIDDEN, + observer_.target_state_at_last_animation_started()); +} + +// Verifies that the value of InkDropRipple::target_ink_drop_state() returns +// the most recent value passed to AnimateToState() when notifying observers +// that an animation has ended within the AnimateToState() function call. +TEST_P(InkDropRippleTest, TargetInkDropStateOnAnimationEnded) { + ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); + ink_drop_ripple_->AnimateToState(views::InkDropState::HIDDEN); + + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(views::InkDropState::HIDDEN, + observer_.target_state_at_last_animation_ended()); +} + +} // namespace test +} // namespace views diff --git a/chromium/ui/views/animation/ink_drop_state.h b/chromium/ui/views/animation/ink_drop_state.h index 2456455c5da..91214d39d9a 100644 --- a/chromium/ui/views/animation/ink_drop_state.h +++ b/chromium/ui/views/animation/ink_drop_state.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_ANIMATION_INK_DROP_STATE_H_ #define UI_VIEWS_ANIMATION_INK_DROP_STATE_H_ +#include <iosfwd> #include <string> #include "ui/views/views_export.h" @@ -36,7 +37,12 @@ enum class InkDropState { }; // Returns a human readable string for |state|. Useful for logging. -std::string ToString(InkDropState state); +VIEWS_EXPORT std::string ToString(InkDropState state); + +// This is declared here for use in gtest-based unit tests but is defined in +// the views_test_support target. Depend on that to use this in your unit test. +// This should not be used in production code - call ToString() instead. +void PrintTo(InkDropState ink_drop_state, ::std::ostream* os); } // namespace views diff --git a/chromium/ui/views/animation/scroll_animator.h b/chromium/ui/views/animation/scroll_animator.h index 5473315f7f7..d9b64c99a41 100644 --- a/chromium/ui/views/animation/scroll_animator.h +++ b/chromium/ui/views/animation/scroll_animator.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_ANIMATION_SCROLL_ANIMATOR_H_ #define UI_VIEWS_ANIMATION_SCROLL_ANIMATOR_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/views/views_export.h" @@ -53,7 +54,7 @@ class VIEWS_EXPORT ScrollAnimator : public gfx::AnimationDelegate { float duration_; float acceleration_; - scoped_ptr<gfx::SlideAnimation> animation_; + std::unique_ptr<gfx::SlideAnimation> animation_; DISALLOW_COPY_AND_ASSIGN(ScrollAnimator); }; diff --git a/chromium/ui/views/animation/square_ink_drop_animation.cc b/chromium/ui/views/animation/square_ink_drop_ripple.cc index 58320aa8246..142a3a6ff77 100644 --- a/chromium/ui/views/animation/square_ink_drop_animation.cc +++ b/chromium/ui/views/animation/square_ink_drop_ripple.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/animation/square_ink_drop_animation.h" +#include "ui/views/animation/square_ink_drop_ripple.h" #include <algorithm> @@ -127,9 +127,9 @@ int kAnimationDurationInMs[] = { // Returns the InkDropState sub animation duration for the given |state|. base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) { return base::TimeDelta::FromMilliseconds( - (views::InkDropAnimation::UseFastAnimations() + (views::InkDropRipple::UseFastAnimations() ? 1 - : views::InkDropAnimation::kSlowAnimationDurationFactor) * + : views::InkDropRipple::kSlowAnimationDurationFactor) * kAnimationDurationInMs[state]); } @@ -163,12 +163,12 @@ gfx::Transform CalculateRectTransform(const gfx::Point& drawn_center_point, namespace views { -SquareInkDropAnimation::SquareInkDropAnimation(const gfx::Size& large_size, - int large_corner_radius, - const gfx::Size& small_size, - int small_corner_radius, - const gfx::Point& center_point, - SkColor color) +SquareInkDropRipple::SquareInkDropRipple(const gfx::Size& large_size, + int large_corner_radius, + const gfx::Size& small_size, + int small_corner_radius, + const gfx::Point& center_point, + SkColor color) : large_size_(large_size), large_corner_radius_(large_corner_radius), small_size_(small_size), @@ -178,7 +178,7 @@ SquareInkDropAnimation::SquareInkDropAnimation(const gfx::Size& large_size, std::min(large_size_.width(), large_size_.height()) / 2)), rect_layer_delegate_(new RectangleLayerDelegate(color, large_size_)), root_layer_(ui::LAYER_NOT_DRAWN) { - root_layer_.set_name("SquareInkDropAnimation:ROOT_LAYER"); + root_layer_.set_name("SquareInkDropRipple:ROOT_LAYER"); for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) AddPaintLayer(static_cast<PaintedShape>(i)); @@ -193,33 +193,33 @@ SquareInkDropAnimation::SquareInkDropAnimation(const gfx::Size& large_size, SetStateToHidden(); } -SquareInkDropAnimation::~SquareInkDropAnimation() { +SquareInkDropRipple::~SquareInkDropRipple() { // Explicitly aborting all the animations ensures all callbacks are invoked // while this instance still exists. AbortAllAnimations(); } -void SquareInkDropAnimation::SnapToActivated() { - InkDropAnimation::SnapToActivated(); +void SquareInkDropRipple::SnapToActivated() { + InkDropRipple::SnapToActivated(); SetOpacity(kVisibleOpacity); InkDropTransforms transforms; GetActivatedTargetTransforms(&transforms); SetTransforms(transforms); } -ui::Layer* SquareInkDropAnimation::GetRootLayer() { +ui::Layer* SquareInkDropRipple::GetRootLayer() { return &root_layer_; } -bool SquareInkDropAnimation::IsVisible() const { +bool SquareInkDropRipple::IsVisible() const { return root_layer_.visible(); } -float SquareInkDropAnimation::GetCurrentOpacity() const { +float SquareInkDropRipple::GetCurrentOpacity() const { return root_layer_.opacity(); } -std::string SquareInkDropAnimation::ToLayerName(PaintedShape painted_shape) { +std::string SquareInkDropRipple::ToLayerName(PaintedShape painted_shape) { switch (painted_shape) { case TOP_LEFT_CIRCLE: return "TOP_LEFT_CIRCLE"; @@ -240,7 +240,7 @@ std::string SquareInkDropAnimation::ToLayerName(PaintedShape painted_shape) { return "UNKNOWN"; } -void SquareInkDropAnimation::AnimateStateChange( +void SquareInkDropRipple::AnimateStateChange( InkDropState old_ink_drop_state, InkDropState new_ink_drop_state, ui::LayerAnimationObserver* animation_observer) { @@ -379,22 +379,22 @@ void SquareInkDropAnimation::AnimateStateChange( } } -void SquareInkDropAnimation::SetStateToHidden() { +void SquareInkDropRipple::SetStateToHidden() { InkDropTransforms transforms; // Use non-zero size to avoid visual anomalies. CalculateCircleTransforms(gfx::Size(1, 1), &transforms); SetTransforms(transforms); - root_layer_.SetOpacity(InkDropAnimation::kHiddenOpacity); + root_layer_.SetOpacity(InkDropRipple::kHiddenOpacity); root_layer_.SetVisible(false); } -void SquareInkDropAnimation::AbortAllAnimations() { +void SquareInkDropRipple::AbortAllAnimations() { root_layer_.GetAnimator()->AbortAllAnimations(); for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) painted_layers_[i]->GetAnimator()->AbortAllAnimations(); } -void SquareInkDropAnimation::AnimateToTransforms( +void SquareInkDropRipple::AnimateToTransforms( const InkDropTransforms transforms, base::TimeDelta duration, ui::LayerAnimator::PreemptionStrategy preemption_strategy, @@ -418,16 +418,16 @@ void SquareInkDropAnimation::AnimateToTransforms( } } -void SquareInkDropAnimation::SetTransforms(const InkDropTransforms transforms) { +void SquareInkDropRipple::SetTransforms(const InkDropTransforms transforms) { for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) painted_layers_[i]->SetTransform(transforms[i]); } -void SquareInkDropAnimation::SetOpacity(float opacity) { +void SquareInkDropRipple::SetOpacity(float opacity) { root_layer_.SetOpacity(opacity); } -void SquareInkDropAnimation::AnimateToOpacity( +void SquareInkDropRipple::AnimateToOpacity( float opacity, base::TimeDelta duration, ui::LayerAnimator::PreemptionStrategy preemption_strategy, @@ -448,14 +448,14 @@ void SquareInkDropAnimation::AnimateToOpacity( animator->StartAnimation(animation_sequence); } -void SquareInkDropAnimation::CalculateCircleTransforms( +void SquareInkDropRipple::CalculateCircleTransforms( const gfx::Size& size, InkDropTransforms* transforms_out) const { CalculateRectTransforms(size, std::min(size.width(), size.height()) / 2.0f, transforms_out); } -void SquareInkDropAnimation::CalculateRectTransforms( +void SquareInkDropRipple::CalculateRectTransforms( const gfx::Size& size, float corner_radius, InkDropTransforms* transforms_out) const { @@ -509,18 +509,18 @@ void SquareInkDropAnimation::CalculateRectTransforms( std::max(kMinimumRectScale, size.height() / rect_delegate_height)); } -void SquareInkDropAnimation::GetCurrentTransforms( +void SquareInkDropRipple::GetCurrentTransforms( InkDropTransforms* transforms_out) const { for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) (*transforms_out)[i] = painted_layers_[i]->transform(); } -void SquareInkDropAnimation::GetActivatedTargetTransforms( +void SquareInkDropRipple::GetActivatedTargetTransforms( InkDropTransforms* transforms_out) const { CalculateRectTransforms(small_size_, small_corner_radius_, transforms_out); } -void SquareInkDropAnimation::AddPaintLayer(PaintedShape painted_shape) { +void SquareInkDropRipple::AddPaintLayer(PaintedShape painted_shape) { ui::LayerDelegate* delegate = nullptr; switch (painted_shape) { case TOP_LEFT_CIRCLE: diff --git a/chromium/ui/views/animation/square_ink_drop_animation.h b/chromium/ui/views/animation/square_ink_drop_ripple.h index d704e7eb4af..dbc05ad6f33 100644 --- a/chromium/ui/views/animation/square_ink_drop_animation.h +++ b/chromium/ui/views/animation/square_ink_drop_ripple.h @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_SQUARE_INK_DROP_ANIMATION_H_ -#define UI_VIEWS_ANIMATION_SQUARE_INK_DROP_ANIMATION_H_ +#ifndef UI_VIEWS_ANIMATION_SQUARE_INK_DROP_RIPPLE_H_ +#define UI_VIEWS_ANIMATION_SQUARE_INK_DROP_RIPPLE_H_ +#include <memory> #include <string> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/layer.h" @@ -17,7 +17,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/transform.h" -#include "ui/views/animation/ink_drop_animation.h" +#include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/views_export.h" @@ -30,10 +30,10 @@ class CircleLayerDelegate; class RectangleLayerDelegate; namespace test { -class SquareInkDropAnimationTestApi; +class SquareInkDropRippleTestApi; } // namespace test -// An ink drop animation that smoothly animates between a circle and a rounded +// An ink drop ripple that smoothly animates between a circle and a rounded // rectangle of different sizes for each of the different InkDropStates. The // final frame for each InkDropState will be bounded by either a |large_size_| // rectangle or a |small_size_| rectangle. @@ -48,23 +48,23 @@ class SquareInkDropAnimationTestApi; // {All InkDropStates} => ACTIVATED // {All InkDropStates} => DEACTIVATED // -class VIEWS_EXPORT SquareInkDropAnimation : public InkDropAnimation { +class VIEWS_EXPORT SquareInkDropRipple : public InkDropRipple { public: - SquareInkDropAnimation(const gfx::Size& large_size, - int large_corner_radius, - const gfx::Size& small_size, - int small_corner_radius, - const gfx::Point& center_point, - SkColor color); - ~SquareInkDropAnimation() override; - - // InkDropAnimation: + SquareInkDropRipple(const gfx::Size& large_size, + int large_corner_radius, + const gfx::Size& small_size, + int small_corner_radius, + const gfx::Point& center_point, + SkColor color); + ~SquareInkDropRipple() override; + + // InkDropRipple: void SnapToActivated() override; ui::Layer* GetRootLayer() override; bool IsVisible() const override; private: - friend class test::SquareInkDropAnimationTestApi; + friend class test::SquareInkDropRippleTestApi; // Enumeration of the different shapes that compose the ink drop. enum PaintedShape { @@ -87,7 +87,7 @@ class VIEWS_EXPORT SquareInkDropAnimation : public InkDropAnimation { float GetCurrentOpacity() const; - // InkDropAnimation: + // InkDropRipple: void AnimateStateChange(InkDropState old_ink_drop_state, InkDropState new_ink_drop_state, ui::LayerAnimationObserver* observer) override; @@ -163,10 +163,10 @@ class VIEWS_EXPORT SquareInkDropAnimation : public InkDropAnimation { int small_corner_radius_; // ui::LayerDelegate to paint circles for all the circle layers. - scoped_ptr<CircleLayerDelegate> circle_layer_delegate_; + std::unique_ptr<CircleLayerDelegate> circle_layer_delegate_; // ui::LayerDelegate to paint rectangles for all the rectangle layers. - scoped_ptr<RectangleLayerDelegate> rect_layer_delegate_; + std::unique_ptr<RectangleLayerDelegate> rect_layer_delegate_; // The root layer that parents the animating layers. The root layer is used to // manipulate opacity and location, and its children are used to manipulate @@ -174,11 +174,11 @@ class VIEWS_EXPORT SquareInkDropAnimation : public InkDropAnimation { ui::Layer root_layer_; // ui::Layers for all of the painted shape layers that compose the ink drop. - scoped_ptr<ui::Layer> painted_layers_[PAINTED_SHAPE_COUNT]; + std::unique_ptr<ui::Layer> painted_layers_[PAINTED_SHAPE_COUNT]; - DISALLOW_COPY_AND_ASSIGN(SquareInkDropAnimation); + DISALLOW_COPY_AND_ASSIGN(SquareInkDropRipple); }; } // namespace views -#endif // UI_VIEWS_ANIMATION_SQUARE_INK_DROP_ANIMATION_H_ +#endif // UI_VIEWS_ANIMATION_SQUARE_INK_DROP_RIPPLE_H_ diff --git a/chromium/ui/views/animation/square_ink_drop_animation_unittest.cc b/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc index 0b11630ca5e..44ec224aa0f 100644 --- a/chromium/ui/views/animation/square_ink_drop_animation_unittest.cc +++ b/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc @@ -2,28 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ +#include "ui/views/animation/square_ink_drop_ripple.h" -#include "ui/views/animation/square_ink_drop_animation.h" +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" -#include "ui/views/animation/ink_drop_animation_observer.h" +#include "ui/views/animation/ink_drop_ripple_observer.h" #include "ui/views/animation/ink_drop_state.h" -#include "ui/views/animation/test/square_ink_drop_animation_test_api.h" -#include "ui/views/animation/test/test_ink_drop_animation_observer.h" +#include "ui/views/animation/test/square_ink_drop_ripple_test_api.h" +#include "ui/views/animation/test/test_ink_drop_ripple_observer.h" namespace views { namespace test { namespace { -using PaintedShape = views::test::SquareInkDropAnimationTestApi::PaintedShape; +using PaintedShape = views::test::SquareInkDropRippleTestApi::PaintedShape; // Transforms a copy of |point| with |transform| and returns it. gfx::Point TransformPoint(const gfx::Transform& transform, @@ -33,10 +31,10 @@ gfx::Point TransformPoint(const gfx::Transform& transform, return transformed_point; } -class SquareInkDropAnimationCalculateTransformsTest : public testing::Test { +class SquareInkDropRippleCalculateTransformsTest : public testing::Test { public: - SquareInkDropAnimationCalculateTransformsTest(); - ~SquareInkDropAnimationCalculateTransformsTest() override; + SquareInkDropRippleCalculateTransformsTest(); + ~SquareInkDropRippleCalculateTransformsTest() override; protected: // Half the width/height of the drawn ink drop. @@ -62,66 +60,63 @@ class SquareInkDropAnimationCalculateTransformsTest : public testing::Test { static const gfx::Point kDrawnBottomMidPoint; // The test target. - SquareInkDropAnimation ink_drop_animation_; + SquareInkDropRipple ink_drop_ripple_; // Provides internal access to the test target. - SquareInkDropAnimationTestApi test_api_; + SquareInkDropRippleTestApi test_api_; // The gfx::Transforms collection that is populated via the // Calculate*Transforms() calls. - SquareInkDropAnimationTestApi::InkDropTransforms transforms_; + SquareInkDropRippleTestApi::InkDropTransforms transforms_; private: - DISALLOW_COPY_AND_ASSIGN(SquareInkDropAnimationCalculateTransformsTest); + DISALLOW_COPY_AND_ASSIGN(SquareInkDropRippleCalculateTransformsTest); }; -const int SquareInkDropAnimationCalculateTransformsTest::kHalfDrawnSize = 5; -const int SquareInkDropAnimationCalculateTransformsTest::kDrawnSize = +const int SquareInkDropRippleCalculateTransformsTest::kHalfDrawnSize = 5; +const int SquareInkDropRippleCalculateTransformsTest::kDrawnSize = 2 * kHalfDrawnSize; -const int SquareInkDropAnimationCalculateTransformsTest::kTransformedRadius = - 10; -const int SquareInkDropAnimationCalculateTransformsTest::kHalfTransformedSize = +const int SquareInkDropRippleCalculateTransformsTest::kTransformedRadius = 10; +const int SquareInkDropRippleCalculateTransformsTest::kHalfTransformedSize = 100; -const int SquareInkDropAnimationCalculateTransformsTest::kTransformedSize = +const int SquareInkDropRippleCalculateTransformsTest::kTransformedSize = 2 * kHalfTransformedSize; -const gfx::Point - SquareInkDropAnimationCalculateTransformsTest::kDrawnCenterPoint = - gfx::Point(kHalfDrawnSize, kHalfDrawnSize); +const gfx::Point SquareInkDropRippleCalculateTransformsTest::kDrawnCenterPoint = + gfx::Point(kHalfDrawnSize, kHalfDrawnSize); const gfx::Point - SquareInkDropAnimationCalculateTransformsTest::kDrawnMidLeftPoint = + SquareInkDropRippleCalculateTransformsTest::kDrawnMidLeftPoint = gfx::Point(0, kHalfDrawnSize); const gfx::Point - SquareInkDropAnimationCalculateTransformsTest::kDrawnMidRightPoint = + SquareInkDropRippleCalculateTransformsTest::kDrawnMidRightPoint = gfx::Point(kDrawnSize, kHalfDrawnSize); -const gfx::Point - SquareInkDropAnimationCalculateTransformsTest::kDrawnTopMidPoint = - gfx::Point(kHalfDrawnSize, 0); +const gfx::Point SquareInkDropRippleCalculateTransformsTest::kDrawnTopMidPoint = + gfx::Point(kHalfDrawnSize, 0); const gfx::Point - SquareInkDropAnimationCalculateTransformsTest::kDrawnBottomMidPoint = + SquareInkDropRippleCalculateTransformsTest::kDrawnBottomMidPoint = gfx::Point(kHalfDrawnSize, kDrawnSize); -SquareInkDropAnimationCalculateTransformsTest:: - SquareInkDropAnimationCalculateTransformsTest() - : ink_drop_animation_(gfx::Size(kDrawnSize, kDrawnSize), - 2, - gfx::Size(kHalfDrawnSize, kHalfDrawnSize), - 1, - gfx::Point(), - SK_ColorBLACK), - test_api_(&ink_drop_animation_) {} +SquareInkDropRippleCalculateTransformsTest:: + SquareInkDropRippleCalculateTransformsTest() + : ink_drop_ripple_(gfx::Size(kDrawnSize, kDrawnSize), + 2, + gfx::Size(kHalfDrawnSize, kHalfDrawnSize), + 1, + gfx::Point(), + SK_ColorBLACK), + test_api_(&ink_drop_ripple_) {} -SquareInkDropAnimationCalculateTransformsTest:: - ~SquareInkDropAnimationCalculateTransformsTest() {} +SquareInkDropRippleCalculateTransformsTest:: + ~SquareInkDropRippleCalculateTransformsTest() {} } // namespace -TEST_F(SquareInkDropAnimationCalculateTransformsTest, +TEST_F(SquareInkDropRippleCalculateTransformsTest, TransformedPointsUsingTransformsFromCalculateCircleTransforms) { test_api_.CalculateCircleTransforms( gfx::Size(kTransformedSize, kTransformedSize), &transforms_); @@ -179,7 +174,7 @@ TEST_F(SquareInkDropAnimationCalculateTransformsTest, } } -TEST_F(SquareInkDropAnimationCalculateTransformsTest, +TEST_F(SquareInkDropRippleCalculateTransformsTest, TransformedPointsUsingTransformsFromCalculateRectTransforms) { test_api_.CalculateRectTransforms( gfx::Size(kTransformedSize, kTransformedSize), kTransformedRadius, @@ -244,5 +239,3 @@ TEST_F(SquareInkDropAnimationCalculateTransformsTest, } // namespace test } // namespace views - -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_UNITTEST_H_ diff --git a/chromium/ui/views/border.cc b/chromium/ui/views/border.cc index a7a11440923..f2eb92ff111 100644 --- a/chromium/ui/views/border.cc +++ b/chromium/ui/views/border.cc @@ -4,9 +4,11 @@ #include "ui/views/border.h" +#include <memory> + #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "third_party/skia/include/core/SkPaint.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect_f.h" @@ -137,7 +139,7 @@ gfx::Size EmptyBorder::GetMinimumSize() const { class BorderPainter : public Border { public: - BorderPainter(Painter* painter, const gfx::Insets& insets); + BorderPainter(std::unique_ptr<Painter> painter, const gfx::Insets& insets); // Overridden from Border: void Paint(const View& view, gfx::Canvas* canvas) override; @@ -145,16 +147,16 @@ class BorderPainter : public Border { gfx::Size GetMinimumSize() const override; private: - scoped_ptr<Painter> painter_; + std::unique_ptr<Painter> painter_; const gfx::Insets insets_; DISALLOW_COPY_AND_ASSIGN(BorderPainter); }; -BorderPainter::BorderPainter(Painter* painter, const gfx::Insets& insets) - : painter_(painter), - insets_(insets) { - DCHECK(painter); +BorderPainter::BorderPainter(std::unique_ptr<Painter> painter, + const gfx::Insets& insets) + : painter_(std::move(painter)), insets_(insets) { + DCHECK(painter_); } void BorderPainter::Paint(const View& view, gfx::Canvas* canvas) { @@ -178,50 +180,52 @@ Border::~Border() { } // static -scoped_ptr<Border> Border::NullBorder() { +std::unique_ptr<Border> Border::NullBorder() { return nullptr; } // static -scoped_ptr<Border> Border::CreateSolidBorder(int thickness, SkColor color) { - return make_scoped_ptr(new SolidSidedBorder(gfx::Insets(thickness), color)); +std::unique_ptr<Border> Border::CreateSolidBorder(int thickness, + SkColor color) { + return base::WrapUnique(new SolidSidedBorder(gfx::Insets(thickness), color)); } // static -scoped_ptr<Border> Border::CreateEmptyBorder(const gfx::Insets& insets) { - return make_scoped_ptr(new EmptyBorder(insets)); +std::unique_ptr<Border> Border::CreateEmptyBorder(const gfx::Insets& insets) { + return base::WrapUnique(new EmptyBorder(insets)); } // static -scoped_ptr<Border> Border::CreateRoundedRectBorder(int thickness, - int corner_radius, - SkColor color) { - return make_scoped_ptr( +std::unique_ptr<Border> Border::CreateRoundedRectBorder(int thickness, + int corner_radius, + SkColor color) { + return base::WrapUnique( new RoundedRectBorder(thickness, corner_radius, color)); } // static -scoped_ptr<Border> Border::CreateEmptyBorder(int top, - int left, - int bottom, - int right) { +std::unique_ptr<Border> Border::CreateEmptyBorder(int top, + int left, + int bottom, + int right) { return CreateEmptyBorder(gfx::Insets(top, left, bottom, right)); } // static -scoped_ptr<Border> Border::CreateSolidSidedBorder(int top, - int left, - int bottom, - int right, - SkColor color) { - return make_scoped_ptr(new SolidSidedBorder( - gfx::Insets(top, left, bottom, right), color)); +std::unique_ptr<Border> Border::CreateSolidSidedBorder(int top, + int left, + int bottom, + int right, + SkColor color) { + return base::WrapUnique( + new SolidSidedBorder(gfx::Insets(top, left, bottom, right), color)); } // static -scoped_ptr<Border> Border::CreateBorderPainter(Painter* painter, - const gfx::Insets& insets) { - return make_scoped_ptr(new BorderPainter(painter, insets)); +std::unique_ptr<Border> Border::CreateBorderPainter( + std::unique_ptr<Painter> painter, + const gfx::Insets& insets) { + return base::WrapUnique(new BorderPainter(std::move(painter), insets)); } } // namespace views diff --git a/chromium/ui/views/border.h b/chromium/ui/views/border.h index e09dbeb09c8..d30cc7ca0b0 100644 --- a/chromium/ui/views/border.h +++ b/chromium/ui/views/border.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_BORDER_H_ #define UI_VIEWS_BORDER_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/views_export.h" @@ -43,39 +44,40 @@ class VIEWS_EXPORT Border { virtual ~Border(); // Convenience for creating a scoped_ptr with no Border. - static scoped_ptr<Border> NullBorder(); + static std::unique_ptr<Border> NullBorder(); // Creates a border that is a simple line of the specified thickness and // color. - static scoped_ptr<Border> CreateSolidBorder(int thickness, SkColor color); + static std::unique_ptr<Border> CreateSolidBorder(int thickness, + SkColor color); // Creates a border that is a rounded rectangle of the specified thickness and // color. - static scoped_ptr<Border> CreateRoundedRectBorder(int thickness, - int corner_radius, - SkColor color); + static std::unique_ptr<Border> CreateRoundedRectBorder(int thickness, + int corner_radius, + SkColor color); // Creates a border for reserving space. The returned border does not // paint anything. - static scoped_ptr<Border> CreateEmptyBorder(const gfx::Insets& insets); - static scoped_ptr<Border> CreateEmptyBorder(int top, - int left, - int bottom, - int right); + static std::unique_ptr<Border> CreateEmptyBorder(const gfx::Insets& insets); + static std::unique_ptr<Border> CreateEmptyBorder(int top, + int left, + int bottom, + int right); // Creates a border of the specified color, and specified thickness on each // side. - static scoped_ptr<Border> CreateSolidSidedBorder(int top, - int left, - int bottom, - int right, - SkColor color); + static std::unique_ptr<Border> CreateSolidSidedBorder(int top, + int left, + int bottom, + int right, + SkColor color); - // Creates a Border from the specified Painter. The border owns the painter, - // thus the painter is deleted when the Border is deleted. + // Creates a Border from the specified Painter. // |insets| define size of an area allocated for a Border. - static scoped_ptr<Border> CreateBorderPainter(Painter* painter, - const gfx::Insets& insets); + static std::unique_ptr<Border> CreateBorderPainter( + std::unique_ptr<Painter> painter, + const gfx::Insets& insets); // Renders the border for the specified view. virtual void Paint(const View& view, gfx::Canvas* canvas) = 0; diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h index 057459f2539..2ebdf9c6156 100644 --- a/chromium/ui/views/bubble/bubble_border.h +++ b/chromium/ui/views/bubble/bubble_border.h @@ -5,10 +5,11 @@ #ifndef UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_ #define UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -34,7 +35,7 @@ struct BorderImages { int corner_radius); virtual ~BorderImages(); - scoped_ptr<Painter> border_painter; + std::unique_ptr<Painter> border_painter; gfx::ImageSkia left_arrow; gfx::ImageSkia top_arrow; gfx::ImageSkia right_arrow; diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc index 31323822936..ffb0fbb0700 100644 --- a/chromium/ui/views/bubble/bubble_border_unittest.cc +++ b/chromium/ui/views/bubble/bubble_border_unittest.cc @@ -6,8 +6,9 @@ #include <stddef.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" diff --git a/chromium/ui/views/bubble/bubble_delegate.cc b/chromium/ui/views/bubble/bubble_delegate.cc deleted file mode 100644 index 5850c3f827a..00000000000 --- a/chromium/ui/views/bubble/bubble_delegate.cc +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright (c) 2012 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 "ui/views/bubble/bubble_delegate.h" - -#include "build/build_config.h" -#include "ui/accessibility/ax_view_state.h" -#include "ui/base/default_style.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/bubble/bubble_frame_view.h" -#include "ui/views/focus/view_storage.h" -#include "ui/views/layout/layout_constants.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" - -#if defined(OS_WIN) -#include "ui/base/win/shell.h" -#endif - -namespace views { - -namespace { - -// Create a widget to host the bubble. -Widget* CreateBubbleWidget(BubbleDelegateView* bubble) { - Widget* bubble_widget = new Widget(); - Widget::InitParams bubble_params(Widget::InitParams::TYPE_BUBBLE); - bubble_params.delegate = bubble; - bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; - bubble_params.accept_events = bubble->accept_events(); - if (bubble->parent_window()) - bubble_params.parent = bubble->parent_window(); - else if (bubble->anchor_widget()) - bubble_params.parent = bubble->anchor_widget()->GetNativeView(); - bubble_params.activatable = bubble->CanActivate() ? - Widget::InitParams::ACTIVATABLE_YES : Widget::InitParams::ACTIVATABLE_NO; - bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget); - bubble_widget->Init(bubble_params); - if (bubble_params.parent) - bubble_widget->StackAbove(bubble_params.parent); - return bubble_widget; -} - -} // namespace - -// static -const char BubbleDelegateView::kViewClassName[] = "BubbleDelegateView"; - -BubbleDelegateView::BubbleDelegateView() - : BubbleDelegateView(nullptr, BubbleBorder::TOP_LEFT) {} - -BubbleDelegateView::BubbleDelegateView(View* anchor_view, - BubbleBorder::Arrow arrow) - : close_on_esc_(true), - close_on_deactivate_(true), - anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()), - anchor_widget_(NULL), - arrow_(arrow), - shadow_(BubbleBorder::SMALL_SHADOW), - color_explicitly_set_(false), - margins_(kPanelVertMargin, - kPanelHorizMargin, - kPanelVertMargin, - kPanelHorizMargin), - accept_events_(true), - border_accepts_events_(true), - adjust_if_offscreen_(true), - parent_window_(NULL), - close_reason_(CloseReason::UNKNOWN) { - if (anchor_view) - SetAnchorView(anchor_view); - AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); - UpdateColorsFromTheme(GetNativeTheme()); -} - -BubbleDelegateView::~BubbleDelegateView() { - if (GetWidget()) - GetWidget()->RemoveObserver(this); - SetLayoutManager(NULL); - SetAnchorView(NULL); -} - -// static -Widget* BubbleDelegateView::CreateBubble(BubbleDelegateView* bubble_delegate) { - bubble_delegate->Init(); - // Get the latest anchor widget from the anchor view at bubble creation time. - bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView()); - Widget* bubble_widget = CreateBubbleWidget(bubble_delegate); - -#if defined(OS_WIN) - // If glass is enabled, the bubble is allowed to extend outside the bounds of - // the parent frame and let DWM handle compositing. If not, then we don't - // want to allow the bubble to extend the frame because it will be clipped. - bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled()); -#elif (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX) - // Linux clips bubble windows that extend outside their parent window bounds. - // Mac never adjusts. - bubble_delegate->set_adjust_if_offscreen(false); -#endif - - bubble_delegate->SizeToContents(); - bubble_widget->AddObserver(bubble_delegate); - return bubble_widget; -} - -BubbleDelegateView* BubbleDelegateView::AsBubbleDelegate() { - return this; -} - -bool BubbleDelegateView::ShouldShowCloseButton() const { - return false; -} - -View* BubbleDelegateView::GetContentsView() { - return this; -} - -NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView( - Widget* widget) { - BubbleFrameView* frame = new BubbleFrameView( - gfx::Insets(kPanelVertMargin, kPanelHorizMargin, 0, kPanelHorizMargin), - margins()); - // Note: In CreateBubble, the call to SizeToContents() will cause - // the relayout that this call requires. - frame->SetTitleFontList(GetTitleFontList()); - frame->SetFootnoteView(CreateFootnoteView()); - - BubbleBorder::Arrow adjusted_arrow = arrow(); - if (base::i18n::IsRTL()) - adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow); - frame->SetBubbleBorder(scoped_ptr<BubbleBorder>( - new BubbleBorder(adjusted_arrow, shadow(), color()))); - return frame; -} - -void BubbleDelegateView::GetAccessibleState(ui::AXViewState* state) { - state->role = ui::AX_ROLE_DIALOG; -} - -const char* BubbleDelegateView::GetClassName() const { - return kViewClassName; -} - -void BubbleDelegateView::OnWidgetClosing(Widget* widget) { - DCHECK(GetBubbleFrameView()); - if (widget == GetWidget() && close_reason_ == CloseReason::UNKNOWN && - GetBubbleFrameView()->close_button_clicked()) { - close_reason_ = CloseReason::CLOSE_BUTTON; - } -} - -void BubbleDelegateView::OnWidgetDestroying(Widget* widget) { - if (anchor_widget() == widget) - SetAnchorView(NULL); -} - -void BubbleDelegateView::OnWidgetVisibilityChanging(Widget* widget, - bool visible) { -#if defined(OS_WIN) - // On Windows we need to handle this before the bubble is visible or hidden. - // Please see the comment on the OnWidgetVisibilityChanging function. On - // other platforms it is fine to handle it after the bubble is shown/hidden. - HandleVisibilityChanged(widget, visible); -#endif -} - -void BubbleDelegateView::OnWidgetVisibilityChanged(Widget* widget, - bool visible) { -#if !defined(OS_WIN) - HandleVisibilityChanged(widget, visible); -#endif -} - -void BubbleDelegateView::OnWidgetActivationChanged(Widget* widget, - bool active) { - if (close_on_deactivate() && widget == GetWidget() && !active) { - if (close_reason_ == CloseReason::UNKNOWN) - close_reason_ = CloseReason::DEACTIVATION; - GetWidget()->Close(); - } -} - -void BubbleDelegateView::OnWidgetBoundsChanged(Widget* widget, - const gfx::Rect& new_bounds) { - if (GetBubbleFrameView() && anchor_widget() == widget) - SizeToContents(); -} - -View* BubbleDelegateView::GetAnchorView() const { - return ViewStorage::GetInstance()->RetrieveView(anchor_view_storage_id_); -} - -gfx::Rect BubbleDelegateView::GetAnchorRect() const { - if (!GetAnchorView()) - return anchor_rect_; - - anchor_rect_ = GetAnchorView()->GetBoundsInScreen(); - anchor_rect_.Inset(anchor_view_insets_); - return anchor_rect_; -} - -void BubbleDelegateView::OnBeforeBubbleWidgetInit(Widget::InitParams* params, - Widget* widget) const { -} - -View* BubbleDelegateView::CreateFootnoteView() { - return nullptr; -} - -void BubbleDelegateView::UseCompactMargins() { - const int kCompactMargin = 6; - margins_.Set(kCompactMargin, kCompactMargin, kCompactMargin, kCompactMargin); -} - -void BubbleDelegateView::SetAlignment(BubbleBorder::BubbleAlignment alignment) { - GetBubbleFrameView()->bubble_border()->set_alignment(alignment); - SizeToContents(); -} - -void BubbleDelegateView::SetArrowPaintType( - BubbleBorder::ArrowPaintType paint_type) { - GetBubbleFrameView()->bubble_border()->set_paint_arrow(paint_type); - SizeToContents(); -} - -void BubbleDelegateView::OnAnchorBoundsChanged() { - SizeToContents(); -} - -bool BubbleDelegateView::AcceleratorPressed( - const ui::Accelerator& accelerator) { - if (!close_on_esc() || accelerator.key_code() != ui::VKEY_ESCAPE) - return false; - close_reason_ = CloseReason::ESCAPE; - GetWidget()->Close(); - return true; -} - -void BubbleDelegateView::OnNativeThemeChanged(const ui::NativeTheme* theme) { - UpdateColorsFromTheme(theme); -} - -void BubbleDelegateView::Init() {} - -void BubbleDelegateView::SetAnchorView(View* anchor_view) { - // When the anchor view gets set the associated anchor widget might - // change as well. - if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) { - if (anchor_widget()) { - anchor_widget_->RemoveObserver(this); - anchor_widget_ = NULL; - } - if (anchor_view) { - anchor_widget_ = anchor_view->GetWidget(); - if (anchor_widget_) - anchor_widget_->AddObserver(this); - } - } - - // Remove the old storage item and set the new (if there is one). - ViewStorage* view_storage = ViewStorage::GetInstance(); - if (view_storage->RetrieveView(anchor_view_storage_id_)) - view_storage->RemoveView(anchor_view_storage_id_); - if (anchor_view) - view_storage->StoreView(anchor_view_storage_id_, anchor_view); - - // Do not update anchoring for NULL views; this could indicate that our - // NativeWindow is being destroyed, so it would be dangerous for us to update - // our anchor bounds at that point. (It's safe to skip this, since if we were - // to update the bounds when |anchor_view| is NULL, the bubble won't move.) - if (anchor_view && GetWidget()) - OnAnchorBoundsChanged(); -} - -void BubbleDelegateView::SetAnchorRect(const gfx::Rect& rect) { - anchor_rect_ = rect; - if (GetWidget()) - OnAnchorBoundsChanged(); -} - -void BubbleDelegateView::SizeToContents() { - GetWidget()->SetBounds(GetBubbleBounds()); -} - -BubbleFrameView* BubbleDelegateView::GetBubbleFrameView() const { - const NonClientView* view = - GetWidget() ? GetWidget()->non_client_view() : NULL; - return view ? static_cast<BubbleFrameView*>(view->frame_view()) : NULL; -} - -gfx::Rect BubbleDelegateView::GetBubbleBounds() { - // The argument rect has its origin at the bubble's arrow anchor point; - // its size is the preferred size of the bubble's client view (this view). - bool anchor_minimized = anchor_widget() && anchor_widget()->IsMinimized(); - return GetBubbleFrameView()->GetUpdatedWindowBounds(GetAnchorRect(), - GetPreferredSize(), adjust_if_offscreen_ && !anchor_minimized); -} - -const gfx::FontList& BubbleDelegateView::GetTitleFontList() const { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb.GetFontListWithDelta(ui::kTitleFontSizeDelta); -} - -void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) { - if (!color_explicitly_set_) - color_ = theme->GetSystemColor(ui::NativeTheme::kColorId_BubbleBackground); - set_background(Background::CreateSolidBackground(color())); - BubbleFrameView* frame_view = GetBubbleFrameView(); - if (frame_view) - frame_view->bubble_border()->set_background_color(color()); -} - -void BubbleDelegateView::HandleVisibilityChanged(Widget* widget, bool visible) { - if (widget == GetWidget() && anchor_widget() && - anchor_widget()->GetTopLevelWidget()) { - anchor_widget()->GetTopLevelWidget()->SetAlwaysRenderAsActive(visible); - } - - // Fire AX_EVENT_ALERT for bubbles marked as AX_ROLE_ALERT_DIALOG; this - // instructs accessibility tools to read the bubble in its entirety rather - // than just its title and initially focused view. See - // http://crbug.com/474622 for details. - if (widget == GetWidget() && visible) { - ui::AXViewState state; - GetAccessibleState(&state); - if (state.role == ui::AX_ROLE_ALERT_DIALOG) - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); - } -} - -} // namespace views diff --git a/chromium/ui/views/bubble/bubble_delegate.h b/chromium/ui/views/bubble/bubble_delegate.h deleted file mode 100644 index 9392251e22d..00000000000 --- a/chromium/ui/views/bubble/bubble_delegate.h +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) 2012 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 UI_VIEWS_BUBBLE_BUBBLE_DELEGATE_H_ -#define UI_VIEWS_BUBBLE_BUBBLE_DELEGATE_H_ - -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "ui/views/bubble/bubble_border.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/widget/widget_observer.h" - -namespace gfx { -class FontList; -class Rect; -} - -namespace views { - -class BubbleFrameView; - -// BubbleDelegateView creates frame and client views for bubble Widgets. -// BubbleDelegateView itself is the client's contents view. -// TODO(estade): remove this in favor of BubbleDialogDelegateView. -class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, - public WidgetObserver { - public: - // Internal class name. - static const char kViewClassName[]; - - enum class CloseReason { - DEACTIVATION, - ESCAPE, - CLOSE_BUTTON, - UNKNOWN, - }; - - BubbleDelegateView(); - BubbleDelegateView(View* anchor_view, BubbleBorder::Arrow arrow); - ~BubbleDelegateView() override; - - // Create and initialize the bubble Widget(s) with proper bounds. - static Widget* CreateBubble(BubbleDelegateView* bubble_delegate); - - // WidgetDelegateView overrides: - BubbleDelegateView* AsBubbleDelegate() override; - bool ShouldShowCloseButton() const override; - View* GetContentsView() override; - NonClientFrameView* CreateNonClientFrameView(Widget* widget) override; - void GetAccessibleState(ui::AXViewState* state) override; - const char* GetClassName() const override; - - // WidgetObserver overrides: - void OnWidgetClosing(Widget* widget) override; - void OnWidgetDestroying(Widget* widget) override; - void OnWidgetVisibilityChanging(Widget* widget, bool visible) override; - void OnWidgetVisibilityChanged(Widget* widget, bool visible) override; - void OnWidgetActivationChanged(Widget* widget, bool active) override; - void OnWidgetBoundsChanged(Widget* widget, - const gfx::Rect& new_bounds) override; - - bool close_on_esc() const { return close_on_esc_; } - void set_close_on_esc(bool close_on_esc) { close_on_esc_ = close_on_esc; } - - bool close_on_deactivate() const { return close_on_deactivate_; } - void set_close_on_deactivate(bool close) { close_on_deactivate_ = close; } - - View* GetAnchorView() const; - Widget* anchor_widget() const { return anchor_widget_; } - - // The anchor rect is used in the absence of an assigned anchor view. - const gfx::Rect& anchor_rect() const { return anchor_rect_; } - - BubbleBorder::Arrow arrow() const { return arrow_; } - void set_arrow(BubbleBorder::Arrow arrow) { arrow_ = arrow; } - - BubbleBorder::Shadow shadow() const { return shadow_; } - void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; } - - SkColor color() const { return color_; } - void set_color(SkColor color) { - color_ = color; - color_explicitly_set_ = true; - } - - const gfx::Insets& margins() const { return margins_; } - void set_margins(const gfx::Insets& margins) { margins_ = margins; } - - const gfx::Insets& anchor_view_insets() const { return anchor_view_insets_; } - void set_anchor_view_insets(const gfx::Insets& i) { anchor_view_insets_ = i; } - - gfx::NativeView parent_window() const { return parent_window_; } - void set_parent_window(gfx::NativeView window) { parent_window_ = window; } - - bool accept_events() const { return accept_events_; } - void set_accept_events(bool accept_events) { accept_events_ = accept_events; } - - bool border_accepts_events() const { return border_accepts_events_; } - void set_border_accepts_events(bool event) { border_accepts_events_ = event; } - - bool adjust_if_offscreen() const { return adjust_if_offscreen_; } - void set_adjust_if_offscreen(bool adjust) { adjust_if_offscreen_ = adjust; } - - CloseReason close_reason() const { return close_reason_; } - - // Get the arrow's anchor rect in screen space. - virtual gfx::Rect GetAnchorRect() const; - - // Allows delegates to provide custom parameters before widget initialization. - virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params, - Widget* widget) const; - - // Creates and returns a view to be displayed at the bottom of the bubble. - virtual View* CreateFootnoteView(); - - // Sets |margins_| to a default picked for smaller bubbles. - void UseCompactMargins(); - - // Sets the bubble alignment relative to the anchor. This may only be called - // after calling CreateBubble. - void SetAlignment(BubbleBorder::BubbleAlignment alignment); - - // Sets the bubble arrow paint type. - void SetArrowPaintType(BubbleBorder::ArrowPaintType paint_type); - - // Call this method when the anchor bounds have changed to reposition the - // bubble. The bubble is automatically repositioned when the anchor view - // bounds change as a result of the widget's bounds changing. - void OnAnchorBoundsChanged(); - - protected: - // Get bubble bounds from the anchor rect and client view's preferred size. - virtual gfx::Rect GetBubbleBounds(); - - // Return a FontList to use for the title of the bubble. - // (The default is MediumFont). - virtual const gfx::FontList& GetTitleFontList() const; - - // View overrides: - bool AcceleratorPressed(const ui::Accelerator& accelerator) override; - void OnNativeThemeChanged(const ui::NativeTheme* theme) override; - - // Perform view initialization on the contents for bubble sizing. - virtual void Init(); - - // Sets the anchor view or rect and repositions the bubble. Note that if a - // valid view gets passed, the anchor rect will get ignored. If the view gets - // deleted, but no new view gets set, the last known anchor postion will get - // returned. - void SetAnchorView(View* anchor_view); - void SetAnchorRect(const gfx::Rect& rect); - - // Resize and potentially move the bubble to fit the content's preferred size. - void SizeToContents(); - - BubbleFrameView* GetBubbleFrameView() const; - - private: - friend class BubbleBorderDelegate; - friend class BubbleWindowTargeter; - - FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CreateDelegate); - FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, NonClientHitTest); - - // Update the bubble color from |theme|, unless it was explicitly set. - void UpdateColorsFromTheme(const ui::NativeTheme* theme); - - // Handles widget visibility changes. - void HandleVisibilityChanged(Widget* widget, bool visible); - - // Flags controlling bubble closure on the escape key and deactivation. - bool close_on_esc_; - bool close_on_deactivate_; - - // The view and widget to which this bubble is anchored. Since an anchor view - // can be deleted without notice, we store it in the ViewStorage and retrieve - // it from there. It will make sure that the view is still valid. - const int anchor_view_storage_id_; - Widget* anchor_widget_; - - // The anchor rect used in the absence of an anchor view. - mutable gfx::Rect anchor_rect_; - - // The arrow's location on the bubble. - BubbleBorder::Arrow arrow_; - - // Bubble border shadow to use. - BubbleBorder::Shadow shadow_; - - // The background color of the bubble; and flag for when it's explicitly set. - SkColor color_; - bool color_explicitly_set_; - - // The margins between the content and the inside of the border. - gfx::Insets margins_; - - // Insets applied to the |anchor_view_| bounds. - gfx::Insets anchor_view_insets_; - - // Specifies whether the bubble (or its border) handles mouse events, etc. - bool accept_events_; - bool border_accepts_events_; - - // If true (defaults to true), the arrow may be mirrored and moved to fit the - // bubble on screen better. It would be a no-op if the bubble has no arrow. - bool adjust_if_offscreen_; - - // Parent native window of the bubble. - gfx::NativeView parent_window_; - - CloseReason close_reason_; - - DISALLOW_COPY_AND_ASSIGN(BubbleDelegateView); -}; - -} // namespace views - -#endif // UI_VIEWS_BUBBLE_BUBBLE_DELEGATE_H_ diff --git a/chromium/ui/views/bubble/bubble_delegate_unittest.cc b/chromium/ui/views/bubble/bubble_delegate_unittest.cc deleted file mode 100644 index f7656f06151..00000000000 --- a/chromium/ui/views/bubble/bubble_delegate_unittest.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2012 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 <stddef.h> - -#include "base/macros.h" -#include "ui/base/hit_test.h" -#include "ui/events/event_utils.h" -#include "ui/views/bubble/bubble_delegate.h" -#include "ui/views/bubble/bubble_frame_view.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/test/test_widget_observer.h" -#include "ui/views/test/views_test_base.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" - -namespace views { - -namespace { - -class TestBubbleDelegateView : public BubbleDelegateView { - public: - TestBubbleDelegateView(View* anchor_view) - : BubbleDelegateView(anchor_view, BubbleBorder::TOP_LEFT), - view_(new View()) { - view_->SetFocusable(true); - AddChildView(view_); - } - ~TestBubbleDelegateView() override {} - - void SetAnchorRectForTest(gfx::Rect rect) { - SetAnchorRect(rect); - } - - void SetAnchorViewForTest(View* view) { - SetAnchorView(view); - } - - // BubbleDelegateView overrides: - View* GetInitiallyFocusedView() override { return view_; } - gfx::Size GetPreferredSize() const override { return gfx::Size(200, 200); } - - BubbleFrameView* GetBubbleFrameViewForTest() const { - return GetBubbleFrameView(); - } - - private: - View* view_; - - DISALLOW_COPY_AND_ASSIGN(TestBubbleDelegateView); -}; - -class BubbleDelegateTest : public ViewsTestBase { - public: - BubbleDelegateTest() {} - ~BubbleDelegateTest() override {} - - // Creates a test widget that owns its native widget. - Widget* CreateTestWidget() { - Widget* widget = new Widget(); - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(params); - return widget; - } - - private: - DISALLOW_COPY_AND_ASSIGN(BubbleDelegateTest); -}; - -} // namespace - -TEST_F(BubbleDelegateTest, CreateDelegate) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - bubble_delegate->set_color(SK_ColorGREEN); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate()); - EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget()); - test::TestWidgetObserver bubble_observer(bubble_widget); - bubble_widget->Show(); - - BubbleBorder* border = bubble_delegate->GetBubbleFrameView()->bubble_border(); - EXPECT_EQ(bubble_delegate->arrow(), border->arrow()); - EXPECT_EQ(bubble_delegate->color(), border->background_color()); - - EXPECT_FALSE(bubble_observer.widget_closed()); - bubble_widget->CloseNow(); - EXPECT_TRUE(bubble_observer.widget_closed()); -} - -TEST_F(BubbleDelegateTest, CloseAnchorWidget) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - // Preventing close on deactivate should not prevent closing with the anchor. - bubble_delegate->set_close_on_deactivate(false); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate()); - EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget()); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - test::TestWidgetObserver bubble_observer(bubble_widget); - EXPECT_FALSE(bubble_observer.widget_closed()); - - bubble_widget->Show(); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - EXPECT_FALSE(bubble_observer.widget_closed()); - - // TODO(msw): Remove activation hack to prevent bookkeeping errors in: - // aura::test::TestActivationClient::OnWindowDestroyed(). - scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); - EXPECT_FALSE(bubble_observer.widget_closed()); - - // Ensure that closing the anchor widget also closes the bubble itself. - anchor_widget->CloseNow(); - EXPECT_TRUE(bubble_observer.widget_closed()); -} - -// This test checks that the bubble delegate is capable to handle an early -// destruction of the used anchor view. (Animations and delayed closure of the -// bubble will call upon the anchor view to get its location). -TEST_F(BubbleDelegateTest, CloseAnchorViewTest) { - // Create an anchor widget and add a view to be used as an anchor view. - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - scoped_ptr<View> anchor_view(new View()); - anchor_widget->GetContentsView()->AddChildView(anchor_view.get()); - TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView( - anchor_view.get()); - // Prevent flakes by avoiding closing on activation changes. - bubble_delegate->set_close_on_deactivate(false); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - - // Check that the anchor view is correct and set up an anchor view rect. - // Make sure that this rect will get ignored (as long as the anchor view is - // attached). - EXPECT_EQ(anchor_view.get(), bubble_delegate->GetAnchorView()); - const gfx::Rect set_anchor_rect = gfx::Rect(10, 10, 100, 100); - bubble_delegate->SetAnchorRectForTest(set_anchor_rect); - const gfx::Rect view_rect = bubble_delegate->GetAnchorRect(); - EXPECT_NE(view_rect.ToString(), set_anchor_rect.ToString()); - - // Create the bubble. - bubble_widget->Show(); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - - // Remove now the anchor view and make sure that the original found rect - // is still kept, so that the bubble does not jump when the view gets deleted. - anchor_widget->GetContentsView()->RemoveChildView(anchor_view.get()); - anchor_view.reset(); - EXPECT_EQ(NULL, bubble_delegate->GetAnchorView()); - EXPECT_EQ(view_rect.ToString(), bubble_delegate->GetAnchorRect().ToString()); -} - -// Testing that a move of the anchor view will lead to new bubble locations. -TEST_F(BubbleDelegateTest, TestAnchorRectMovesWithViewTest) { - // Create an anchor widget and add a view to be used as anchor view. - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView( - anchor_widget->GetContentsView()); - BubbleDelegateView::CreateBubble(bubble_delegate); - - anchor_widget->GetContentsView()->SetBounds(10, 10, 100, 100); - const gfx::Rect view_rect = bubble_delegate->GetAnchorRect(); - - anchor_widget->GetContentsView()->SetBounds(20, 10, 100, 100); - const gfx::Rect view_rect_2 = bubble_delegate->GetAnchorRect(); - EXPECT_NE(view_rect.ToString(), view_rect_2.ToString()); -} - -TEST_F(BubbleDelegateTest, ResetAnchorWidget) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - - // Make sure the bubble widget is parented to a widget other than the anchor - // widget so that closing the anchor widget does not close the bubble widget. - scoped_ptr<Widget> parent_widget(CreateTestWidget()); - bubble_delegate->set_parent_window(parent_widget->GetNativeView()); - // Preventing close on deactivate should not prevent closing with the parent. - bubble_delegate->set_close_on_deactivate(false); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate()); - EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget()); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - test::TestWidgetObserver bubble_observer(bubble_widget); - EXPECT_FALSE(bubble_observer.widget_closed()); - - // Showing and hiding the bubble widget should have no effect on its anchor. - bubble_widget->Show(); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - bubble_widget->Hide(); - EXPECT_EQ(anchor_widget.get(), bubble_delegate->anchor_widget()); - - // Ensure that closing the anchor widget clears the bubble's reference to that - // anchor widget, but the bubble itself does not close. - anchor_widget->CloseNow(); - EXPECT_NE(anchor_widget.get(), bubble_delegate->anchor_widget()); - EXPECT_FALSE(bubble_observer.widget_closed()); - - // TODO(msw): Remove activation hack to prevent bookkeeping errors in: - // aura::test::TestActivationClient::OnWindowDestroyed(). - scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); - EXPECT_FALSE(bubble_observer.widget_closed()); - - // Ensure that closing the parent widget also closes the bubble itself. - parent_widget->CloseNow(); - EXPECT_TRUE(bubble_observer.widget_closed()); -} - -TEST_F(BubbleDelegateTest, InitiallyFocusedView) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - EXPECT_EQ(bubble_delegate->GetInitiallyFocusedView(), - bubble_widget->GetFocusManager()->GetFocusedView()); - bubble_widget->CloseNow(); -} - -TEST_F(BubbleDelegateTest, NonClientHitTest) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - TestBubbleDelegateView* bubble_delegate = - new TestBubbleDelegateView(anchor_widget->GetContentsView()); - BubbleDelegateView::CreateBubble(bubble_delegate); - BubbleFrameView* frame = bubble_delegate->GetBubbleFrameView(); - const int border = frame->bubble_border()->GetBorderThickness(); - - struct { - const int point; - const int hit; - } cases[] = { - { border, HTNOWHERE }, - { border + 50, HTCLIENT }, - { 1000, HTNOWHERE }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - gfx::Point point(cases[i].point, cases[i].point); - EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point)) - << " with border: " << border << ", at point " << cases[i].point; - } -} - -TEST_F(BubbleDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - test::TestWidgetObserver bubble_observer(bubble_widget); - EXPECT_FALSE(bubble_observer.widget_closed()); - - anchor_widget->Show(); - bubble_widget->Show(); - EXPECT_TRUE(bubble_widget->IsVisible()); - anchor_widget->SetBounds(gfx::Rect(10, 10, 100, 100)); - EXPECT_TRUE(bubble_widget->IsVisible()); -} - -// Test that setting WidgetDelegate::set_can_activate() to false makes the -// widget created via BubbleDelegateView::CreateBubble() not activatable. -TEST_F(BubbleDelegateTest, NotActivatable) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - bubble_delegate->set_can_activate(false); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - bubble_widget->Show(); - EXPECT_FALSE(bubble_widget->CanActivate()); -} - -TEST_F(BubbleDelegateTest, CloseReasons) { - { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - bubble_delegate->set_close_on_deactivate(true); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - anchor_widget->Show(); - bubble_widget->Show(); - anchor_widget->Activate(); - EXPECT_TRUE(bubble_widget->IsClosed()); - EXPECT_EQ(BubbleDelegateView::CloseReason::DEACTIVATION, - bubble_delegate->close_reason()); - } - - { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - BubbleDelegateView* bubble_delegate = new BubbleDelegateView( - anchor_widget->GetContentsView(), BubbleBorder::NONE); - bubble_delegate->set_close_on_esc(true); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - bubble_widget->Show(); - // Cast as a test hack to access AcceleratorPressed() (which is protected - // in BubbleDelegate). - static_cast<View*>(bubble_delegate) - ->AcceleratorPressed(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); - EXPECT_TRUE(bubble_widget->IsClosed()); - EXPECT_EQ(BubbleDelegateView::CloseReason::ESCAPE, - bubble_delegate->close_reason()); - } - - { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - TestBubbleDelegateView* bubble_delegate = - new TestBubbleDelegateView(anchor_widget->GetContentsView()); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate); - bubble_widget->Show(); - BubbleFrameView* frame_view = bubble_delegate->GetBubbleFrameViewForTest(); - LabelButton* close_button = frame_view->close_; - ASSERT_TRUE(close_button); - frame_view->ButtonPressed( - close_button, - ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0), - ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE)); - EXPECT_TRUE(bubble_widget->IsClosed()); - EXPECT_EQ(BubbleDelegateView::CloseReason::CLOSE_BUTTON, - bubble_delegate->close_reason()); - } -} - -} // namespace views diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.cc b/chromium/ui/views/bubble/bubble_dialog_delegate.cc index 9673891dc39..066626b81da 100644 --- a/chromium/ui/views/bubble/bubble_dialog_delegate.cc +++ b/chromium/ui/views/bubble/bubble_dialog_delegate.cc @@ -94,6 +94,7 @@ bool BubbleDialogDelegateView::ShouldShowCloseButton() const { ClientView* BubbleDialogDelegateView::CreateClientView(Widget* widget) { DialogClientView* client = new DialogClientView(widget, GetContentsView()); client->set_button_row_insets(gfx::Insets()); + widget->non_client_view()->set_mirror_client_in_rtl(mirror_arrow_in_rtl_); return client; } @@ -108,17 +109,13 @@ NonClientFrameView* BubbleDialogDelegateView::CreateNonClientFrameView( frame->SetFootnoteView(CreateFootnoteView()); BubbleBorder::Arrow adjusted_arrow = arrow(); - if (base::i18n::IsRTL()) + if (base::i18n::IsRTL() && mirror_arrow_in_rtl_) adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow); - frame->SetBubbleBorder(scoped_ptr<BubbleBorder>( + frame->SetBubbleBorder(std::unique_ptr<BubbleBorder>( new BubbleBorder(adjusted_arrow, shadow(), color()))); return frame; } -void BubbleDialogDelegateView::GetAccessibleState(ui::AXViewState* state) { - state->role = ui::AX_ROLE_DIALOG; -} - const char* BubbleDialogDelegateView::GetClassName() const { return kViewClassName; } @@ -205,6 +202,7 @@ BubbleDialogDelegateView::BubbleDialogDelegateView(View* anchor_view, anchor_view_storage_id_(ViewStorage::GetInstance()->CreateStorageID()), anchor_widget_(NULL), arrow_(arrow), + mirror_arrow_in_rtl_(true), shadow_(BubbleBorder::SMALL_SHADOW), color_explicitly_set_(false), margins_(kPanelVertMargin, diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.h b/chromium/ui/views/bubble/bubble_dialog_delegate.h index 13c576efd7e..7c8fbce4689 100644 --- a/chromium/ui/views/bubble/bubble_dialog_delegate.h +++ b/chromium/ui/views/bubble/bubble_dialog_delegate.h @@ -44,7 +44,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView, bool ShouldShowCloseButton() const override; ClientView* CreateClientView(Widget* widget) override; NonClientFrameView* CreateNonClientFrameView(Widget* widget) override; - void GetAccessibleState(ui::AXViewState* state) override; const char* GetClassName() const override; // WidgetObserver overrides: @@ -67,6 +66,8 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView, BubbleBorder::Arrow arrow() const { return arrow_; } void set_arrow(BubbleBorder::Arrow arrow) { arrow_ = arrow; } + void set_mirror_arrow_in_rtl(bool mirror) { mirror_arrow_in_rtl_ = mirror; } + BubbleBorder::Shadow shadow() const { return shadow_; } void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; } @@ -173,6 +174,9 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView, // The arrow's location on the bubble. BubbleBorder::Arrow arrow_; + // Automatically mirror the arrow in RTL layout. + bool mirror_arrow_in_rtl_; + // Bubble border shadow to use. BubbleBorder::Shadow shadow_; diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc index 6c43388c944..ea787f8d094 100644 --- a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc +++ b/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc @@ -6,6 +6,7 @@ #include <stddef.h> +#include "base/i18n/rtl.h" #include "base/macros.h" #include "ui/base/hit_test.h" #include "ui/events/event_utils.h" @@ -25,7 +26,7 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView { TestBubbleDialogDelegateView(View* anchor_view) : BubbleDialogDelegateView(anchor_view, BubbleBorder::TOP_LEFT), view_(new View()) { - view_->SetFocusable(true); + view_->SetFocusBehavior(FocusBehavior::ALWAYS); AddChildView(view_); } ~TestBubbleDialogDelegateView() override {} @@ -48,12 +49,13 @@ class BubbleDialogDelegateTest : public ViewsTestBase { BubbleDialogDelegateTest() {} ~BubbleDialogDelegateTest() override {} - // Creates a test widget that owns its native widget. + // Creates and shows a test widget that owns its native widget. Widget* CreateTestWidget() { Widget* widget = new Widget(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(params); + widget->Show(); return widget; } @@ -64,7 +66,7 @@ class BubbleDialogDelegateTest : public ViewsTestBase { } // namespace TEST_F(BubbleDialogDelegateTest, CreateDelegate) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); bubble_delegate->set_color(SK_ColorGREEN); @@ -76,7 +78,6 @@ TEST_F(BubbleDialogDelegateTest, CreateDelegate) { bubble_widget->Show(); BubbleBorder* border = bubble_delegate->GetBubbleFrameView()->bubble_border(); - EXPECT_EQ(bubble_delegate->arrow(), border->arrow()); EXPECT_EQ(bubble_delegate->color(), border->background_color()); EXPECT_FALSE(bubble_observer.widget_closed()); @@ -84,8 +85,27 @@ TEST_F(BubbleDialogDelegateTest, CreateDelegate) { EXPECT_TRUE(bubble_observer.widget_closed()); } +TEST_F(BubbleDialogDelegateTest, MirrorArrowInRtl) { + std::string default_locale = base::i18n::GetConfiguredLocale(); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); + for (bool rtl : {false, true}) { + base::i18n::SetICUDefaultLocale(rtl ? "he" : "en"); + EXPECT_EQ(rtl, base::i18n::IsRTL()); + for (bool mirror : {false, true}) { + TestBubbleDialogDelegateView* bubble = + new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); + bubble->set_mirror_arrow_in_rtl(mirror); + BubbleDialogDelegateView::CreateBubble(bubble); + EXPECT_EQ(rtl && mirror ? BubbleBorder::horizontal_mirror(bubble->arrow()) + : bubble->arrow(), + bubble->GetBubbleFrameView()->bubble_border()->arrow()); + } + } + base::i18n::SetICUDefaultLocale(default_locale); +} + TEST_F(BubbleDialogDelegateTest, CloseAnchorWidget) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); // Preventing close on deactivate should not prevent closing with the anchor. @@ -104,7 +124,7 @@ TEST_F(BubbleDialogDelegateTest, CloseAnchorWidget) { // TODO(msw): Remove activation hack to prevent bookkeeping errors in: // aura::test::TestActivationClient::OnWindowDestroyed(). - scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); + std::unique_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); EXPECT_FALSE(bubble_observer.widget_closed()); // Ensure that closing the anchor widget also closes the bubble itself. @@ -117,8 +137,8 @@ TEST_F(BubbleDialogDelegateTest, CloseAnchorWidget) { // bubble will call upon the anchor view to get its location). TEST_F(BubbleDialogDelegateTest, CloseAnchorViewTest) { // Create an anchor widget and add a view to be used as an anchor view. - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); - scoped_ptr<View> anchor_view(new View()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<View> anchor_view(new View()); anchor_widget->GetContentsView()->AddChildView(anchor_view.get()); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_view.get()); @@ -151,7 +171,7 @@ TEST_F(BubbleDialogDelegateTest, CloseAnchorViewTest) { // Testing that a move of the anchor view will lead to new bubble locations. TEST_F(BubbleDialogDelegateTest, TestAnchorRectMovesWithViewTest) { // Create an anchor widget and add a view to be used as anchor view. - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); BubbleDialogDelegateView::CreateBubble(bubble_delegate); @@ -165,13 +185,13 @@ TEST_F(BubbleDialogDelegateTest, TestAnchorRectMovesWithViewTest) { } TEST_F(BubbleDialogDelegateTest, ResetAnchorWidget) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); // Make sure the bubble widget is parented to a widget other than the anchor // widget so that closing the anchor widget does not close the bubble widget. - scoped_ptr<Widget> parent_widget(CreateTestWidget()); + std::unique_ptr<Widget> parent_widget(CreateTestWidget()); bubble_delegate->set_parent_window(parent_widget->GetNativeView()); // Preventing close on deactivate should not prevent closing with the parent. bubble_delegate->set_close_on_deactivate(false); @@ -197,7 +217,7 @@ TEST_F(BubbleDialogDelegateTest, ResetAnchorWidget) { // TODO(msw): Remove activation hack to prevent bookkeeping errors in: // aura::test::TestActivationClient::OnWindowDestroyed(). - scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); + std::unique_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget()); EXPECT_FALSE(bubble_observer.widget_closed()); // Ensure that closing the parent widget also closes the bubble itself. @@ -206,7 +226,7 @@ TEST_F(BubbleDialogDelegateTest, ResetAnchorWidget) { } TEST_F(BubbleDialogDelegateTest, InitiallyFocusedView) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); Widget* bubble_widget = @@ -218,7 +238,7 @@ TEST_F(BubbleDialogDelegateTest, InitiallyFocusedView) { } TEST_F(BubbleDialogDelegateTest, NonClientHitTest) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); BubbleDialogDelegateView::CreateBubble(bubble_delegate); @@ -240,7 +260,7 @@ TEST_F(BubbleDialogDelegateTest, NonClientHitTest) { } TEST_F(BubbleDialogDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); Widget* bubble_widget = @@ -248,7 +268,6 @@ TEST_F(BubbleDialogDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) { test::TestWidgetObserver bubble_observer(bubble_widget); EXPECT_FALSE(bubble_observer.widget_closed()); - anchor_widget->Show(); bubble_widget->Show(); EXPECT_TRUE(bubble_widget->IsVisible()); anchor_widget->SetBounds(gfx::Rect(10, 10, 100, 100)); @@ -258,7 +277,7 @@ TEST_F(BubbleDialogDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) { // Test that setting WidgetDelegate::set_can_activate() to false makes the // widget created via BubbleDialogDelegateView::CreateBubble() not activatable. TEST_F(BubbleDialogDelegateTest, NotActivatable) { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); bubble_delegate->set_can_activate(false); @@ -270,20 +289,19 @@ TEST_F(BubbleDialogDelegateTest, NotActivatable) { TEST_F(BubbleDialogDelegateTest, CloseMethods) { { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); bubble_delegate->set_close_on_deactivate(true); Widget* bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble_delegate); - anchor_widget->Show(); bubble_widget->Show(); anchor_widget->Activate(); EXPECT_TRUE(bubble_widget->IsClosed()); } { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); BubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); Widget* bubble_widget = @@ -296,7 +314,7 @@ TEST_F(BubbleDialogDelegateTest, CloseMethods) { } { - scoped_ptr<Widget> anchor_widget(CreateTestWidget()); + std::unique_ptr<Widget> anchor_widget(CreateTestWidget()); TestBubbleDialogDelegateView* bubble_delegate = new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); Widget* bubble_widget = diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc index 3f8411b22d8..43bac842f05 100644 --- a/chromium/ui/views/bubble/bubble_frame_view.cc +++ b/chromium/ui/views/bubble/bubble_frame_view.cc @@ -14,9 +14,10 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/path.h" -#include "ui/gfx/screen.h" #include "ui/gfx/skia_util.h" #include "ui/native_theme/native_theme.h" #include "ui/resources/grit/ui_resources.h" @@ -220,7 +221,6 @@ void BubbleFrameView::UpdateWindowIcon() { title_icon_->SetImage(&image); } - void BubbleFrameView::UpdateWindowTitle() { title_->SetText(GetWidget()->widget_delegate()->GetWindowTitle()); title_->SetVisible(GetWidget()->widget_delegate()->ShouldShowWindowTitle()); @@ -303,6 +303,7 @@ void BubbleFrameView::Layout() { gfx::Size title_icon_pref_size(title_icon_->GetPreferredSize()); int padding = 0; + int title_height = title_icon_pref_size.height(); if (title_->visible() && !title_->text().empty()) { if (title_icon_pref_size.width() > 0) @@ -311,11 +312,11 @@ void BubbleFrameView::Layout() { const int title_label_x = bounds.x() + title_icon_pref_size.width() + padding; title_->SizeToFit(std::max(1, close_->x() - title_label_x)); - title_->SetPosition(gfx::Point(title_label_x, bounds.y())); + title_height = std::max(title_height, title_->height()); + title_->SetPosition(gfx::Point( + title_label_x, bounds.y() + (title_height - title_->height()) / 2)); } - const int title_height = - std::max(title_icon_pref_size.height(), title_->height()); title_icon_->SetBounds(bounds.x(), bounds.y(), title_icon_pref_size.width(), title_height); bounds.set_width(title_->bounds().right() - bounds.x()); @@ -364,7 +365,7 @@ void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) { } } -void BubbleFrameView::SetBubbleBorder(scoped_ptr<BubbleBorder> border) { +void BubbleFrameView::SetBubbleBorder(std::unique_ptr<BubbleBorder> border) { bubble_border_ = border.get(); SetBorder(std::move(border)); @@ -414,7 +415,7 @@ gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect, gfx::Rect BubbleFrameView::GetAvailableScreenBounds( const gfx::Rect& rect) const { // The bubble attempts to fit within the current screen bounds. - return gfx::Screen::GetScreen() + return display::Screen::GetScreen() ->GetDisplayNearestPoint(rect.CenterPoint()) .work_area(); } diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h index 812c3e77f35..90f1030c7d9 100644 --- a/chromium/ui/views/bubble/bubble_frame_view.h +++ b/chromium/ui/views/bubble/bubble_frame_view.h @@ -70,7 +70,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, // Use bubble_border() and SetBubbleBorder(), not border() and SetBorder(). BubbleBorder* bubble_border() const { return bubble_border_; } - void SetBubbleBorder(scoped_ptr<BubbleBorder> border); + void SetBubbleBorder(std::unique_ptr<BubbleBorder> border); gfx::Insets content_margins() const { return content_margins_; } @@ -85,6 +85,8 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView, bool close_button_clicked() const { return close_button_clicked_; } + LabelButton* GetCloseButtonForTest() { return close_; } + protected: // Returns the available screen bounds if the frame were to show in |rect|. virtual gfx::Rect GetAvailableScreenBounds(const gfx::Rect& rect) const; diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc index d71137f5eb2..9f489f525d2 100644 --- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc +++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/bubble/bubble_frame_view.h" + +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/views/bubble/bubble_border.h" -#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" @@ -70,7 +72,7 @@ class TestBubbleFrameView : public BubbleFrameView { : BubbleFrameView(gfx::Insets(), gfx::Insets(kMargin)), test_base_(test_base), available_bounds_(gfx::Rect(0, 0, 1000, 1000)) { - SetBubbleBorder(scoped_ptr<BubbleBorder>( + SetBubbleBorder(std::unique_ptr<BubbleBorder>( new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor))); } ~TestBubbleFrameView() override {} @@ -102,8 +104,8 @@ class TestBubbleFrameView : public BubbleFrameView { gfx::Rect available_bounds_; // Widget returned by GetWidget(). Only created if GetWidget() is called. - mutable scoped_ptr<TestBubbleFrameViewWidgetDelegate> widget_delegate_; - mutable scoped_ptr<Widget> widget_; + mutable std::unique_ptr<TestBubbleFrameViewWidgetDelegate> widget_delegate_; + mutable std::unique_ptr<Widget> widget_; DISALLOW_COPY_AND_ASSIGN(TestBubbleFrameView); }; diff --git a/chromium/ui/views/bubble/bubble_window_targeter.cc b/chromium/ui/views/bubble/bubble_window_targeter.cc index 19e0c85f91a..8fa0da81c94 100644 --- a/chromium/ui/views/bubble/bubble_window_targeter.cc +++ b/chromium/ui/views/bubble/bubble_window_targeter.cc @@ -7,15 +7,14 @@ #include "ui/aura/window.h" #include "ui/gfx/path.h" #include "ui/gfx/skia_util.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/bubble/bubble_frame_view.h" namespace views { -BubbleWindowTargeter::BubbleWindowTargeter(BubbleDelegateView* bubble) +BubbleWindowTargeter::BubbleWindowTargeter(BubbleDialogDelegateView* bubble) : wm::MaskedWindowTargeter(bubble->GetWidget()->GetNativeView()), - bubble_(bubble) { -} + bubble_(bubble) {} BubbleWindowTargeter::~BubbleWindowTargeter() { } diff --git a/chromium/ui/views/bubble/bubble_window_targeter.h b/chromium/ui/views/bubble/bubble_window_targeter.h index fd9550fcd6e..7b7f87b5f76 100644 --- a/chromium/ui/views/bubble/bubble_window_targeter.h +++ b/chromium/ui/views/bubble/bubble_window_targeter.h @@ -11,21 +11,22 @@ class Window; } namespace views { -class BubbleDelegateView; + +class BubbleDialogDelegateView; // A convenient window-targeter that uses a mask based on the content-bounds of // the bubble-frame. class VIEWS_EXPORT BubbleWindowTargeter : public NON_EXPORTED_BASE(wm::MaskedWindowTargeter) { public: - explicit BubbleWindowTargeter(BubbleDelegateView* bubble); + explicit BubbleWindowTargeter(BubbleDialogDelegateView* bubble); ~BubbleWindowTargeter() override; private: // wm::MaskedWindowTargeter: bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override; - views::BubbleDelegateView* bubble_; + views::BubbleDialogDelegateView* bubble_; DISALLOW_COPY_AND_ASSIGN(BubbleWindowTargeter); }; diff --git a/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc b/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc index f40aa326977..3533ad2fb38 100644 --- a/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc +++ b/chromium/ui/views/bubble/bubble_window_targeter_unittest.cc @@ -9,7 +9,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/events/event_utils.h" #include "ui/views/bubble/bubble_border.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" @@ -17,16 +17,15 @@ namespace views { namespace { -class WidgetOwnsNativeBubble : public BubbleDelegateView { +class WidgetOwnsNativeBubble : public BubbleDialogDelegateView { public: WidgetOwnsNativeBubble(View* content, BubbleBorder::Arrow arrow) - : BubbleDelegateView(content, arrow) { - } + : BubbleDialogDelegateView(content, arrow) {} ~WidgetOwnsNativeBubble() override {} private: - // BubbleDelegateView: + // BubbleDialogDelegateView: void OnBeforeBubbleWidgetInit(Widget::InitParams* params, Widget* widget) const override { params->ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -62,7 +61,7 @@ class BubbleWindowTargeterTest : public ViewsTestBase { Widget* anchor_widget() { return anchor_.get(); } Widget* bubble_widget() { return bubble_widget_.get(); } - BubbleDelegateView* bubble_delegate() { return bubble_delegate_; } + BubbleDialogDelegateView* bubble_delegate() { return bubble_delegate_; } private: void CreateAnchorWidget() { @@ -76,12 +75,13 @@ class BubbleWindowTargeterTest : public ViewsTestBase { bubble_delegate_ = new WidgetOwnsNativeBubble( anchor_->GetContentsView(), BubbleBorder::NONE); bubble_delegate_->set_color(SK_ColorGREEN); - bubble_widget_.reset(BubbleDelegateView::CreateBubble(bubble_delegate_)); + bubble_widget_.reset( + BubbleDialogDelegateView::CreateBubble(bubble_delegate_)); } - scoped_ptr<Widget> anchor_; - scoped_ptr<Widget> bubble_widget_; - BubbleDelegateView* bubble_delegate_; + std::unique_ptr<Widget> anchor_; + std::unique_ptr<Widget> bubble_widget_; + BubbleDialogDelegateView* bubble_delegate_; DISALLOW_COPY_AND_ASSIGN(BubbleWindowTargeterTest); }; @@ -107,7 +107,7 @@ TEST_F(BubbleWindowTargeterTest, HitTest) { EXPECT_EQ(bubble_window, targeter->FindTargetForEvent(root, &move1)); } - bubble_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>( + bubble_window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>( new BubbleWindowTargeter(bubble_delegate()))); { bubble_delegate()->set_margins(gfx::Insets(20)); diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc index ad3267fe659..0303ea5c1f8 100644 --- a/chromium/ui/views/bubble/tray_bubble_view.cc +++ b/chromium/ui/views/bubble/tray_bubble_view.cc @@ -320,7 +320,7 @@ TrayBubbleView::TrayBubbleView(gfx::NativeView parent_window, View* anchor, Delegate* delegate, const InitParams& init_params) - : BubbleDelegateView(anchor, init_params.arrow), + : BubbleDialogDelegateView(anchor, init_params.arrow), params_(init_params), delegate_(delegate), preferred_width_(init_params.min_width), @@ -346,7 +346,7 @@ TrayBubbleView::~TrayBubbleView() { } void TrayBubbleView::InitializeAndShowBubble() { - // Must occur after call to BubbleDelegateView::CreateBubble(). + // Must occur after call to BubbleDialogDelegateView::CreateBubble(). SetAlignment(params_.arrow_alignment); bubble_border_->UpdateArrowOffset(); @@ -354,7 +354,7 @@ void TrayBubbleView::InitializeAndShowBubble() { GetWidget()->Show(); GetWidget()->GetNativeWindow()->SetEventTargeter( - scoped_ptr<ui::EventTargeter>(new BubbleWindowTargeter(this))); + std::unique_ptr<ui::EventTargeter>(new BubbleWindowTargeter(this))); UpdateBubble(); } @@ -391,6 +391,10 @@ gfx::Insets TrayBubbleView::GetBorderInsets() const { return bubble_border_->GetInsets(); } +int TrayBubbleView::GetDialogButtons() const { + return ui::DIALOG_BUTTON_NONE; +} + void TrayBubbleView::Init() { BoxLayout* layout = new BottomAlignedBoxLayout(this); layout->SetDefaultFlex(1); @@ -411,7 +415,7 @@ bool TrayBubbleView::CanActivate() const { NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) { BubbleFrameView* frame = static_cast<BubbleFrameView*>( - BubbleDelegateView::CreateNonClientFrameView(widget)); + BubbleDialogDelegateView::CreateNonClientFrameView(widget)); frame->SetBubbleBorder(std::move(owned_bubble_border_)); return frame; } diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h index c0c0c7c2872..b24a2e90eef 100644 --- a/chromium/ui/views/bubble/tray_bubble_view.h +++ b/chromium/ui/views/bubble/tray_bubble_view.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_BUBBLE_TRAY_BUBBLE_VIEW_H_ #define UI_VIEWS_BUBBLE_TRAY_BUBBLE_VIEW_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/mouse_watcher.h" #include "ui/views/views_export.h" @@ -31,7 +32,7 @@ class TrayBubbleContentMask; // Ash status area). Mostly this handles custom anchor location and arrow and // border rendering. This also has its own delegate for handling mouse events // and other implementation specific details. -class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, +class VIEWS_EXPORT TrayBubbleView : public views::BubbleDialogDelegateView, public views::MouseWatcherListener { public: // AnchorType differentiates between bubbles that are anchored on a tray @@ -73,7 +74,7 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, // accessible name for the bubble. virtual base::string16 GetAccessibleNameForBubble() = 0; - // Passes responsibility for BubbleDelegateView::GetAnchorRect to the + // Passes responsibility for BubbleDialogDelegateView::GetAnchorRect to the // delegate. virtual gfx::Rect GetAnchorRect( views::Widget* anchor_widget, @@ -154,7 +155,7 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, bool WidgetHasHitTestMask() const override; void GetWidgetHitTestMask(gfx::Path* mask) const override; - // Overridden from views::BubbleDelegateView. + // Overridden from views::BubbleDialogDelegateView. gfx::Rect GetAnchorRect() const override; // Overridden from views::View. @@ -174,7 +175,8 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, Delegate* delegate, const InitParams& init_params); - // Overridden from views::BubbleDelegateView. + // Overridden from views::BubbleDialogDelegateView. + int GetDialogButtons() const override; void Init() override; // Overridden from views::View. @@ -189,8 +191,8 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, // |bubble_border_| and |owned_bubble_border_| point to the same thing, but // the latter ensures we don't leak it before passing off ownership. internal::TrayBubbleBorder* bubble_border_; - scoped_ptr<views::BubbleBorder> owned_bubble_border_; - scoped_ptr<internal::TrayBubbleContentMask> bubble_content_mask_; + std::unique_ptr<views::BubbleBorder> owned_bubble_border_; + std::unique_ptr<internal::TrayBubbleContentMask> bubble_content_mask_; bool is_gesture_dragging_; // True once the mouse cursor was actively moved by the user over the bubble. @@ -198,7 +200,7 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView, bool mouse_actively_entered_; // Used to find any mouse movements. - scoped_ptr<MouseWatcher> mouse_watcher_; + std::unique_ptr<MouseWatcher> mouse_watcher_; DISALLOW_COPY_AND_ASSIGN(TrayBubbleView); }; diff --git a/chromium/ui/views/button_drag_utils.cc b/chromium/ui/views/button_drag_utils.cc index 60bd6e5abca..70ecf3a3891 100644 --- a/chromium/ui/views/button_drag_utils.cc +++ b/chromium/ui/views/button_drag_utils.cc @@ -81,7 +81,7 @@ void SetDragImage(const GURL& url, press_point = gfx::Vector2d(prefsize.width() / 2, prefsize.height() / 2); // Render the image. - scoped_ptr<gfx::Canvas> canvas( + std::unique_ptr<gfx::Canvas> canvas( views::GetCanvasForDragImage(widget, prefsize)); button.Paint(ui::CanvasPainter(canvas.get(), 1.f).context()); drag_utils::SetDragImageOnDataObject(*canvas, press_point, data); diff --git a/chromium/ui/views/cocoa/bridged_content_view.h b/chromium/ui/views/cocoa/bridged_content_view.h index f4b6a867cd7..20111a8bf6b 100644 --- a/chromium/ui/views/cocoa/bridged_content_view.h +++ b/chromium/ui/views/cocoa/bridged_content_view.h @@ -79,6 +79,10 @@ class View; // Update windowMask_ depending on the current view bounds. - (void)updateWindowMask; +// Notifies the associated FocusManager whether full keyboard access is enabled +// or not. +- (void)updateFullKeyboardAccess; + @end #endif // UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_ diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm index 6d72fef5cf7..a59d4f07884 100644 --- a/chromium/ui/views/cocoa/bridged_content_view.mm +++ b/chromium/ui/views/cocoa/bridged_content_view.mm @@ -32,6 +32,9 @@ using views::MenuController; namespace { +NSString* const kFullKeyboardAccessChangedNotification = + @"com.apple.KeyboardUIModeDidChange"; + // Returns true if all four corners of |rect| are contained inside |path|. bool IsRectInsidePath(NSRect rect, NSBezierPath* path) { return [path containsPoint:rect.origin] && @@ -160,6 +163,40 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, return union_rect; } +// Returns the string corresponding to |requested_range| for the given |client|. +// If a gfx::Range::InvalidRange() is passed, the full string stored by |client| +// is returned. Sets |actual_range| corresponding to the returned string. +base::string16 AttributedSubstringForRangeHelper( + const ui::TextInputClient* client, + const gfx::Range& requested_range, + gfx::Range* actual_range) { + // NSRange doesn't support reversed ranges. + DCHECK(!requested_range.is_reversed()); + DCHECK(actual_range); + + base::string16 substring; + gfx::Range text_range; + *actual_range = gfx::Range::InvalidRange(); + if (!client || !client->GetTextRange(&text_range)) + return substring; + + // gfx::Range::Intersect() behaves a bit weirdly. If B is an empty range + // contained inside a non-empty range A, B intersection A returns + // gfx::Range::InvalidRange(), instead of returning B. + *actual_range = text_range.Contains(requested_range) + ? requested_range + : text_range.Intersect(requested_range); + + // This is a special case for which the complete string should should be + // returned. NSTextView also follows this, though the same is not mentioned in + // NSTextInputClient documentation. + if (!requested_range.IsValid()) + *actual_range = text_range; + + client->GetTextFromRange(*actual_range, &substring); + return substring; +} + } // namespace @interface BridgedContentView () @@ -185,6 +222,9 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, domCode:(ui::DomCode)domCode eventFlags:(int)eventFlags; +// Notification handler invoked when the Full Keyboard Access mode is changed. +- (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification; + // Menu action handlers. - (void)undo:(id)sender; - (void)redo:(id)sender; @@ -221,6 +261,17 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, owner:self userInfo:nil]); [self addTrackingArea:cursorTrackingArea_.get()]; + + // Get notified whenever Full Keyboard Access mode is changed. + [[NSDistributedNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onFullKeyboardAccessModeChanged:) + name:kFullKeyboardAccessChangedNotification + object:nil]; + + // Initialize the focus manager with the correct keyboard accessibility + // setting. + [self updateFullKeyboardAccess]; } return self; } @@ -228,6 +279,7 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, - (void)clearView { textInputClient_ = nullptr; hostedView_ = nullptr; + [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; [cursorTrackingArea_.get() clearOwner]; [self removeTrackingArea:cursorTrackingArea_.get()]; } @@ -293,6 +345,16 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, [windowMask_ transformUsingAffineTransform:flipTransform]; } +- (void)updateFullKeyboardAccess { + if (!hostedView_) + return; + + views::FocusManager* focusManager = + hostedView_->GetWidget()->GetFocusManager(); + if (focusManager) + focusManager->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]); +} + // BridgedContentView private implementation. - (void)handleKeyEvent:(NSEvent*)theEvent { @@ -328,6 +390,12 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event); } +- (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification { + DCHECK([[notification name] + isEqualToString:kFullKeyboardAccessChangedNotification]); + [self updateFullKeyboardAccess]; +} + - (void)undo:(id)sender { // This DCHECK is more strict than a similar check in handleAction:. It can be // done here because the actors sending these actions should be calling @@ -567,6 +635,9 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, // TODO(tapted): Make this list complete, except for insert* methods which are // dispatched as regular key events in doCommandBySelector:. +// views::Textfields are single-line only, map Paragraph and Document commands +// to Line. Also, Up/Down commands correspond to beginning/end of line. + // The insertText action message forwards to the TextInputClient unless a menu // is active. Note that NSResponder's interpretKeyEvents: implementation doesn't // direct insertText: through doCommandBySelector:, so this is still needed to @@ -578,6 +649,11 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, // Selection movement and scrolling. +- (void)moveForward:(id)sender { + IsTextRTL(textInputClient_) ? [self moveLeft:sender] + : [self moveRight:sender]; +} + - (void)moveRight:(id)sender { [self handleAction:IDS_MOVE_RIGHT keyCode:ui::VKEY_RIGHT @@ -585,6 +661,11 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, eventFlags:0]; } +- (void)moveBackward:(id)sender { + IsTextRTL(textInputClient_) ? [self moveRight:sender] + : [self moveLeft:sender]; +} + - (void)moveLeft:(id)sender { [self handleAction:IDS_MOVE_LEFT keyCode:ui::VKEY_LEFT @@ -593,19 +674,177 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, } - (void)moveUp:(id)sender { - [self handleAction:0 + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE keyCode:ui::VKEY_UP domCode:ui::DomCode::ARROW_UP eventFlags:0]; } - (void)moveDown:(id)sender { - [self handleAction:0 + [self handleAction:IDS_MOVE_TO_END_OF_LINE keyCode:ui::VKEY_DOWN domCode:ui::DomCode::ARROW_DOWN eventFlags:0]; } +- (void)moveWordForward:(id)sender { + IsTextRTL(textInputClient_) ? [self moveWordLeft:sender] + : [self moveWordRight:sender]; +} + +- (void)moveWordBackward:(id)sender { + IsTextRTL(textInputClient_) ? [self moveWordRight:sender] + : [self moveWordLeft:sender]; +} + +- (void)moveToBeginningOfLine:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE + keyCode:ui::VKEY_HOME + domCode:ui::DomCode::HOME + eventFlags:0]; +} + +- (void)moveToEndOfLine:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE + keyCode:ui::VKEY_END + domCode:ui::DomCode::END + eventFlags:0]; +} + +- (void)moveToBeginningOfParagraph:(id)sender { + [self moveToBeginningOfLine:sender]; +} + +- (void)moveToEndOfParagraph:(id)sender { + [self moveToEndOfLine:sender]; +} + +- (void)moveToEndOfDocument:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE + keyCode:ui::VKEY_END + domCode:ui::DomCode::END + eventFlags:ui::EF_CONTROL_DOWN]; +} + +- (void)moveToBeginningOfDocument:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE + keyCode:ui::VKEY_HOME + domCode:ui::DomCode::HOME + eventFlags:ui::EF_CONTROL_DOWN]; +} + +- (void)pageDown:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE + keyCode:ui::VKEY_NEXT + domCode:ui::DomCode::PAGE_DOWN + eventFlags:0]; +} + +- (void)pageUp:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE + keyCode:ui::VKEY_PRIOR + domCode:ui::DomCode::PAGE_UP + eventFlags:0]; +} + +- (void)moveBackwardAndModifySelection:(id)sender { + IsTextRTL(textInputClient_) ? [self moveRightAndModifySelection:sender] + : [self moveLeftAndModifySelection:sender]; +} + +- (void)moveForwardAndModifySelection:(id)sender { + IsTextRTL(textInputClient_) ? [self moveLeftAndModifySelection:sender] + : [self moveRightAndModifySelection:sender]; +} + +- (void)moveWordForwardAndModifySelection:(id)sender { + IsTextRTL(textInputClient_) ? [self moveWordLeftAndModifySelection:sender] + : [self moveWordRightAndModifySelection:sender]; +} + +- (void)moveWordBackwardAndModifySelection:(id)sender { + IsTextRTL(textInputClient_) ? [self moveWordRightAndModifySelection:sender] + : [self moveWordLeftAndModifySelection:sender]; +} + +- (void)moveUpAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UP + domCode:ui::DomCode::ARROW_UP + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)moveDownAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_DOWN + domCode:ui::DomCode::ARROW_DOWN + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)moveToBeginningOfLineAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_HOME + domCode:ui::DomCode::HOME + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)moveToEndOfLineAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_END + domCode:ui::DomCode::END + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)moveToBeginningOfParagraphAndModifySelection:(id)sender { + [self moveToBeginningOfLineAndModifySelection:sender]; +} + +- (void)moveToEndOfParagraphAndModifySelection:(id)sender { + [self moveToEndOfLineAndModifySelection:sender]; +} + +- (void)moveToEndOfDocumentAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_END + domCode:ui::DomCode::END + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + +- (void)moveToBeginningOfDocumentAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_HOME + domCode:ui::DomCode::HOME + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + +- (void)pageDownAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_NEXT + domCode:ui::DomCode::PAGE_DOWN + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)pageUpAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_PRIOR + domCode:ui::DomCode::PAGE_UP + eventFlags:ui::EF_SHIFT_DOWN]; +} + +- (void)moveParagraphForwardAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_DOWN + domCode:ui::DomCode::ARROW_DOWN + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + +- (void)moveParagraphBackwardAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UP + domCode:ui::DomCode::ARROW_UP + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + - (void)moveWordRight:(id)sender { [self handleAction:IDS_MOVE_WORD_RIGHT keyCode:ui::VKEY_RIGHT @@ -620,13 +859,6 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, eventFlags:ui::EF_CONTROL_DOWN]; } -- (void)moveLeftAndModifySelection:(id)sender { - [self handleAction:IDS_MOVE_LEFT_AND_MODIFY_SELECTION - keyCode:ui::VKEY_LEFT - domCode:ui::DomCode::ARROW_LEFT - eventFlags:ui::EF_SHIFT_DOWN]; -} - - (void)moveRightAndModifySelection:(id)sender { [self handleAction:IDS_MOVE_RIGHT_AND_MODIFY_SELECTION keyCode:ui::VKEY_RIGHT @@ -634,6 +866,13 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, eventFlags:ui::EF_SHIFT_DOWN]; } +- (void)moveLeftAndModifySelection:(id)sender { + [self handleAction:IDS_MOVE_LEFT_AND_MODIFY_SELECTION + keyCode:ui::VKEY_LEFT + domCode:ui::DomCode::ARROW_LEFT + eventFlags:ui::EF_SHIFT_DOWN]; +} + - (void)moveWordRightAndModifySelection:(id)sender { [self handleAction:IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION keyCode:ui::VKEY_RIGHT @@ -649,31 +888,25 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, } - (void)moveToLeftEndOfLine:(id)sender { - [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE - keyCode:ui::VKEY_HOME - domCode:ui::DomCode::HOME - eventFlags:0]; + IsTextRTL(textInputClient_) ? [self moveToEndOfLine:sender] + : [self moveToBeginningOfLine:sender]; } - (void)moveToRightEndOfLine:(id)sender { - [self handleAction:IDS_MOVE_TO_END_OF_LINE - keyCode:ui::VKEY_END - domCode:ui::DomCode::END - eventFlags:0]; + IsTextRTL(textInputClient_) ? [self moveToBeginningOfLine:sender] + : [self moveToEndOfLine:sender]; } - (void)moveToLeftEndOfLineAndModifySelection:(id)sender { - [self handleAction:IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION - keyCode:ui::VKEY_HOME - domCode:ui::DomCode::HOME - eventFlags:ui::EF_SHIFT_DOWN]; + IsTextRTL(textInputClient_) + ? [self moveToEndOfLineAndModifySelection:sender] + : [self moveToBeginningOfLineAndModifySelection:sender]; } - (void)moveToRightEndOfLineAndModifySelection:(id)sender { - [self handleAction:IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION - keyCode:ui::VKEY_END - domCode:ui::DomCode::END - eventFlags:ui::EF_SHIFT_DOWN]; + IsTextRTL(textInputClient_) + ? [self moveToBeginningOfLineAndModifySelection:sender] + : [self moveToEndOfLineAndModifySelection:sender]; } // Deletions. @@ -706,6 +939,28 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, eventFlags:ui::EF_CONTROL_DOWN]; } +- (void)deleteToBeginningOfLine:(id)sender { + [self handleAction:IDS_DELETE_TO_BEGINNING_OF_LINE + keyCode:ui::VKEY_BACK + domCode:ui::DomCode::BACKSPACE + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + +- (void)deleteToEndOfLine:(id)sender { + [self handleAction:IDS_DELETE_TO_END_OF_LINE + keyCode:ui::VKEY_DELETE + domCode:ui::DomCode::DEL + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; +} + +- (void)deleteToBeginningOfParagraph:(id)sender { + [self deleteToBeginningOfLine:sender]; +} + +- (void)deleteToEndOfParagraph:(id)sender { + [self deleteToEndOfLine:sender]; +} + // Cancellation. - (void)cancelOperation:(id)sender { @@ -759,17 +1014,20 @@ gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client, - (NSAttributedString*) attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - base::string16 substring; - if (textInputClient_) { - gfx::Range textRange; - textInputClient_->GetTextRange(&textRange); - gfx::Range subrange = textRange.Intersect(gfx::Range(range)); - textInputClient_->GetTextFromRange(subrange, &substring); - if (actualRange) - *actualRange = subrange.ToNSRange(); + gfx::Range actual_range; + base::string16 substring = AttributedSubstringForRangeHelper( + textInputClient_, gfx::Range(range), &actual_range); + if (actualRange) { + // To maintain consistency with NSTextView, return range {0,0} for an out of + // bounds requested range. + *actualRange = + actual_range.IsValid() ? actual_range.ToNSRange() : NSMakeRange(0, 0); } - return [[[NSAttributedString alloc] - initWithString:base::SysUTF16ToNSString(substring)] autorelease]; + return substring.empty() + ? nil + : [[[NSAttributedString alloc] + initWithString:base::SysUTF16ToNSString(substring)] + autorelease]; } - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint { diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h index fc521597ee7..e4df8e78faa 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget.h +++ b/chromium/ui/views/cocoa/bridged_native_widget.h @@ -7,11 +7,11 @@ #import <Cocoa/Cocoa.h> +#include <memory> #include <vector> #import "base/mac/scoped_nsobject.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #import "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/base/ime/input_method_delegate.h" #include "ui/compositor/layer_owner.h" @@ -260,9 +260,9 @@ class VIEWS_EXPORT BridgedNativeWidget base::scoped_nsobject<NSWindow> window_; base::scoped_nsobject<ViewsNSWindowDelegate> window_delegate_; base::scoped_nsobject<BridgedContentView> bridged_view_; - scoped_ptr<ui::InputMethod> input_method_; - scoped_ptr<CocoaMouseCapture> mouse_capture_; - scoped_ptr<TooltipManager> tooltip_manager_; + std::unique_ptr<ui::InputMethod> input_method_; + std::unique_ptr<CocoaMouseCapture> mouse_capture_; + std::unique_ptr<TooltipManager> tooltip_manager_; FocusManager* focus_manager_; // Weak. Owned by our Widget. Widget::InitParams::Type widget_type_; @@ -270,8 +270,8 @@ class VIEWS_EXPORT BridgedNativeWidget std::vector<BridgedNativeWidget*> child_windows_; base::scoped_nsobject<NSView> compositor_superview_; - scoped_ptr<ui::AcceleratedWidgetMac> compositor_widget_; - scoped_ptr<ui::Compositor> compositor_; + std::unique_ptr<ui::AcceleratedWidgetMac> compositor_widget_; + std::unique_ptr<ui::Compositor> compositor_; // Tracks the bounds when the window last started entering fullscreen. Used to // provide an answer for GetRestoredBounds(), but not ever sent to Cocoa (it diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm index 0ccff9d15a0..1c9560f2e88 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget.mm +++ b/chromium/ui/views/cocoa/bridged_native_widget.mm @@ -12,17 +12,17 @@ #import "base/mac/foundation_util.h" #include "base/mac/mac_util.h" #import "base/mac/sdk_forward_declarations.h" -#include "base/thread_task_runner_handle.h" +#include "base/threading/thread_task_runner_handle.h" #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/input_method_factory.h" -#include "ui/gfx/display.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/geometry/dip_util.h" #import "ui/gfx/mac/coordinate_conversion.h" #import "ui/gfx/mac/nswindow_frame_controls.h" -#include "ui/gfx/screen.h" #import "ui/views/cocoa/bridged_content_view.h" #import "ui/views/cocoa/cocoa_mouse_capture.h" #include "ui/views/cocoa/tooltip_manager_mac.h" @@ -107,8 +107,8 @@ const int kResizeAreaCornerSize = 12; int kWindowPropertiesKey; float GetDeviceScaleFactorFromView(NSView* view) { - gfx::Display display = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow(view); DCHECK(display.is_valid()); return display.device_scale_factor(); } @@ -799,6 +799,9 @@ void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) { if ([window_ contentView] == [window_ firstResponder]) { if (is_key) { widget->OnNativeFocus(); + // Explicitly set the keyboard accessibility state on regaining key + // window status. + [bridged_view_ updateFullKeyboardAccess]; widget->GetFocusManager()->RestoreFocusedView(); } else { widget->OnNativeBlur(); diff --git a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm index 79fdac10510..9dc032a2ffe 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm +++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm @@ -70,7 +70,7 @@ class BridgedNativeWidgetUITest : public test::WidgetTest { } protected: - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; }; // Tests for correct fullscreen tracking, regardless of whether it is initiated diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm index 3b3eb082631..1faee145fec 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm @@ -6,19 +6,21 @@ #import <Cocoa/Cocoa.h> +#include <memory> + #import "base/mac/foundation_util.h" #import "base/mac/mac_util.h" #import "base/mac/sdk_forward_declarations.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #import "testing/gtest_mac.h" #import "ui/base/cocoa/window_size_constants.h" #include "ui/base/ime/input_method.h" -#import "ui/gfx/test/ui_cocoa_test_helper.h" #import "ui/gfx/mac/coordinate_conversion.h" +#import "ui/gfx/test/ui_cocoa_test_helper.h" #import "ui/views/cocoa/bridged_content_view.h" #import "ui/views/cocoa/native_widget_mac_nswindow.h" #import "ui/views/cocoa/views_nswindow_delegate.h" @@ -38,6 +40,21 @@ using base::SysUTF8ToNSString; EXPECT_EQ(a.location, b.location); \ EXPECT_EQ(a.length, b.length); +// Helpers to verify an expectation against both the actual toolkit-views +// behaviour and the Cocoa behaviour. + +#define EXPECT_NSEQ_3(expected_literal, expected_cocoa, actual_views) \ + EXPECT_NSEQ(expected_literal, actual_views); \ + EXPECT_NSEQ(expected_cocoa, actual_views); + +#define EXPECT_EQ_RANGE_3(expected_literal, expected_cocoa, actual_views) \ + EXPECT_EQ_RANGE(expected_literal, actual_views); \ + EXPECT_EQ_RANGE(expected_cocoa, actual_views); + +#define EXPECT_EQ_3(expected_literal, expected_cocoa, actual_views) \ + EXPECT_EQ(expected_literal, actual_views); \ + EXPECT_EQ(expected_cocoa, actual_views); + namespace { // Empty range shortcut for readibility. @@ -125,9 +142,7 @@ class MockNativeWidgetMac : public NativeWidgetMac { MockNativeWidgetMac(Widget* delegate) : NativeWidgetMac(delegate) {} // Expose a reference, so that it can be reset() independently. - scoped_ptr<BridgedNativeWidget>& bridge() { - return bridge_; - } + std::unique_ptr<BridgedNativeWidget>& bridge() { return bridge_; } // internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override { @@ -157,7 +172,7 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest { native_widget_mac_(new MockNativeWidgetMac(widget_.get())) { } - scoped_ptr<BridgedNativeWidget>& bridge() { + std::unique_ptr<BridgedNativeWidget>& bridge() { return native_widget_mac_->bridge(); } @@ -184,7 +199,7 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest { } protected: - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. // Make the InitParams available to tests to cover initialization codepaths. @@ -197,24 +212,69 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase { ~BridgedNativeWidgetTest() override; // Install a textfield with input type |text_input_type| in the view hierarchy - // and make it the text input client. - void InstallTextField(const std::string& text, + // and make it the text input client. Also initializes |dummy_text_view_|. + void InstallTextField(const base::string16& text, ui::TextInputType text_input_type); // Install a textfield with input type ui::TEXT_INPUT_TYPE_TEXT in the view - // hierarchy and make it the text input client. + // hierarchy and make it the text input client. Also initializes + // |dummy_text_view_|. + void InstallTextField(const base::string16& text); + void InstallTextField(const std::string& text); - // Returns the current text as std::string. - std::string GetText(); + // Returns the actual current text for |ns_view_|. + NSString* GetActualText(); + + // Returns the expected current text from |dummy_text_view_|. + NSString* GetExpectedText(); + + // Returns the actual selection range for |ns_view_|. + NSRange GetActualSelectionRange(); + + // Returns the expected selection range from |dummy_text_view_|. + NSRange GetExpectedSelectionRange(); + + // Set the selection range for the installed textfield and |dummy_text_view_|. + void SetSelectionRange(NSRange range); + + // Perform command |sel| on |ns_view_| and |dummy_text_view_|. + void PerformCommand(SEL sel); + + // Make selection from |start| to |end| on installed views::Textfield and + // |dummy_text_view_|. If |start| > |end|, extend selection to left from + // |start|. + void MakeSelection(int start, int end); // testing::Test: void SetUp() override; void TearDown() override; protected: - scoped_ptr<views::View> view_; - BridgedContentView* ns_view_; // Weak. Owned by bridge(). + // Test delete to beginning of line or paragraph based on |sel|. |sel| can be + // either deleteToBeginningOfLine: or deleteToBeginningOfParagraph:. + void TestDeleteBeginning(SEL sel); + + // Test delete to end of line or paragraph based on |sel|. |sel| can be + // either deleteToEndOfLine: or deleteToEndOfParagraph:. + void TestDeleteEnd(SEL sel); + + // Test editing commands in |selectors| against the expectations set by + // |dummy_text_view_|. This is done by selecting every substring within a set + // of test strings (both RTL and non-RTL) and performing every selector on + // both the NSTextView and the BridgedContentView hosting a focused + // views::TextField to ensure the resulting text and selection ranges match. + // |selectors| is an NSArray of NSStrings. + void TestEditingCommands(NSArray* selectors); + + std::unique_ptr<views::View> view_; + + // Weak. Owned by bridge(). + BridgedContentView* ns_view_; + + // An NSTextView which helps set the expectations for our tests. + base::scoped_nsobject<NSTextView> dummy_text_view_; + base::MessageLoopForUI message_loop_; private: @@ -228,10 +288,10 @@ BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { } void BridgedNativeWidgetTest::InstallTextField( - const std::string& text, + const base::string16& text, ui::TextInputType text_input_type) { Textfield* textfield = new Textfield(); - textfield->SetText(ASCIIToUTF16(text)); + textfield->SetText(text); textfield->SetTextInputType(text_input_type); view_->RemoveAllChildViews(true); view_->AddChildView(textfield); @@ -243,17 +303,67 @@ void BridgedNativeWidgetTest::InstallTextField( textfield->RequestFocus(); [ns_view_ setTextInputClient:textfield]; + + // Initialize the dummy text view. + dummy_text_view_.reset([[NSTextView alloc] initWithFrame:NSZeroRect]); + [dummy_text_view_ setString:SysUTF16ToNSString(text)]; } -void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { +void BridgedNativeWidgetTest::InstallTextField(const base::string16& text) { InstallTextField(text, ui::TEXT_INPUT_TYPE_TEXT); } -std::string BridgedNativeWidgetTest::GetText() { +void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { + InstallTextField(base::ASCIIToUTF16(text), ui::TEXT_INPUT_TYPE_TEXT); +} + +NSString* BridgedNativeWidgetTest::GetActualText() { NSRange range = NSMakeRange(0, NSUIntegerMax); - NSAttributedString* text = - [ns_view_ attributedSubstringForProposedRange:range actualRange:NULL]; - return SysNSStringToUTF8([text string]); + return [[ns_view_ attributedSubstringForProposedRange:range + actualRange:nullptr] string]; +} + +NSString* BridgedNativeWidgetTest::GetExpectedText() { + NSRange range = NSMakeRange(0, NSUIntegerMax); + return + [[dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:nullptr] string]; +} + +NSRange BridgedNativeWidgetTest::GetActualSelectionRange() { + return [ns_view_ selectedRange]; +} + +NSRange BridgedNativeWidgetTest::GetExpectedSelectionRange() { + return [dummy_text_view_ selectedRange]; +} + +void BridgedNativeWidgetTest::SetSelectionRange(NSRange range) { + ui::TextInputClient* client = [ns_view_ textInputClient]; + client->SetSelectionRange(gfx::Range(range)); + + [dummy_text_view_ setSelectedRange:range]; +} + +void BridgedNativeWidgetTest::PerformCommand(SEL sel) { + [ns_view_ doCommandBySelector:sel]; + [dummy_text_view_ doCommandBySelector:sel]; +} + +void BridgedNativeWidgetTest::MakeSelection(int start, int end) { + ui::TextInputClient* client = [ns_view_ textInputClient]; + client->SetSelectionRange(gfx::Range(start, end)); + + // Though NSTextView has a selectionAffinity property, it does not seem to + // correspond to the selection direction. Hence we extend the selection from + //|start| to |end|. + [dummy_text_view_ setSelectedRange:NSMakeRange(start, 0)]; + SEL sel = start > end ? @selector(moveBackwardAndModifySelection:) + : @selector(moveForwardAndModifySelection:); + size_t delta = std::abs(end - start); + + for (size_t i = 0; i < delta; i++) + [dummy_text_view_ doCommandBySelector:sel]; } void BridgedNativeWidgetTest::SetUp() { @@ -285,6 +395,97 @@ void BridgedNativeWidgetTest::TearDown() { BridgedNativeWidgetTestBase::TearDown(); } +void BridgedNativeWidgetTest::TestDeleteBeginning(SEL sel) { + InstallTextField("foo bar baz"); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret to the beginning of the line. + SetSelectionRange(NSMakeRange(0, 0)); + // Verify no deletion takes place. + PerformCommand(sel); + EXPECT_NSEQ_3(@"foo bar baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret as- "foo| bar baz". + SetSelectionRange(NSMakeRange(3, 0)); + PerformCommand(sel); + // Verify state is "| bar baz". + EXPECT_NSEQ_3(@" bar baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Make a selection as- " bar |baz|". + SetSelectionRange(NSMakeRange(5, 3)); + PerformCommand(sel); + // Verify only the selection is deleted so that the state is " bar |". + EXPECT_NSEQ_3(@" bar ", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(5, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); +} + +void BridgedNativeWidgetTest::TestDeleteEnd(SEL sel) { + InstallTextField("foo bar baz"); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Caret is at the end of the line. Verify no deletion takes place. + PerformCommand(sel); + EXPECT_NSEQ_3(@"foo bar baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret as- "foo bar| baz". + SetSelectionRange(NSMakeRange(7, 0)); + PerformCommand(sel); + // Verify state is "foo bar|". + EXPECT_NSEQ_3(@"foo bar", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(7, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Make a selection as- "|foo |bar". + SetSelectionRange(NSMakeRange(0, 4)); + PerformCommand(sel); + // Verify only the selection is deleted so that the state is "|bar". + EXPECT_NSEQ_3(@"bar", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); +} + +void BridgedNativeWidgetTest::TestEditingCommands(NSArray* selectors) { + const base::string16 test_strings[] = { + base::WideToUTF16(L"ab c"), + base::WideToUTF16(L"\x0634\x0632 \x064A") // RTL string. + }; + + for (const base::string16& test_string : test_strings) { + for (NSString* selector_string in selectors) { + SEL sel = NSSelectorFromString(selector_string); + const int len = test_string.length(); + for (int i = 0; i <= len; i++) { + for (int j = 0; j <= len; j++) { + SCOPED_TRACE(base::StringPrintf( + "Testing range [%d-%d] for case %s and selector %s\n", i, j, + base::UTF16ToUTF8(test_string).c_str(), + base::SysNSStringToUTF8(selector_string).c_str())); + + InstallTextField(test_string); + MakeSelection(i, j); + EXPECT_EQ_RANGE_3(NSMakeRange(std::min(i, j), std::abs(i - j)), + GetExpectedSelectionRange(), + GetActualSelectionRange()); + + PerformCommand(sel); + EXPECT_NSEQ(GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE(GetExpectedSelectionRange(), + GetActualSelectionRange()); + } + } + } + } +} + // The TEST_VIEW macro expects the view it's testing to have a superview. In // these tests, the NSView bridge is a contentView, at the root. These mimic // what TEST_VIEW usually does. @@ -418,7 +619,7 @@ TEST_F(BridgedNativeWidgetInitTest, ShadowType) { // Ensure a nil NSTextInputContext is returned when the ui::TextInputClient is // not editable, a password field, or unset. TEST_F(BridgedNativeWidgetTest, InputContext) { - const std::string test_string = "test_str"; + const base::string16 test_string = base::ASCIIToUTF16("test_str"); InstallTextField(test_string, ui::TEXT_INPUT_TYPE_PASSWORD); EXPECT_FALSE([ns_view_ inputContext]); InstallTextField(test_string, ui::TEXT_INPUT_TYPE_TEXT); @@ -436,11 +637,18 @@ TEST_F(BridgedNativeWidgetTest, TextInput_GetCompleteString) { NSRange range = NSMakeRange(0, test_string.size()); NSRange actual_range; - NSAttributedString* text = + + NSAttributedString* actual_text = [ns_view_ attributedSubstringForProposedRange:range actualRange:&actual_range]; - EXPECT_EQ(test_string, SysNSStringToUTF8([text string])); - EXPECT_EQ_RANGE(range, actual_range); + + NSRange expected_range; + NSAttributedString* expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + + EXPECT_NSEQ_3(@"foo bar baz", [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(range, expected_range, actual_range); } // Test getting middle substring using text input protocol. @@ -450,11 +658,17 @@ TEST_F(BridgedNativeWidgetTest, TextInput_GetMiddleSubstring) { NSRange range = NSMakeRange(4, 3); NSRange actual_range; - NSAttributedString* text = + NSAttributedString* actual_text = [ns_view_ attributedSubstringForProposedRange:range actualRange:&actual_range]; - EXPECT_EQ("bar", SysNSStringToUTF8([text string])); - EXPECT_EQ_RANGE(range, actual_range); + + NSRange expected_range; + NSAttributedString* expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + + EXPECT_NSEQ_3(@"bar", [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(range, expected_range, actual_range); } // Test getting ending substring using text input protocol. @@ -464,12 +678,16 @@ TEST_F(BridgedNativeWidgetTest, TextInput_GetEndingSubstring) { NSRange range = NSMakeRange(8, 100); NSRange actual_range; - NSAttributedString* text = + NSAttributedString* actual_text = [ns_view_ attributedSubstringForProposedRange:range actualRange:&actual_range]; - EXPECT_EQ("baz", SysNSStringToUTF8([text string])); - EXPECT_EQ(range.location, actual_range.location); - EXPECT_EQ(3U, actual_range.length); + NSRange expected_range; + NSAttributedString* expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + + EXPECT_NSEQ_3(@"baz", [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(NSMakeRange(8, 3), expected_range, actual_range); } // Test getting empty substring using text input protocol. @@ -477,13 +695,45 @@ TEST_F(BridgedNativeWidgetTest, TextInput_GetEmptySubstring) { const std::string test_string = "foo bar baz"; InstallTextField(test_string); + // Try with EmptyRange(). This behaves specially and should return the + // complete string and the corresponding text range. NSRange range = EmptyRange(); - NSRange actual_range; - NSAttributedString* text = + NSRange actual_range = EmptyRange(); + NSRange expected_range = EmptyRange(); + NSAttributedString* actual_text = [ns_view_ attributedSubstringForProposedRange:range actualRange:&actual_range]; - EXPECT_EQ("", SysNSStringToUTF8([text string])); - EXPECT_EQ_RANGE(range, actual_range); + NSAttributedString* expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + EXPECT_NSEQ_3(@"foo bar baz", [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(NSMakeRange(0, test_string.length()), expected_range, + actual_range); + + // Try with a valid empty range. + range = NSMakeRange(2, 0); + actual_range = EmptyRange(); + expected_range = EmptyRange(); + actual_text = [ns_view_ attributedSubstringForProposedRange:range + actualRange:&actual_range]; + expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + EXPECT_NSEQ_3(nil, [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(range, expected_range, actual_range); + + // Try with an out of bounds empty range. + range = NSMakeRange(20, 0); + actual_range = EmptyRange(); + expected_range = EmptyRange(); + actual_text = [ns_view_ attributedSubstringForProposedRange:range + actualRange:&actual_range]; + expected_text = + [dummy_text_view_ attributedSubstringForProposedRange:range + actualRange:&expected_range]; + + EXPECT_NSEQ_3(nil, [expected_text string], [actual_text string]); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), expected_range, actual_range); } // Test inserting text using text input protocol. @@ -493,10 +743,10 @@ TEST_F(BridgedNativeWidgetTest, TextInput_InsertText) { [ns_view_ insertText:SysUTF8ToNSString(test_string) replacementRange:EmptyRange()]; - gfx::Range range(0, test_string.size()); - base::string16 text; - EXPECT_TRUE([ns_view_ textInputClient]->GetTextFromRange(range, &text)); - EXPECT_EQ(ASCIIToUTF16(test_string), text); + [dummy_text_view_ insertText:SysUTF8ToNSString(test_string) + replacementRange:EmptyRange()]; + + EXPECT_NSEQ_3(@"foofoo", GetExpectedText(), GetActualText()); } // Test replacing text using text input protocol. @@ -505,7 +755,9 @@ TEST_F(BridgedNativeWidgetTest, TextInput_ReplaceText) { InstallTextField(test_string); [ns_view_ insertText:@"baz" replacementRange:NSMakeRange(4, 3)]; - EXPECT_EQ("foo baz", GetText()); + [dummy_text_view_ insertText:@"baz" replacementRange:NSMakeRange(4, 3)]; + + EXPECT_NSEQ_3(@"foo baz", GetExpectedText(), GetActualText()); } // Test IME composition using text input protocol. @@ -513,7 +765,14 @@ TEST_F(BridgedNativeWidgetTest, TextInput_Compose) { const std::string test_string = "foo "; InstallTextField(test_string); - EXPECT_FALSE([ns_view_ hasMarkedText]); + EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]); + + // As per NSTextInputClient documentation, markedRange should return + // {NSNotFound, 0} iff hasMarked returns false. However, NSTextView returns + // {text_length, text_length} for this case. We maintain consistency with the + // documentation, hence the EXPECT_FALSE check. + EXPECT_FALSE( + NSEqualRanges([dummy_text_view_ markedRange], [ns_view_ markedRange])); EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]); // Start composition. @@ -522,68 +781,234 @@ TEST_F(BridgedNativeWidgetTest, TextInput_Compose) { [ns_view_ setMarkedText:compositionText selectedRange:NSMakeRange(0, 2) replacementRange:EmptyRange()]; - EXPECT_TRUE([ns_view_ hasMarkedText]); - EXPECT_EQ_RANGE(NSMakeRange(test_string.size(), compositionLength), - [ns_view_ markedRange]); - EXPECT_EQ_RANGE(NSMakeRange(test_string.size(), 2), [ns_view_ selectedRange]); + [dummy_text_view_ setMarkedText:compositionText + selectedRange:NSMakeRange(0, 2) + replacementRange:EmptyRange()]; + EXPECT_EQ_3(YES, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]); + EXPECT_EQ_RANGE_3(NSMakeRange(test_string.size(), compositionLength), + [dummy_text_view_ markedRange], [ns_view_ markedRange]); + EXPECT_EQ_RANGE_3(NSMakeRange(test_string.size(), 2), + GetExpectedSelectionRange(), GetActualSelectionRange()); // Confirm composition. [ns_view_ unmarkText]; - EXPECT_FALSE([ns_view_ hasMarkedText]); + [dummy_text_view_ unmarkText]; + + EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]); + EXPECT_FALSE( + NSEqualRanges([dummy_text_view_ markedRange], [ns_view_ markedRange])); EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]); - EXPECT_EQ("foo bar", GetText()); - EXPECT_EQ_RANGE(NSMakeRange(GetText().size(), 0), [ns_view_ selectedRange]); + EXPECT_NSEQ_3(@"foo bar", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange([GetActualText() length], 0), + GetExpectedSelectionRange(), GetActualSelectionRange()); } // Test moving the caret left and right using text input protocol. TEST_F(BridgedNativeWidgetTest, TextInput_MoveLeftRight) { InstallTextField("foo"); - EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); + EXPECT_EQ_RANGE_3(NSMakeRange(3, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Move right not allowed, out of range. - [ns_view_ doCommandBySelector:@selector(moveRight:)]; - EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(moveRight:)); + EXPECT_EQ_RANGE_3(NSMakeRange(3, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Move left. - [ns_view_ doCommandBySelector:@selector(moveLeft:)]; - EXPECT_EQ_RANGE(NSMakeRange(2, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(moveLeft:)); + EXPECT_EQ_RANGE_3(NSMakeRange(2, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Move right. - [ns_view_ doCommandBySelector:@selector(moveRight:)]; - EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(moveRight:)); + EXPECT_EQ_RANGE_3(NSMakeRange(3, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); } // Test backward delete using text input protocol. TEST_F(BridgedNativeWidgetTest, TextInput_DeleteBackward) { InstallTextField("a"); - EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); + EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Delete one character. - [ns_view_ doCommandBySelector:@selector(deleteBackward:)]; - EXPECT_EQ("", GetText()); - EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(deleteBackward:)); + EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Try to delete again on an empty string. - [ns_view_ doCommandBySelector:@selector(deleteBackward:)]; - EXPECT_EQ("", GetText()); - EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(deleteBackward:)); + EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); } // Test forward delete using text input protocol. TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) { InstallTextField("a"); - EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); + EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // At the end of the string, can't delete forward. - [ns_view_ doCommandBySelector:@selector(deleteForward:)]; - EXPECT_EQ("a", GetText()); - EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(deleteForward:)); + EXPECT_NSEQ_3(@"a", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); // Should succeed after moving left first. - [ns_view_ doCommandBySelector:@selector(moveLeft:)]; - [ns_view_ doCommandBySelector:@selector(deleteForward:)]; - EXPECT_EQ("", GetText()); - EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); + PerformCommand(@selector(moveLeft:)); + PerformCommand(@selector(deleteForward:)); + EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); +} + +// Test forward word deletion using text input protocol. +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteWordForward) { + InstallTextField("foo bar baz"); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Caret is at the end of the line. Verify no deletion takes place. + PerformCommand(@selector(deleteWordForward:)); + EXPECT_NSEQ_3(@"foo bar baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret as- "foo b|ar baz". + SetSelectionRange(NSMakeRange(5, 0)); + PerformCommand(@selector(deleteWordForward:)); + // Verify state is "foo b| baz" + EXPECT_NSEQ_3(@"foo b baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(5, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Make a selection as- "|fo|o b baz". + SetSelectionRange(NSMakeRange(0, 2)); + PerformCommand(@selector(deleteWordForward:)); + // Verify only the selection is deleted and state is "|o b baz". + EXPECT_NSEQ_3(@"o b baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); +} + +// Test backward word deletion using text input protocol. +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteWordBackward) { + InstallTextField("foo bar baz"); + EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret to the beginning of the line. + SetSelectionRange(NSMakeRange(0, 0)); + // Verify no deletion takes place. + PerformCommand(@selector(deleteWordBackward:)); + EXPECT_NSEQ_3(@"foo bar baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Move the caret as- "foo ba|r baz". + SetSelectionRange(NSMakeRange(6, 0)); + PerformCommand(@selector(deleteWordBackward:)); + // Verify state is "foo |r baz". + EXPECT_NSEQ_3(@"foo r baz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(4, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); + + // Make a selection as- "f|oo r b|az". + SetSelectionRange(NSMakeRange(1, 6)); + PerformCommand(@selector(deleteWordBackward:)); + // Verify only the selection is deleted and state is "f|az" + EXPECT_NSEQ_3(@"faz", GetExpectedText(), GetActualText()); + EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(), + GetActualSelectionRange()); +} + +// Test deleting to beginning/end of line/paragraph using text input protocol. + +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteToBeginningOfLine) { + TestDeleteBeginning(@selector(deleteToBeginningOfLine:)); +} + +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteToEndOfLine) { + TestDeleteEnd(@selector(deleteToEndOfLine:)); +} + +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteToBeginningOfParagraph) { + TestDeleteBeginning(@selector(deleteToBeginningOfParagraph:)); +} + +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteToEndOfParagraph) { + TestDeleteEnd(@selector(deleteToEndOfParagraph:)); +} + +// Test move commands against expectations set by |dummy_text_view_|. +TEST_F(BridgedNativeWidgetTest, TextInput_MoveEditingCommands) { + NSArray* selectors = @[ + @"moveForward:", + @"moveRight:", + @"moveBackward:", + @"moveLeft:", + @"moveUp:", + @"moveDown:", + @"moveWordForward:", + @"moveWordBackward:", + @"moveToBeginningOfLine:", + @"moveToEndOfLine:", + @"moveToBeginningOfParagraph:", + @"moveToEndOfParagraph:", + @"moveToEndOfDocument:", + @"moveToBeginningOfDocument:", + @"pageDown:", + @"pageUp:", + @"moveWordRight:", + @"moveWordLeft:", + @"moveToLeftEndOfLine:", + @"moveToRightEndOfLine:" + ]; + TestEditingCommands(selectors); +} + +// Todo(karandeepb): Enable this test once the behavior of all move and select +// commands are fixed. +// Test move and select commands against expectations set by |dummy_text_view_|. +TEST_F(BridgedNativeWidgetTest, + TextInput_MoveAndSelectEditingCommands_DISABLED) { + NSArray* selectors = @[ + @"moveBackwardAndModifySelection:", + @"moveForwardAndModifySelection:", + @"moveWordForwardAndModifySelection:", + @"moveWordBackwardAndModifySelection:", + @"moveUpAndModifySelection:", + @"moveDownAndModifySelection:", + @"moveToBeginningOfLineAndModifySelection:", + @"moveToEndOfLineAndModifySelection:", + @"moveToBeginningOfParagraphAndModifySelection:", + @"moveToEndOfParagraphAndModifySelection:", + @"moveToEndOfDocumentAndModifySelection:", + @"moveToBeginningOfDocumentAndModifySelection:", + @"pageDownAndModifySelection:", + @"pageUpAndModifySelection:", + @"moveParagraphForwardAndModifySelection:", + @"moveParagraphBackwardAndModifySelection:", + @"moveRightAndModifySelection:", + @"moveLeftAndModifySelection:", + @"moveWordRightAndModifySelection:", + @"moveWordLeftAndModifySelection:", + @"moveToLeftEndOfLineAndModifySelection:", + @"moveToRightEndOfLineAndModifySelection:" + ]; + TestEditingCommands(selectors); +} + +// Test delete commands against expectations set by |dummy_text_view_|. +TEST_F(BridgedNativeWidgetTest, TextInput_DeleteCommands) { + NSArray* selectors = @[ + @"deleteForward:", @"deleteBackward:", @"deleteWordForward:", + @"deleteWordBackward:", @"deleteToBeginningOfLine:", @"deleteToEndOfLine:", + @"deleteToBeginningOfParagraph:", @"deleteToEndOfParagraph:" + ]; + TestEditingCommands(selectors); } // Test firstRectForCharacterRange:actualRange for cases where query range is @@ -717,8 +1142,7 @@ TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) { EXPECT_FALSE(bridge()->target_fullscreen_state()); // Cocoa follows up with a failure message sent to the NSWindowDelegate (there - // is no equivalent notification for failure). Called via id so that this - // compiles on 10.6. + // is no equivalent notification for failure). ViewsNSWindowDelegate* window_delegate = base::mac::ObjCCast<ViewsNSWindowDelegate>([window delegate]); [window_delegate windowDidFailToEnterFullScreen:window]; diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture.h b/chromium/ui/views/cocoa/cocoa_mouse_capture.h index 55f87ede81c..247caa4e82c 100644 --- a/chromium/ui/views/cocoa/cocoa_mouse_capture.h +++ b/chromium/ui/views/cocoa/cocoa_mouse_capture.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_ #define UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/views_export.h" namespace views { @@ -36,7 +37,7 @@ class VIEWS_EXPORT CocoaMouseCapture { // The active event tap for this capture. Owned by this, but can be cleared // out early if another instance of CocoaMouseCapture is created. - scoped_ptr<ActiveEventTap> active_handle_; + std::unique_ptr<ActiveEventTap> active_handle_; DISALLOW_COPY_AND_ASSIGN(CocoaMouseCapture); }; diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm b/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm index 371a3fc6350..5b4e2bdf995 100644 --- a/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm +++ b/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm @@ -50,7 +50,7 @@ class TestCaptureDelegate : public CocoaMouseCaptureDelegate { void OnMouseCaptureLost() override { ++capture_lost_count_; } private: - scoped_ptr<CocoaMouseCapture> mouse_capture_; + std::unique_ptr<CocoaMouseCapture> mouse_capture_; int event_count_; int capture_lost_count_; diff --git a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm index 4acbd946877..8c12aaa696b 100644 --- a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm +++ b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm @@ -12,6 +12,10 @@ #include "ui/views/widget/native_widget_mac.h" #include "ui/views/widget/widget_delegate.h" +@interface NSWindow (Private) +- (BOOL)hasKeyAppearance; +@end + @interface NativeWidgetMacNSWindow () - (ViewsNSWindowDelegate*)viewsNSWindowDelegate; - (views::Widget*)viewsWidget; @@ -41,6 +45,12 @@ return self; } +// This override doesn't do anything, but keeping it helps diagnose lifetime +// issues in crash stacktraces by inserting a symbol on NativeWidgetMacNSWindow. +- (void)dealloc { + [super dealloc]; +} + // Public methods. - (void)setCommandDispatcherDelegate:(id<CommandDispatcherDelegate>)delegate { @@ -91,10 +101,10 @@ } // Lets the traffic light buttons on the parent window keep their active state. -- (BOOL)_sharesParentKeyState { - // Follow -canBecomeMainWindow unless the window provides its own buttons. - return ([self styleMask] & NSClosableWindowMask) == 0 && - ![self canBecomeMainWindow]; +- (BOOL)hasKeyAppearance { + if ([self delegate] && [self viewsWidget]->IsAlwaysRenderAsActive()) + return YES; + return [super hasKeyAppearance]; } // Override sendEvent to allow key events to be forwarded to a toolkit-views @@ -199,9 +209,13 @@ // command handler, defer to AppController. if ([item action] == @selector(commandDispatch:) || [item action] == @selector(commandDispatchUsingKeyModifiers:)) { - return commandHandler_ - ? [commandHandler_ validateUserInterfaceItem:item window:self] - : [[NSApp delegate] validateUserInterfaceItem:item]; + if (commandHandler_) + return [commandHandler_ validateUserInterfaceItem:item window:self]; + + id appController = [NSApp delegate]; + DCHECK([appController + conformsToProtocol:@protocol(NSUserInterfaceValidations)]); + return [appController validateUserInterfaceItem:item]; } return [super validateUserInterfaceItem:item]; diff --git a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm b/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm index d85184ef5a4..63cc4468d95 100644 --- a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm +++ b/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm @@ -62,8 +62,22 @@ WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter( } void WidgetOwnerNSWindowAdapter::OnWindowWillClose() { - [child_->ns_window() close]; + // Retain the child window before closing it. If the last reference to the + // NSWindow goes away inside -[NSWindow close], then bad stuff can happen. + // See e.g. http://crbug.com/616701. + base::scoped_nsobject<NSWindow> child_window(child_->ns_window(), + base::scoped_policy::RETAIN); + + // AppKit child window relationships break when the windows are not visible, + // so if the child is not visible, it won't currently be a child. + DCHECK(![child_window isVisible] || [child_window parentWindow]); + DCHECK([child_window delegate]); + + [child_window close]; // Note: |this| will be deleted here. + + DCHECK(![child_window parentWindow]); + DCHECK(![child_window delegate]); } NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() { diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc index e0aea825e9e..ca3f2034061 100644 --- a/chromium/ui/views/color_chooser/color_chooser_view.cc +++ b/chromium/ui/views/color_chooser/color_chooser_view.cc @@ -11,7 +11,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/effects/SkGradientShader.h" @@ -141,7 +140,6 @@ class ColorChooserView::HueView : public LocatedEventHandlerView { ColorChooserView::HueView::HueView(ColorChooserView* chooser_view) : chooser_view_(chooser_view), level_(0) { - SetFocusable(false); } void ColorChooserView::HueView::OnHueChanged(SkScalar hue) { @@ -251,7 +249,6 @@ ColorChooserView::SaturationValueView::SaturationValueView( ColorChooserView* chooser_view) : chooser_view_(chooser_view), hue_(0) { - SetFocusable(false); SetBorder(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY)); } @@ -344,7 +341,6 @@ class ColorChooserView::SelectedColorPatchView : public views::View { }; ColorChooserView::SelectedColorPatchView::SelectedColorPatchView() { - SetFocusable(false); SetVisible(true); SetBorder(Border::CreateSolidBorder(kBorderWidth, SK_ColorGRAY)); } @@ -366,7 +362,6 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener, : listener_(listener) { DCHECK(listener_); - SetFocusable(false); set_background(Background::CreateSolidBackground(SK_ColorLTGRAY)); SetLayoutManager(new BoxLayout(BoxLayout::kVertical, kMarginWidth, kMarginWidth, kMarginWidth)); diff --git a/chromium/ui/views/controls/button/blue_button.cc b/chromium/ui/views/controls/button/blue_button.cc index 12ea638c160..c0e8b9902d0 100644 --- a/chromium/ui/views/controls/button/blue_button.cc +++ b/chromium/ui/views/controls/button/blue_button.cc @@ -51,10 +51,10 @@ const char* BlueButton::GetClassName() const { return BlueButton::kViewClassName; } -scoped_ptr<LabelButtonBorder> BlueButton::CreateDefaultBorder() const { +std::unique_ptr<LabelButtonBorder> BlueButton::CreateDefaultBorder() const { // Insets for splitting the images. const gfx::Insets insets(5); - scoped_ptr<LabelButtonAssetBorder> button_border( + std::unique_ptr<LabelButtonAssetBorder> button_border( new LabelButtonAssetBorder(style())); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); button_border->SetPainter(false, STATE_NORMAL, Painter::CreateImagePainter( diff --git a/chromium/ui/views/controls/button/blue_button.h b/chromium/ui/views/controls/button/blue_button.h index 2599a88f4b6..ec414de1790 100644 --- a/chromium/ui/views/controls/button/blue_button.h +++ b/chromium/ui/views/controls/button/blue_button.h @@ -23,7 +23,7 @@ class VIEWS_EXPORT BlueButton : public LabelButton { // Overridden from LabelButton: void ResetColorsFromNativeTheme() override; const char* GetClassName() const override; - scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const override; + std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override; DISALLOW_COPY_AND_ASSIGN(BlueButton); }; diff --git a/chromium/ui/views/controls/button/blue_button_unittest.cc b/chromium/ui/views/controls/button/blue_button_unittest.cc index 8fc77280e9f..68712179085 100644 --- a/chromium/ui/views/controls/button/blue_button_unittest.cc +++ b/chromium/ui/views/controls/button/blue_button_unittest.cc @@ -44,12 +44,15 @@ TEST_F(BlueButtonTest, Border) { widget->GetContentsView()->AddChildView(blue_button); blue_button->SizeToPreferredSize(); #if defined(OS_MACOSX) - // On Mac, the default styled border has a large minimum width. To ensure that - // the bitmaps are comparable, the size needs to match (checked below). - // Increase the minimum size of the blue button to pass the size check. + // On Mac, themed STYLE_BUTTON buttons provide blue theming for dialog-default + // buttons. This makes it unlikely that they will appear together with a + // BlueButton on the same dialog. So the sizes don't really need to be + // consistent. However, for the purposes of this test (e.g. to ensure we don't + // accidentally make BlueButtons look like themed buttons on Mac), force the + // sizes to match (ignoring the minimum size) so that the bitmaps can be + // compared. EXPECT_NE(button->size(), blue_button->size()); // Verify this is needed. - blue_button->SetMinSize(button->border()->GetMinimumSize()); - blue_button->SizeToPreferredSize(); + blue_button->SetSize(button->size()); #endif gfx::Canvas canvas(blue_button->size(), 1.0, true); diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc index 92603dd1459..37f8aa3f6b4 100644 --- a/chromium/ui/views/controls/button/button.cc +++ b/chromium/ui/views/controls/button/button.cc @@ -30,6 +30,15 @@ Button::ButtonState Button::GetButtonStateFrom(ui::NativeTheme::State state) { Button::~Button() { } +void Button::SetFocusForPlatform() { +#if defined(OS_MACOSX) + // On Mac, buttons are focusable only in full keyboard access mode. + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); +#else + SetFocusBehavior(FocusBehavior::ALWAYS); +#endif +} + void Button::SetTooltipText(const base::string16& tooltip_text) { tooltip_text_ = tooltip_text; if (accessible_name_.empty()) @@ -64,7 +73,7 @@ void Button::GetAccessibleState(ui::AXViewState* state) { Button::Button(ButtonListener* listener) : listener_(listener), tag_(-1) { - SetAccessibilityFocusable(true); + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); } void Button::NotifyClick(const ui::Event& event) { diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h index dab4870ad53..e7acdc91ef0 100644 --- a/chromium/ui/views/controls/button/button.h +++ b/chromium/ui/views/controls/button/button.h @@ -49,6 +49,9 @@ class VIEWS_EXPORT Button : public InkDropHostView { static ButtonState GetButtonStateFrom(ui::NativeTheme::State state); + // Make the button focusable as per the platform. + void SetFocusForPlatform(); + void SetTooltipText(const base::string16& tooltip_text); int tag() const { return tag_; } diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc index 2ab281f1943..8ee9dc18baa 100644 --- a/chromium/ui/views/controls/button/checkbox.cc +++ b/chromium/ui/views/controls/button/checkbox.cc @@ -24,11 +24,12 @@ Checkbox::Checkbox(const base::string16& label) : LabelButton(NULL, label), checked_(false) { SetHorizontalAlignment(gfx::ALIGN_LEFT); - scoped_ptr<LabelButtonBorder> button_border(new LabelButtonBorder()); + std::unique_ptr<LabelButtonBorder> button_border(new LabelButtonBorder()); // Inset the trailing side by a couple pixels for the focus border. button_border->set_insets(gfx::Insets(0, 0, 0, 2)); SetBorder(std::move(button_border)); - SetFocusable(true); + SetFocusForPlatform(); + set_request_focus_on_press(true); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); diff --git a/chromium/ui/views/controls/button/custom_button.cc b/chromium/ui/views/controls/button/custom_button.cc index 6e80eb12d9f..133f73f0657 100644 --- a/chromium/ui/views/controls/button/custom_button.cc +++ b/chromium/ui/views/controls/button/custom_button.cc @@ -12,7 +12,6 @@ #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme.h" #include "ui/views/animation/ink_drop_delegate.h" #include "ui/views/animation/ink_drop_hover.h" @@ -48,12 +47,13 @@ class MdFocusRing : public views::View { MdFocusRing() { SetPaintToLayer(true); layer()->SetFillsBoundsOpaquely(false); - - // Don't accept input events. - SetEnabled(false); } ~MdFocusRing() override {} + bool CanProcessEventsWithinSubtree() const override { + return false; + } + void OnPaint(gfx::Canvas* canvas) override { CustomButton::PaintMdFocusRing(canvas, this); } @@ -268,6 +268,10 @@ bool CustomButton::OnKeyPressed(const ui::KeyEvent& event) { // KeyRelease and Enter clicks the button on KeyPressed. if (event.key_code() == ui::VKEY_SPACE) { SetState(STATE_PRESSED); + if (ink_drop_delegate_ && + ink_drop_delegate_->GetTargetInkDropState() != + views::InkDropState::ACTION_PENDING) + ink_drop_delegate_->OnAction(views::InkDropState::ACTION_PENDING); } else if (event.key_code() == ui::VKEY_RETURN) { SetState(STATE_NORMAL); NotifyClick(event); @@ -382,7 +386,7 @@ void CustomButton::VisibilityChanged(View* starting_from, bool visible) { SetState(visible && ShouldEnterHoveredState() ? STATE_HOVERED : STATE_NORMAL); } -scoped_ptr<InkDropHover> CustomButton::CreateInkDropHover() const { +std::unique_ptr<InkDropHover> CustomButton::CreateInkDropHover() const { return ShouldShowInkDropHover() ? Button::CreateInkDropHover() : nullptr; } @@ -438,7 +442,7 @@ CustomButton::CustomButton(ButtonListener* listener) animate_on_state_change_(true), is_throbbing_(false), triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON), - request_focus_on_press_(true), + request_focus_on_press_(false), ink_drop_delegate_(nullptr), notify_action_(NOTIFY_ON_RELEASE), has_ink_drop_action_on_click_(false), diff --git a/chromium/ui/views/controls/button/custom_button.h b/chromium/ui/views/controls/button/custom_button.h index cd94e3c3095..e03b5a520d7 100644 --- a/chromium/ui/views/controls/button/custom_button.h +++ b/chromium/ui/views/controls/button/custom_button.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_CONTROLS_BUTTON_CUSTOM_BUTTON_H_ #define UI_VIEWS_CONTROLS_BUTTON_CUSTOM_BUTTON_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/events/event_constants.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/throb_animation.h" @@ -19,8 +20,8 @@ class InkDropDelegate; // A button with custom rendering. The base of ImageButton and LabelButton. // Note that this type of button is not focusable by default and will not be -// part of the focus chain. Call SetFocusable(true) to make it part of the -// focus chain. +// part of the focus chain, unless in accessibility mode. Call +// SetFocusForPlatform() to make it part of the focus chain. class VIEWS_EXPORT CustomButton : public Button, public gfx::AnimationDelegate { public: // An enum describing the events on which a button should notify its listener. @@ -59,7 +60,7 @@ class VIEWS_EXPORT CustomButton : public Button, public gfx::AnimationDelegate { int triggerable_event_flags() const { return triggerable_event_flags_; } // Sets whether |RequestFocus| should be invoked on a mouse press. The default - // is true. + // is false. void set_request_focus_on_press(bool value) { request_focus_on_press_ = value; } @@ -106,7 +107,7 @@ class VIEWS_EXPORT CustomButton : public Button, public gfx::AnimationDelegate { void OnDragDone() override; void GetAccessibleState(ui::AXViewState* state) override; void VisibilityChanged(View* starting_from, bool is_visible) override; - scoped_ptr<InkDropHover> CreateInkDropHover() const override; + std::unique_ptr<InkDropHover> CreateInkDropHover() const override; SkColor GetInkDropBaseColor() const override; // Overridden from gfx::AnimationDelegate: diff --git a/chromium/ui/views/controls/button/custom_button_unittest.cc b/chromium/ui/views/controls/button/custom_button_unittest.cc index bd34cb036c4..4b9ca78c755 100644 --- a/chromium/ui/views/controls/button/custom_button_unittest.cc +++ b/chromium/ui/views/controls/button/custom_button_unittest.cc @@ -5,13 +5,14 @@ #include "ui/views/controls/button/custom_button.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/layout.h" #include "ui/base/material_design/material_design_controller.h" +#include "ui/display/screen.h" #include "ui/events/event_utils.h" #include "ui/events/test/event_generator.h" -#include "ui/gfx/screen.h" #include "ui/views/animation/ink_drop_delegate.h" #include "ui/views/animation/ink_drop_host.h" #include "ui/views/animation/test/test_ink_drop_delegate.h" @@ -85,7 +86,7 @@ class TestCustomButton : public CustomButton, public ButtonListener { }; // An InkDropDelegate that keeps track of ink drop visibility. -class TestInkDropDelegateThatTracksVisibilty : public InkDropDelegate { +class TestInkDropDelegateThatTracksVisibilty : public TestInkDropDelegate { public: TestInkDropDelegateThatTracksVisibilty(bool* ink_shown, bool* ink_hidden) : ink_shown_(ink_shown), ink_hidden_(ink_hidden) {} @@ -93,7 +94,8 @@ class TestInkDropDelegateThatTracksVisibilty : public InkDropDelegate { // InkDropDelegate: void OnAction(InkDropState state) override { - switch (state) { + TestInkDropDelegate::OnAction(state); + switch (GetTargetInkDropState()) { case InkDropState::ACTION_PENDING: case InkDropState::ALTERNATE_ACTION_PENDING: case InkDropState::ACTIVATED: @@ -123,14 +125,14 @@ class TestInkDropDelegateThatTracksVisibilty : public InkDropDelegate { // A test Button class that owns a TestInkDropDelegate. class TestButtonWithInkDrop : public TestCustomButton { public: - TestButtonWithInkDrop(scoped_ptr<InkDropDelegate> ink_drop_delegate) + TestButtonWithInkDrop(std::unique_ptr<InkDropDelegate> ink_drop_delegate) : TestCustomButton(), ink_drop_delegate_(std::move(ink_drop_delegate)) { set_ink_drop_delegate(ink_drop_delegate_.get()); } ~TestButtonWithInkDrop() override {} private: - scoped_ptr<views::InkDropDelegate> ink_drop_delegate_; + std::unique_ptr<views::InkDropDelegate> ink_drop_delegate_; DISALLOW_COPY_AND_ASSIGN(TestButtonWithInkDrop); }; @@ -163,7 +165,8 @@ class CustomButtonTest : public ViewsTestBase { ViewsTestBase::TearDown(); } - void CreateButtonWithInkDrop(scoped_ptr<InkDropDelegate> ink_drop_delegate) { + void CreateButtonWithInkDrop( + std::unique_ptr<InkDropDelegate> ink_drop_delegate) { delete button_; button_ = new TestButtonWithInkDrop(std::move(ink_drop_delegate)); widget_->SetContentsView(button_); @@ -177,7 +180,7 @@ class CustomButtonTest : public ViewsTestBase { } private: - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; TestCustomButton* button_; DISALLOW_COPY_AND_ASSIGN(CustomButtonTest); @@ -390,10 +393,10 @@ TEST_F(CustomButtonTest, AsCustomButton) { // Note: Ink drop is not hidden upon release because CustomButton descendants // may enter a different ink drop state. TEST_F(CustomButtonTest, ButtonClickTogglesInkDrop) { - gfx::Point old_cursor = gfx::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point old_cursor = display::Screen::GetScreen()->GetCursorScreenPoint(); bool ink_shown = false; bool ink_hidden = false; - CreateButtonWithInkDrop(make_scoped_ptr( + CreateButtonWithInkDrop(base::WrapUnique( new TestInkDropDelegateThatTracksVisibilty(&ink_shown, &ink_hidden))); ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow()); @@ -409,10 +412,10 @@ TEST_F(CustomButtonTest, ButtonClickTogglesInkDrop) { // Tests that pressing a button shows and releasing capture hides ink drop. // Releasing capture should also reset PRESSED button state to NORMAL. TEST_F(CustomButtonTest, CaptureLossHidesInkDrop) { - gfx::Point old_cursor = gfx::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point old_cursor = display::Screen::GetScreen()->GetCursorScreenPoint(); bool ink_shown = false; bool ink_hidden = false; - CreateButtonWithInkDrop(make_scoped_ptr( + CreateButtonWithInkDrop(base::WrapUnique( new TestInkDropDelegateThatTracksVisibilty(&ink_shown, &ink_hidden))); ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow()); @@ -435,7 +438,7 @@ TEST_F(CustomButtonTest, CaptureLossHidesInkDrop) { TEST_F(CustomButtonTest, HideInkDropWhenShowingContextMenu) { TestInkDropDelegate* ink_drop_delegate = new TestInkDropDelegate(); - CreateButtonWithInkDrop(make_scoped_ptr(ink_drop_delegate)); + CreateButtonWithInkDrop(base::WrapUnique(ink_drop_delegate)); TestContextMenuController context_menu_controller; button()->set_context_menu_controller(&context_menu_controller); button()->set_hide_ink_drop_when_showing_context_menu(true); @@ -446,12 +449,12 @@ TEST_F(CustomButtonTest, HideInkDropWhenShowingContextMenu) { button()->ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); EXPECT_FALSE(ink_drop_delegate->is_hovered()); - EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate->state()); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate->GetTargetInkDropState()); } TEST_F(CustomButtonTest, DontHideInkDropWhenShowingContextMenu) { TestInkDropDelegate* ink_drop_delegate = new TestInkDropDelegate(); - CreateButtonWithInkDrop(make_scoped_ptr(ink_drop_delegate)); + CreateButtonWithInkDrop(base::WrapUnique(ink_drop_delegate)); TestContextMenuController context_menu_controller; button()->set_context_menu_controller(&context_menu_controller); button()->set_hide_ink_drop_when_showing_context_menu(false); @@ -462,12 +465,13 @@ TEST_F(CustomButtonTest, DontHideInkDropWhenShowingContextMenu) { button()->ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); EXPECT_TRUE(ink_drop_delegate->is_hovered()); - EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop_delegate->state()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + ink_drop_delegate->GetTargetInkDropState()); } TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) { TestInkDropDelegate* ink_drop_delegate = new TestInkDropDelegate(); - CreateButtonWithInkDrop(make_scoped_ptr(ink_drop_delegate)); + CreateButtonWithInkDrop(base::WrapUnique(ink_drop_delegate)); button()->set_context_menu_controller(nullptr); ink_drop_delegate->SetHovered(true); @@ -476,7 +480,8 @@ TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) { button()->ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); EXPECT_TRUE(ink_drop_delegate->is_hovered()); - EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop_delegate->state()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + ink_drop_delegate->GetTargetInkDropState()); } } // namespace views diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc index a79341914de..a9fda37f5b4 100644 --- a/chromium/ui/views/controls/button/image_button.cc +++ b/chromium/ui/views/controls/button/image_button.cc @@ -73,7 +73,7 @@ void ImageButton::SetImageAlignment(HorizontalAlignment h_align, SchedulePaint(); } -void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) { +void ImageButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { focus_painter_ = std::move(focus_painter); } diff --git a/chromium/ui/views/controls/button/image_button.h b/chromium/ui/views/controls/button/image_button.h index 71311fe08f4..3732c690705 100644 --- a/chromium/ui/views/controls/button/image_button.h +++ b/chromium/ui/views/controls/button/image_button.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_ #define UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_ +#include <memory> + #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/base/layout.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/custom_button.h" @@ -17,11 +18,9 @@ namespace views { class Painter; // An image button. - // Note that this type of button is not focusable by default and will not be -// part of the focus chain. Call SetFocusable(true) to make it part of the -// focus chain. - +// part of the focus chain, unless in accessibility mode. Call +// SetFocusForPlatform() to make it part of the focus chain. class VIEWS_EXPORT ImageButton : public CustomButton { public: static const char kViewClassName[]; @@ -56,7 +55,7 @@ class VIEWS_EXPORT ImageButton : public CustomButton { void SetImageAlignment(HorizontalAlignment h_align, VerticalAlignment v_align); - void SetFocusPainter(scoped_ptr<Painter> focus_painter); + void SetFocusPainter(std::unique_ptr<Painter> focus_painter); // The minimum size of the contents (not including the border). The contents // will be at least this size, but may be larger if the image itself is @@ -113,7 +112,7 @@ class VIEWS_EXPORT ImageButton : public CustomButton { // resources. bool draw_image_mirrored_; - scoped_ptr<Painter> focus_painter_; + std::unique_ptr<Painter> focus_painter_; DISALLOW_COPY_AND_ASSIGN(ImageButton); }; diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc index 6687b6e03c6..98b6e0da97a 100644 --- a/chromium/ui/views/controls/button/label_button.cc +++ b/chromium/ui/views/controls/button/label_button.cc @@ -10,7 +10,7 @@ #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "build/build_config.h" #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" @@ -18,7 +18,7 @@ #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/native_theme/native_theme.h" -#include "ui/views/animation/flood_fill_ink_drop_animation.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_hover.h" #include "ui/views/background.h" #include "ui/views/controls/button/label_button_border.h" @@ -31,12 +31,6 @@ namespace { // The default spacing between the icon and text. const int kSpacing = 5; -#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS)) -// Default text and shadow colors for STYLE_BUTTON. -const SkColor kStyleButtonTextColor = SK_ColorBLACK; -const SkColor kStyleButtonShadowColor = SK_ColorWHITE; -#endif - const gfx::FontList& GetDefaultNormalFontList() { static base::LazyInstance<gfx::FontList>::Leaky font_list = LAZY_INSTANCE_INITIALIZER; @@ -44,6 +38,9 @@ const gfx::FontList& GetDefaultNormalFontList() { } const gfx::FontList& GetDefaultBoldFontList() { + if (!views::PlatformStyle::kDefaultLabelButtonHasBoldFont) + return GetDefaultNormalFontList(); + static base::LazyInstance<gfx::FontList>::Leaky font_list = LAZY_INSTANCE_INITIALIZER; if ((font_list.Get().GetFontStyle() & gfx::Font::BOLD) == 0) { @@ -164,10 +161,15 @@ const gfx::FontList& LabelButton::GetFontList() const { void LabelButton::SetFontList(const gfx::FontList& font_list) { cached_normal_font_list_ = font_list; - cached_bold_font_list_ = font_list.DeriveWithStyle( - font_list.GetFontStyle() | gfx::Font::BOLD); - label_->SetFontList(is_default_ ? - cached_bold_font_list_ : cached_normal_font_list_); + if (PlatformStyle::kDefaultLabelButtonHasBoldFont) { + cached_bold_font_list_ = + font_list.DeriveWithStyle(font_list.GetFontStyle() | gfx::Font::BOLD); + if (is_default_) { + label_->SetFontList(cached_bold_font_list_); + return; + } + } + label_->SetFontList(cached_normal_font_list_); } void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) { @@ -199,9 +201,7 @@ void LabelButton::SetIsDefault(bool is_default) { ui::Accelerator accel(ui::VKEY_RETURN, ui::EF_NONE); is_default_ ? AddAccelerator(accel) : RemoveAccelerator(accel); - label_->SetFontList( - is_default ? cached_bold_font_list_ : cached_normal_font_list_); - InvalidateLayout(); + UpdateStyleToIndicateDefaultStatus(); } void LabelButton::SetStyle(ButtonStyle style) { @@ -215,8 +215,10 @@ void LabelButton::SetStyle(ButtonStyle style) { SetFocusPainter(nullptr); SetHorizontalAlignment(gfx::ALIGN_CENTER); - SetFocusable(true); - SetMinSize(gfx::Size(70, 33)); + SetFocusForPlatform(); + set_request_focus_on_press(true); + SetMinSize(gfx::Size(PlatformStyle::kMinLabelButtonWidth, + PlatformStyle::kMinLabelButtonHeight)); // Themed borders will be set once the button is added to a Widget, since that // provides the value of GetNativeTheme(). @@ -230,7 +232,7 @@ void LabelButton::SetImageLabelSpacing(int spacing) { InvalidateLayout(); } -void LabelButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) { +void LabelButton::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { focus_painter_ = std::move(focus_painter); } @@ -242,7 +244,7 @@ gfx::Size LabelButton::GetPreferredSize() const { Label label(GetText(), cached_normal_font_list_); label.SetShadows(label_->shadows()); - if (style() == STYLE_BUTTON) { + if (style_ == STYLE_BUTTON && PlatformStyle::kDefaultLabelButtonHasBoldFont) { // Some text appears wider when rendered normally than when rendered bold. // Accommodate the widest, as buttons may show bold and shouldn't resize. const int current_width = label.GetPreferredSize().width(); @@ -363,11 +365,11 @@ void LabelButton::EnableCanvasFlippingForRTLUI(bool flip) { image_->EnableCanvasFlippingForRTLUI(flip); } -scoped_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const { +std::unique_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const { return PlatformStyle::CreateLabelButtonBorder(style()); } -void LabelButton::SetBorder(scoped_ptr<Border> border) { +void LabelButton::SetBorder(std::unique_ptr<Border> border) { border_is_themed_border_ = false; View::SetBorder(std::move(border)); ResetCachedPreferredSize(); @@ -397,6 +399,7 @@ void LabelButton::OnBlur() { void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { ResetColorsFromNativeTheme(); UpdateThemedBorder(); + ResetLabelEnabledColor(); // Invalidate the layout to pickup the new insets from the border. InvalidateLayout(); } @@ -414,20 +417,18 @@ void LabelButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { ink_drop_container_->SetVisible(false); } -scoped_ptr<views::InkDropAnimation> LabelButton::CreateInkDropAnimation() - const { - return GetText().empty() - ? CustomButton::CreateInkDropAnimation() - : make_scoped_ptr(new views::FloodFillInkDropAnimation( - GetLocalBounds(), GetInkDropCenter(), - GetInkDropBaseColor())); +std::unique_ptr<views::InkDropRipple> LabelButton::CreateInkDropRipple() const { + return GetText().empty() ? CustomButton::CreateInkDropRipple() + : base::WrapUnique(new views::FloodFillInkDropRipple( + GetLocalBounds(), GetInkDropCenter(), + GetInkDropBaseColor())); } -scoped_ptr<views::InkDropHover> LabelButton::CreateInkDropHover() const { +std::unique_ptr<views::InkDropHover> LabelButton::CreateInkDropHover() const { if (!ShouldShowInkDropHover()) return nullptr; return GetText().empty() ? CustomButton::CreateInkDropHover() - : make_scoped_ptr(new views::InkDropHover( + : base::WrapUnique(new views::InkDropHover( size(), kInkDropSmallCornerRadius, GetInkDropCenter(), GetInkDropBaseColor())); } @@ -442,9 +443,7 @@ gfx::Point LabelButton::GetInkDropCenter() const { void LabelButton::StateChanged() { const gfx::Size previous_image_size(image_->GetPreferredSize()); UpdateImage(); - const SkColor color = button_state_colors_[state()]; - if (state() != STATE_DISABLED && label_->enabled_color() != color) - label_->SetEnabledColor(color); + ResetLabelEnabledColor(); label_->SetEnabled(state() != STATE_DISABLED); if (image_->GetPreferredSize() != previous_image_size) Layout(); @@ -469,38 +468,21 @@ void LabelButton::ResetColorsFromNativeTheme() { theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonDisabledColor), }; - // Certain styles do not change text color when hovered or pressed. - bool constant_text_color = false; // Use hardcoded colors for inverted color scheme support and STYLE_BUTTON. if (color_utils::IsInvertedColorScheme()) { - constant_text_color = true; - colors[STATE_NORMAL] = SK_ColorWHITE; + colors[STATE_NORMAL] = colors[STATE_HOVERED] = colors[STATE_PRESSED] = + SK_ColorWHITE; label_->SetBackgroundColor(SK_ColorBLACK); label_->set_background(Background::CreateSolidBackground(SK_ColorBLACK)); label_->SetAutoColorReadabilityEnabled(true); label_->SetShadows(gfx::ShadowValues()); } else if (style() == STYLE_BUTTON) { - // TODO(erg): This is disabled on desktop linux because of the binary asset - // confusion. These details should either be pushed into ui::NativeThemeWin - // or should be obsoleted by rendering buttons with paint calls instead of - // with static assets. http://crbug.com/350498 -#if !(defined(OS_LINUX) && !defined(OS_CHROMEOS)) - constant_text_color = true; - colors[STATE_NORMAL] = kStyleButtonTextColor; - label_->SetBackgroundColor(theme->GetSystemColor( - ui::NativeTheme::kColorId_ButtonBackgroundColor)); - label_->SetAutoColorReadabilityEnabled(false); - label_->SetShadows(gfx::ShadowValues( - 1, gfx::ShadowValue(gfx::Vector2d(0, 1), 0, kStyleButtonShadowColor))); -#endif - label_->set_background(NULL); + PlatformStyle::ApplyLabelButtonTextStyle(label_, &colors); + label_->set_background(nullptr); } else { - label_->set_background(NULL); + label_->set_background(nullptr); } - if (constant_text_color) - colors[STATE_HOVERED] = colors[STATE_PRESSED] = colors[STATE_NORMAL]; - for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state) { if (!explicitly_set_colors_[state]) { SetTextColor(static_cast<ButtonState>(state), colors[state]); @@ -509,6 +491,14 @@ void LabelButton::ResetColorsFromNativeTheme() { } } +void LabelButton::UpdateStyleToIndicateDefaultStatus() { + const bool bold = + PlatformStyle::kDefaultLabelButtonHasBoldFont && is_default_; + label_->SetFontList(bold ? cached_bold_font_list_ : cached_normal_font_list_); + InvalidateLayout(); + ResetLabelEnabledColor(); +} + void LabelButton::UpdateImage() { image_->SetImage(GetImage(state())); ResetCachedPreferredSize(); @@ -575,4 +565,13 @@ void LabelButton::ResetCachedPreferredSize() { cached_preferred_size_ = gfx::Size(); } +void LabelButton::ResetLabelEnabledColor() { + const SkColor color = + explicitly_set_colors_[state()] + ? button_state_colors_[state()] + : PlatformStyle::TextColorForButton(button_state_colors_, *this); + if (state() != STATE_DISABLED && label_->enabled_color() != color) + label_->SetEnabledColor(color); +} + } // namespace views diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h index a8f419c96fa..ceed96d9579 100644 --- a/chromium/ui/views/controls/button/label_button.h +++ b/chromium/ui/views/controls/button/label_button.h @@ -5,10 +5,11 @@ #ifndef UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_H_ #define UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/custom_button.h" @@ -18,7 +19,7 @@ namespace views { -class InkDropAnimation; +class InkDropRipple; class InkDropHover; class LabelButtonBorder; class Painter; @@ -87,15 +88,15 @@ class VIEWS_EXPORT LabelButton : public CustomButton, // Call SetMinSize(gfx::Size()) to clear the size if needed. void SetImageLabelSpacing(int spacing); - void SetFocusPainter(scoped_ptr<Painter> focus_painter); + void SetFocusPainter(std::unique_ptr<Painter> focus_painter); Painter* focus_painter() { return focus_painter_.get(); } // Creates the default border for this button. This can be overridden by // subclasses. - virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const; + virtual std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const; // View: - void SetBorder(scoped_ptr<Border> border) override; + void SetBorder(std::unique_ptr<Border> border) override; gfx::Size GetPreferredSize() const override; int GetHeightForWidth(int w) const override; void Layout() override; @@ -103,14 +104,18 @@ class VIEWS_EXPORT LabelButton : public CustomButton, void EnableCanvasFlippingForRTLUI(bool flip) override; void AddInkDropLayer(ui::Layer* ink_drop_layer) override; void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; - scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const override; - scoped_ptr<InkDropHover> CreateInkDropHover() const override; + std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<InkDropHover> CreateInkDropHover() const override; gfx::Point GetInkDropCenter() const override; protected: ImageView* image() const { return image_; } Label* label() const { return label_; } + bool explicitly_set_normal_color() const { + return explicitly_set_colors_[STATE_NORMAL]; + } + // Returns the available area for the label and image. Subclasses can change // these bounds if they need room to do manual painting. virtual gfx::Rect GetChildAreaBounds(); @@ -130,6 +135,10 @@ class VIEWS_EXPORT LabelButton : public CustomButton, // Resets colors from the NativeTheme, explicitly set colors are unchanged. virtual void ResetColorsFromNativeTheme(); + // Changes the visual styling of this button to reflect the state of + // |is_default()|. + virtual void UpdateStyleToIndicateDefaultStatus(); + // Updates the image view to contain the appropriate button state image. void UpdateImage(); @@ -146,7 +155,6 @@ class VIEWS_EXPORT LabelButton : public CustomButton, FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Image); FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, LabelAndImage); FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, FontList); - FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, ButtonStyleIsDefaultSize); void SetTextInternal(const base::string16& text); @@ -167,6 +175,11 @@ class VIEWS_EXPORT LabelButton : public CustomButton, // as false. void ResetCachedPreferredSize(); + // Updates additional state related to focus or default status, rather than + // merely the CustomButton::state(). E.g. ensures the label text color is + // correct for the current background. + void ResetLabelEnabledColor(); + // The image and label shown in the button. ImageView* image_; Label* label_; @@ -216,7 +229,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton, // UI direction). gfx::HorizontalAlignment horizontal_alignment_; - scoped_ptr<Painter> focus_painter_; + std::unique_ptr<Painter> focus_painter_; DISALLOW_COPY_AND_ASSIGN(LabelButton); }; diff --git a/chromium/ui/views/controls/button/label_button_border.h b/chromium/ui/views/controls/button/label_button_border.h index 48b33524a92..fabbde5e60e 100644 --- a/chromium/ui/views/controls/button/label_button_border.h +++ b/chromium/ui/views/controls/button/label_button_border.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_BORDER_H_ #define UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_BORDER_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/border.h" #include "ui/views/controls/button/button.h" @@ -61,7 +62,7 @@ class VIEWS_EXPORT LabelButtonAssetBorder : public LabelButtonBorder { private: // The painters used for each unfocused or focused button state. - scoped_ptr<Painter> painters_[2][Button::STATE_COUNT]; + std::unique_ptr<Painter> painters_[2][Button::STATE_COUNT]; DISALLOW_COPY_AND_ASSIGN(LabelButtonAssetBorder); }; diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc index d5b60451e9f..f8c0da76cd6 100644 --- a/chromium/ui/views/controls/button/label_button_unittest.cc +++ b/chromium/ui/views/controls/button/label_button_unittest.cc @@ -4,19 +4,23 @@ #include "ui/views/controls/button/label_button.h" +#include "base/command_line.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/test/material_design_controller_test_api.h" +#include "ui/base/ui_base_switches.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/text_utils.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/animation/button_ink_drop_delegate.h" +#include "ui/views/style/platform_style.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/widget_test.h" @@ -34,10 +38,34 @@ gfx::ImageSkia CreateTestImage(int width, int height) { namespace views { +// Testing button that exposes protected methods. +class TestLabelButton : public LabelButton { + public: + TestLabelButton() : LabelButton(nullptr, base::string16()) {} + + using LabelButton::label; + + private: + DISALLOW_COPY_AND_ASSIGN(TestLabelButton); +}; + class LabelButtonTest : public test::WidgetTest { public: LabelButtonTest() {} + // Adds a LabelButton to the test Widget with the STYLE_BUTTON platform style. + TestLabelButton* AddStyledButton(const char* label, bool is_default) { + TestLabelButton* button = new TestLabelButton; + button->SetText(ASCIIToUTF16(label)); + button->SetStyle(CustomButton::STYLE_BUTTON); + if (is_default) + button->SetIsDefault(true); + button_->GetWidget()->GetContentsView()->AddChildView(button); + button->SizeToPreferredSize(); + button->Layout(); + return button; + } + // testing::Test: void SetUp() override { WidgetTest::SetUp(); @@ -45,8 +73,26 @@ class LabelButtonTest : public test::WidgetTest { // used (which could be derived from the Widget's NativeTheme). test_widget_ = CreateTopLevelPlatformWidget(); - button_ = new LabelButton(nullptr, base::string16()); + button_ = new TestLabelButton; test_widget_->GetContentsView()->AddChildView(button_); + + // Establish the expected text colors for testing changes due to state. + themed_normal_text_color_ = button_->GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ButtonEnabledColor); +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + // The Linux theme provides a non-black highlight text color, but it's not + // used for styled buttons. + styled_highlight_text_color_ = themed_normal_text_color_; + styled_normal_text_color_ = themed_normal_text_color_; +#else + styled_highlight_text_color_ = button_->GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ButtonHighlightColor); + + // For styled buttons only, platforms other than Desktop Linux either ignore + // NativeTheme and use a hardcoded black or (on Mac) have a NativeTheme that + // reliably returns black. + styled_normal_text_color_ = SK_ColorBLACK; +#endif } void TearDown() override { @@ -55,7 +101,11 @@ class LabelButtonTest : public test::WidgetTest { } protected: - LabelButton* button_ = nullptr; + TestLabelButton* button_ = nullptr; + + SkColor themed_normal_text_color_ = 0; + SkColor styled_normal_text_color_ = 0; + SkColor styled_highlight_text_color_ = 0; private: Widget* test_widget_ = nullptr; @@ -290,21 +340,65 @@ TEST_F(LabelButtonTest, ChangeLabelImageSpacing) { EXPECT_EQ(original_width, button_->GetPreferredSize().width()); } -// Make sure the label gets the width it asks for and bolding it (via -// SetDefault) causes the size to update. Regression test for crbug.com/578722 -TEST_F(LabelButtonTest, ButtonStyleIsDefaultSize) { - LabelButton* button = new LabelButton(nullptr, base::ASCIIToUTF16("Save")); - button->SetStyle(CustomButton::STYLE_BUTTON); - button_->GetWidget()->GetContentsView()->AddChildView(button); - button->SizeToPreferredSize(); - button->Layout(); - gfx::Size non_default_size = button->label_->size(); - EXPECT_EQ(button->label_->GetPreferredSize().width(), +// Ensure the label gets the correct style for default buttons (e.g. bolding) +// and button size updates correctly. Regression test for crbug.com/578722. +TEST_F(LabelButtonTest, ButtonStyleIsDefaultStyle) { + TestLabelButton* button = AddStyledButton("Save", false); + gfx::Size non_default_size = button->label()->size(); + EXPECT_EQ(button->label()->GetPreferredSize().width(), non_default_size.width()); + EXPECT_FALSE(button->label()->font_list().GetFontStyle() & gfx::Font::BOLD); + EXPECT_EQ(styled_normal_text_color_, button->label()->enabled_color()); button->SetIsDefault(true); button->SizeToPreferredSize(); button->Layout(); - EXPECT_NE(non_default_size, button->label_->size()); + EXPECT_EQ(styled_highlight_text_color_, button->label()->enabled_color()); + if (PlatformStyle::kDefaultLabelButtonHasBoldFont) { + EXPECT_NE(non_default_size, button->label()->size()); + EXPECT_TRUE(button->label()->font_list().GetFontStyle() & gfx::Font::BOLD); + } else { + EXPECT_EQ(non_default_size, button->label()->size()); + EXPECT_FALSE(button->label()->font_list().GetFontStyle() & gfx::Font::BOLD); + } +} + +// Ensure the label gets the correct style when pressed or becoming default. +TEST_F(LabelButtonTest, HighlightedButtonStyle) { +#if defined(OS_MACOSX) + // On Mac, ensure the normal and highlight colors are different, to ensure the + // tests are actually testing something. This might be the case on other + // platforms. + EXPECT_NE(styled_normal_text_color_, styled_highlight_text_color_); +#endif + + // For STYLE_TEXTBUTTON, the NativeTheme might not provide SK_ColorBLACK, but + // it should be the same for normal and pressed states. + EXPECT_EQ(themed_normal_text_color_, button_->label()->enabled_color()); + button_->SetState(Button::STATE_PRESSED); + EXPECT_EQ(themed_normal_text_color_, button_->label()->enabled_color()); + + // Add a non-default button. + TestLabelButton* styled_button = AddStyledButton("OK", false); + EXPECT_EQ(styled_normal_text_color_, styled_button->label()->enabled_color()); + styled_button->SetState(Button::STATE_PRESSED); + EXPECT_EQ(styled_highlight_text_color_, + styled_button->label()->enabled_color()); + + // If there's an explicit color set for STATE_PRESSED, that should be used. + styled_button->SetEnabledTextColors(SK_ColorRED); + EXPECT_EQ(SK_ColorRED, styled_button->label()->enabled_color()); + + // Test becoming default after adding to the Widget. + TestLabelButton* default_after = AddStyledButton("OK", false); + EXPECT_EQ(styled_normal_text_color_, default_after->label()->enabled_color()); + default_after->SetIsDefault(true); + EXPECT_EQ(styled_highlight_text_color_, + default_after->label()->enabled_color()); + + // Test becoming default before adding to the Widget. + TestLabelButton* default_before = AddStyledButton("OK", true); + EXPECT_EQ(styled_highlight_text_color_, + default_before->label()->enabled_color()); } // A ButtonInkDropDelegate that tracks the last hover state requested. @@ -358,9 +452,8 @@ class InkDropLabelButtonTest : public ViewsTestBase { // ViewsTestBase: void SetUp() override { - ui::test::MaterialDesignControllerTestAPI::SetMode( - ui::MaterialDesignController::MATERIAL_NORMAL); - + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kTopChromeMD, switches::kTopChromeMDMaterial); ViewsTestBase::SetUp(); // Create a widget so that the CustomButton can query the hover state @@ -379,12 +472,12 @@ class InkDropLabelButtonTest : public ViewsTestBase { void TearDown() override { widget_.reset(); ViewsTestBase::TearDown(); - ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); + ui::test::MaterialDesignControllerTestAPI::Uninitialize(); } protected: // Required to host the test target. - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; // The test target. InkDropLabelButton* button_ = nullptr; diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc index bf0c9bd03dd..ceaf7c6d739 100644 --- a/chromium/ui/views/controls/button/md_text_button.cc +++ b/chromium/ui/views/controls/button/md_text_button.cc @@ -10,6 +10,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/views/background.h" #include "ui/views/border.h" +#include "ui/views/controls/button/blue_button.h" #include "ui/views/painter.h" namespace views { @@ -23,19 +24,47 @@ const int kVerticalPadding = 6; // Minimum size to reserve for the button contents. const int kMinWidth = 48; +LabelButton* CreateButton(ButtonListener* listener, + const base::string16& text, + bool md) { + if (md) + return MdTextButton::CreateMdButton(listener, text); + + LabelButton* button = new LabelButton(listener, text); + button->SetStyle(CustomButton::STYLE_BUTTON); + return button; +} + } // namespace // static LabelButton* MdTextButton::CreateStandardButton(ButtonListener* listener, const base::string16& text) { - if (ui::MaterialDesignController::IsModeMaterial()) - return CreateMdButton(listener, text); + return CreateButton(listener, text, + ui::MaterialDesignController::IsModeMaterial()); +} - LabelButton* button = new LabelButton(listener, text); - button->SetStyle(STYLE_BUTTON); - return button; +// static +LabelButton* MdTextButton::CreateSecondaryUiButton(ButtonListener* listener, + const base::string16& text) { + return CreateButton(listener, text, + ui::MaterialDesignController::IsSecondaryUiMaterial()); } +// static +LabelButton* MdTextButton::CreateSecondaryUiBlueButton( + ButtonListener* listener, + const base::string16& text) { + if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { + MdTextButton* md_button = MdTextButton::CreateMdButton(listener, text); + md_button->SetCallToAction(MdTextButton::STRONG_CALL_TO_ACTION); + return md_button; + } + + return new BlueButton(listener, text); +} + +// static MdTextButton* MdTextButton::CreateMdButton(ButtonListener* listener, const base::string16& text) { MdTextButton* button = new MdTextButton(listener); @@ -45,6 +74,7 @@ MdTextButton* MdTextButton::CreateMdButton(ButtonListener* listener, button->SetBorder( Border::CreateEmptyBorder(kVerticalPadding, kHorizontalPadding, kVerticalPadding, kHorizontalPadding)); + button->SetFocusForPlatform(); return button; } @@ -69,6 +99,15 @@ void MdTextButton::SetText(const base::string16& text) { LabelButton::SetText(base::i18n::ToUpper(text)); } +void MdTextButton::UpdateStyleToIndicateDefaultStatus() { + // Update the call to action state to reflect defaultness. Don't change strong + // call to action to weak. + if (!is_default()) + SetCallToAction(NO_CALL_TO_ACTION); + else if (cta_ == NO_CALL_TO_ACTION) + SetCallToAction(WEAK_CALL_TO_ACTION); +} + MdTextButton::MdTextButton(ButtonListener* listener) : LabelButton(listener, base::string16()), ink_drop_delegate_(this, this), @@ -76,7 +115,7 @@ MdTextButton::MdTextButton(ButtonListener* listener) set_ink_drop_delegate(&ink_drop_delegate_); set_has_ink_drop_action_on_click(true); SetHorizontalAlignment(gfx::ALIGN_CENTER); - SetFocusable(true); + SetFocusForPlatform(); SetMinSize(gfx::Size(kMinWidth, 0)); SetFocusPainter(nullptr); UseMdFocusRing(); @@ -89,7 +128,11 @@ void MdTextButton::UpdateColorsFromNativeTheme() { ui::NativeTheme::ColorId fg_color_id = ui::NativeTheme::kColorId_NumColors; switch (cta_) { case NO_CALL_TO_ACTION: - fg_color_id = ui::NativeTheme::kColorId_ButtonEnabledColor; + // When there's no call to action, respect a color override if one has + // been set. For other call to action states, don't let individual buttons + // specify a color. + if (!explicitly_set_normal_color()) + fg_color_id = ui::NativeTheme::kColorId_ButtonEnabledColor; break; case WEAK_CALL_TO_ACTION: fg_color_id = ui::NativeTheme::kColorId_CallToActionColor; @@ -99,7 +142,8 @@ void MdTextButton::UpdateColorsFromNativeTheme() { break; } ui::NativeTheme* theme = GetNativeTheme(); - SetEnabledTextColors(theme->GetSystemColor(fg_color_id)); + if (fg_color_id != ui::NativeTheme::kColorId_NumColors) + SetEnabledTextColors(theme->GetSystemColor(fg_color_id)); set_background( cta_ == STRONG_CALL_TO_ACTION diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h index 8350dac7c68..cc85b261336 100644 --- a/chromium/ui/views/controls/button/md_text_button.h +++ b/chromium/ui/views/controls/button/md_text_button.h @@ -5,7 +5,8 @@ #ifndef UI_VIEWS_CONTROLS_BUTTON_MD_TEXT_BUTTON_H_ #define UI_VIEWS_CONTROLS_BUTTON_MD_TEXT_BUTTON_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/views/animation/button_ink_drop_delegate.h" #include "ui/views/controls/button/label_button.h" @@ -26,6 +27,12 @@ class VIEWS_EXPORT MdTextButton : public LabelButton { // in MD mode. static LabelButton* CreateStandardButton(ButtonListener* listener, const base::string16& text); + // As above, but only creates an MdTextButton if MD is enabled in the + // secondary UI (as opposed to just "top chrome"/"primary" UI). + static LabelButton* CreateSecondaryUiButton(ButtonListener* listener, + const base::string16& text); + static LabelButton* CreateSecondaryUiBlueButton(ButtonListener* listener, + const base::string16& text); static MdTextButton* CreateMdButton(ButtonListener* listener, const base::string16& text); @@ -35,6 +42,7 @@ class VIEWS_EXPORT MdTextButton : public LabelButton { void OnNativeThemeChanged(const ui::NativeTheme* theme) override; SkColor GetInkDropBaseColor() const override; void SetText(const base::string16& text) override; + void UpdateStyleToIndicateDefaultStatus() override; private: MdTextButton(ButtonListener* listener); diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc index 4d1a1b97281..3602b45bc9c 100644 --- a/chromium/ui/views/controls/button/menu_button.cc +++ b/chromium/ui/views/controls/button/menu_button.cc @@ -10,11 +10,11 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches_util.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/image.h" -#include "ui/gfx/screen.h" #include "ui/gfx/text_constants.h" #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc index fdfc4d0a9b4..e34315ec014 100644 --- a/chromium/ui/views/controls/button/menu_button_unittest.cc +++ b/chromium/ui/views/controls/button/menu_button_unittest.cc @@ -4,8 +4,9 @@ #include "ui/views/controls/button/menu_button.h" +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "ui/base/dragdrop/drag_drop_types.h" @@ -104,7 +105,7 @@ class MenuButtonTest : public ViewsTestBase { Widget* widget_; TestMenuButton* button_; - scoped_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<ui::test::EventGenerator> generator_; DISALLOW_COPY_AND_ASSIGN(MenuButtonTest); }; @@ -184,7 +185,7 @@ class PressStateMenuButtonListener : public MenuButtonListener { private: MenuButton* menu_button_; - scoped_ptr<MenuButton::PressedLock> pressed_lock_; + std::unique_ptr<MenuButton::PressedLock> pressed_lock_; // The |pressed_lock_| will be released when true. bool release_lock_; @@ -349,7 +350,7 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) { EXPECT_EQ(Button::STATE_HOVERED, button()->state()); // Introduce a PressedLock, which should make the button pressed. - scoped_ptr<MenuButton::PressedLock> pressed_lock1( + std::unique_ptr<MenuButton::PressedLock> pressed_lock1( new MenuButton::PressedLock(button())); EXPECT_EQ(Button::STATE_PRESSED, button()->state()); @@ -358,7 +359,7 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) { EXPECT_EQ(Button::STATE_PRESSED, button()->state()); // Creating a new lock should obviously keep the button pressed. - scoped_ptr<MenuButton::PressedLock> pressed_lock2( + std::unique_ptr<MenuButton::PressedLock> pressed_lock2( new MenuButton::PressedLock(button())); EXPECT_EQ(Button::STATE_PRESSED, button()->state()); @@ -436,7 +437,7 @@ TEST_F(MenuButtonTest, InkDropStateForMenuButtonActivationsWithoutListener) { button()->set_ink_drop_delegate(&ink_drop_delegate); button()->Activate(nullptr); - EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate.GetTargetInkDropState()); } TEST_F(MenuButtonTest, @@ -447,7 +448,8 @@ TEST_F(MenuButtonTest, button()->set_ink_drop_delegate(&ink_drop_delegate); button()->Activate(nullptr); - EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTION_TRIGGERED, + ink_drop_delegate.GetTargetInkDropState()); } TEST_F( @@ -460,7 +462,7 @@ TEST_F( button()->set_ink_drop_delegate(&ink_drop_delegate); button()->Activate(nullptr); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); // Prevent the button from accessing invalid memory during clean up. button()->set_ink_drop_delegate(nullptr); @@ -475,7 +477,8 @@ TEST_F(MenuButtonTest, button()->set_ink_drop_delegate(&ink_drop_delegate); button()->Activate(nullptr); - EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::DEACTIVATED, + ink_drop_delegate.GetTargetInkDropState()); } TEST_F(MenuButtonTest, InkDropStateForMenuButtonsWithPressedLocks) { @@ -483,21 +486,22 @@ TEST_F(MenuButtonTest, InkDropStateForMenuButtonsWithPressedLocks) { TestInkDropDelegate ink_drop_delegate; button()->set_ink_drop_delegate(&ink_drop_delegate); - scoped_ptr<MenuButton::PressedLock> pressed_lock1( + std::unique_ptr<MenuButton::PressedLock> pressed_lock1( new MenuButton::PressedLock(button())); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); - scoped_ptr<MenuButton::PressedLock> pressed_lock2( + std::unique_ptr<MenuButton::PressedLock> pressed_lock2( new MenuButton::PressedLock(button())); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); pressed_lock1.reset(); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); pressed_lock2.reset(); - EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::DEACTIVATED, + ink_drop_delegate.GetTargetInkDropState()); } // Verifies only one ink drop animation is triggered when multiple PressedLocks @@ -507,16 +511,17 @@ TEST_F(MenuButtonTest, OneInkDropAnimationForReentrantPressedLocks) { TestInkDropDelegate ink_drop_delegate; button()->set_ink_drop_delegate(&ink_drop_delegate); - scoped_ptr<MenuButton::PressedLock> pressed_lock1( + std::unique_ptr<MenuButton::PressedLock> pressed_lock1( new MenuButton::PressedLock(button())); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); ink_drop_delegate.OnAction(InkDropState::ACTION_PENDING); - scoped_ptr<MenuButton::PressedLock> pressed_lock2( + std::unique_ptr<MenuButton::PressedLock> pressed_lock2( new MenuButton::PressedLock(button())); - EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTION_PENDING, + ink_drop_delegate.GetTargetInkDropState()); } // Verifies the InkDropState is left as ACTIVATED if a PressedLock is active @@ -531,7 +536,7 @@ TEST_F(MenuButtonTest, button()->Activate(nullptr); - EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.state()); + EXPECT_EQ(InkDropState::ACTIVATED, ink_drop_delegate.GetTargetInkDropState()); } #if defined(USE_AURA) diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc index 3de636fbdc1..dc7797936b7 100644 --- a/chromium/ui/views/controls/combobox/combobox.cc +++ b/chromium/ui/views/controls/combobox/combobox.cc @@ -46,6 +46,10 @@ namespace views { namespace { +// Action style arrow container padding widths +const int kActionLeftPadding = 12; +const int kActionRightPadding = 11; + // Menu border widths const int kMenuBorderWidthLeft = 1; const int kMenuBorderWidthTop = 1; @@ -54,12 +58,6 @@ const int kMenuBorderWidthRight = 1; // Limit how small a combobox can be. const int kMinComboboxWidth = 25; -// Size of the combobox arrow margins -const int kDisclosureArrowLeftPadding = 7; -const int kDisclosureArrowRightPadding = 7; -const int kDisclosureArrowButtonLeftPadding = 11; -const int kDisclosureArrowButtonRightPadding = 12; - // Define the id of the first item in the menu (since it needs to be > 0) const int kFirstMenuItemId = 1000; @@ -89,12 +87,29 @@ const int kFocusedPressedMenuButtonImages[] = #undef MENU_IMAGE_GRID +gfx::Rect PositionArrowWithinContainer(const gfx::Rect& container_bounds, + const gfx::Size& arrow_size, + Combobox::Style style) { + gfx::Rect bounds(container_bounds); + if (style == Combobox::STYLE_ACTION) { + // This positions the arrow horizontally. The later call to + // ClampToCenteredSize will position it vertically without touching the + // horizontal position. + bounds.Inset(kActionLeftPadding, 0, kActionRightPadding, 0); + DCHECK_EQ(bounds.width(), arrow_size.width()); + } + + bounds.ClampToCenteredSize(arrow_size); + return bounds; +} + // The transparent button which holds a button state but is not rendered. class TransparentButton : public CustomButton { public: TransparentButton(ButtonListener* listener) : CustomButton(listener) { SetAnimationDuration(LabelButton::kHoverAnimationDurationMs); + SetFocusBehavior(FocusBehavior::NEVER); } ~TransparentButton() override {} @@ -342,21 +357,28 @@ class Combobox::ComboboxMenuModelAdapter : public ui::MenuModel, //////////////////////////////////////////////////////////////////////////////// // Combobox, public: -Combobox::Combobox(ui::ComboboxModel* model) +Combobox::Combobox(ui::ComboboxModel* model, Style style) : model_(model), - style_(STYLE_NORMAL), + style_(style), listener_(NULL), - selected_index_(model_->GetDefaultIndex()), + selected_index_(style == STYLE_ACTION ? 0 : model_->GetDefaultIndex()), invalid_(false), menu_model_adapter_(new ComboboxMenuModelAdapter(this, model)), text_button_(new TransparentButton(this)), arrow_button_(new TransparentButton(this)), weak_ptr_factory_(this) { ModelChanged(); - SetFocusable(true); +#if defined(OS_MACOSX) + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); +#else + SetFocusBehavior(FocusBehavior::ALWAYS); +#endif + UpdateBorder(); + arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style); // set_background() takes ownership but takes a raw pointer. - scoped_ptr<Background> b = PlatformStyle::CreateComboboxBackground(); + std::unique_ptr<Background> b = + PlatformStyle::CreateComboboxBackground(GetArrowContainerWidth()); set_background(b.release()); // Initialize the button images. @@ -381,8 +403,6 @@ Combobox::Combobox(ui::ComboboxModel* model) text_button_->SetVisible(true); arrow_button_->SetVisible(true); - text_button_->SetFocusable(false); - arrow_button_->SetFocusable(false); AddChildView(text_button_); AddChildView(arrow_button_); } @@ -400,19 +420,6 @@ const gfx::FontList& Combobox::GetFontList() { return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta); } -void Combobox::SetStyle(Style style) { - if (style_ == style) - return; - - style_ = style; - if (style_ == STYLE_ACTION) - selected_index_ = 0; - - UpdateBorder(); - content_size_ = GetContentSize(); - PreferredSizeChanged(); -} - void Combobox::ModelChanged() { // If the selection is no longer valid (or the model is empty), restore the // default index. @@ -461,12 +468,6 @@ void Combobox::SetInvalid(bool invalid) { SchedulePaint(); } -int Combobox::GetArrowButtonWidth() const { - return GetDisclosureArrowLeftPadding() + - ArrowSize().width() + - GetDisclosureArrowRightPadding(); -} - void Combobox::Layout() { PrefixDelegate::Layout(); @@ -480,9 +481,7 @@ void Combobox::Layout() { break; } case STYLE_ACTION: { - arrow_button_width = GetDisclosureArrowLeftPadding() + - ArrowSize().width() + - GetDisclosureArrowRightPadding(); + arrow_button_width = GetArrowContainerWidth(); text_button_width = width() - arrow_button_width; break; } @@ -493,6 +492,11 @@ void Combobox::Layout() { arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height()); } +void Combobox::OnEnabledChanged() { + PrefixDelegate::OnEnabledChanged(); + arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style_); +} + int Combobox::GetRowCount() { return model()->GetItemCount(); } @@ -525,8 +529,7 @@ gfx::Size Combobox::GetPreferredSize() const { Textfield::kTextPadding, Textfield::kTextPadding); int total_width = std::max(kMinComboboxWidth, content_size_.width()) + - insets.width() + GetDisclosureArrowLeftPadding() + - ArrowSize().width() + GetDisclosureArrowRightPadding(); + insets.width() + GetArrowContainerWidth(); return gfx::Size(total_width, content_size_.height() + insets.height()); } @@ -700,7 +703,8 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) { } void Combobox::UpdateBorder() { - scoped_ptr<FocusableBorder> border(PlatformStyle::CreateComboboxBorder()); + std::unique_ptr<FocusableBorder> border( + PlatformStyle::CreateComboboxBorder()); if (style_ == STYLE_ACTION) border->SetInsets(5, 10, 5, 10); if (invalid_) @@ -733,8 +737,7 @@ void Combobox::PaintText(gfx::Canvas* canvas) { base::string16 text = model()->GetItemAt(selected_index_); gfx::Size arrow_size = ArrowSize(); - int disclosure_arrow_offset = width() - arrow_size.width() - - GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding(); + int disclosure_arrow_offset = width() - GetArrowContainerWidth(); const gfx::FontList& font_list = Combobox::GetFontList(); int text_width = gfx::GetStringWidth(text, font_list); @@ -745,26 +748,19 @@ void Combobox::PaintText(gfx::Canvas* canvas) { AdjustBoundsForRTLUI(&text_bounds); canvas->DrawStringRect(text, font_list, text_color, text_bounds); - int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding(); - gfx::Rect arrow_bounds(arrow_x, - height() / 2 - arrow_size.height() / 2, - arrow_size.width(), - arrow_size.height()); + gfx::Rect arrow_bounds(disclosure_arrow_offset, 0, GetArrowContainerWidth(), + height()); + arrow_bounds = + PositionArrowWithinContainer(arrow_bounds, ArrowSize(), style_); AdjustBoundsForRTLUI(&arrow_bounds); - gfx::ImageSkia arrow_image = PlatformStyle::CreateComboboxArrow( - enabled(), style_); - canvas->DrawImageInt(arrow_image, arrow_bounds.x(), arrow_bounds.y()); + canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y()); } void Combobox::PaintButtons(gfx::Canvas* canvas) { DCHECK(style_ == STYLE_ACTION); - gfx::ScopedCanvas scoped_canvas(canvas); - if (base::i18n::IsRTL()) { - canvas->Translate(gfx::Vector2d(width(), 0)); - canvas->Scale(-1, 1); - } + gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, bounds()); bool focused = HasFocus(); const std::vector<const gfx::ImageSkia*>& arrow_button_images = @@ -872,30 +868,8 @@ void Combobox::OnPerformAction() { selected_index_ = 0; } -int Combobox::GetDisclosureArrowLeftPadding() const { - switch (style_) { - case STYLE_NORMAL: - return kDisclosureArrowLeftPadding; - case STYLE_ACTION: - return kDisclosureArrowButtonLeftPadding; - } - NOTREACHED(); - return 0; -} - -int Combobox::GetDisclosureArrowRightPadding() const { - switch (style_) { - case STYLE_NORMAL: - return kDisclosureArrowRightPadding; - case STYLE_ACTION: - return kDisclosureArrowButtonRightPadding; - } - NOTREACHED(); - return 0; -} - gfx::Size Combobox::ArrowSize() const { - return PlatformStyle::CreateComboboxArrow(enabled(), style_).size(); + return arrow_image_.size(); } gfx::Size Combobox::GetContentSize() const { @@ -921,4 +895,12 @@ PrefixSelector* Combobox::GetPrefixSelector() { return selector_.get(); } +int Combobox::GetArrowContainerWidth() const { + const int kNormalPadding = 7; + int padding = style_ == STYLE_NORMAL + ? kNormalPadding * 2 + : kActionLeftPadding + kActionRightPadding; + return ArrowSize().width() + padding; +} + } // namespace views diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h index 64e4baa9be1..a3112c7eb9c 100644 --- a/chromium/ui/views/controls/combobox/combobox.h +++ b/chromium/ui/views/controls/combobox/combobox.h @@ -53,7 +53,7 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { static const char kViewClassName[]; // |model| is not owned by the combobox. - explicit Combobox(ui::ComboboxModel* model); + explicit Combobox(ui::ComboboxModel* model, Style style = STYLE_NORMAL); ~Combobox() override; static const gfx::FontList& GetFontList(); @@ -61,8 +61,6 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { // Sets the listener which will be called when a selection has been made. void set_listener(ComboboxListener* listener) { listener_ = listener; } - void SetStyle(Style style); - // Informs the combobox that its model changed. void ModelChanged(); @@ -85,10 +83,6 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { void SetInvalid(bool invalid); bool invalid() const { return invalid_; } - // Returns the width of the arrow button component of the combobox: the arrow - // button itself, and the padding on either side of it. - int GetArrowButtonWidth() const; - // Overridden from View: gfx::Size GetPreferredSize() const override; const char* GetClassName() const override; @@ -100,6 +94,7 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { void OnBlur() override; void GetAccessibleState(ui::AXViewState* state) override; void Layout() override; + void OnEnabledChanged() override; // Overridden from PrefixDelegate: int GetRowCount() override; @@ -148,11 +143,14 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { PrefixSelector* GetPrefixSelector(); + // Returns the width of the combobox's arrow container. + int GetArrowContainerWidth() const; + // Our model. Not owned. ui::ComboboxModel* model_; // The visual style of this combobox. - Style style_; + const Style style_; // Our listener. Not owned. Notified when the selected index change. ComboboxListener* listener_; @@ -167,10 +165,10 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { base::string16 accessible_name_; // A helper used to select entries by keyboard input. - scoped_ptr<PrefixSelector> selector_; + std::unique_ptr<PrefixSelector> selector_; // Adapts a ComboboxModel for use by a views MenuRunner. - scoped_ptr<ui::MenuModel> menu_model_adapter_; + std::unique_ptr<ui::MenuModel> menu_model_adapter_; // Like MenuButton, we use a time object in order to keep track of when the // combobox was closed. The time is used for simulating menu behavior; that @@ -186,7 +184,7 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { // The painters or images that are used when |style_| is STYLE_BUTTONS. The // first index means the state of unfocused or focused. // The images are owned by ResourceBundle. - scoped_ptr<Painter> body_button_painters_[2][Button::STATE_COUNT]; + std::unique_ptr<Painter> body_button_painters_[2][Button::STATE_COUNT]; std::vector<const gfx::ImageSkia*> menu_button_images_[2][Button::STATE_COUNT]; @@ -201,7 +199,10 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener { // Set while the dropdown is showing. Ensures the menu is closed if |this| is // destroyed. - scoped_ptr<views::MenuRunner> menu_runner_; + std::unique_ptr<views::MenuRunner> menu_runner_; + + // The image to be drawn for this combobox's arrow. + gfx::ImageSkia arrow_image_; // Used for making calbacks. base::WeakPtrFactory<Combobox> weak_ptr_factory_; diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc index 65659c97b7d..8d585c63a94 100644 --- a/chromium/ui/views/controls/combobox/combobox_unittest.cc +++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc @@ -35,10 +35,8 @@ namespace { // OnKeyReleased() methods. class TestCombobox : public Combobox { public: - explicit TestCombobox(ui::ComboboxModel* model) - : Combobox(model), - key_handled_(false), - key_received_(false) {} + TestCombobox(ui::ComboboxModel* model, Combobox::Style style) + : Combobox(model, style), key_handled_(false), key_received_(false) {} bool OnKeyPressed(const ui::KeyEvent& e) override { key_received_ = true; @@ -195,14 +193,14 @@ class ComboboxTest : public ViewsTestBase { ViewsTestBase::TearDown(); } - void InitCombobox(const std::set<int>* separators) { + void InitCombobox(const std::set<int>* separators, Combobox::Style style) { model_.reset(new TestComboboxModel()); if (separators) model_->SetSeparators(*separators); ASSERT_FALSE(combobox_); - combobox_ = new TestCombobox(model_.get()); + combobox_ = new TestCombobox(model_.get(), style); test_api_.reset(new ComboboxTestApi(combobox_)); combobox_->set_id(1); @@ -251,17 +249,17 @@ class ComboboxTest : public ViewsTestBase { // |combobox_| will be allocated InitCombobox() and then owned by |widget_|. TestCombobox* combobox_; - scoped_ptr<ComboboxTestApi> test_api_; + std::unique_ptr<ComboboxTestApi> test_api_; // Combobox does not take ownership of the model, hence it needs to be scoped. - scoped_ptr<TestComboboxModel> model_; + std::unique_ptr<TestComboboxModel> model_; private: DISALLOW_COPY_AND_ASSIGN(ComboboxTest); }; TEST_F(ComboboxTest, KeyTest) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); SendKeyEvent(ui::VKEY_END); EXPECT_EQ(combobox_->selected_index() + 1, model_->GetItemCount()); SendKeyEvent(ui::VKEY_HOME); @@ -287,7 +285,7 @@ TEST_F(ComboboxTest, DisabilityTest) { model_.reset(new TestComboboxModel()); ASSERT_FALSE(combobox_); - combobox_ = new TestCombobox(model_.get()); + combobox_ = new TestCombobox(model_.get(), Combobox::STYLE_NORMAL); combobox_->SetEnabled(false); widget_ = new Widget; @@ -305,7 +303,7 @@ TEST_F(ComboboxTest, DisabilityTest) { TEST_F(ComboboxTest, SkipSeparatorSimple) { std::set<int> separators; separators.insert(2); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(0, combobox_->selected_index()); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(1, combobox_->selected_index()); @@ -326,7 +324,7 @@ TEST_F(ComboboxTest, SkipSeparatorSimple) { TEST_F(ComboboxTest, SkipSeparatorBeginning) { std::set<int> separators; separators.insert(0); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(1, combobox_->selected_index()); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(2, combobox_->selected_index()); @@ -347,7 +345,7 @@ TEST_F(ComboboxTest, SkipSeparatorBeginning) { TEST_F(ComboboxTest, SkipSeparatorEnd) { std::set<int> separators; separators.insert(TestComboboxModel::kItemCount - 1); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(8); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(8, combobox_->selected_index()); @@ -365,7 +363,7 @@ TEST_F(ComboboxTest, SkipMultipleSeparatorsAtBeginning) { separators.insert(0); separators.insert(1); separators.insert(2); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(3, combobox_->selected_index()); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(4, combobox_->selected_index()); @@ -389,7 +387,7 @@ TEST_F(ComboboxTest, SkipMultipleAdjacentSeparatorsAtMiddle) { separators.insert(4); separators.insert(5); separators.insert(6); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(3); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(7, combobox_->selected_index()); @@ -405,7 +403,7 @@ TEST_F(ComboboxTest, SkipMultipleSeparatorsAtEnd) { separators.insert(7); separators.insert(8); separators.insert(9); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(6); SendKeyEvent(ui::VKEY_DOWN); EXPECT_EQ(6, combobox_->selected_index()); @@ -426,7 +424,7 @@ TEST_F(ComboboxTest, GetTextForRowTest) { separators.insert(0); separators.insert(1); separators.insert(9); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); for (int i = 0; i < combobox_->GetRowCount(); ++i) { if (separators.count(i) != 0) { EXPECT_TRUE(combobox_->GetTextForRow(i).empty()) << i; @@ -439,7 +437,7 @@ TEST_F(ComboboxTest, GetTextForRowTest) { // Verifies selecting the first matching value (and returning whether found). TEST_F(ComboboxTest, SelectValue) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); ASSERT_EQ(model_->GetDefaultIndex(), combobox_->selected_index()); EXPECT_TRUE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER"))); EXPECT_EQ(0, combobox_->selected_index()); @@ -447,9 +445,11 @@ TEST_F(ComboboxTest, SelectValue) { EXPECT_EQ(1, combobox_->selected_index()); EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS"))); EXPECT_EQ(1, combobox_->selected_index()); +} +TEST_F(ComboboxTest, SelectValueActionStyle) { // With the action style, the selected index is always 0. - combobox_->SetStyle(Combobox::STYLE_ACTION); + InitCombobox(nullptr, Combobox::STYLE_ACTION); EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER"))); EXPECT_EQ(0, combobox_->selected_index()); EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("JELLY"))); @@ -459,10 +459,9 @@ TEST_F(ComboboxTest, SelectValue) { } TEST_F(ComboboxTest, SelectIndexActionStyle) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_ACTION); // With the action style, the selected index is always 0. - combobox_->SetStyle(Combobox::STYLE_ACTION); combobox_->SetSelectedIndex(1); EXPECT_EQ(0, combobox_->selected_index()); combobox_->SetSelectedIndex(2); @@ -475,24 +474,23 @@ TEST_F(ComboboxTest, ListenerHandlesDelete) { TestComboboxModel model; // |combobox| will be deleted on change. - TestCombobox* combobox = new TestCombobox(&model); - scoped_ptr<EvilListener> evil_listener(new EvilListener()); + TestCombobox* combobox = new TestCombobox(&model, Combobox::STYLE_NORMAL); + std::unique_ptr<EvilListener> evil_listener(new EvilListener()); combobox->set_listener(evil_listener.get()); ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2)); EXPECT_TRUE(evil_listener->deleted()); // With STYLE_ACTION // |combobox| will be deleted on change. - combobox = new TestCombobox(&model); + combobox = new TestCombobox(&model, Combobox::STYLE_ACTION); evil_listener.reset(new EvilListener()); combobox->set_listener(evil_listener.get()); - combobox->SetStyle(Combobox::STYLE_ACTION); ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2)); EXPECT_TRUE(evil_listener->deleted()); } TEST_F(ComboboxTest, Click) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); TestComboboxListener listener; combobox_->set_listener(&listener); @@ -510,7 +508,7 @@ TEST_F(ComboboxTest, Click) { } TEST_F(ComboboxTest, ClickButDisabled) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); TestComboboxListener listener; combobox_->set_listener(&listener); @@ -528,7 +526,7 @@ TEST_F(ComboboxTest, ClickButDisabled) { } TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); TestComboboxListener listener; combobox_->set_listener(&listener); @@ -536,16 +534,22 @@ TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) { // With STYLE_NORMAL, the click event is ignored. SendKeyEvent(ui::VKEY_RETURN); EXPECT_FALSE(listener.on_perform_action_called()); +} + +TEST_F(ComboboxTest, NotifyOnClickWithReturnKeyActionStyle) { + InitCombobox(nullptr, Combobox::STYLE_ACTION); + + TestComboboxListener listener; + combobox_->set_listener(&listener); // With STYLE_ACTION, the click event is notified. - combobox_->SetStyle(Combobox::STYLE_ACTION); SendKeyEvent(ui::VKEY_RETURN); EXPECT_TRUE(listener.on_perform_action_called()); EXPECT_EQ(0, listener.perform_action_index()); } TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); TestComboboxListener listener; combobox_->set_listener(&listener); @@ -555,9 +559,15 @@ TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) { EXPECT_FALSE(listener.on_perform_action_called()); SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); EXPECT_FALSE(listener.on_perform_action_called()); +} + +TEST_F(ComboboxTest, NotifyOnClickWithSpaceKeyActionStyle) { + InitCombobox(nullptr, Combobox::STYLE_ACTION); + + TestComboboxListener listener; + combobox_->set_listener(&listener); // With STYLE_ACTION, the click event is notified after releasing. - combobox_->SetStyle(Combobox::STYLE_ACTION); SendKeyEvent(ui::VKEY_SPACE); EXPECT_FALSE(listener.on_perform_action_called()); SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); @@ -566,12 +576,11 @@ TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) { } TEST_F(ComboboxTest, NotifyOnClickWithMouse) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_ACTION); TestComboboxListener listener; combobox_->set_listener(&listener); - combobox_->SetStyle(Combobox::STYLE_ACTION); combobox_->Layout(); // Click the right side (arrow button). The menu is shown. @@ -593,16 +602,18 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) { } TEST_F(ComboboxTest, ConsumingPressKeyEvents) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); EXPECT_FALSE(combobox_->OnKeyPressed( ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE))); EXPECT_FALSE(combobox_->OnKeyPressed( ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE))); +} +TEST_F(ComboboxTest, ConsumingKeyPressEventsActionStyle) { // When the combobox's style is STYLE_ACTION, pressing events of a space key // or an enter key will be consumed. - combobox_->SetStyle(Combobox::STYLE_ACTION); + InitCombobox(nullptr, Combobox::STYLE_ACTION); EXPECT_TRUE(combobox_->OnKeyPressed( ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE))); EXPECT_TRUE(combobox_->OnKeyPressed( @@ -612,8 +623,10 @@ TEST_F(ComboboxTest, ConsumingPressKeyEvents) { TEST_F(ComboboxTest, ContentWidth) { std::vector<std::string> values; VectorComboboxModel model(&values); - TestCombobox combobox(&model); + TestCombobox combobox(&model, Combobox::STYLE_NORMAL); + TestCombobox action_combobox(&model, Combobox::STYLE_ACTION); ComboboxTestApi test_api(&combobox); + ComboboxTestApi action_test_api(&action_combobox); std::string long_item = "this is the long item"; std::string short_item = "s"; @@ -621,11 +634,13 @@ TEST_F(ComboboxTest, ContentWidth) { values.resize(1); values[0] = long_item; combobox.ModelChanged(); + action_combobox.ModelChanged(); const int long_item_width = test_api.content_size().width(); values[0] = short_item; combobox.ModelChanged(); + action_combobox.ModelChanged(); const int short_item_width = test_api.content_size().width(); @@ -633,21 +648,20 @@ TEST_F(ComboboxTest, ContentWidth) { values[0] = short_item; values[1] = long_item; combobox.ModelChanged(); + action_combobox.ModelChanged(); // When the style is STYLE_NORMAL, the width will fit with the longest item. - combobox.SetStyle(Combobox::STYLE_NORMAL); EXPECT_EQ(long_item_width, test_api.content_size().width()); // When the style is STYLE_ACTION, the width will fit with the selected item's // width. - combobox.SetStyle(Combobox::STYLE_ACTION); - EXPECT_EQ(short_item_width, test_api.content_size().width()); + EXPECT_EQ(short_item_width, action_test_api.content_size().width()); } // Test that model updates preserve the selected index, so long as it is in // range. TEST_F(ComboboxTest, ModelChanged) { - InitCombobox(nullptr); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); EXPECT_EQ(0, combobox_->GetSelectedRow()); EXPECT_EQ(10, combobox_->GetRowCount()); @@ -689,7 +703,7 @@ TEST_F(ComboboxTest, ModelChanged) { } TEST_F(ComboboxTest, TypingPrefixNotifiesListener) { - InitCombobox(NULL); + InitCombobox(nullptr, Combobox::STYLE_NORMAL); TestComboboxListener listener; combobox_->set_listener(&listener); @@ -732,7 +746,7 @@ TEST_F(ComboboxTest, MenuModel) { const int kSeparatorIndex = 3; std::set<int> separators; separators.insert(kSeparatorIndex); - InitCombobox(&separators); + InitCombobox(&separators, Combobox::STYLE_NORMAL); ui::MenuModel* menu_model = test_api_->menu_model(); @@ -758,9 +772,27 @@ TEST_F(ComboboxTest, MenuModel) { EXPECT_EQ(ASCIIToUTF16("PEANUT BUTTER"), menu_model->GetLabelAt(0)); EXPECT_EQ(ASCIIToUTF16("JELLY"), menu_model->GetLabelAt(1)); - // Check that with STYLE_ACTION, the first item (only) is not shown. EXPECT_TRUE(menu_model->IsVisibleAt(0)); - combobox_->SetStyle(Combobox::STYLE_ACTION); +} + +// Check that with STYLE_ACTION, the first item (only) is not shown. +TEST_F(ComboboxTest, MenuModelActionStyleMac) { + const int kSeparatorIndex = 3; + std::set<int> separators; + separators.insert(kSeparatorIndex); + InitCombobox(&separators, Combobox::STYLE_ACTION); + + ui::MenuModel* menu_model = test_api_->menu_model(); + + EXPECT_EQ(TestComboboxModel::kItemCount, menu_model->GetItemCount()); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, + menu_model->GetTypeAt(kSeparatorIndex)); + + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu_model->GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu_model->GetTypeAt(1)); + + EXPECT_EQ(ASCIIToUTF16("PEANUT BUTTER"), menu_model->GetLabelAt(0)); + EXPECT_EQ(ASCIIToUTF16("JELLY"), menu_model->GetLabelAt(1)); EXPECT_FALSE(menu_model->IsVisibleAt(0)); EXPECT_TRUE(menu_model->IsVisibleAt(1)); } diff --git a/chromium/ui/views/controls/focusable_border.cc b/chromium/ui/views/controls/focusable_border.cc index b3ddd149272..a4e76ff1ba2 100644 --- a/chromium/ui/views/controls/focusable_border.cc +++ b/chromium/ui/views/controls/focusable_border.cc @@ -6,10 +6,13 @@ #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/skia_util.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/controls/textfield/textfield.h" namespace { @@ -21,7 +24,7 @@ namespace views { FocusableBorder::FocusableBorder() : insets_(kInsetSize, kInsetSize, kInsetSize, kInsetSize), - override_color_(SK_ColorWHITE), + override_color_(gfx::kPlaceholderColor), use_default_color_(true) { } @@ -38,14 +41,21 @@ void FocusableBorder::UseDefaultColor() { } void FocusableBorder::Paint(const View& view, gfx::Canvas* canvas) { - SkPath path; - path.addRect(gfx::RectToSkRect(view.GetLocalBounds()), SkPath::kCW_Direction); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(GetCurrentColor(view)); - paint.setStrokeWidth(SkIntToScalar(2)); + SkPath path; + if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { + path.moveTo(Textfield::kTextPadding, view.height() - 1); + path.rLineTo(view.width() - Textfield::kTextPadding * 2, 0); + path.offset(0.5f, 0.5f); + paint.setStrokeWidth(SkIntToScalar(1)); + } else { + path.addRect(gfx::RectToSkRect(view.GetLocalBounds()), + SkPath::kCW_Direction); + paint.setStrokeWidth(SkIntToScalar(2)); + } canvas->DrawPath(path, paint); } diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc index 7127ca4f070..8b5952fa1c2 100644 --- a/chromium/ui/views/controls/image_view.cc +++ b/chromium/ui/views/controls/image_view.cc @@ -84,7 +84,7 @@ void ImageView::ResetImageSize() { image_size_set_ = false; } -void ImageView::SetFocusPainter(scoped_ptr<Painter> focus_painter) { +void ImageView::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { focus_painter_ = std::move(focus_painter); } diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h index b3b762bcd43..eb3f727ead7 100644 --- a/chromium/ui/views/controls/image_view.h +++ b/chromium/ui/views/controls/image_view.h @@ -77,7 +77,7 @@ class VIEWS_EXPORT ImageView : public View { void set_interactive(bool interactive) { interactive_ = interactive; } - void SetFocusPainter(scoped_ptr<Painter> focus_painter); + void SetFocusPainter(std::unique_ptr<Painter> focus_painter); // Overriden from View: gfx::Size GetPreferredSize() const override; @@ -133,7 +133,7 @@ class VIEWS_EXPORT ImageView : public View { // safe to cache. void* last_painted_bitmap_pixels_; - scoped_ptr<views::Painter> focus_painter_; + std::unique_ptr<views::Painter> focus_painter_; DISALLOW_COPY_AND_ASSIGN(ImageView); }; diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc index d1a6cafa9c1..0f927f308d7 100644 --- a/chromium/ui/views/controls/label.cc +++ b/chromium/ui/views/controls/label.cc @@ -213,7 +213,7 @@ base::string16 Label::GetDisplayTextForTesting() { gfx::Insets Label::GetInsets() const { gfx::Insets insets = View::GetInsets(); - if (focusable()) { + if (focus_behavior() != FocusBehavior::NEVER) { insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding, kFocusBorderPadding, kFocusBorderPadding); } @@ -332,15 +332,16 @@ bool Label::GetTooltipText(const gfx::Point& p, base::string16* tooltip) const { } void Label::OnEnabledChanged() { - RecalculateColors(); + ApplyTextColors(); + View::OnEnabledChanged(); } -scoped_ptr<gfx::RenderText> Label::CreateRenderText( +std::unique_ptr<gfx::RenderText> Label::CreateRenderText( const base::string16& text, gfx::HorizontalAlignment alignment, gfx::DirectionalityMode directionality, gfx::ElideBehavior elide_behavior) { - scoped_ptr<gfx::RenderText> render_text( + std::unique_ptr<gfx::RenderText> render_text( render_text_->CreateInstanceOfSameType()); render_text->SetHorizontalAlignment(alignment); render_text->SetDirectionalityMode(directionality); @@ -435,7 +436,7 @@ void Label::MaybeBuildRenderTextLines() { return; gfx::Rect rect = GetContentsBounds(); - if (focusable()) + if (focus_behavior() != FocusBehavior::NEVER) rect.Inset(kFocusBorderPadding, kFocusBorderPadding); if (rect.IsEmpty()) return; @@ -458,7 +459,7 @@ void Label::MaybeBuildRenderTextLines() { gfx::ElideBehavior elide_behavior = multi_line() ? gfx::NO_ELIDE : elide_behavior_; if (!multi_line() || render_text_->MultilineSupported()) { - scoped_ptr<gfx::RenderText> render_text = + std::unique_ptr<gfx::RenderText> render_text = CreateRenderText(text(), alignment, directionality, elide_behavior); render_text->SetDisplayRect(rect); render_text->SetMultiline(multi_line()); @@ -471,7 +472,7 @@ void Label::MaybeBuildRenderTextLines() { const int bottom = GetContentsBounds().bottom(); for (size_t i = 0; i < lines.size() && rect.y() <= bottom; ++i) { - scoped_ptr<gfx::RenderText> line = + std::unique_ptr<gfx::RenderText> line = CreateRenderText(lines[i], alignment, directionality, elide_behavior); line->SetDisplayRect(rect); lines_.push_back(std::move(line)); @@ -481,7 +482,7 @@ void Label::MaybeBuildRenderTextLines() { for (size_t i = lines_.size(); i < lines.size(); ++i) lines_.back()->SetText(lines_.back()->text() + lines[i]); } - RecalculateColors(); + ApplyTextColors(); } gfx::Rect Label::GetFocusBounds() { @@ -535,7 +536,8 @@ gfx::Size Label::GetTextSize() const { } else { // Get the natural text size, unelided and only wrapped on newlines. std::vector<base::string16> lines = GetLinesForWidth(width()); - scoped_ptr<gfx::RenderText> render_text(gfx::RenderText::CreateInstance()); + std::unique_ptr<gfx::RenderText> render_text( + gfx::RenderText::CreateInstance()); render_text->SetFontList(font_list()); for (size_t i = 0; i < lines.size(); ++i) { render_text->SetText(lines[i]); @@ -559,6 +561,11 @@ void Label::RecalculateColors() { background_color_) : requested_disabled_color_; + ApplyTextColors(); + SchedulePaint(); +} + +void Label::ApplyTextColors() { SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_; bool subpixel_rendering_suppressed = SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_; @@ -566,7 +573,6 @@ void Label::RecalculateColors() { lines_[i]->SetColor(color); lines_[i]->set_subpixel_rendering_suppressed(subpixel_rendering_suppressed); } - SchedulePaint(); } void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) { diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h index b2520e3d876..8ede4c04b88 100644 --- a/chromium/ui/views/controls/label.h +++ b/chromium/ui/views/controls/label.h @@ -137,7 +137,7 @@ class VIEWS_EXPORT Label : public View { protected: // Create a single RenderText instance to actually be painted. - virtual scoped_ptr<gfx::RenderText> CreateRenderText( + virtual std::unique_ptr<gfx::RenderText> CreateRenderText( const base::string16& text, gfx::HorizontalAlignment alignment, gfx::DirectionalityMode directionality, @@ -176,18 +176,22 @@ class VIEWS_EXPORT Label : public View { // Get the text size for the current layout. gfx::Size GetTextSize() const; + // Updates |actual_{enabled,disabled}_color_| from requested colors. void RecalculateColors(); + // Applies |actual_{enabled,disabled}_color_| to |lines_|. + void ApplyTextColors(); + // Updates any colors that have not been explicitly set from the theme. void UpdateColorsFromTheme(const ui::NativeTheme* theme); bool ShouldShowDefaultTooltip() const; // An un-elided and single-line RenderText object used for preferred sizing. - scoped_ptr<gfx::RenderText> render_text_; + std::unique_ptr<gfx::RenderText> render_text_; // The RenderText instances used to display elided and multi-line text. - std::vector<scoped_ptr<gfx::RenderText>> lines_; + std::vector<std::unique_ptr<gfx::RenderText>> lines_; SkColor requested_enabled_color_; SkColor actual_enabled_color_; diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc index 63a12a85c7f..e2ab5080acc 100644 --- a/chromium/ui/views/controls/label_unittest.cc +++ b/chromium/ui/views/controls/label_unittest.cc @@ -22,8 +22,12 @@ using base::ASCIIToUTF16; namespace views { +namespace { -typedef ViewsTestBase LabelTest; +// All text sizing measurements (width and height) should be greater than this. +const int kMinTextDimension = 4; + +using LabelTest = ViewsTestBase; class LabelFocusTest : public FocusManagerTest { public: @@ -31,7 +35,7 @@ class LabelFocusTest : public FocusManagerTest { ~LabelFocusTest() override {} protected: - views::Label* label() { return label_; } + Label* label() { return label_; } private: // FocusManagerTest: @@ -40,11 +44,31 @@ class LabelFocusTest : public FocusManagerTest { GetContentsView()->AddChildView(label_); } - views::Label* label_; + Label* label_; }; -// All text sizing measurements (width and height) should be greater than this. -const int kMinTextDimension = 4; +class TestLabel : public Label { + public: + TestLabel() : Label(ASCIIToUTF16("TestLabel")) { SizeToPreferredSize(); } + + int schedule_paint_count() const { return schedule_paint_count_; } + + void SimulatePaint() { + gfx::Canvas canvas(bounds().size(), 1.0, false /* is_opaque */); + Paint(ui::CanvasPainter(&canvas, 1.f).context()); + } + + // View: + void SchedulePaintInRect(const gfx::Rect& r) override { + ++schedule_paint_count_; + Label::SchedulePaintInRect(r); + } + + private: + int schedule_paint_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(TestLabel); +}; // A test utility function to set the application default text direction. void SetRTL(bool rtl) { @@ -53,7 +77,22 @@ void SetRTL(bool rtl) { EXPECT_EQ(rtl, base::i18n::IsRTL()); } -TEST_F(LabelTest, FontPropertySymbol) { +// Returns true if |current| is bigger than |last|. Sets |last| to |current|. +bool Increased(int current, int* last) { + bool increased = current > *last; + *last = current; + return increased; +} + +} // namespace + +// Crashes on Linux only. http://crbug.com/612406 +#if defined(OS_LINUX) +#define MAYBE_FontPropertySymbol DISABLED_FontPropertySymbol +#else +#define MAYBE_FontPropertySymbol FontPropertySymbol +#endif +TEST_F(LabelTest, MAYBE_FontPropertySymbol) { Label label; std::string font_name("symbol"); gfx::Font font(font_name, 26); @@ -376,7 +415,6 @@ TEST_F(LabelTest, PreferredSizeForAllowCharacterBreak) { TEST_F(LabelTest, MultiLineSizing) { Label label; - label.SetFocusable(false); label.SetText( ASCIIToUTF16("A random string\nwith multiple lines\nand returns!")); label.SetMultiLine(true); @@ -461,7 +499,6 @@ TEST_F(LabelTest, MultiLineSizingWithElide) { const base::string16 text = ASCIIToUTF16("A random string\nwith multiple lines\nand returns!"); Label label; - label.SetFocusable(false); label.SetText(text); label.SetMultiLine(true); @@ -591,7 +628,8 @@ TEST_F(LabelTest, ResetRenderTextData) { #if !defined(OS_MACOSX) TEST_F(LabelTest, MultilineSupportedRenderText) { - scoped_ptr<gfx::RenderText> render_text(gfx::RenderText::CreateInstance()); + std::unique_ptr<gfx::RenderText> render_text( + gfx::RenderText::CreateInstance()); ASSERT_TRUE(render_text->MultilineSupported()); Label label; @@ -607,11 +645,41 @@ TEST_F(LabelTest, MultilineSupportedRenderText) { } #endif +// Ensures SchedulePaint() calls are not made in OnPaint(). +TEST_F(LabelTest, NoSchedulePaintInOnPaint) { + TestLabel label; + + // Initialization should schedule at least one paint, but the precise number + // doesn't really matter. + int count = label.schedule_paint_count(); + EXPECT_LT(0, count); + + // Painting should never schedule another paint. + label.SimulatePaint(); + EXPECT_EQ(count, label.schedule_paint_count()); + + // Test a few things that should schedule paints. Multiple times is OK. + label.SetEnabled(false); + EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); + + label.SetText(label.text() + ASCIIToUTF16("Changed")); + EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); + + label.SizeToPreferredSize(); + EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); + + label.SetEnabledColor(SK_ColorBLUE); + EXPECT_TRUE(Increased(label.schedule_paint_count(), &count)); + + label.SimulatePaint(); + EXPECT_EQ(count, label.schedule_paint_count()); // Unchanged. +} + TEST_F(LabelFocusTest, FocusBounds) { label()->SetText(ASCIIToUTF16("Example")); gfx::Size normal_size = label()->GetPreferredSize(); - label()->SetFocusable(true); + label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); label()->RequestFocus(); gfx::Size focusable_size = label()->GetPreferredSize(); // Focusable label requires larger size to paint the focus rectangle. @@ -648,7 +716,7 @@ TEST_F(LabelFocusTest, FocusBounds) { } TEST_F(LabelFocusTest, EmptyLabel) { - label()->SetFocusable(true); + label()->SetFocusBehavior(View::FocusBehavior::ALWAYS); label()->RequestFocus(); label()->SizeToPreferredSize(); diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc index ec955b38597..df1177f452e 100644 --- a/chromium/ui/views/controls/link.cc +++ b/chromium/ui/views/controls/link.cc @@ -159,10 +159,7 @@ void Link::SetFontList(const gfx::FontList& font_list) { void Link::SetText(const base::string16& text) { Label::SetText(text); - // Disable focusability for empty links. Otherwise Label::GetInsets() will - // give them an unconditional 1-px. inset on every side to allow for a focus - // border, when in this case we probably wanted zero width. - SetFocusable(!text.empty()); + ConfigureFocus(); } void Link::OnNativeThemeChanged(const ui::NativeTheme* theme) { @@ -193,14 +190,14 @@ void Link::SetUnderline(bool underline) { void Link::Init() { listener_ = NULL; pressed_ = false; - underline_ = true; + underline_ = !ui::MaterialDesignController::IsSecondaryUiMaterial(); RecalculateFont(); // Label::Init() calls SetText(), but if that's being called from Label(), our // SetText() override will not be reached (because the constructed class is - // only a Label at the moment, not yet a Link). So so the set_focusable() - // call explicitly here. - SetFocusable(!text().empty()); + // only a Label at the moment, not yet a Link). So explicitly configure focus + // here. + ConfigureFocus(); } void Link::SetPressed(bool pressed) { @@ -221,6 +218,21 @@ void Link::RecalculateFont() { Label::SetFontList(font_list().DeriveWithStyle(intended_style)); } +void Link::ConfigureFocus() { + // Disable focusability for empty links. Otherwise Label::GetInsets() will + // give them an unconditional 1-px. inset on every side to allow for a focus + // border, when in this case we probably wanted zero width. + if (text().empty()) { + SetFocusBehavior(FocusBehavior::NEVER); + } else { +#if defined(OS_MACOSX) + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); +#else + SetFocusBehavior(FocusBehavior::ALWAYS); +#endif + } +} + SkColor Link::GetEnabledColor() { // In material mode, there is no pressed effect, so always use the unpressed // color. diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h index 01da62ee97f..58cdc08b92a 100644 --- a/chromium/ui/views/controls/link.h +++ b/chromium/ui/views/controls/link.h @@ -53,6 +53,8 @@ class VIEWS_EXPORT Link : public Label { void SetEnabledColor(SkColor color) override; void SetPressedColor(SkColor color); + // TODO(estade): almost all the places that call this pass false. With MD, + // false is already the default so those callsites can be removed. void SetUnderline(bool underline); static const char kViewClassName[]; @@ -64,6 +66,8 @@ class VIEWS_EXPORT Link : public Label { void RecalculateFont(); + void ConfigureFocus(); + SkColor GetEnabledColor(); SkColor GetPressedColor(); diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc index fcc41e8168a..030600f84cc 100644 --- a/chromium/ui/views/controls/menu/menu_controller.cc +++ b/chromium/ui/views/controls/menu/menu_controller.cc @@ -12,13 +12,13 @@ #include "build/build_config.h" #include "ui/base/dragdrop/drag_utils.h" #include "ui/base/dragdrop/os_exchange_data.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/native_widget_types.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/menu/menu_config.h" @@ -41,7 +41,7 @@ #if defined(OS_WIN) #include "ui/aura/window_tree_host.h" #include "ui/base/win/internal_constants.h" -#include "ui/gfx/win/dpi.h" +#include "ui/display/win/screen_win.h" #include "ui/views/win/hwnd_util.h" #endif @@ -176,7 +176,8 @@ static void RepostEventImpl(const ui::LocatedEvent* event, return; #if defined(OS_WIN) - gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc); + gfx::Point screen_loc_pixels = + display::win::ScreenWin::DIPToScreenPoint(screen_loc); HWND target_window = ::WindowFromPoint(screen_loc_pixels.ToPOINT()); // If we don't find a native window for the HWND at the current location, // then attempt to find a native window from its parent if one exists. @@ -491,6 +492,11 @@ MenuItemView* MenuController::Run(Widget* parent, if (result_event_flags) *result_event_flags = accept_event_flags_; + // The nested message loop could have been killed externally. Check to see if + // there are nested asynchronous menus to shutdown. + if (async_run_ && delegate_stack_.size() > 1) + ExitAsyncRun(); + return ExitMenuRun(); } @@ -1030,14 +1036,17 @@ ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent( else OnKeyDown(key_code); - TerminateNestedMessageLoopIfNecessary(); + // MenuController may have been deleted, so check for an active instance + // before accessing member variables. + if (GetActiveInstance()) + TerminateNestedMessageLoopIfNecessary(); return ui::POST_DISPATCH_NONE; } void MenuController::UpdateSubmenuSelection(SubmenuView* submenu) { if (submenu->IsShowing()) { - gfx::Point point = gfx::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint(); const SubmenuView* root_submenu = submenu->GetMenuItem()->GetRootMenuItem()->GetSubmenu(); View::ConvertPointFromScreen( @@ -1182,7 +1191,7 @@ void MenuController::StartDrag(SubmenuView* source, View::ConvertPointFromScreen(item, &press_loc); gfx::Point widget_loc(press_loc); View::ConvertPointToWidget(item, &widget_loc); - scoped_ptr<gfx::Canvas> canvas(GetCanvasForDragImage( + std::unique_ptr<gfx::Canvas> canvas(GetCanvasForDragImage( source->GetWidget(), gfx::Size(item->width(), item->height()))); item->PaintButton(canvas.get(), MenuItemView::PB_FOR_DRAG); @@ -1392,14 +1401,14 @@ void MenuController::UpdateInitialLocation(const gfx::Rect& bounds, // Calculate the bounds of the monitor we'll show menus on. Do this once to // avoid repeated system queries for the info. - pending_state_.monitor_bounds = gfx::Screen::GetScreen() + pending_state_.monitor_bounds = display::Screen::GetScreen() ->GetDisplayNearestPoint(bounds.origin()) .work_area(); if (!pending_state_.monitor_bounds.Contains(bounds)) { // Use the monitor area if the work area doesn't contain the bounds. This // handles showing a menu from the launcher. - gfx::Rect monitor_area = gfx::Screen::GetScreen() + gfx::Rect monitor_area = display::Screen::GetScreen() ->GetDisplayNearestPoint(bounds.origin()) .bounds(); if (monitor_area.Contains(bounds)) @@ -1434,11 +1443,12 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source, return false; } - gfx::NativeWindow window_under_mouse = - gfx::Screen::GetScreen()->GetWindowUnderCursor(); // TODO(oshima): Replace with views only API. - if (!owner_ || window_under_mouse != owner_->GetNativeWindow()) + if (!owner_ || + !display::Screen::GetScreen()->IsWindowUnderCursor( + owner_->GetNativeWindow())) { return false; + } // The user moved the mouse outside the menu and over the owning window. See // if there is a sibling menu we should show. @@ -2321,7 +2331,7 @@ void MenuController::RepostEventAndCancel(SubmenuView* source, gfx::NativeView native_view = source->GetWidget()->GetNativeView(); gfx::NativeWindow window = nullptr; if (native_view) { - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); window = screen->GetWindowAtScreenPoint(screen_loc); } #endif @@ -2659,15 +2669,19 @@ void MenuController::SetInitialHotTrackedView( void MenuController::SetHotTrackedButton(CustomButton* hot_button) { if (hot_button == hot_button_) { // Hot-tracked state may change outside of the MenuController. Correct it. - if (hot_button && !hot_button->IsHotTracked()) + if (hot_button && !hot_button->IsHotTracked()) { hot_button->SetHotTracked(true); + hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + } return; } if (hot_button_) hot_button_->SetHotTracked(false); hot_button_ = hot_button; - if (hot_button) + if (hot_button) { hot_button->SetHotTracked(true); + hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + } } } // namespace views diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h index dc21826d6d4..20c1bee5d2f 100644 --- a/chromium/ui/views/controls/menu/menu_controller.h +++ b/chromium/ui/views/controls/menu/menu_controller.h @@ -5,19 +5,18 @@ #ifndef UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_ #define UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_ -#include "build/build_config.h" - #include <stddef.h> #include <list> +#include <memory> #include <set> #include <vector> #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/linked_ptr.h" -#include "base/memory/scoped_ptr.h" #include "base/timer/timer.h" +#include "build/build_config.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/events/platform/platform_event_dispatcher.h" @@ -26,9 +25,6 @@ #include "ui/views/controls/menu/menu_delegate.h" #include "ui/views/widget/widget_observer.h" -namespace gfx { -class Screen; -} namespace ui { class OSExchangeData; class ScopedEventDispatcher; @@ -54,6 +50,7 @@ class MenuRunnerImpl; namespace test { class MenuControllerTest; +class MenuControllerTestApi; } // MenuController ------------------------------------------------------------- @@ -200,6 +197,7 @@ class VIEWS_EXPORT MenuController : public WidgetObserver { private: friend class internal::MenuRunnerImpl; friend class test::MenuControllerTest; + friend class test::MenuControllerTestApi; friend class MenuKeyEventHandler; friend class MenuHostRootView; friend class MenuItemView; @@ -654,10 +652,10 @@ class VIEWS_EXPORT MenuController : public WidgetObserver { // Task for scrolling the menu. If non-null indicates a scroll is currently // underway. - scoped_ptr<MenuScrollTask> scroll_task_; + std::unique_ptr<MenuScrollTask> scroll_task_; // The lock to keep the menu button pressed while a menu is visible. - scoped_ptr<MenuButton::PressedLock> pressed_lock_; + std::unique_ptr<MenuButton::PressedLock> pressed_lock_; // ViewStorage id used to store the view mouse drag events are forwarded to. // See UpdateActiveMouseView() for details. @@ -702,10 +700,10 @@ class VIEWS_EXPORT MenuController : public WidgetObserver { // A mask of the EventFlags for the mouse buttons currently pressed. int current_mouse_pressed_state_; - scoped_ptr<MenuMessageLoop> message_loop_; + std::unique_ptr<MenuMessageLoop> message_loop_; #if defined(USE_AURA) - scoped_ptr<MenuKeyEventHandler> key_event_handler_; + std::unique_ptr<MenuKeyEventHandler> key_event_handler_; #endif DISALLOW_COPY_AND_ASSIGN(MenuController); diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc index ee26fb24200..2dd80af066e 100644 --- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc +++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc @@ -24,6 +24,7 @@ #include "ui/views/controls/menu/menu_message_loop.h" #include "ui/views/controls/menu/menu_scroll_view_container.h" #include "ui/views/controls/menu/submenu_view.h" +#include "ui/views/test/menu_test_utils.h" #include "ui/views/test/views_test_base.h" #if defined(USE_AURA) @@ -44,34 +45,6 @@ namespace test { namespace { -// Test implementation of MenuDelegate that only reports calls of OnPerformDrop. -class TestMenuDelegate : public MenuDelegate { - public: - TestMenuDelegate(); - ~TestMenuDelegate() override; - - bool on_perform_drop_called() { return on_perform_drop_called_; } - - int OnPerformDrop(MenuItemView* menu, - DropPosition position, - const ui::DropTargetEvent& event) override; - - private: - bool on_perform_drop_called_; - DISALLOW_COPY_AND_ASSIGN(TestMenuDelegate); -}; - -TestMenuDelegate::TestMenuDelegate() : on_perform_drop_called_(false) {} - -TestMenuDelegate::~TestMenuDelegate() {} - -int TestMenuDelegate::OnPerformDrop(MenuItemView* menu, - DropPosition position, - const ui::DropTargetEvent& event) { - on_perform_drop_called_ = true; - return ui::DragDropTypes::DRAG_COPY; -} - // Test implementation of MenuControllerDelegate that only reports the values // called of OnMenuClosed. class TestMenuControllerDelegate : public internal::MenuControllerDelegate { @@ -176,26 +149,29 @@ class TestEventHandler : public ui::EventHandler { // loop is running or not. class TestMenuMessageLoop : public MenuMessageLoop { public: - explicit TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original); + explicit TestMenuMessageLoop(std::unique_ptr<MenuMessageLoop> original); ~TestMenuMessageLoop() override; bool is_running() const { return is_running_; } + // MenuMessageLoop: + void QuitNow() override; + private: // MenuMessageLoop: void Run(MenuController* controller, Widget* owner, bool nested_menu) override; - void QuitNow() override; void ClearOwner() override; - scoped_ptr<MenuMessageLoop> original_; + std::unique_ptr<MenuMessageLoop> original_; bool is_running_; DISALLOW_COPY_AND_ASSIGN(TestMenuMessageLoop); }; -TestMenuMessageLoop::TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original) +TestMenuMessageLoop::TestMenuMessageLoop( + std::unique_ptr<MenuMessageLoop> original) : original_(std::move(original)) { DCHECK(original_); } @@ -269,7 +245,7 @@ class MenuControllerTest : public ViewsTestBase { // the menu to not handle the key event. aura::ScopedWindowTargeter scoped_targeter( owner()->GetNativeWindow()->GetRootWindow(), - scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter)); + std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter)); event_generator_->PressKey(ui::VKEY_ESCAPE, 0); EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type()); } @@ -283,7 +259,7 @@ class MenuControllerTest : public ViewsTestBase { void TestAsynchronousNestedExitAll() { ASSERT_TRUE(test_message_loop_->is_running()); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); menu_controller()->AddNestedDelegate(nested_delegate.get()); @@ -305,7 +281,7 @@ class MenuControllerTest : public ViewsTestBase { void TestAsynchronousNestedExitOutermost() { ASSERT_TRUE(test_message_loop_->is_running()); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); menu_controller()->AddNestedDelegate(nested_delegate.get()); @@ -329,6 +305,17 @@ class MenuControllerTest : public ViewsTestBase { EXPECT_FALSE(test_message_loop_->is_running()); } + // This nested an asynchronous delegate onto a menu with a nested message + // loop, then kills the loop. Simulates the loop being killed not by + // MenuController. + void TestNestedMessageLoopKillsItself( + TestMenuControllerDelegate* nested_delegate) { + menu_controller_->AddNestedDelegate(nested_delegate); + menu_controller_->SetAsyncRun(true); + + test_message_loop_->QuitNow(); + } + protected: void SetPendingStateItem(MenuItemView* item) { menu_controller_->pending_state_.item = item; @@ -416,7 +403,8 @@ class MenuControllerTest : public ViewsTestBase { void RunMenu() { #if defined(USE_AURA) - scoped_ptr<MenuKeyEventHandler> key_event_handler(new MenuKeyEventHandler); + std::unique_ptr<MenuKeyEventHandler> key_event_handler( + new MenuKeyEventHandler); #endif menu_controller_->message_loop_depth_++; @@ -455,7 +443,8 @@ class MenuControllerTest : public ViewsTestBase { for (int i = 0; i < 3; ++i) { LabelButton* button = new LabelButton(nullptr, base::ASCIIToUTF16("Label")); - button->SetFocusable(true); + // This is an in-menu button. Hence it must be always focusable. + button->SetFocusBehavior(View::FocusBehavior::ALWAYS); item_view->AddChildView(button); } menu_item()->GetSubmenu()->ShowAt(owner(), menu_item()->bounds(), false); @@ -521,11 +510,11 @@ class MenuControllerTest : public ViewsTestBase { menu_item_->SetController(menu_controller_); } - scoped_ptr<Widget> owner_; - scoped_ptr<ui::test::EventGenerator> event_generator_; - scoped_ptr<TestMenuItemViewShown> menu_item_; - scoped_ptr<TestMenuControllerDelegate> menu_controller_delegate_; - scoped_ptr<MenuDelegate> menu_delegate_; + std::unique_ptr<Widget> owner_; + std::unique_ptr<ui::test::EventGenerator> event_generator_; + std::unique_ptr<TestMenuItemViewShown> menu_item_; + std::unique_ptr<TestMenuControllerDelegate> menu_controller_delegate_; + std::unique_ptr<MenuDelegate> menu_delegate_; MenuController* menu_controller_; TestMenuMessageLoop* test_message_loop_; @@ -958,7 +947,7 @@ TEST_F(MenuControllerTest, AsynchronousCancelAll) { TEST_F(MenuControllerTest, AsynchronousNestedDelegate) { MenuController* controller = menu_controller(); TestMenuControllerDelegate* delegate = menu_controller_delegate(); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); ASSERT_FALSE(IsAsyncRun()); @@ -1034,7 +1023,7 @@ TEST_F(MenuControllerTest, AsynchronousDragComplete) { TEST_F(MenuControllerTest, DoubleAsynchronousNested) { MenuController* controller = menu_controller(); TestMenuControllerDelegate* delegate = menu_controller_delegate(); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); ASSERT_FALSE(IsAsyncRun()); @@ -1061,7 +1050,7 @@ TEST_F(MenuControllerTest, DoubleAsynchronousNested) { TEST_F(MenuControllerTest, AsynchronousRepostEvent) { MenuController* controller = menu_controller(); TestMenuControllerDelegate* delegate = menu_controller_delegate(); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); ASSERT_FALSE(IsAsyncRun()); @@ -1160,7 +1149,7 @@ TEST_F(MenuControllerTest, AsynchronousNestedExitOutermost) { // cause a crash. ASAN bots should not detect use-after-free in MenuController. TEST_F(MenuControllerTest, AsynchronousRepostEventDeletesController) { MenuController* controller = menu_controller(); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); ASSERT_FALSE(IsAsyncRun()); @@ -1203,7 +1192,7 @@ TEST_F(MenuControllerTest, AsynchronousRepostEventDeletesController) { // cause a crash. ASAN bots should not detect use-after-free in MenuController. TEST_F(MenuControllerTest, AsynchronousGestureDeletesController) { MenuController* controller = menu_controller(); - scoped_ptr<TestMenuControllerDelegate> nested_delegate( + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( new TestMenuControllerDelegate()); ASSERT_FALSE(IsAsyncRun()); @@ -1238,5 +1227,28 @@ TEST_F(MenuControllerTest, AsynchronousGestureDeletesController) { EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); } +// Tests that when an asynchronous menu is nested, and the nested message loop +// is kill not by the MenuController, that the nested menu is notified of +// destruction. +TEST_F(MenuControllerTest, NestedMessageLoopDiesWithNestedMenu) { + menu_controller()->CancelAll(); + InstallTestMenuMessageLoop(); + std::unique_ptr<TestMenuControllerDelegate> nested_delegate( + new TestMenuControllerDelegate()); + // This will nest an asynchronous menu, and then kill the nested message loop. + base::MessageLoopForUI::current()->PostTask( + FROM_HERE, + base::Bind(&MenuControllerTest::TestNestedMessageLoopKillsItself, + base::Unretained(this), nested_delegate.get())); + + int result_event_flags = 0; + // This creates a nested message loop. + EXPECT_EQ(nullptr, menu_controller()->Run(owner(), nullptr, menu_item(), + gfx::Rect(), MENU_ANCHOR_TOPLEFT, + false, false, &result_event_flags)); + EXPECT_FALSE(menu_controller_delegate()->on_menu_closed_called()); + EXPECT_TRUE(nested_delegate->on_menu_closed_called()); +} + } // namespace test } // namespace views diff --git a/chromium/ui/views/controls/menu/menu_host.h b/chromium/ui/views/controls/menu/menu_host.h index ba931f8ed20..1de12373563 100644 --- a/chromium/ui/views/controls/menu/menu_host.h +++ b/chromium/ui/views/controls/menu/menu_host.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_CONTROLS_MENU_MENU_HOST_H_ #define UI_VIEWS_CONTROLS_MENU_MENU_HOST_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/widget/widget.h" @@ -83,7 +84,7 @@ class MenuHost : public Widget { #if !defined(OS_MACOSX) // Handles raw touch events at the moment. - scoped_ptr<internal::PreMenuEventDispatchHandler> pre_dispatch_handler_; + std::unique_ptr<internal::PreMenuEventDispatchHandler> pre_dispatch_handler_; #endif DISALLOW_COPY_AND_ASSIGN(MenuHost); diff --git a/chromium/ui/views/controls/menu/menu_image_util.cc b/chromium/ui/views/controls/menu/menu_image_util.cc index 55f6e551c2f..7f342ac6dc1 100644 --- a/chromium/ui/views/controls/menu/menu_image_util.cc +++ b/chromium/ui/views/controls/menu/menu_image_util.cc @@ -12,8 +12,7 @@ namespace views { gfx::ImageSkia GetMenuCheckImage(SkColor icon_color) { - return gfx::CreateVectorIcon(gfx::VectorIconId::MENU_CHECK, kMenuCheckSize, - icon_color); + return gfx::CreateVectorIcon(gfx::VectorIconId::MENU_CHECK, icon_color); } gfx::ImageSkia GetRadioButtonImage(bool toggled, @@ -27,8 +26,7 @@ gfx::ImageSkia GetRadioButtonImage(bool toggled, } gfx::ImageSkia GetSubmenuArrowImage(SkColor icon_color) { - return gfx::CreateVectorIcon(gfx::VectorIconId::SUBMENU_ARROW, - kSubmenuArrowSize, icon_color); + return gfx::CreateVectorIcon(gfx::VectorIconId::SUBMENU_ARROW, icon_color); } } // namespace views diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc index f2653751716..dab58be36c9 100644 --- a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc +++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc @@ -106,8 +106,8 @@ void MenuMessageLoop::RepostEventToWindow(const ui::LocatedEvent* event, gfx::Point root_loc(screen_loc); spc->ConvertPointFromScreen(root, &root_loc); - scoped_ptr<ui::Event> clone = ui::Event::Clone(*event); - scoped_ptr<ui::LocatedEvent> located_event( + std::unique_ptr<ui::Event> clone = ui::Event::Clone(*event); + std::unique_ptr<ui::LocatedEvent> located_event( static_cast<ui::LocatedEvent*>(clone.release())); located_event->set_location(root_loc); located_event->set_root_location(root_loc); @@ -132,7 +132,7 @@ void MenuMessageLoopAura::Run(MenuController* controller, base::AutoReset<base::Closure> reset_quit_closure(&message_loop_quit_, base::Closure()); - scoped_ptr<ActivationChangeObserverImpl> observer; + std::unique_ptr<ActivationChangeObserverImpl> observer; if (root) { if (!nested_menu) observer.reset(new ActivationChangeObserverImpl(controller, root)); diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.h b/chromium/ui/views/controls/menu/menu_message_loop_aura.h index fce8858dd09..6ebe8393f80 100644 --- a/chromium/ui/views/controls/menu/menu_message_loop_aura.h +++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.h @@ -5,10 +5,11 @@ #ifndef UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_ #define UI_VIEWS_CONTROLS_MENU_MENU_MESSAGE_LOOP_AURA_H_ +#include <memory> + #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/controls/menu/menu_message_loop.h" namespace ui { diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc index 63d7788c4bc..9fddfaf9317 100644 --- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc +++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc @@ -154,7 +154,7 @@ class RootModel : public MenuModelBase { ~RootModel() override {} private: - scoped_ptr<MenuModel> submenu_model_; + std::unique_ptr<MenuModel> submenu_model_; DISALLOW_COPY_AND_ASSIGN(RootModel); }; @@ -173,7 +173,7 @@ TEST_F(MenuModelAdapterTest, BasicTest) { // Create menu. Build menu twice to check that rebuilding works properly. MenuItemView* menu = new views::MenuItemView(&delegate); // MenuRunner takes ownership of menu. - scoped_ptr<MenuRunner> menu_runner(new MenuRunner(menu, 0)); + std::unique_ptr<MenuRunner> menu_runner(new MenuRunner(menu, 0)); delegate.BuildMenu(menu); delegate.BuildMenu(menu); EXPECT_TRUE(menu->HasSubmenu()); diff --git a/chromium/ui/views/controls/menu/menu_runner.cc b/chromium/ui/views/controls/menu/menu_runner.cc index f639f687f09..4cfdafed99b 100644 --- a/chromium/ui/views/controls/menu/menu_runner.cc +++ b/chromium/ui/views/controls/menu/menu_runner.cc @@ -72,7 +72,7 @@ base::TimeDelta MenuRunner::closing_event_time() const { } void MenuRunner::SetRunnerHandler( - scoped_ptr<MenuRunnerHandler> runner_handler) { + std::unique_ptr<MenuRunnerHandler> runner_handler) { runner_handler_ = std::move(runner_handler); } diff --git a/chromium/ui/views/controls/menu/menu_runner.h b/chromium/ui/views/controls/menu/menu_runner.h index ea2438ee980..5d98ec0e1bb 100644 --- a/chromium/ui/views/controls/menu/menu_runner.h +++ b/chromium/ui/views/controls/menu/menu_runner.h @@ -7,9 +7,10 @@ #include <stdint.h> +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/base/ui_base_types.h" #include "ui/views/controls/menu/menu_types.h" #include "ui/views/views_export.h" @@ -135,7 +136,7 @@ class VIEWS_EXPORT MenuRunner { friend class test::MenuRunnerTestAPI; // Sets an implementation of RunMenuAt. This is intended to be used at test. - void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler); + void SetRunnerHandler(std::unique_ptr<MenuRunnerHandler> runner_handler); const int32_t run_types_; @@ -144,9 +145,9 @@ class VIEWS_EXPORT MenuRunner { // An implementation of RunMenuAt. This is usually NULL and ignored. If this // is not NULL, this implementation will be used. - scoped_ptr<MenuRunnerHandler> runner_handler_; + std::unique_ptr<MenuRunnerHandler> runner_handler_; - scoped_ptr<internal::DisplayChangeListener> display_change_listener_; + std::unique_ptr<internal::DisplayChangeListener> display_change_listener_; DISALLOW_COPY_AND_ASSIGN(MenuRunner); }; diff --git a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm index 73e02eca385..ee86b982756 100644 --- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm +++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm @@ -137,8 +137,14 @@ class MenuRunnerCocoaTest : public ViewsTestBase { runner_ = nullptr; } + void MenuCancelAndDeleteCallback() { + runner_->Cancel(); + runner_->Release(); + runner_ = nullptr; + } + protected: - scoped_ptr<TestModel> menu_; + std::unique_ptr<TestModel> menu_; internal::MenuRunnerImplCocoa* runner_ = nullptr; views::Widget* parent_ = nullptr; NSRect last_anchor_frame_ = NSZeroRect; @@ -182,6 +188,15 @@ TEST_F(MenuRunnerCocoaTest, RunMenuAndDelete) { EXPECT_EQ(MenuRunner::MENU_DELETED, result); } +// Ensure a menu can be safely released immediately after a call to Cancel() in +// the same run loop iteration. +TEST_F(MenuRunnerCocoaTest, DestroyAfterCanceling) { + MenuRunner::RunResult result = + RunMenu(base::Bind(&MenuRunnerCocoaTest::MenuCancelAndDeleteCallback, + base::Unretained(this))); + EXPECT_EQ(MenuRunner::MENU_DELETED, result); +} + TEST_F(MenuRunnerCocoaTest, RunMenuTwice) { for (int i = 0; i < 2; ++i) { MenuRunner::RunResult result = RunMenu(base::Bind( diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.cc b/chromium/ui/views/controls/menu/menu_runner_impl.cc index b48edcdd129..4e35f3aad8f 100644 --- a/chromium/ui/views/controls/menu/menu_runner_impl.cc +++ b/chromium/ui/views/controls/menu/menu_runner_impl.cc @@ -60,14 +60,19 @@ void MenuRunnerImpl::Release() { empty_delegate_.reset(new MenuDelegate()); menu_->set_delegate(empty_delegate_.get()); - DCHECK(controller_); - // Release is invoked when MenuRunner is destroyed. Assume this is happening - // because the object referencing the menu has been destroyed and the menu - // button is no longer valid. - controller_->Cancel(MenuController::EXIT_DESTROYED); - } else { - delete this; + // Verify that the MenuController is still active. It may have been + // destroyed out of order. + if (MenuController::GetActiveInstance()) { + DCHECK(controller_); + // Release is invoked when MenuRunner is destroyed. Assume this is + // happening because the object referencing the menu has been destroyed + // and the menu button is no longer valid. + controller_->Cancel(MenuController::EXIT_DESTROYED); + return; + } } + + delete this; } MenuRunner::RunResult MenuRunnerImpl::RunMenuAt(Widget* parent, diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.h b/chromium/ui/views/controls/menu/menu_runner_impl.h index cf31f8156e6..c893e4aea39 100644 --- a/chromium/ui/views/controls/menu/menu_runner_impl.h +++ b/chromium/ui/views/controls/menu/menu_runner_impl.h @@ -5,16 +5,17 @@ #ifndef UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_IMPL_H_ #define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_IMPL_H_ -#include "ui/views/controls/menu/menu_runner_impl_interface.h" - #include <stdint.h> #include <set> +#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "ui/views/controls/menu/menu_controller_delegate.h" +#include "ui/views/controls/menu/menu_runner_impl_interface.h" +#include "ui/views/views_export.h" namespace views { @@ -25,8 +26,9 @@ class MenuItemView; namespace internal { // A menu runner implementation that uses views::MenuItemView to show a menu. -class MenuRunnerImpl : public MenuRunnerImplInterface, - public MenuControllerDelegate { +class VIEWS_EXPORT MenuRunnerImpl + : NON_EXPORTED_BASE(public MenuRunnerImplInterface), + NON_EXPORTED_BASE(public MenuControllerDelegate) { public: explicit MenuRunnerImpl(MenuItemView* menu); @@ -69,7 +71,7 @@ class MenuRunnerImpl : public MenuRunnerImplInterface, // invoked. This is done to make sure the delegate isn't notified after // Release() is invoked. We do this as we assume the delegate is no longer // valid if MenuRunner has been deleted. - scoped_ptr<MenuDelegate> empty_delegate_; + std::unique_ptr<MenuDelegate> empty_delegate_; // Are we in run waiting for it to return? bool running_; diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h index f41abe14704..973afdbe870 100644 --- a/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h +++ b/chromium/ui/views/controls/menu/menu_runner_impl_adapter.h @@ -34,7 +34,7 @@ class MenuRunnerImplAdapter : public MenuRunnerImplInterface { private: ~MenuRunnerImplAdapter() override; - scoped_ptr<MenuModelAdapter> menu_model_adapter_; + std::unique_ptr<MenuModelAdapter> menu_model_adapter_; MenuRunnerImpl* impl_; DISALLOW_COPY_AND_ASSIGN(MenuRunnerImplAdapter); diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h index f1ae21fb88d..ac5b263e2b4 100644 --- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h +++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.h @@ -39,6 +39,9 @@ class VIEWS_EXPORT MenuRunnerImplCocoa : public MenuRunnerImplInterface { // The Cocoa menu controller that this instance is bridging. base::scoped_nsobject<MenuController> menu_controller_; + // Are we in run waiting for it to return? + bool running_; + // Set if |running_| and Release() has been invoked. bool delete_after_run_; diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm index 454c951817b..c6802381ab6 100644 --- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm +++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm @@ -93,13 +93,15 @@ MenuRunnerImplInterface* MenuRunnerImplInterface::Create( } MenuRunnerImplCocoa::MenuRunnerImplCocoa(ui::MenuModel* menu) - : delete_after_run_(false), closing_event_time_(base::TimeDelta()) { + : running_(false), + delete_after_run_(false), + closing_event_time_(base::TimeDelta()) { menu_controller_.reset( [[MenuController alloc] initWithModel:menu useWithPopUpButtonCell:NO]); } bool MenuRunnerImplCocoa::IsRunning() const { - return [menu_controller_ isMenuOpen]; + return running_; } void MenuRunnerImplCocoa::Release() { @@ -123,6 +125,7 @@ MenuRunner::RunResult MenuRunnerImplCocoa::RunMenuAt(Widget* parent, DCHECK(!IsRunning()); DCHECK(parent); closing_event_time_ = base::TimeDelta(); + running_ = true; if (run_types & MenuRunner::CONTEXT_MENU) { [NSMenu popUpContextMenu:[menu_controller_ menu] @@ -143,6 +146,7 @@ MenuRunner::RunResult MenuRunnerImplCocoa::RunMenuAt(Widget* parent, } closing_event_time_ = ui::EventTimeForNow(); + running_ = false; if (delete_after_run_) { delete this; diff --git a/chromium/ui/views/controls/menu/menu_runner_unittest.cc b/chromium/ui/views/controls/menu/menu_runner_unittest.cc index 49ba8832a1e..6d76f7e92e2 100644 --- a/chromium/ui/views/controls/menu/menu_runner_unittest.cc +++ b/chromium/ui/views/controls/menu/menu_runner_unittest.cc @@ -6,73 +6,26 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/ui_base_types.h" #include "ui/events/test/event_generator.h" #include "ui/views/controls/menu/menu_delegate.h" #include "ui/views/controls/menu/menu_item_view.h" +#include "ui/views/controls/menu/menu_runner_impl.h" #include "ui/views/controls/menu/menu_types.h" #include "ui/views/controls/menu/submenu_view.h" +#include "ui/views/test/menu_test_utils.h" +#include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" +#include "ui/views/widget/native_widget_private.h" #include "ui/views/widget/widget.h" namespace views { namespace test { -// Implementation of MenuDelegate that only reports the values of calls to -// OnMenuClosed and ExecuteCommand. -class TestMenuDelegate : public MenuDelegate { - public: - TestMenuDelegate(); - ~TestMenuDelegate() override; - - int execute_command_id() const { return execute_command_id_; } - - int on_menu_closed_called() const { return on_menu_closed_called_; } - MenuItemView* on_menu_closed_menu() const { return on_menu_closed_menu_; } - MenuRunner::RunResult on_menu_closed_run_result() const { - return on_menu_closed_run_result_; - } - - // MenuDelegate: - void ExecuteCommand(int id) override; - void OnMenuClosed(MenuItemView* menu, MenuRunner::RunResult result) override; - - private: - // ID of last executed command. - int execute_command_id_; - - // The number of times OnMenuClosed was called. - int on_menu_closed_called_; - - // The values of the last call to OnMenuClosed. - MenuItemView* on_menu_closed_menu_; - MenuRunner::RunResult on_menu_closed_run_result_; - - DISALLOW_COPY_AND_ASSIGN(TestMenuDelegate); -}; - -TestMenuDelegate::TestMenuDelegate() - : execute_command_id_(0), - on_menu_closed_called_(0), - on_menu_closed_menu_(nullptr), - on_menu_closed_run_result_(MenuRunner::MENU_DELETED) {} - -TestMenuDelegate::~TestMenuDelegate() {} - -void TestMenuDelegate::ExecuteCommand(int id) { - execute_command_id_ = id; -} - -void TestMenuDelegate::OnMenuClosed(MenuItemView* menu, - MenuRunner::RunResult result) { - on_menu_closed_called_++; - on_menu_closed_menu_ = menu; - on_menu_closed_run_result_ = result; -} - class MenuRunnerTest : public ViewsTestBase { public: MenuRunnerTest(); @@ -95,9 +48,9 @@ class MenuRunnerTest : public ViewsTestBase { // Owned by MenuRunner. MenuItemView* menu_item_view_; - scoped_ptr<TestMenuDelegate> menu_delegate_; - scoped_ptr<MenuRunner> menu_runner_; - scoped_ptr<Widget> owner_; + std::unique_ptr<TestMenuDelegate> menu_delegate_; + std::unique_ptr<MenuRunner> menu_runner_; + std::unique_ptr<Widget> owner_; DISALLOW_COPY_AND_ASSIGN(MenuRunnerTest); }; @@ -220,9 +173,9 @@ TEST_F(MenuRunnerTest, NestingDuringDrag) { EXPECT_EQ(MenuRunner::NORMAL_EXIT, result); EXPECT_TRUE(runner->IsRunning()); - scoped_ptr<TestMenuDelegate> nested_delegate(new TestMenuDelegate); + std::unique_ptr<TestMenuDelegate> nested_delegate(new TestMenuDelegate); MenuItemView* nested_menu = new MenuItemView(nested_delegate.get()); - scoped_ptr<MenuRunner> nested_runner( + std::unique_ptr<MenuRunner> nested_runner( new MenuRunner(nested_menu, MenuRunner::IS_NESTED | MenuRunner::ASYNC)); result = nested_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_NONE); @@ -235,5 +188,107 @@ TEST_F(MenuRunnerTest, NestingDuringDrag) { EXPECT_EQ(MenuRunner::NORMAL_EXIT, delegate->on_menu_closed_run_result()); } +namespace { + +// An EventHandler that launches a menu in response to a mouse press. +class MenuLauncherEventHandler : public ui::EventHandler { + public: + MenuLauncherEventHandler(MenuRunner* runner, Widget* owner) + : runner_(runner), owner_(owner) {} + ~MenuLauncherEventHandler() override {} + + private: + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + if (event->type() == ui::ET_MOUSE_PRESSED) { + runner_->RunMenuAt(owner_, nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, + ui::MENU_SOURCE_NONE); + event->SetHandled(); + } + } + + MenuRunner* runner_; + Widget* owner_; + + DISALLOW_COPY_AND_ASSIGN(MenuLauncherEventHandler); +}; + +} // namespace + +// Tests that when a mouse press launches a menu, that the target widget does +// not take explicit capture, nor closes the menu. +TEST_F(MenuRunnerTest, WidgetDoesntTakeCapture) { + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + widget->Init(params); + widget->Show(); + widget->SetSize(gfx::Size(300, 300)); + + EventCountView* event_count_view = new EventCountView(); + event_count_view->SetBounds(0, 0, 300, 300); + widget->GetRootView()->AddChildView(event_count_view); + + InitMenuRunner(MenuRunner::ASYNC); + MenuRunner* runner = menu_runner(); + + MenuLauncherEventHandler consumer(runner, owner()); + event_count_view->AddPostTargetHandler(&consumer); + EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture( + widget->GetNativeView())); + std::unique_ptr<ui::test::EventGenerator> generator( + new ui::test::EventGenerator( + IsMus() ? widget->GetNativeWindow() : GetContext(), + widget->GetNativeWindow())); + // Implicit capture should not be held by |widget|. + generator->PressLeftButton(); + EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_NE( + widget->GetNativeView(), + internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView())); + + // The menu should still be open. + TestMenuDelegate* delegate = menu_delegate(); + EXPECT_TRUE(runner->IsRunning()); + EXPECT_EQ(0, delegate->on_menu_closed_called()); + + widget->CloseNow(); +} + +typedef MenuRunnerTest MenuRunnerImplTest; + +// Tests that when nested menu runners are destroyed out of order, that +// MenuController is not accessed after it has been destroyed. This should not +// crash on ASAN bots. +TEST_F(MenuRunnerImplTest, NestedMenuRunnersDestroyedOutOfOrder) { + internal::MenuRunnerImpl* menu_runner = + new internal::MenuRunnerImpl(menu_item_view()); + EXPECT_EQ(MenuRunner::NORMAL_EXIT, + menu_runner->RunMenuAt(owner(), nullptr, gfx::Rect(), + MENU_ANCHOR_TOPLEFT, MenuRunner::ASYNC)); + + std::unique_ptr<TestMenuDelegate> menu_delegate2(new TestMenuDelegate); + MenuItemView* menu_item_view2 = new MenuItemView(menu_delegate2.get()); + menu_item_view2->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); + + internal::MenuRunnerImpl* menu_runner2 = + new internal::MenuRunnerImpl(menu_item_view2); + EXPECT_EQ(MenuRunner::NORMAL_EXIT, + menu_runner2->RunMenuAt(owner(), nullptr, gfx::Rect(), + MENU_ANCHOR_TOPLEFT, + MenuRunner::ASYNC | MenuRunner::IS_NESTED)); + + // Hide the controller so we can test out of order destruction. + MenuControllerTestApi menu_controller; + menu_controller.Hide(); + + // This destroyed MenuController + menu_runner->OnMenuClosed(internal::MenuControllerDelegate::NOTIFY_DELEGATE, + nullptr, 0); + + // This should not access the destroyed MenuController + menu_runner2->Release(); + menu_runner->Release(); +} + } // namespace test } // namespace views diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc index 381bef70f6f..9350283fde1 100644 --- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc +++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc @@ -5,6 +5,7 @@ #include "ui/views/controls/menu/menu_scroll_view_container.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/accessibility/ax_view_state.h" @@ -293,7 +294,8 @@ void MenuScrollViewContainer::CreateDefaultBorder() { ui::NativeTheme::kColorId_MenuBorderColor) : gfx::kPlaceholderColor; SetBorder(views::Border::CreateBorderPainter( - new views::RoundRectPainter(color, menu_config.corner_radius), + base::WrapUnique( + new views::RoundRectPainter(color, menu_config.corner_radius)), gfx::Insets(top, left, bottom, right))); } else { SetBorder(Border::CreateEmptyBorder(top, left, bottom, right)); @@ -304,7 +306,7 @@ void MenuScrollViewContainer::CreateBubbleBorder() { bubble_border_ = new BubbleBorder(arrow_, BubbleBorder::SMALL_SHADOW, SK_ColorWHITE); - SetBorder(scoped_ptr<Border>(bubble_border_)); + SetBorder(std::unique_ptr<Border>(bubble_border_)); set_background(new BubbleBackground(bubble_border_)); } diff --git a/chromium/ui/views/controls/menu/menu_separator_win.cc b/chromium/ui/views/controls/menu/menu_separator_win.cc index 182cc2b3294..2ecabdbeb1c 100644 --- a/chromium/ui/views/controls/menu/menu_separator_win.cc +++ b/chromium/ui/views/controls/menu/menu_separator_win.cc @@ -8,9 +8,9 @@ #include <uxtheme.h> #include <Vssym32.h> +#include "ui/display/win/dpi.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/win/dpi.h" #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_aura.h" #include "ui/views/controls/menu/menu_item_view.h" @@ -29,7 +29,7 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) { // Hack to get the separator to display correctly on Windows where we may // have fractional scales. We move the separator 1 pixel down to ensure that // it falls within the clipping rect which is scaled up. - float device_scale = gfx::GetDPIScale(); + float device_scale = display::win::GetDPIScale(); bool is_fractional_scale = (device_scale - static_cast<int>(device_scale) != 0); if (is_fractional_scale && separator_bounds.y() == 0) diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc index 8b66b10e979..e205fda62f9 100644 --- a/chromium/ui/views/controls/menu/native_menu_win.cc +++ b/chromium/ui/views/controls/menu/native_menu_win.cc @@ -22,7 +22,7 @@ struct NativeMenuWin::ItemData { base::string16 label; // Someone needs to own submenus, it may as well be us. - scoped_ptr<NativeMenuWin> submenu; + std::unique_ptr<NativeMenuWin> submenu; // We need a pointer back to the containing menu in various circumstances. NativeMenuWin* native_menu_win; diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h index 11243ff1900..1f929750bbc 100644 --- a/chromium/ui/views/controls/menu/submenu_view.h +++ b/chromium/ui/views/controls/menu/submenu_view.h @@ -205,7 +205,7 @@ class VIEWS_EXPORT SubmenuView : public PrefixDelegate, bool resize_open_menu_; // The submenu's scroll animator - scoped_ptr<ScrollAnimator> scroll_animator_; + std::unique_ptr<ScrollAnimator> scroll_animator_; // Difference between current position and cumulative deltas passed to // OnScroll. diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h index f0770ba8f8d..6b9aa0ea4ac 100644 --- a/chromium/ui/views/controls/native/native_view_host.h +++ b/chromium/ui/views/controls/native/native_view_host.h @@ -108,7 +108,7 @@ class VIEWS_EXPORT NativeViewHost : public View { // A platform-specific wrapper that does the OS-level manipulation of the // attached gfx::NativeView. - scoped_ptr<NativeViewHostWrapper> native_wrapper_; + std::unique_ptr<NativeViewHostWrapper> native_wrapper_; // The preferred size of this View gfx::Size preferred_size_; diff --git a/chromium/ui/views/controls/native/native_view_host_aura.h b/chromium/ui/views/controls/native/native_view_host_aura.h index 67d7756397c..45e859082eb 100644 --- a/chromium/ui/views/controls/native/native_view_host_aura.h +++ b/chromium/ui/views/controls/native/native_view_host_aura.h @@ -57,13 +57,13 @@ class VIEWS_EXPORT NativeViewHostAura : public NativeViewHostWrapper, // Our associated NativeViewHost. NativeViewHost* host_; - scoped_ptr<ClippingWindowDelegate> clipping_window_delegate_; + std::unique_ptr<ClippingWindowDelegate> clipping_window_delegate_; // Window that exists between the native view and the parent that allows for // clipping to occur. This is positioned in the coordinate space of // host_->GetWidget(). aura::Window clipping_window_; - scoped_ptr<gfx::Rect> clip_rect_; + std::unique_ptr<gfx::Rect> clip_rect_; DISALLOW_COPY_AND_ASSIGN(NativeViewHostAura); }; diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc index 685267de3b9..dbc34713528 100644 --- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc +++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc @@ -4,8 +4,9 @@ #include "ui/views/controls/native/native_view_host_aura.h" +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/base/cursor/cursor.h" @@ -105,7 +106,7 @@ class NativeViewHostAuraTest : public test::NativeViewHostTestBase { } private: - scoped_ptr<Widget> child_; + std::unique_ptr<Widget> child_; DISALLOW_COPY_AND_ASSIGN(NativeViewHostAuraTest); }; diff --git a/chromium/ui/views/controls/native/native_view_host_mac.mm b/chromium/ui/views/controls/native/native_view_host_mac.mm index b3e0cfcd4b6..45a315736a4 100644 --- a/chromium/ui/views/controls/native/native_view_host_mac.mm +++ b/chromium/ui/views/controls/native/native_view_host_mac.mm @@ -59,9 +59,15 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) { // are reference counted so there isn't a reliable signal. Instead, a // reference is retained until the NativeViewHost is detached. DCHECK(!destroyed); + // |native_view_| can be nil here if RemovedFromWidget() is called before // NativeViewHost::Detach(). - DCHECK(!native_view_ || native_view_ == host_->native_view()); + if (!native_view_) { + DCHECK(![host_->native_view() superview]); + return; + } + + DCHECK(native_view_ == host_->native_view()); [host_->native_view() setHidden:YES]; [host_->native_view() removeFromSuperview]; diff --git a/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm b/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm index ea91605a7fa..0208dc14a5b 100644 --- a/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm +++ b/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm @@ -6,10 +6,11 @@ #import <Cocoa/Cocoa.h> +#include <memory> + #import "base/mac/scoped_nsautorelease_pool.h" #import "base/mac/scoped_nsobject.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #import "testing/gtest_mac.h" #include "ui/views/controls/native/native_view_host.h" #include "ui/views/controls/native/native_view_host_test_base.h" diff --git a/chromium/ui/views/controls/native/native_view_host_test_base.h b/chromium/ui/views/controls/native/native_view_host_test_base.h index f663956da61..ad39c162d15 100644 --- a/chromium/ui/views/controls/native/native_view_host_test_base.h +++ b/chromium/ui/views/controls/native/native_view_host_test_base.h @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/test/views_test_base.h" namespace views { @@ -54,8 +55,8 @@ class NativeViewHostTestBase : public ViewsTestBase { private: class NativeViewHostTesting; - scoped_ptr<Widget> toplevel_; - scoped_ptr<NativeViewHost> host_; + std::unique_ptr<Widget> toplevel_; + std::unique_ptr<NativeViewHost> host_; int host_destroyed_count_; DISALLOW_COPY_AND_ASSIGN(NativeViewHostTestBase); diff --git a/chromium/ui/views/controls/native/native_view_host_unittest.cc b/chromium/ui/views/controls/native/native_view_host_unittest.cc index c15295942ff..0baba8257c3 100644 --- a/chromium/ui/views/controls/native/native_view_host_unittest.cc +++ b/chromium/ui/views/controls/native/native_view_host_unittest.cc @@ -4,8 +4,9 @@ #include "ui/views/controls/native/native_view_host.h" +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/aura/window.h" #include "ui/views/controls/native/native_view_host_test_base.h" #include "ui/views/test/views_test_base.h" @@ -98,10 +99,8 @@ TEST_F(NativeViewHostTest, NativeViewHierarchyChanged) { NativeViewHierarchyChangedTestView* test_view = new NativeViewHierarchyChangedTestView; NativeViewHost* host = new NativeViewHost; - scoped_ptr<Widget> child(CreateChildForHost(toplevel()->GetNativeView(), - toplevel()->GetRootView(), - test_view, - host)); + std::unique_ptr<Widget> child(CreateChildForHost( + toplevel()->GetNativeView(), toplevel()->GetRootView(), test_view, host)); #if defined(USE_AURA) // Two notifications are generated from inserting the native view into the // clipping window and then inserting the clipping window into the root @@ -159,20 +158,14 @@ TEST_F(NativeViewHostTest, ViewHierarchyChangedForHost) { // Add two children widgets attached to a NativeViewHost, and a test // grandchild as child widget of host0. NativeViewHost* host0 = new NativeViewHost; - scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(), - toplevel()->GetRootView(), - new View, - host0)); + std::unique_ptr<Widget> child0(CreateChildForHost( + toplevel()->GetNativeView(), toplevel()->GetRootView(), new View, host0)); NativeViewHost* host1 = new NativeViewHost; - scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(), - toplevel()->GetRootView(), - new View, - host1)); + std::unique_ptr<Widget> child1(CreateChildForHost( + toplevel()->GetNativeView(), toplevel()->GetRootView(), new View, host1)); ViewHierarchyChangedTestHost* test_host = new ViewHierarchyChangedTestHost; - scoped_ptr<Widget> test_child(CreateChildForHost(host0->native_view(), - host0, - new View, - test_host)); + std::unique_ptr<Widget> test_child( + CreateChildForHost(host0->native_view(), host0, new View, test_host)); // Remove test_host from host0, expect 1 parent change. test_host->ResetParentChanges(); @@ -224,15 +217,11 @@ TEST_F(NativeViewHostTest, ViewHierarchyChangedForHostParent) { // To each child view, add a child widget. ViewHierarchyChangedTestHost* host0 = new ViewHierarchyChangedTestHost; - scoped_ptr<Widget> child0(CreateChildForHost(toplevel()->GetNativeView(), - view0, - new View, - host0)); + std::unique_ptr<Widget> child0( + CreateChildForHost(toplevel()->GetNativeView(), view0, new View, host0)); ViewHierarchyChangedTestHost* host1 = new ViewHierarchyChangedTestHost; - scoped_ptr<Widget> child1(CreateChildForHost(toplevel()->GetNativeView(), - view1, - new View, - host1)); + std::unique_ptr<Widget> child1( + CreateChildForHost(toplevel()->GetNativeView(), view1, new View, host1)); // Remove view0 from top level, expect 1 parent change. host0->ResetParentChanges(); diff --git a/chromium/ui/views/controls/prefix_selector_unittest.cc b/chromium/ui/views/controls/prefix_selector_unittest.cc index cb109c267a4..8619c76229c 100644 --- a/chromium/ui/views/controls/prefix_selector_unittest.cc +++ b/chromium/ui/views/controls/prefix_selector_unittest.cc @@ -54,7 +54,7 @@ class PrefixSelectorTest : public ViewsTestBase { } protected: - scoped_ptr<PrefixSelector> selector_; + std::unique_ptr<PrefixSelector> selector_; TestPrefixDelegate delegate_; private: diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc index 011f65d38a1..d90784ca906 100644 --- a/chromium/ui/views/controls/scroll_view_unittest.cc +++ b/chromium/ui/views/controls/scroll_view_unittest.cc @@ -476,7 +476,8 @@ TEST(ScrollViewTest, CornerViewVisibility) { // Tests the overlay scrollbars on Mac. Ensure that they show up properly and // do not overlap each other. TEST(ScrollViewTest, CocoaOverlayScrollBars) { - scoped_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_override; + std::unique_ptr<ui::test::ScopedPreferredScrollerStyle> + scroller_style_override; scroller_style_override.reset( new ui::test::ScopedPreferredScrollerStyle(true)); ScrollView scroll_view; diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc index e9333e1458c..28da57db9a8 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc @@ -24,10 +24,6 @@ #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" #include "ui/views/widget/widget.h" -#if defined(OS_LINUX) -#include "ui/gfx/screen.h" -#endif - #undef min #undef max diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h index 178fdc1e908..6d6944259d3 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h @@ -177,8 +177,8 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar, // was invoked. int context_menu_mouse_position_; - scoped_ptr<MenuRunner> menu_runner_; - scoped_ptr<ScrollAnimator> scroll_animator_; + std::unique_ptr<MenuRunner> menu_runner_; + std::unique_ptr<ScrollAnimator> scroll_animator_; // Difference between current position and cumulative deltas obtained from // scroll update events. diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc index d3fb7071ed8..e2befaee43a 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.cc @@ -6,8 +6,8 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "ui/display/screen.h" #include "ui/events/event_utils.h" -#include "ui/gfx/screen.h" namespace views { @@ -36,7 +36,8 @@ void BaseScrollBarButton::OnMouseCaptureLost() { void BaseScrollBarButton::RepeaterNotifyClick() { // TODO(sky): See if we can convert to using |Screen| everywhere. - gfx::Point cursor_point = gfx::Screen::GetScreen()->GetCursorScreenPoint(); + gfx::Point cursor_point = + display::Screen::GetScreen()->GetCursorScreenPoint(); ui::MouseEvent event(ui::ET_MOUSE_RELEASED, cursor_point, cursor_point, ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.h index cb269baf7b1..6e8716bebb5 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.h +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar_button.h @@ -11,10 +11,6 @@ #include "build/build_config.h" #include "ui/views/repeat_controller.h" -#if defined(OS_LINUX) -#include "ui/gfx/screen.h" -#endif - namespace views { /////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc index 3348b5bcbca..421a56da3f2 100644 --- a/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc +++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar_views.cc @@ -72,8 +72,7 @@ class ScrollBarThumb : public BaseScrollBarThumb { ScrollBarButton::ScrollBarButton(ButtonListener* listener, Type type) : BaseScrollBarButton(listener), type_(type) { - SetFocusable(false); - SetAccessibilityFocusable(false); + SetFocusBehavior(FocusBehavior::NEVER); } ScrollBarButton::~ScrollBarButton() { @@ -150,8 +149,6 @@ ui::NativeTheme::State ScrollBarThumb::ScrollBarThumb(BaseScrollBar* scroll_bar) : BaseScrollBarThumb(scroll_bar), scroll_bar_(scroll_bar) { - SetFocusable(false); - SetAccessibilityFocusable(false); } ScrollBarThumb::~ScrollBarThumb() { diff --git a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc index 84471929234..b225098c7a7 100644 --- a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc +++ b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc @@ -93,7 +93,7 @@ class NativeScrollBarTest : public ViewsTestBase { // scroll to the middle. int track_size_; - scoped_ptr<TestScrollBarController> controller_; + std::unique_ptr<TestScrollBarController> controller_; }; // TODO(dnicoara) Can't run the test on Windows since the scrollbar |Part| diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc index e16346127ba..16fb2209789 100644 --- a/chromium/ui/views/controls/separator.cc +++ b/chromium/ui/views/controls/separator.cc @@ -22,7 +22,6 @@ Separator::Separator(Orientation orientation) : orientation_(orientation), color_(kDefaultColor), size_(kSeparatorSize) { - SetFocusable(false); } Separator::~Separator() { diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc index e063456aaaf..c930e3c66ee 100644 --- a/chromium/ui/views/controls/slider.cc +++ b/chromium/ui/views/controls/slider.cc @@ -67,7 +67,12 @@ Slider::Slider(SliderListener* listener, Orientation orientation) bar_active_images_(kBarImagesActive), bar_disabled_images_(kBarImagesDisabled) { EnableCanvasFlippingForRTLUI(true); - SetFocusable(true); +#if defined(OS_MACOSX) + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); +#else + SetFocusBehavior(FocusBehavior::ALWAYS); +#endif + UpdateState(true); } diff --git a/chromium/ui/views/controls/slider.h b/chromium/ui/views/controls/slider.h index 294004331a5..3d2090aca47 100644 --- a/chromium/ui/views/controls/slider.h +++ b/chromium/ui/views/controls/slider.h @@ -122,7 +122,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate { SliderListener* listener_; Orientation orientation_; - scoped_ptr<gfx::SlideAnimation> move_animation_; + std::unique_ptr<gfx::SlideAnimation> move_animation_; float value_; float keyboard_increment_; diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc index ded1f367c5a..46641a212e2 100644 --- a/chromium/ui/views/controls/slider_unittest.cc +++ b/chromium/ui/views/controls/slider_unittest.cc @@ -4,11 +4,11 @@ #include "ui/views/controls/slider.h" +#include <memory> #include <string> #include "base/i18n/rtl.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" @@ -169,7 +169,7 @@ class SliderTest : public views::ViewsTestBase { // The widget container for the slider being tested. views::Widget* widget_; // An event generator. - scoped_ptr<ui::test::EventGenerator> event_generator_; + std::unique_ptr<ui::test::EventGenerator> event_generator_; DISALLOW_COPY_AND_ASSIGN(SliderTest); }; diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc index 9c8f720cee1..f46c93c046f 100644 --- a/chromium/ui/views/controls/styled_label.cc +++ b/chromium/ui/views/controls/styled_label.cc @@ -32,12 +32,12 @@ int CalculateLineHeight(const gfx::FontList& font_list) { return label.GetPreferredSize().height(); } -scoped_ptr<Label> CreateLabelRange( +std::unique_ptr<Label> CreateLabelRange( const base::string16& text, const gfx::FontList& font_list, const StyledLabel::RangeStyleInfo& style_info, views::LinkListener* link_listener) { - scoped_ptr<Label> result; + std::unique_ptr<Label> result; if (style_info.is_link) { Link* link = new Link(text); @@ -307,7 +307,7 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { base::string16 chunk = substrings[0]; - scoped_ptr<Label> label; + std::unique_ptr<Label> label; if (position >= range.start()) { const RangeStyleInfo& style_info = current_range->style_info; diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc index cae7f67744e..408212b385c 100644 --- a/chromium/ui/views/controls/styled_label_unittest.cc +++ b/chromium/ui/views/controls/styled_label_unittest.cc @@ -2,19 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/controls/styled_label.h" + #include <stddef.h> +#include <memory> #include <string> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/font_list.h" #include "ui/views/border.h" #include "ui/views/controls/link.h" -#include "ui/views/controls/styled_label.h" #include "ui/views/controls/styled_label_listener.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" @@ -46,7 +47,7 @@ class StyledLabelTest : public ViewsTestBase, public StyledLabelListener { } private: - scoped_ptr<StyledLabel> styled_; + std::unique_ptr<StyledLabel> styled_; DISALLOW_COPY_AND_ASSIGN(StyledLabelTest); }; diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc index 5579bb07c04..8b948e70bbf 100644 --- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc +++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc @@ -277,7 +277,12 @@ TabbedPane::TabbedPane() tab_strip_(new TabStrip(this)), contents_(new View()), selected_tab_index_(-1) { - SetFocusable(true); +#if defined(OS_MACOSX) + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); +#else + SetFocusBehavior(FocusBehavior::ALWAYS); +#endif + AddChildView(tab_strip_); AddChildView(contents_); } diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc index c13e6376828..7152f7eb4f0 100644 --- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc +++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/controls/tabbed_pane/tabbed_pane.h" + +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/controls/tabbed_pane/tabbed_pane.h" #include "ui/views/test/views_test_base.h" using base::ASCIIToUTF16; @@ -35,7 +37,7 @@ typedef ViewsTestBase TabbedPaneTest; // Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). TEST_F(TabbedPaneTest, SizeAndLayout) { - scoped_ptr<TabbedPane> tabbed_pane(new TabbedPane()); + std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); View* child1 = new FixedSizeView(gfx::Size(20, 10)); tabbed_pane->AddTab(ASCIIToUTF16("tab1"), child1); View* child2 = new FixedSizeView(gfx::Size(5, 5)); @@ -67,7 +69,7 @@ TEST_F(TabbedPaneTest, SizeAndLayout) { } TEST_F(TabbedPaneTest, AddAndSelect) { - scoped_ptr<TabbedPane> tabbed_pane(new TabbedPane()); + std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); // Add several tabs; only the first should be a selected automatically. for (int i = 0; i < 3; ++i) { View* tab = new View(); diff --git a/chromium/ui/views/controls/table/table_header.h b/chromium/ui/views/controls/table/table_header.h index 7fd54e91a21..3c671987d5d 100644 --- a/chromium/ui/views/controls/table/table_header.h +++ b/chromium/ui/views/controls/table/table_header.h @@ -80,7 +80,7 @@ class VIEWS_EXPORT TableHeader : public views::View { TableView* table_; // If non-null a resize is in progress. - scoped_ptr<ColumnResizeDetails> resize_details_; + std::unique_ptr<ColumnResizeDetails> resize_details_; DISALLOW_COPY_AND_ASSIGN(TableHeader); }; diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc index 3a289f3b22c..c09c6ead905 100644 --- a/chromium/ui/views/controls/table/table_view.cc +++ b/chromium/ui/views/controls/table/table_view.cc @@ -145,7 +145,8 @@ TableView::TableView(ui::TableModel* model, visible_column.column = columns[i]; visible_columns_.push_back(visible_column); } - SetFocusable(true); + // Always focusable, even on Mac (consistent with NSTableView). + SetFocusBehavior(FocusBehavior::ALWAYS); SetModel(model); } @@ -178,7 +179,7 @@ View* TableView::CreateParentIfNecessary() { } void TableView::SetRowBackgroundPainter( - scoped_ptr<TableViewRowBackgroundPainter> painter) { + std::unique_ptr<TableViewRowBackgroundPainter> painter) { row_background_painter_ = std::move(painter); } diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h index 55c7a31d8ff..fc7f028164b 100644 --- a/chromium/ui/views/controls/table/table_view.h +++ b/chromium/ui/views/controls/table/table_view.h @@ -5,10 +5,10 @@ #ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_ #define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_ +#include <memory> #include <vector> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/base/models/list_selection_model.h" #include "ui/base/models/table_model.h" #include "ui/base/models/table_model_observer.h" @@ -107,7 +107,7 @@ class VIEWS_EXPORT TableView View* CreateParentIfNecessary(); void SetRowBackgroundPainter( - scoped_ptr<TableViewRowBackgroundPainter> painter); + std::unique_ptr<TableViewRowBackgroundPainter> painter); // Sets the TableGrouper. TableView does not own |grouper| (common use case is // to have TableModel implement TableGrouper). @@ -351,7 +351,7 @@ class VIEWS_EXPORT TableView std::vector<int> view_to_model_; std::vector<int> model_to_view_; - scoped_ptr<TableViewRowBackgroundPainter> row_background_painter_; + std::unique_ptr<TableViewRowBackgroundPainter> row_background_painter_; TableGrouper* grouper_; diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc index 2618a2f0176..b290c0def29 100644 --- a/chromium/ui/views/controls/table/table_view_unittest.cc +++ b/chromium/ui/views/controls/table/table_view_unittest.cc @@ -238,15 +238,15 @@ class TableViewTest : public testing::Test { } protected: - scoped_ptr<TestTableModel2> model_; + std::unique_ptr<TestTableModel2> model_; // Owned by |parent_|. TableView* table_; - scoped_ptr<TableViewTestHelper> helper_; + std::unique_ptr<TableViewTestHelper> helper_; private: - scoped_ptr<View> parent_; + std::unique_ptr<View> parent_; DISALLOW_COPY_AND_ASSIGN(TableViewTest); }; diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc index 74d18b70564..dc0a9f25358 100644 --- a/chromium/ui/views/controls/textfield/textfield.cc +++ b/chromium/ui/views/controls/textfield/textfield.cc @@ -21,13 +21,13 @@ #include "ui/base/ui_base_switches_util.h" #include "ui/compositor/canvas_painter.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/events/base_event_utils.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/display.h" #include "ui/gfx/geometry/insets.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/background.h" @@ -40,6 +40,7 @@ #include "ui/views/metrics.h" #include "ui/views/native_cursor.h" #include "ui/views/painter.h" +#include "ui/views/style/platform_style.h" #include "ui/views/views_delegate.h" #include "ui/views/widget/widget.h" @@ -82,8 +83,8 @@ int GetDragSelectionDelay() { return 100; } -// Get the default command for a given key |event| and selection state. -int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) { +// Get the default command for a given key |event|. +int GetCommandForKeyEvent(const ui::KeyEvent& event) { if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode()) return kNoCommand; @@ -128,7 +129,7 @@ int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) { return shift ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION : IDS_MOVE_TO_END_OF_LINE; case ui::VKEY_BACK: - if (!control || has_selection) + if (!control) return IDS_DELETE_BACKWARD; #if defined(OS_LINUX) // Only erase by line break on Linux and ChromeOS. @@ -137,14 +138,14 @@ int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) { #endif return IDS_DELETE_WORD_BACKWARD; case ui::VKEY_DELETE: - if (!control || has_selection) - return (shift && has_selection) ? IDS_APP_CUT : IDS_DELETE_FORWARD; #if defined(OS_LINUX) // Only erase by line break on Linux and ChromeOS. - if (shift) + if (shift && control) return IDS_DELETE_TO_END_OF_LINE; #endif - return IDS_DELETE_WORD_FORWARD; + if (control) + return IDS_DELETE_WORD_FORWARD; + return shift ? IDS_APP_CUT : IDS_DELETE_FORWARD; case ui::VKEY_INSERT: if (control && !shift) return IDS_APP_COPY; @@ -292,8 +293,8 @@ Textfield::Textfield() set_context_menu_controller(this); set_drag_controller(this); GetRenderText()->SetFontList(GetDefaultFontList()); - SetBorder(scoped_ptr<Border>(new FocusableBorder())); - SetFocusable(true); + SetBorder(std::unique_ptr<Border>(new FocusableBorder())); + SetFocusBehavior(FocusBehavior::ALWAYS); if (ViewsDelegate::GetInstance()) { password_reveal_duration_ = @@ -572,7 +573,7 @@ void Textfield::ExecuteCommand(int command_id) { ExecuteCommand(command_id, ui::EF_NONE); } -void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) { +void Textfield::SetFocusPainter(std::unique_ptr<Painter> focus_painter) { focus_painter_ = std::move(focus_painter); } @@ -729,7 +730,7 @@ bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { #endif if (edit_command == kNoCommand) - edit_command = GetCommandForKeyEvent(event, HasSelection()); + edit_command = GetCommandForKeyEvent(event); if (!handled && IsCommandIdEnabled(edit_command)) { ExecuteCommand(edit_command); @@ -833,7 +834,7 @@ void Textfield::OnGestureEvent(ui::GestureEvent* event) { bool Textfield::AcceleratorPressed(const ui::Accelerator& accelerator) { ui::KeyEvent event(accelerator.type(), accelerator.key_code(), accelerator.modifiers()); - ExecuteCommand(GetCommandForKeyEvent(event, HasSelection())); + ExecuteCommand(GetCommandForKeyEvent(event)); return true; } @@ -1098,11 +1099,11 @@ void Textfield::WriteDragDataForView(View* sender, label.SetSubpixelRenderingEnabled(false); gfx::Size size(label.GetPreferredSize()); gfx::NativeView native_view = GetWidget()->GetNativeView(); - gfx::Display display = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(native_view); + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow(native_view); size.SetToMin(gfx::Size(display.size().width(), height())); label.SetBoundsRect(gfx::Rect(size)); - scoped_ptr<gfx::Canvas> canvas( + std::unique_ptr<gfx::Canvas> canvas( GetCanvasForDragImage(GetWidget(), label.size())); label.SetEnabledColor(GetTextColor()); #if defined(OS_LINUX) && !defined(OS_CHROMEOS) @@ -1302,6 +1303,22 @@ bool Textfield::GetAcceleratorForCommandId(int command_id, void Textfield::ExecuteCommand(int command_id, int event_flags) { DestroyTouchSelection(); + + // Some codepaths may bypass GetCommandForKeyEvent, so any selection-dependent + // modifications of the command should happen here. + if (HasSelection()) { + switch (command_id) { + case IDS_DELETE_WORD_BACKWARD: + case IDS_DELETE_TO_BEGINNING_OF_LINE: + command_id = IDS_DELETE_BACKWARD; + break; + case IDS_DELETE_WORD_FORWARD: + case IDS_DELETE_TO_END_OF_LINE: + command_id = IDS_DELETE_FORWARD; + break; + } + } + if (!IsCommandIdEnabled(command_id)) return; @@ -1475,7 +1492,7 @@ void Textfield::InsertChar(const ui::KeyEvent& event) { DoInsertChar(ch); if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD && - password_reveal_duration_ != base::TimeDelta()) { + !password_reveal_duration_.is_zero()) { const size_t change_offset = model_->GetCursorPosition(); DCHECK_GT(change_offset, 0u); RevealPasswordChar(change_offset - 1); @@ -1746,7 +1763,18 @@ void Textfield::MoveCursorTo(const gfx::Point& point, bool select) { void Textfield::SelectThroughLastDragLocation() { OnBeforeUserAction(); - model_->MoveCursorTo(last_drag_location_, true); + + const bool drags_to_end = PlatformStyle::kTextfieldDragVerticallyDragsToEnd; + if (drags_to_end && last_drag_location_.y() < 0) { + model_->MoveCursor(gfx::BreakType::LINE_BREAK, + gfx::VisualCursorDirection::CURSOR_LEFT, true); + } else if (drags_to_end && last_drag_location_.y() > height()) { + model_->MoveCursor(gfx::BreakType::LINE_BREAK, + gfx::VisualCursorDirection::CURSOR_RIGHT, true); + } else { + model_->MoveCursorTo(last_drag_location_, true); + } + if (aggregated_clicks_ == 1) { model_->SelectWord(); // Expand the selection so the initially selected word remains selected. diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h index b153edd0d89..738dec2982f 100644 --- a/chromium/ui/views/controls/textfield/textfield.h +++ b/chromium/ui/views/controls/textfield/textfield.h @@ -8,11 +8,11 @@ #include <stddef.h> #include <stdint.h> +#include <memory> #include <string> #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/timer/timer.h" @@ -206,7 +206,7 @@ class VIEWS_EXPORT Textfield : public View, // Performs the action associated with the specified command id. void ExecuteCommand(int command_id); - void SetFocusPainter(scoped_ptr<Painter> focus_painter); + void SetFocusPainter(std::unique_ptr<Painter> focus_painter); // Returns whether there is a drag operation originating from the textfield. bool HasTextBeingDragged(); @@ -392,7 +392,7 @@ class VIEWS_EXPORT Textfield : public View, void PasteSelectionClipboard(const ui::MouseEvent& event); // The text model. - scoped_ptr<TextfieldModel> model_; + std::unique_ptr<TextfieldModel> model_; // This is the current listener for events from this Textfield. TextfieldController* controller_; @@ -410,7 +410,7 @@ class VIEWS_EXPORT Textfield : public View, // This will be reported as the "desired size". Defaults to 0. int default_width_in_chars_; - scoped_ptr<Painter> focus_painter_; + std::unique_ptr<Painter> focus_painter_; // Flags indicating whether various system colors should be used, and if not, // what overriding color values should be used instead. @@ -470,7 +470,8 @@ class VIEWS_EXPORT Textfield : public View, gfx::Point last_click_location_; gfx::Range double_click_word_; - scoped_ptr<ui::TouchEditingControllerDeprecated> touch_selection_controller_; + std::unique_ptr<ui::TouchEditingControllerDeprecated> + touch_selection_controller_; // Used to track touch drag starting location and offset to enable touch // scrolling. @@ -482,8 +483,8 @@ class VIEWS_EXPORT Textfield : public View, bool touch_handles_hidden_due_to_scroll_; // Context menu related members. - scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; - scoped_ptr<views::MenuRunner> context_menu_runner_; + std::unique_ptr<ui::SimpleMenuModel> context_menu_contents_; + std::unique_ptr<views::MenuRunner> context_menu_runner_; // Used to bind callback functions to this object. base::WeakPtrFactory<Textfield> weak_ptr_factory_; diff --git a/chromium/ui/views/controls/textfield/textfield_model.h b/chromium/ui/views/controls/textfield/textfield_model.h index 9bdb48c834f..135524e289a 100644 --- a/chromium/ui/views/controls/textfield/textfield_model.h +++ b/chromium/ui/views/controls/textfield/textfield_model.h @@ -8,11 +8,11 @@ #include <stddef.h> #include <list> +#include <memory> #include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" #include "ui/base/ime/composition_text.h" #include "ui/gfx/render_text.h" @@ -268,7 +268,7 @@ class VIEWS_EXPORT TextfieldModel { Delegate* delegate_; // The stylized text, cursor, selection, and the visual layout model. - scoped_ptr<gfx::RenderText> render_text_; + std::unique_ptr<gfx::RenderText> render_text_; // The composition range. gfx::Range composition_range_; diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc index 4908c2bec10..03cb08d76ea 100644 --- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc +++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/controls/textfield/textfield_model.h" + #include <stddef.h> +#include <memory> #include <vector> #include "base/auto_reset.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" @@ -19,7 +21,6 @@ #include "ui/gfx/range/range.h" #include "ui/gfx/render_text.h" #include "ui/views/controls/textfield/textfield.h" -#include "ui/views/controls/textfield/textfield_model.h" #include "ui/views/test/test_views_delegate.h" #include "ui/views/test/views_test_base.h" diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc index 97595c57cb4..82a712abe53 100644 --- a/chromium/ui/views/controls/textfield/textfield_unittest.cc +++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc @@ -12,10 +12,12 @@ #include <vector> #include "base/command_line.h" +#include "base/format_macros.h" #include "base/i18n/rtl.h" #include "base/macros.h" #include "base/pickle.h" #include "base/strings/string16.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "ui/accessibility/ax_view_state.h" @@ -39,6 +41,7 @@ #include "ui/views/controls/textfield/textfield_model.h" #include "ui/views/controls/textfield/textfield_test_api.h" #include "ui/views/focus/focus_manager.h" +#include "ui/views/style/platform_style.h" #include "ui/views/test/test_views_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/widget_test.h" @@ -329,7 +332,7 @@ class TextfieldDestroyerController : public views::TextfieldController { } private: - scoped_ptr<views::Textfield> target_; + std::unique_ptr<views::Textfield> target_; }; base::string16 GetClipboardText(ui::ClipboardType type) { @@ -634,11 +637,49 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController { EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */)); } + void PressLeftMouseButton(int extra_flags) { + ui::MouseEvent click(ui::ET_MOUSE_PRESSED, mouse_position_, mouse_position_, + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON | extra_flags); + textfield_->OnMousePressed(click); + } + + void PressLeftMouseButton() { + PressLeftMouseButton(0); + } + + void ReleaseLeftMouseButton() { + ui::MouseEvent release(ui::ET_MOUSE_RELEASED, mouse_position_, + mouse_position_, ui::EventTimeForNow(), + ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); + textfield_->OnMouseReleased(release); + } + + void ClickLeftMouseButton(int extra_flags) { + PressLeftMouseButton(extra_flags); + ReleaseLeftMouseButton(); + } + + void ClickLeftMouseButton() { + ClickLeftMouseButton(0); + } + + void DragMouseTo(const gfx::Point& where) { + mouse_position_ = where; + ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, where, where, + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); + textfield_->OnMouseDragged(drag); + } + + // Textfield does not listen to OnMouseMoved, so this function does not send + // an event when it updates the cursor position. + void MoveMouseTo(const gfx::Point& where) { mouse_position_ = where; } + // We need widget to populate wrapper class. Widget* widget_; TestTextfield* textfield_; - scoped_ptr<TextfieldTestApi> test_api_; + std::unique_ptr<TextfieldTestApi> test_api_; TextfieldModel* model_; // The string from Controller::ContentsChanged callback. @@ -654,8 +695,10 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController { int on_after_user_action_; private: + // Position of the mouse for synthetic mouse events. + gfx::Point mouse_position_; ui::ClipboardType copied_to_clipboard_; - scoped_ptr<ui::test::EventGenerator> event_generator_; + std::unique_ptr<ui::test::EventGenerator> event_generator_; DISALLOW_COPY_AND_ASSIGN(TextfieldTest); }; @@ -826,6 +869,33 @@ TEST_F(TextfieldTest, InsertionDeletionTest) { #endif } +// Test that deletion operations behave correctly with an active selection. +TEST_F(TextfieldTest, DeletionWithSelection) { + struct { + ui::KeyboardCode key; + bool shift; + } cases[] = { + {ui::VKEY_BACK, false}, + {ui::VKEY_BACK, true}, + {ui::VKEY_DELETE, false}, + {ui::VKEY_DELETE, true}, + }; + + InitTextfield(); + // [Ctrl] ([Alt] on Mac) + [Delete]/[Backspace] should delete the active + // selection, regardless of [Shift]. + for (size_t i = 0; i < arraysize(cases); ++i) { + SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i)); + textfield_->SetText(ASCIIToUTF16("one two three")); + textfield_->SelectRange(gfx::Range(2, 6)); + // Make selection as - on|e tw|o three. + SendWordEvent(cases[i].key, cases[i].shift); + // Verify state is on|o three. + EXPECT_STR_EQ("ono three", textfield_->text()); + EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange()); + } +} + TEST_F(TextfieldTest, PasswordTest) { InitTextfield(); textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); @@ -922,7 +992,7 @@ TEST_F(TextfieldTest, OnKeyPress) { EXPECT_TRUE(textfield_->key_handled()); textfield_->clear(); - // F20, up/down key won't be handled. + // F20 key won't be handled. SendKeyEvent(ui::VKEY_F20); #if defined(OS_MACOSX) // On Mac, key combinations that don't map to editing commands are forwarded @@ -934,14 +1004,24 @@ TEST_F(TextfieldTest, OnKeyPress) { EXPECT_FALSE(textfield_->key_handled()); textfield_->clear(); + // Up/Down keys won't be handled except on Mac where they map to move + // commands. SendKeyEvent(ui::VKEY_UP); EXPECT_TRUE(textfield_->key_received()); +#if defined(OS_MACOSX) + EXPECT_TRUE(textfield_->key_handled()); +#else EXPECT_FALSE(textfield_->key_handled()); +#endif textfield_->clear(); SendKeyEvent(ui::VKEY_DOWN); EXPECT_TRUE(textfield_->key_received()); +#if defined(OS_MACOSX) + EXPECT_TRUE(textfield_->key_handled()); +#else EXPECT_FALSE(textfield_->key_handled()); +#endif textfield_->clear(); } @@ -1073,10 +1153,8 @@ TEST_F(TextfieldTest, FocusTraversalTest) { // Test if clicking on textfield view sets the focus. widget_->GetFocusManager()->AdvanceFocus(true); EXPECT_EQ(3, GetFocusedView()->id()); - ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(click); + MoveMouseTo(gfx::Point()); + ClickLeftMouseButton(); EXPECT_EQ(1, GetFocusedView()->id()); // Tab/Shift+Tab should also cycle focus, not insert a tab character. @@ -1125,33 +1203,20 @@ TEST_F(TextfieldTest, ContextMenuDisplayTest) { TEST_F(TextfieldTest, DoubleAndTripleClickTest) { InitTextfield(); textfield_->SetText(ASCIIToUTF16("hello world")); - ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), - ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK, - ui::EF_LEFT_MOUSE_BUTTON); // Test for double click. - textfield_->OnMousePressed(click); - textfield_->OnMouseReleased(release); + MoveMouseTo(gfx::Point()); + ClickLeftMouseButton(); EXPECT_TRUE(textfield_->GetSelectedText().empty()); - textfield_->OnMousePressed(double_click); - textfield_->OnMouseReleased(release); + ClickLeftMouseButton(ui::EF_IS_DOUBLE_CLICK); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); // Test for triple click. - textfield_->OnMousePressed(click); - textfield_->OnMouseReleased(release); + ClickLeftMouseButton(); EXPECT_STR_EQ("hello world", textfield_->GetSelectedText()); // Another click should reset back to double click. - textfield_->OnMousePressed(click); - textfield_->OnMouseReleased(release); + ClickLeftMouseButton(); EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); } @@ -1162,39 +1227,70 @@ TEST_F(TextfieldTest, DragToSelect) { const int kEnd = 500; gfx::Point start_point(kStart, 0); gfx::Point end_point(kEnd, 0); - ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); - ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); - ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(click_a); + + MoveMouseTo(start_point); + PressLeftMouseButton(); EXPECT_TRUE(textfield_->GetSelectedText().empty()); + // Check that dragging left selects the beginning of the string. - textfield_->OnMouseDragged(drag_left); + DragMouseTo(gfx::Point()); base::string16 text_left = textfield_->GetSelectedText(); EXPECT_STR_EQ("hello", text_left); + // Check that dragging right selects the rest of the string. - textfield_->OnMouseDragged(drag_right); + DragMouseTo(end_point); base::string16 text_right = textfield_->GetSelectedText(); EXPECT_STR_EQ(" world", text_right); + // Check that releasing in the same location does not alter the selection. - textfield_->OnMouseReleased(release); + ReleaseLeftMouseButton(); EXPECT_EQ(text_right, textfield_->GetSelectedText()); + // Check that dragging from beyond the text length works too. - textfield_->OnMousePressed(click_b); - textfield_->OnMouseDragged(drag_left); - textfield_->OnMouseReleased(release); + MoveMouseTo(end_point); + PressLeftMouseButton(); + DragMouseTo(gfx::Point()); + ReleaseLeftMouseButton(); EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText()); } +// This test checks that dragging above the textfield selects to the beginning +// and dragging below the textfield selects to the end, but only on platforms +// where that is the expected behavior. +TEST_F(TextfieldTest, DragUpOrDownSelectsToEnd) { + InitTextfield(); + textfield_->SetText(ASCIIToUTF16("hello world")); + const base::string16 expected_up = base::ASCIIToUTF16( + PlatformStyle::kTextfieldDragVerticallyDragsToEnd ? "hello" : "lo"); + const base::string16 expected_down = base::ASCIIToUTF16( + PlatformStyle::kTextfieldDragVerticallyDragsToEnd ? " world" : " w"); + const int kStartX = GetCursorPositionX(5); + const int kDownX = GetCursorPositionX(7); + const int kUpX = GetCursorPositionX(3); + gfx::Point start_point(kStartX, 0); + gfx::Point down_point(kDownX, 500); + gfx::Point up_point(kUpX, -500); + + MoveMouseTo(start_point); + PressLeftMouseButton(); + DragMouseTo(up_point); + ReleaseLeftMouseButton(); + EXPECT_EQ(textfield_->GetSelectedText(), expected_up); + + // Click at |up_point|. This is important because drags do not count as clicks + // for the purpose of double-click detection, so if this test doesn't click + // somewhere other than |start_point| before the code below runs, the second + // click at |start_point| will be interpreted as a double-click instead of the + // start of a drag. + ClickLeftMouseButton(); + + MoveMouseTo(start_point); + PressLeftMouseButton(); + DragMouseTo(down_point); + ReleaseLeftMouseButton(); + EXPECT_EQ(textfield_->GetSelectedText(), expected_down); +} + #if defined(OS_WIN) TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) { InitTextfield(); @@ -1277,11 +1373,9 @@ TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) { EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, textfield_->GetDragOperationsForView(NULL, kStringPoint)); textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); + MoveMouseTo(kStringPoint); + PressLeftMouseButton(); // Ensure that textfields only initiate drag operations inside the selection. - ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(press_event); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, textfield_->GetDragOperationsForView(NULL, gfx::Point())); EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(), @@ -1308,17 +1402,13 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheRight) { // Start dragging "ello". textfield_->SelectRange(gfx::Range(1, 5)); gfx::Point point(GetCursorPositionX(3), 0); - ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(click_a); - EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), - gfx::Point())); - operations = textfield_->GetDragOperationsForView(textfield_, - click_a.location()); + MoveMouseTo(point); + PressLeftMouseButton(); + EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, point, point)); + operations = textfield_->GetDragOperationsForView(textfield_, point); EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, operations); - textfield_->WriteDragDataForView(NULL, click_a.location(), &data); + textfield_->WriteDragDataForView(nullptr, point, &data); EXPECT_TRUE(data.GetString(&string)); EXPECT_EQ(textfield_->GetSelectedText(), string); EXPECT_TRUE(textfield_->GetDropFormats(&formats, &format_types)); @@ -1362,17 +1452,13 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) { // Start dragging " worl". textfield_->SelectRange(gfx::Range(5, 10)); gfx::Point point(GetCursorPositionX(7), 0); - ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(click_a); - EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), - gfx::Point())); - operations = textfield_->GetDragOperationsForView(textfield_, - click_a.location()); + MoveMouseTo(point); + PressLeftMouseButton(); + EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, point, gfx::Point())); + operations = textfield_->GetDragOperationsForView(textfield_, point); EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, operations); - textfield_->WriteDragDataForView(NULL, click_a.location(), &data); + textfield_->WriteDragDataForView(nullptr, point, &data); EXPECT_TRUE(data.GetString(&string)); EXPECT_EQ(textfield_->GetSelectedText(), string); EXPECT_TRUE(textfield_->GetDropFormats(&formats, &format_types)); @@ -1410,12 +1496,10 @@ TEST_F(TextfieldTest, DragAndDrop_Canceled) { // Start dragging "worl". textfield_->SelectRange(gfx::Range(6, 10)); gfx::Point point(GetCursorPositionX(8), 0); - ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(click); + MoveMouseTo(point); + PressLeftMouseButton(); ui::OSExchangeData data; - textfield_->WriteDragDataForView(NULL, click.location(), &data); + textfield_->WriteDragDataForView(nullptr, point, &data); EXPECT_TRUE(textfield_->CanDrop(data)); // Drag the text over somewhere valid, outside the current selection. gfx::Point drop_point(GetCursorPositionX(2), 0); @@ -1424,14 +1508,8 @@ TEST_F(TextfieldTest, DragAndDrop_Canceled) { EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop)); // "Cancel" the drag, via move and release over the selection, and OnDragDone. gfx::Point drag_point(GetCursorPositionX(9), 0); - ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); - ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMouseDragged(drag); - textfield_->OnMouseReleased(release); - textfield_->OnDragDone(); + DragMouseTo(drag_point); + ReleaseLeftMouseButton(); EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text()); } @@ -1767,6 +1845,17 @@ TEST_F(TextfieldTest, CutCopyPaste) { EXPECT_STR_EQ("", textfield_->text()); EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); + // Reset clipboard text. + SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, ""); + + // Ensure [Shift]+[Delete] is a no-op in case there is no selection. + textfield_->SetText(ASCIIToUTF16("123")); + textfield_->SelectRange(gfx::Range(0)); + SendAlternateCut(); + EXPECT_STR_EQ("", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); + EXPECT_STR_EQ("123", textfield_->text()); + EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); + // Ensure IDS_APP_COPY copies. textfield_->SetText(ASCIIToUTF16("789")); textfield_->SelectAll(false); @@ -2205,16 +2294,12 @@ TEST_F(TextfieldTest, KeepInitiallySelectedWord) { MouseClick(middle_cursor, 0); const gfx::Point middle(middle_cursor.x(), middle_cursor.y() + middle_cursor.height() / 2); - ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, - ui::EF_LEFT_MOUSE_BUTTON); - textfield_->OnMousePressed(press_event); + MoveMouseTo(middle); + PressLeftMouseButton(); EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange()); // Drag the mouse to the beginning of the textfield. - ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning, - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); - textfield_->OnMouseDragged(drag_event); + DragMouseTo(beginning); EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange()); } @@ -2511,11 +2596,11 @@ TEST_F(TextfieldTouchSelectionTest, TouchSelectionInUnfocusableTextfield) { // Make textfield unfocusable and tap on it. Touch text selection should not // get activated. - textfield_->SetFocusable(false); + textfield_->SetFocusBehavior(View::FocusBehavior::NEVER); Tap(touch_point); EXPECT_FALSE(textfield_->HasFocus()); EXPECT_FALSE(test_api_->touch_selection_controller()); - textfield_->SetFocusable(true); + textfield_->SetFocusBehavior(View::FocusBehavior::ALWAYS); } // No touch on desktop Mac. Tracked in http://crbug.com/445520. diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc index 30428a31cad..70501f872ad 100644 --- a/chromium/ui/views/controls/tree/tree_view.cc +++ b/chromium/ui/views/controls/tree/tree_view.cc @@ -81,7 +81,8 @@ TreeView::TreeView() controller_(NULL), root_shown_(true), row_height_(font_list_.GetHeight() + kTextVerticalPadding * 2) { - SetFocusable(true); + // Always focusable, even on Mac (consistent with NSOutlineView). + SetFocusBehavior(FocusBehavior::ALWAYS); closed_icon_ = *ui::ResourceBundle::GetSharedInstance().GetImageNamed( (base::i18n::IsRTL() ? IDR_FOLDER_CLOSED_RTL : IDR_FOLDER_CLOSED)).ToImageSkia(); diff --git a/chromium/ui/views/controls/tree/tree_view.h b/chromium/ui/views/controls/tree/tree_view.h index 27a51855aa4..2dc764e7f56 100644 --- a/chromium/ui/views/controls/tree/tree_view.h +++ b/chromium/ui/views/controls/tree/tree_view.h @@ -5,11 +5,11 @@ #ifndef UI_VIEWS_CONTROLS_TREE_TREE_VIEW_VIEWS_H_ #define UI_VIEWS_CONTROLS_TREE_TREE_VIEW_VIEWS_H_ +#include <memory> #include <vector> #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/base/models/tree_node_model.h" #include "ui/gfx/font_list.h" #include "ui/gfx/image/image_skia.h" @@ -386,7 +386,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver, // control, icon and offsets. int text_offset_; - scoped_ptr<PrefixSelector> selector_; + std::unique_ptr<PrefixSelector> selector_; DISALLOW_COPY_AND_ASSIGN(TreeView); }; diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc index c5a2b03eb1d..d8afe6ebacc 100644 --- a/chromium/ui/views/controls/webview/web_dialog_view.cc +++ b/chromium/ui/views/controls/webview/web_dialog_view.cc @@ -113,7 +113,7 @@ bool WebDialogView::CanClose() { if (!is_attempting_close_dialog_) { // Fire beforeunload event when user attempts to close the dialog. is_attempting_close_dialog_ = true; - web_view_->web_contents()->DispatchBeforeUnload(false); + web_view_->web_contents()->DispatchBeforeUnload(); } return false; } diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h index a978921c5dd..65be6d54d6d 100644 --- a/chromium/ui/views/controls/webview/web_dialog_view.h +++ b/chromium/ui/views/controls/webview/web_dialog_view.h @@ -7,12 +7,12 @@ #include <stdint.h> +#include <memory> #include <string> #include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/geometry/size.h" #include "ui/views/controls/webview/webview_export.h" #include "ui/views/widget/widget_delegate.h" diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc index 686eeb6ddd4..59f87612fe5 100644 --- a/chromium/ui/views/controls/webview/webview.cc +++ b/chromium/ui/views/controls/webview/webview.cc @@ -67,7 +67,8 @@ void WebView::SetWebContents(content::WebContents* replacement) { observing_render_process_host_->AddObserver(this); } // web_contents() now returns |replacement| from here onwards. - SetFocusable(!!web_contents()); + SetFocusBehavior(web_contents() ? FocusBehavior::ALWAYS + : FocusBehavior::NEVER); if (wc_owner_.get() != replacement) wc_owner_.reset(); if (embed_fullscreen_widget_mode_enabled_) { @@ -112,11 +113,11 @@ const char* WebView::GetClassName() const { return kViewClassName; } -scoped_ptr<content::WebContents> WebView::SwapWebContents( - scoped_ptr<content::WebContents> new_web_contents) { +std::unique_ptr<content::WebContents> WebView::SwapWebContents( + std::unique_ptr<content::WebContents> new_web_contents) { if (wc_owner_) wc_owner_->SetDelegate(NULL); - scoped_ptr<content::WebContents> old_web_contents(std::move(wc_owner_)); + std::unique_ptr<content::WebContents> old_web_contents(std::move(wc_owner_)); wc_owner_ = std::move(new_web_contents); if (wc_owner_) wc_owner_->SetDelegate(this); @@ -284,12 +285,12 @@ void WebView::WebContentsDestroyed() { NotifyAccessibilityWebContentsChanged(); } -void WebView::DidShowFullscreenWidget(int routing_id) { +void WebView::DidShowFullscreenWidget() { if (embed_fullscreen_widget_mode_enabled_) ReattachForFullscreenChange(true); } -void WebView::DidDestroyFullscreenWidget(int routing_id) { +void WebView::DidDestroyFullscreenWidget() { if (embed_fullscreen_widget_mode_enabled_) ReattachForFullscreenChange(false); } diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h index 9ff7c7f6091..e9914e6aa35 100644 --- a/chromium/ui/views/controls/webview/webview.h +++ b/chromium/ui/views/controls/webview/webview.h @@ -7,8 +7,9 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" @@ -98,8 +99,8 @@ class WEBVIEW_EXPORT WebView : public View, protected: // Swaps the owned WebContents |wc_owner_| with |new_web_contents|. Returns // the previously owned WebContents. - scoped_ptr<content::WebContents> SwapWebContents( - scoped_ptr<content::WebContents> new_web_contents); + std::unique_ptr<content::WebContents> SwapWebContents( + std::unique_ptr<content::WebContents> new_web_contents); // Called when the web contents is successfully attached. virtual void OnWebContentsAttached() {} @@ -131,8 +132,8 @@ class WEBVIEW_EXPORT WebView : public View, void RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) override; void WebContentsDestroyed() override; - void DidShowFullscreenWidget(int routing_id) override; - void DidDestroyFullscreenWidget(int routing_id) override; + void DidShowFullscreenWidget() override; + void DidDestroyFullscreenWidget() override; void DidToggleFullscreenModeForTab(bool entered_fullscreen, bool will_cause_resize) override; void DidAttachInterstitialPage() override; @@ -159,7 +160,7 @@ class WEBVIEW_EXPORT WebView : public View, NativeViewHost* const holder_; // Non-NULL if |web_contents()| was created and is owned by this WebView. - scoped_ptr<content::WebContents> wc_owner_; + std::unique_ptr<content::WebContents> wc_owner_; // The RenderProcessHost to which this RenderProcessHostObserver is added. // Since WebView::GetTextInputClient is relying on RWHV::GetTextInputClient, // we have to observe the lifecycle of the underlying RWHV through diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc index 2ecf9578118..7c85a7255b8 100644 --- a/chromium/ui/views/controls/webview/webview_unittest.cc +++ b/chromium/ui/views/controls/webview/webview_unittest.cc @@ -6,8 +6,10 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/test/test_browser_context.h" @@ -138,7 +140,7 @@ class WebViewUnitTest : public views::test::WidgetTest { ~WebViewUnitTest() override {} void SetUp() override { - set_views_delegate(make_scoped_ptr(new WebViewTestViewsDelegate)); + set_views_delegate(base::WrapUnique(new WebViewTestViewsDelegate)); browser_context_.reset(new content::TestBrowserContext); WidgetTest::SetUp(); // Set the test content browser client to avoid pulling in needless @@ -174,8 +176,8 @@ class WebViewUnitTest : public views::test::WidgetTest { WebView* web_view() const { return web_view_; } NativeViewHost* holder() const { return web_view_->holder_; } - scoped_ptr<content::WebContents> CreateWebContents() const { - return make_scoped_ptr(content::WebContents::Create( + std::unique_ptr<content::WebContents> CreateWebContents() const { + return base::WrapUnique(content::WebContents::Create( content::WebContents::CreateParams(browser_context_.get()))); } @@ -183,7 +185,7 @@ class WebViewUnitTest : public views::test::WidgetTest { content::TestBrowserThread ui_thread_; content::TestBrowserThread file_blocking_thread_; content::TestBrowserThread io_thread_; - scoped_ptr<content::TestBrowserContext> browser_context_; + std::unique_ptr<content::TestBrowserContext> browser_context_; content::TestContentBrowserClient test_browser_client_; Widget* top_level_widget_; @@ -197,7 +199,8 @@ class WebViewUnitTest : public views::test::WidgetTest { TEST_F(WebViewUnitTest, TestWebViewAttachDetachWebContents) { // Case 1: Create a new WebContents and set it in the webview via // SetWebContents. This should make the WebContents visible. - const scoped_ptr<content::WebContents> web_contents1(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents1( + CreateWebContents()); WebViewTestWebContentsObserver observer1(web_contents1.get()); EXPECT_FALSE(observer1.was_shown()); @@ -213,7 +216,8 @@ TEST_F(WebViewUnitTest, TestWebViewAttachDetachWebContents) { // Case 2: Create another WebContents and replace the current WebContents // via SetWebContents(). This should hide the current WebContents and show // the new one. - const scoped_ptr<content::WebContents> web_contents2(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents2( + CreateWebContents()); WebViewTestWebContentsObserver observer2(web_contents2.get()); EXPECT_FALSE(observer2.was_shown()); @@ -288,7 +292,7 @@ TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_Layout) { web_view()->SetEmbedFullscreenWidgetMode(true); ASSERT_EQ(1, web_view()->child_count()); - const scoped_ptr<content::WebContents> web_contents(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); WebViewTestWebContentsDelegate delegate; web_contents->SetDelegate(&delegate); web_view()->SetWebContents(web_contents.get()); @@ -341,10 +345,12 @@ TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_Switching) { const gfx::NativeView unset_native_view = holder()->native_view(); // Create two WebContentses to switch between. - const scoped_ptr<content::WebContents> web_contents1(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents1( + CreateWebContents()); WebViewTestWebContentsDelegate delegate1; web_contents1->SetDelegate(&delegate1); - const scoped_ptr<content::WebContents> web_contents2(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents2( + CreateWebContents()); WebViewTestWebContentsDelegate delegate2; web_contents2->SetDelegate(&delegate2); @@ -395,13 +401,13 @@ TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_ClickToFocus) { web_view()->SetBoundsRect(gfx::Rect(0, 0, 100, 90)); views::View* const something_to_focus = new views::View(); something_to_focus->SetBoundsRect(gfx::Rect(0, 90, 100, 10)); - something_to_focus->SetFocusable(true); + something_to_focus->SetFocusBehavior(View::FocusBehavior::ALWAYS); top_level_widget()->GetContentsView()->AddChildView(something_to_focus); web_view()->SetEmbedFullscreenWidgetMode(true); ASSERT_EQ(1, web_view()->child_count()); - const scoped_ptr<content::WebContents> web_contents(CreateWebContents()); + const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); WebViewTestWebContentsDelegate delegate; web_contents->SetDelegate(&delegate); web_view()->SetWebContents(web_contents.get()); @@ -457,4 +463,23 @@ TEST_F(WebViewUnitTest, EmbeddedFullscreenDuringScreenCapture_ClickToFocus) { EXPECT_TRUE(something_to_focus->HasFocus()); } +// Verifies that there is no crash in WebView destructor +// if WebView is already removed from Widget. +TEST_F(WebViewUnitTest, DetachedWebViewDestructor) { + // Init WebView with attached NativeView. + const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); + std::unique_ptr<WebView> webview( + new WebView(web_contents->GetBrowserContext())); + View* contents_view = top_level_widget()->GetContentsView(); + contents_view->AddChildView(webview.get()); + webview->SetWebContents(web_contents.get()); + + // Remove WebView from views hierarchy. NativeView should be detached + // from Widget. + contents_view->RemoveChildView(webview.get()); + // Destroy WebView. NativeView should be detached secondary. + // There should be no crash. + webview.reset(); +} + } // namespace views diff --git a/chromium/ui/views/corewm/cursor_height_provider_win.cc b/chromium/ui/views/corewm/cursor_height_provider_win.cc index 398b009b71b..93a8ceddc52 100644 --- a/chromium/ui/views/corewm/cursor_height_provider_win.cc +++ b/chromium/ui/views/corewm/cursor_height_provider_win.cc @@ -7,14 +7,15 @@ #include <windows.h> #include <stddef.h> #include <stdint.h> + #include <algorithm> #include <map> +#include <memory> -#include "base/memory/scoped_ptr.h" #include "base/win/scoped_hdc.h" namespace { -using PixelData = scoped_ptr<uint32_t[]>; +using PixelData = std::unique_ptr<uint32_t[]>; using HeightStorage = std::map<HCURSOR, int>; const uint32_t kBitsPeruint32 = sizeof(uint32_t) * 8; @@ -39,7 +40,7 @@ PixelData GetBitmapData(HBITMAP handle, const BITMAPINFO& info, HDC hdc) { // When getting pixel data palette is appended to memory pointed by // BITMAPINFO passed so allocate additional memory to store additional data. - scoped_ptr<char[]> header(new char[KHeaderAndPalette]); + std::unique_ptr<char[]> header(new char[KHeaderAndPalette]); memcpy(header.get(), &(info.bmiHeader), sizeof(info.bmiHeader)); data.reset(new uint32_t[info.bmiHeader.biSizeImage / sizeof(uint32_t)]); diff --git a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc index 879cafc86d0..d3aff0dbea7 100644 --- a/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc +++ b/chromium/ui/views/corewm/desktop_capture_controller_unittest.cc @@ -86,8 +86,8 @@ views::Widget* CreateWidget() { // creates two widgets, does a mouse press in one, sets capture in the other and // verifies state is reset in the first. TEST_F(DesktopCaptureControllerTest, ResetMouseHandlers) { - scoped_ptr<Widget> w1(CreateWidget()); - scoped_ptr<Widget> w2(CreateWidget()); + std::unique_ptr<Widget> w1(CreateWidget()); + std::unique_ptr<Widget> w2(CreateWidget()); ui::test::EventGenerator generator1(w1->GetNativeView()->GetRootWindow()); generator1.MoveMouseToCenterOf(w1->GetNativeView()); generator1.PressLeftButton(); @@ -111,12 +111,12 @@ TEST_F(DesktopCaptureControllerTest, ResetMouseHandlers) { // the window which had capture receives the gesture. // TODO(sky): move this test, it should be part of ScopedCaptureClient tests. TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) { - scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client1; - scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client2; + std::unique_ptr<aura::client::ScreenPositionClient> desktop_position_client1; + std::unique_ptr<aura::client::ScreenPositionClient> desktop_position_client2; - scoped_ptr<Widget> widget1(new Widget()); + std::unique_ptr<Widget> widget1(new Widget()); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); - scoped_ptr<wm::ScopedCaptureClient> scoped_capture_client( + std::unique_ptr<wm::ScopedCaptureClient> scoped_capture_client( new wm::ScopedCaptureClient(params.context->GetRootWindow())); aura::client::CaptureClient* capture_client = scoped_capture_client->capture_client(); @@ -137,7 +137,7 @@ TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) { root1->AddChildView(v1); widget1->Show(); - scoped_ptr<Widget> widget2(new Widget()); + std::unique_ptr<Widget> widget2(new Widget()); params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc index 80dac9fd8f6..e51a87265a5 100644 --- a/chromium/ui/views/corewm/tooltip_aura.cc +++ b/chromium/ui/views/corewm/tooltip_aura.cc @@ -9,9 +9,10 @@ #include "base/strings/string_util.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/canvas.h" #include "ui/gfx/render_text.h" -#include "ui/gfx/screen.h" #include "ui/gfx/text_elider.h" #include "ui/gfx/text_utils.h" #include "ui/native_theme/native_theme.h" @@ -118,7 +119,7 @@ class TooltipAura::TooltipView : public views::View { render_text_->SetDisplayRect(gfx::Rect(0, 0, max_text_width, 100000)); } - scoped_ptr<gfx::RenderText> render_text_; + std::unique_ptr<gfx::RenderText> render_text_; int max_width_; DISALLOW_COPY_AND_ASSIGN(TooltipView); @@ -138,7 +139,7 @@ void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos, const gfx::Size& tooltip_size) { gfx::Rect tooltip_rect(mouse_pos, tooltip_size); tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY); - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); gfx::Rect display_bounds(screen->GetDisplayNearestPoint(mouse_pos).bounds()); // If tooltip is out of bounds on the x axis, we simply shift it @@ -166,7 +167,7 @@ void TooltipAura::DestroyWidget() { } int TooltipAura::GetMaxWidth(const gfx::Point& location) const { - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); gfx::Rect display_bounds(screen->GetDisplayNearestPoint(location).bounds()); return std::min(kTooltipMaxWidthPixels, (display_bounds.width() + 1) / 2); } diff --git a/chromium/ui/views/corewm/tooltip_aura.h b/chromium/ui/views/corewm/tooltip_aura.h index 781acf97c41..2e8212fcb9f 100644 --- a/chromium/ui/views/corewm/tooltip_aura.h +++ b/chromium/ui/views/corewm/tooltip_aura.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_COREWM_TOOLTIP_AURA_H_ #define UI_VIEWS_COREWM_TOOLTIP_AURA_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/corewm/tooltip.h" #include "ui/views/widget/widget_observer.h" @@ -51,7 +52,7 @@ class VIEWS_EXPORT TooltipAura : public Tooltip, public WidgetObserver { void OnWidgetDestroying(Widget* widget) override; // The view showing the tooltip. - scoped_ptr<TooltipView> tooltip_view_; + std::unique_ptr<TooltipView> tooltip_view_; // The widget containing the tooltip. May be NULL. Widget* widget_; diff --git a/chromium/ui/views/corewm/tooltip_controller.cc b/chromium/ui/views/corewm/tooltip_controller.cc index c5dad8c4598..a45b406fec2 100644 --- a/chromium/ui/views/corewm/tooltip_controller.cc +++ b/chromium/ui/views/corewm/tooltip_controller.cc @@ -17,10 +17,10 @@ #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/window.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/gfx/font.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/screen.h" #include "ui/gfx/text_elider.h" #include "ui/views/corewm/tooltip.h" #include "ui/views/widget/tooltip_manager.h" @@ -97,7 +97,7 @@ aura::Window* GetTooltipTarget(const ui::MouseEvent& event, gfx::Point screen_loc(event.location()); aura::client::GetScreenPositionClient(event_target->GetRootWindow())-> ConvertPointToScreen(event_target, &screen_loc); - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc); if (!target) return NULL; @@ -124,7 +124,7 @@ aura::Window* GetTooltipTarget(const ui::MouseEvent& event, //////////////////////////////////////////////////////////////////////////////// // TooltipController public: -TooltipController::TooltipController(scoped_ptr<Tooltip> tooltip) +TooltipController::TooltipController(std::unique_ptr<Tooltip> tooltip) : tooltip_window_(NULL), tooltip_id_(NULL), tooltip_window_at_mouse_press_(NULL), @@ -203,8 +203,8 @@ void TooltipController::OnMouseEvent(ui::MouseEvent* event) { case ui::ET_MOUSE_DRAGGED: { curr_mouse_loc_ = event->location(); aura::Window* target = NULL; - // Avoid a call to gfx::Screen::GetWindowAtScreenPoint() since it can be - // very expensive on X11 in cases when the tooltip is hidden anyway. + // Avoid a call to display::Screen::GetWindowAtScreenPoint() since it can + // be very expensive on X11 in cases when the tooltip is hidden anyway. if (tooltips_enabled_ && !aura::Env::GetInstance()->IsMouseButtonDown() && !IsDragDropInProgress()) { diff --git a/chromium/ui/views/corewm/tooltip_controller.h b/chromium/ui/views/corewm/tooltip_controller.h index 5171726c5dc..5a274e319cd 100644 --- a/chromium/ui/views/corewm/tooltip_controller.h +++ b/chromium/ui/views/corewm/tooltip_controller.h @@ -6,9 +6,9 @@ #define UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_ #include <map> +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" #include "base/timer/timer.h" #include "ui/aura/window_observer.h" @@ -35,7 +35,7 @@ class VIEWS_EXPORT TooltipController : public aura::client::TooltipClient, public ui::EventHandler, public aura::WindowObserver { public: - explicit TooltipController(scoped_ptr<Tooltip> tooltip); + explicit TooltipController(std::unique_ptr<Tooltip> tooltip); ~TooltipController() override; // Overridden from aura::client::TooltipClient. @@ -88,7 +88,7 @@ class VIEWS_EXPORT TooltipController : public aura::client::TooltipClient, aura::Window* tooltip_window_at_mouse_press_; base::string16 tooltip_text_at_mouse_press_; - scoped_ptr<Tooltip> tooltip_; + std::unique_ptr<Tooltip> tooltip_; base::RepeatingTimer tooltip_timer_; diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc index 4fc0bc8e428..cd1e7f1a0b7 100644 --- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc +++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc @@ -15,10 +15,10 @@ #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" +#include "ui/display/screen.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/font.h" #include "ui/gfx/geometry/point.h" -#include "ui/gfx/screen.h" #include "ui/gfx/text_elider.h" #include "ui/views/corewm/tooltip_aura.h" #include "ui/views/corewm/tooltip_controller_test_helper.h" @@ -89,9 +89,9 @@ class TooltipControllerTest : public aura::test::AuraTestBase { aura::test::AuraTestBase::SetUp(); new wm::DefaultActivationClient(root_window()); #if defined(OS_CHROMEOS) - controller_.reset(new TooltipController( - scoped_ptr<views::corewm::Tooltip>( - new views::corewm::TooltipAura))); + controller_.reset( + new TooltipController(std::unique_ptr<views::corewm::Tooltip>( + new views::corewm::TooltipAura))); root_window()->AddPreTargetHandler(controller_.get()); SetTooltipClient(root_window(), controller_.get()); #endif @@ -135,15 +135,15 @@ class TooltipControllerTest : public aura::test::AuraTestBase { return view2; } - scoped_ptr<views::Widget> widget_; + std::unique_ptr<views::Widget> widget_; TooltipTestView* view_; - scoped_ptr<TooltipControllerTestHelper> helper_; - scoped_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<TooltipControllerTestHelper> helper_; + std::unique_ptr<ui::test::EventGenerator> generator_; private: - scoped_ptr<TooltipController> controller_; + std::unique_ptr<TooltipController> controller_; - scoped_ptr<views::TestViewsDelegate> views_delegate_; + std::unique_ptr<views::TestViewsDelegate> views_delegate_; #if defined(OS_WIN) ui::ScopedOleInitializer ole_initializer_; @@ -426,13 +426,13 @@ class TooltipControllerCaptureTest : public TooltipControllerTest { &screen_position_client_); #if !defined(OS_CHROMEOS) desktop_screen_.reset(CreateDesktopScreen()); - gfx::Screen::SetScreenInstance(desktop_screen_.get()); + display::Screen::SetScreenInstance(desktop_screen_.get()); #endif } void TearDown() override { #if !defined(OS_CHROMEOS) - gfx::Screen::SetScreenInstance(test_screen()); + display::Screen::SetScreenInstance(test_screen()); desktop_screen_.reset(); #endif aura::client::SetScreenPositionClient(GetRootWindow(), NULL); @@ -441,7 +441,7 @@ class TooltipControllerCaptureTest : public TooltipControllerTest { private: wm::DefaultScreenPositionClient screen_position_client_; - scoped_ptr<gfx::Screen> desktop_screen_; + std::unique_ptr<display::Screen> desktop_screen_; DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest); }; @@ -469,7 +469,8 @@ TEST_F(TooltipControllerCaptureTest, DISABLED_CloseOnCaptureLost) { // Disabled on linux as DesktopScreenX11::GetWindowAtScreenPoint() doesn't // consider z-order. -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// Disabled on Windows due to failing bots. http://crbug.com/604479 +#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_WIN) #define MAYBE_Capture DISABLED_Capture #else #define MAYBE_Capture Capture @@ -482,7 +483,7 @@ TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) { widget_->SetBounds(gfx::Rect(0, 0, 200, 200)); view_->set_tooltip_text(tooltip_text); - scoped_ptr<views::Widget> widget2(CreateWidget(root_window())); + std::unique_ptr<views::Widget> widget2(CreateWidget(root_window())); widget2->SetContentsView(new View); TooltipTestView* view2 = new TooltipTestView; widget2->GetContentsView()->AddChildView(view2); @@ -566,8 +567,8 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase { wm_state_.reset(new wm::WMState); aura::test::AuraTestBase::SetUp(); new wm::DefaultActivationClient(root_window()); - controller_.reset(new TooltipController( - scoped_ptr<corewm::Tooltip>(test_tooltip_))); + controller_.reset( + new TooltipController(std::unique_ptr<corewm::Tooltip>(test_tooltip_))); root_window()->AddPreTargetHandler(controller_.get()); SetTooltipClient(root_window(), controller_.get()); helper_.reset(new TooltipControllerTestHelper(controller_.get())); @@ -587,19 +588,19 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase { protected: // Owned by |controller_|. TestTooltip* test_tooltip_; - scoped_ptr<TooltipControllerTestHelper> helper_; - scoped_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<TooltipControllerTestHelper> helper_; + std::unique_ptr<ui::test::EventGenerator> generator_; private: - scoped_ptr<TooltipController> controller_; - scoped_ptr<wm::WMState> wm_state_; + std::unique_ptr<TooltipController> controller_; + std::unique_ptr<wm::WMState> wm_state_; DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2); }; TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) { aura::test::TestWindowDelegate test_delegate; - scoped_ptr<aura::Window> window( + std::unique_ptr<aura::Window> window( CreateNormalWindow(100, root_window(), &test_delegate)); window->SetBounds(gfx::Rect(0, 0, 300, 300)); base::string16 tooltip_text(ASCIIToUTF16(" \nx ")); @@ -612,7 +613,7 @@ TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) { // Verifies that tooltip is hidden and tooltip window closed upon cancel mode. TEST_F(TooltipControllerTest2, CloseOnCancelMode) { aura::test::TestWindowDelegate test_delegate; - scoped_ptr<aura::Window> window( + std::unique_ptr<aura::Window> window( CreateNormalWindow(100, root_window(), &test_delegate)); window->SetBounds(gfx::Rect(0, 0, 300, 300)); base::string16 tooltip_text(ASCIIToUTF16("Tooltip Text")); @@ -650,7 +651,7 @@ class TooltipControllerTest3 : public aura::test::AuraTestBase { generator_.reset(new ui::test::EventGenerator(GetRootWindow())); controller_.reset(new TooltipController( - scoped_ptr<views::corewm::Tooltip>(test_tooltip_))); + std::unique_ptr<views::corewm::Tooltip>(test_tooltip_))); GetRootWindow()->RemovePreTargetHandler( static_cast<TooltipController*>(aura::client::GetTooltipClient( widget_->GetNativeWindow()->GetRootWindow()))); @@ -676,14 +677,14 @@ class TooltipControllerTest3 : public aura::test::AuraTestBase { protected: // Owned by |controller_|. TestTooltip* test_tooltip_; - scoped_ptr<TooltipControllerTestHelper> helper_; - scoped_ptr<ui::test::EventGenerator> generator_; - scoped_ptr<views::Widget> widget_; + std::unique_ptr<TooltipControllerTestHelper> helper_; + std::unique_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<views::Widget> widget_; TooltipTestView* view_; private: - scoped_ptr<TooltipController> controller_; - scoped_ptr<wm::WMState> wm_state_; + std::unique_ptr<TooltipController> controller_; + std::unique_ptr<wm::WMState> wm_state_; #if defined(OS_WIN) ui::ScopedOleInitializer ole_initializer_; diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc index b892d3871a2..462365750fb 100644 --- a/chromium/ui/views/corewm/tooltip_win.cc +++ b/chromium/ui/views/corewm/tooltip_win.cc @@ -10,9 +10,10 @@ #include "base/i18n/rtl.h" #include "base/logging.h" #include "ui/base/l10n/l10n_util_win.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/display/win/screen_win.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/screen.h" -#include "ui/gfx/win/dpi.h" #include "ui/views/corewm/cursor_height_provider_win.h" namespace views { @@ -77,7 +78,8 @@ bool TooltipWin::EnsureTooltipWindow() { } void TooltipWin::PositionTooltip() { - gfx::Point screen_point = gfx::win::DIPToScreenPoint(location_); + gfx::Point screen_point = + display::win::ScreenWin::DIPToScreenPoint(location_); const int cursoroffset = GetCurrentCursorVisibleHeight(); screen_point.Offset(0, cursoroffset); @@ -85,19 +87,22 @@ void TooltipWin::PositionTooltip() { reinterpret_cast<LPARAM>(&toolinfo_)); const gfx::Size size(LOWORD(tooltip_size), HIWORD(tooltip_size)); - const gfx::Display display( - gfx::Screen::GetScreen()->GetDisplayNearestPoint(screen_point)); + const display::Display display( + display::Screen::GetScreen()->GetDisplayNearestPoint(location_)); gfx::Rect tooltip_bounds(screen_point, size); - tooltip_bounds.AdjustToFit(gfx::win::DIPToScreenRect(display.work_area())); + tooltip_bounds.AdjustToFit( + display::win::ScreenWin::DIPToScreenRect(parent_hwnd_, + display.work_area())); SetWindowPos(tooltip_hwnd_, NULL, tooltip_bounds.x(), tooltip_bounds.y(), 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } int TooltipWin::GetMaxWidth(const gfx::Point& location) const { - const gfx::Point screen_point = gfx::win::DIPToScreenPoint(location); - gfx::Display display( - gfx::Screen::GetScreen()->GetDisplayNearestPoint(screen_point)); + const gfx::Point screen_point = + display::win::ScreenWin::DIPToScreenPoint(location); + display::Display display( + display::Screen::GetScreen()->GetDisplayNearestPoint(screen_point)); const gfx::Rect monitor_bounds = display.bounds(); return (monitor_bounds.width() + 1) / 2; } diff --git a/chromium/ui/views/debug_utils.cc b/chromium/ui/views/debug_utils.cc index 12b4759b33d..b451c2da50e 100644 --- a/chromium/ui/views/debug_utils.cc +++ b/chromium/ui/views/debug_utils.cc @@ -7,26 +7,25 @@ #include <ostream> #include "base/logging.h" -#include "base/strings/utf_string_conversions.h" #include "ui/views/view.h" namespace views { namespace { void PrintViewHierarchyImp(const View* view, int indent, - std::wostringstream* out) { + std::ostringstream* out) { int ind = indent; while (ind-- > 0) - *out << L' '; - *out << base::UTF8ToWide(view->GetClassName()); - *out << L' '; + *out << ' '; + *out << view->GetClassName(); + *out << ' '; *out << view->id(); - *out << L' '; - *out << view->x() << L"," << view->y() << L","; - *out << view->bounds().right() << L"," << view->bounds().bottom(); - *out << L' '; + *out << ' '; + *out << view->x() << "," << view->y() << ","; + *out << view->bounds().right() << "," << view->bounds().bottom(); + *out << ' '; *out << view; - *out << L'\n'; + *out << '\n'; for (int i = 0, count = view->child_count(); i < count; ++i) PrintViewHierarchyImp(view->child_at(i), indent + 2, out); @@ -34,18 +33,18 @@ void PrintViewHierarchyImp(const View* view, void PrintFocusHierarchyImp(const View* view, int indent, - std::wostringstream* out) { + std::ostringstream* out) { int ind = indent; while (ind-- > 0) - *out << L' '; - *out << base::UTF8ToWide(view->GetClassName()); - *out << L' '; + *out << ' '; + *out << view->GetClassName(); + *out << ' '; *out << view->id(); - *out << L' '; + *out << ' '; *out << view->GetClassName(); - *out << L' '; + *out << ' '; *out << view; - *out << L'\n'; + *out << '\n'; if (view->child_count() > 0) PrintFocusHierarchyImp(view->child_at(0), indent + 2, out); @@ -57,16 +56,16 @@ void PrintFocusHierarchyImp(const View* view, } // namespace void PrintViewHierarchy(const View* view) { - std::wostringstream out; - out << L"View hierarchy:\n"; + std::ostringstream out; + out << "View hierarchy:\n"; PrintViewHierarchyImp(view, 0, &out); // Error so users in the field can generate and upload logs. LOG(ERROR) << out.str(); } void PrintFocusHierarchy(const View* view) { - std::wostringstream out; - out << L"Focus hierarchy:\n"; + std::ostringstream out; + out << "Focus hierarchy:\n"; PrintFocusHierarchyImp(view, 0, &out); // Error so users in the field can generate and upload logs. LOG(ERROR) << out.str(); diff --git a/chromium/ui/views/drag_utils.cc b/chromium/ui/views/drag_utils.cc index 9eae9f6472b..f9e6c8be5ab 100644 --- a/chromium/ui/views/drag_utils.cc +++ b/chromium/ui/views/drag_utils.cc @@ -4,10 +4,10 @@ #include "ui/views/drag_utils.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/display.h" #include "ui/gfx/geometry/size.h" -#include "ui/gfx/screen.h" #include "ui/views/widget/widget.h" namespace { @@ -16,8 +16,8 @@ float GetDeviceScaleForNativeView(views::Widget* widget) { float device_scale = 1.0f; if (widget && widget->GetNativeView()) { gfx::NativeView view = widget->GetNativeView(); - gfx::Display display = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow(view); device_scale = display.device_scale_factor(); } return device_scale; diff --git a/chromium/ui/views/event_monitor.h b/chromium/ui/views/event_monitor.h index 183e0950418..2867ecb14bc 100644 --- a/chromium/ui/views/event_monitor.h +++ b/chromium/ui/views/event_monitor.h @@ -5,7 +5,8 @@ #ifndef UI_VIEWS_EVENT_MONITOR_H_ #define UI_VIEWS_EVENT_MONITOR_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/gfx/geometry/point.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/views_export.h" @@ -25,14 +26,14 @@ class VIEWS_EXPORT EventMonitor { // Create an instance for monitoring application events. // Events will be forwarded to |event_handler| before they are dispatched to // the application. - static scoped_ptr<EventMonitor> CreateApplicationMonitor( + static std::unique_ptr<EventMonitor> CreateApplicationMonitor( ui::EventHandler* event_handler); // Create an instance for monitoring events on a specific window. // Events will be forwarded to |event_handler| before they are dispatched to // |target_window|. // The EventMonitor instance must be destroyed before |target_window|. - static scoped_ptr<EventMonitor> CreateWindowMonitor( + static std::unique_ptr<EventMonitor> CreateWindowMonitor( ui::EventHandler* event_handler, gfx::NativeWindow target_window); diff --git a/chromium/ui/views/event_monitor_aura.cc b/chromium/ui/views/event_monitor_aura.cc index 73f55b6bc23..6c52620b157 100644 --- a/chromium/ui/views/event_monitor_aura.cc +++ b/chromium/ui/views/event_monitor_aura.cc @@ -5,6 +5,7 @@ #include "ui/views/event_monitor_aura.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/events/event_target.h" @@ -12,17 +13,17 @@ namespace views { // static -scoped_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor( +std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor( ui::EventHandler* event_handler) { - return make_scoped_ptr( + return base::WrapUnique( new EventMonitorAura(event_handler, aura::Env::GetInstance())); } // static -scoped_ptr<EventMonitor> EventMonitor::CreateWindowMonitor( +std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor( ui::EventHandler* event_handler, gfx::NativeWindow target_window) { - return make_scoped_ptr(new EventMonitorAura(event_handler, target_window)); + return base::WrapUnique(new EventMonitorAura(event_handler, target_window)); } // static diff --git a/chromium/ui/views/event_monitor_mac.mm b/chromium/ui/views/event_monitor_mac.mm index f21aae7cdd3..8fb0e0e9a3d 100644 --- a/chromium/ui/views/event_monitor_mac.mm +++ b/chromium/ui/views/event_monitor_mac.mm @@ -7,29 +7,30 @@ #import <Cocoa/Cocoa.h> #include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_handler.h" #include "ui/events/event_utils.h" -#include "ui/gfx/screen.h" namespace views { // static -scoped_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor( +std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor( ui::EventHandler* event_handler) { - return make_scoped_ptr(new EventMonitorMac(event_handler, nullptr)); + return base::WrapUnique(new EventMonitorMac(event_handler, nullptr)); } // static -scoped_ptr<EventMonitor> EventMonitor::CreateWindowMonitor( +std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor( ui::EventHandler* event_handler, gfx::NativeWindow target_window) { - return make_scoped_ptr(new EventMonitorMac(event_handler, target_window)); + return base::WrapUnique(new EventMonitorMac(event_handler, target_window)); } // static gfx::Point EventMonitor::GetLastMouseLocation() { - return gfx::Screen::GetScreen()->GetCursorScreenPoint(); + return display::Screen::GetScreen()->GetCursorScreenPoint(); } EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler, @@ -38,7 +39,7 @@ EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler, monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:NSAnyEventMask handler:^NSEvent*(NSEvent* event) { if (!target_window || [event window] == target_window) { - scoped_ptr<ui::Event> ui_event = ui::EventFromNative(event); + std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event); if (ui_event) event_handler->OnEvent(ui_event.get()); } diff --git a/chromium/ui/views/event_monitor_unittest.cc b/chromium/ui/views/event_monitor_unittest.cc index 92b364c9105..a73b1f4d148 100644 --- a/chromium/ui/views/event_monitor_unittest.cc +++ b/chromium/ui/views/event_monitor_unittest.cc @@ -32,7 +32,7 @@ class EventMonitorTest : public WidgetTest { protected: Widget* widget_; - scoped_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<ui::test::EventGenerator> generator_; ui::test::TestEventHandler handler_; private: @@ -40,7 +40,7 @@ class EventMonitorTest : public WidgetTest { }; TEST_F(EventMonitorTest, ShouldReceiveAppEventsWhileInstalled) { - scoped_ptr<EventMonitor> monitor( + std::unique_ptr<EventMonitor> monitor( EventMonitor::CreateApplicationMonitor(&handler_)); generator_->ClickLeftButton(); @@ -52,7 +52,7 @@ TEST_F(EventMonitorTest, ShouldReceiveAppEventsWhileInstalled) { } TEST_F(EventMonitorTest, ShouldReceiveWindowEventsWhileInstalled) { - scoped_ptr<EventMonitor> monitor( + std::unique_ptr<EventMonitor> monitor( EventMonitor::CreateWindowMonitor(&handler_, widget_->GetNativeWindow())); generator_->ClickLeftButton(); @@ -65,7 +65,7 @@ TEST_F(EventMonitorTest, ShouldReceiveWindowEventsWhileInstalled) { TEST_F(EventMonitorTest, ShouldNotReceiveEventsFromOtherWindow) { Widget* widget2 = CreateTopLevelNativeWidget(); - scoped_ptr<EventMonitor> monitor( + std::unique_ptr<EventMonitor> monitor( EventMonitor::CreateWindowMonitor(&handler_, widget2->GetNativeWindow())); generator_->ClickLeftButton(); diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn index 6fe7e162852..5e1cfb6492c 100644 --- a/chromium/ui/views/examples/BUILD.gn +++ b/chromium/ui/views/examples/BUILD.gn @@ -105,11 +105,12 @@ executable("views_examples_exe") { "//base", "//base:i18n", "//build/config/sanitizers:deps", + "//build/win:default_exe_manifest", "//ui/base", "//ui/compositor", "//ui/compositor:test_support", "//ui/gfx", - "//ui/gl", + "//ui/gl/init", "//ui/resources:ui_test_pak", "//ui/views", "//ui/views:test_support", @@ -161,6 +162,7 @@ executable("views_examples_with_content_exe") { ":views_examples_with_content_lib", "//base", "//build/config/sanitizers:deps", + "//build/win:default_exe_manifest", "//content", "//content:sandbox_helper_win", "//sandbox", diff --git a/chromium/ui/views/examples/DEPS b/chromium/ui/views/examples/DEPS index 06e440bbb91..47e7bcdb2eb 100644 --- a/chromium/ui/views/examples/DEPS +++ b/chromium/ui/views/examples/DEPS @@ -2,6 +2,6 @@ include_rules = [ "+content/public", "+content/shell", "+sandbox", - "+ui/gl/gl_surface.h", # To initialize GL bindings. + "+ui/gl/init/gl_factory.h", # To initialize GL bindings. "+ui/views_content_client", ] diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc index 597b7adcc61..6aa47909522 100644 --- a/chromium/ui/views/examples/bubble_example.cc +++ b/chromium/ui/views/examples/bubble_example.cc @@ -6,7 +6,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" @@ -49,12 +49,14 @@ base::string16 GetArrowName(BubbleBorder::Arrow arrow) { return ASCIIToUTF16("INVALID"); } -class ExampleBubble : public BubbleDelegateView { +class ExampleBubble : public BubbleDialogDelegateView { public: - ExampleBubble(View* anchor, BubbleBorder::Arrow arrow) - : BubbleDelegateView(anchor, arrow) {} + ExampleBubble(View* anchor, BubbleBorder::Arrow arrow) + : BubbleDialogDelegateView(anchor, arrow) {} protected: + int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; } + void Init() override { SetLayoutManager(new BoxLayout(BoxLayout::kVertical, 50, 50, 0)); AddChildView(new Label(GetArrowName(arrow()))); @@ -117,7 +119,7 @@ void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) { if (sender == persistent_) bubble->set_close_on_deactivate(false); - BubbleDelegateView::CreateBubble(bubble); + BubbleDialogDelegateView::CreateBubble(bubble); if (sender == align_to_edge_) bubble->SetAlignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); diff --git a/chromium/ui/views/examples/button_example.cc b/chromium/ui/views/examples/button_example.cc index 2cf42afa9e3..9736f85e139 100644 --- a/chromium/ui/views/examples/button_example.cc +++ b/chromium/ui/views/examples/button_example.cc @@ -29,12 +29,7 @@ const char kLongText[] = "Start of Really Really Really Really Really Really " namespace views { namespace examples { -ButtonExample::ButtonExample() - : ExampleBase("Button"), - label_button_(NULL), - image_button_(NULL), - icon_(NULL), - count_(0) { +ButtonExample::ButtonExample() : ExampleBase("Button") { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); icon_ = rb.GetImageNamed(IDR_CLOSE_H).ToImageSkia(); } @@ -49,19 +44,18 @@ void ButtonExample::CreateExampleView(View* container) { container->SetLayoutManager(layout); label_button_ = new LabelButton(this, ASCIIToUTF16(kLabelButton)); - label_button_->SetFocusable(true); + label_button_->SetFocusForPlatform(); + label_button_->set_request_focus_on_press(true); container->AddChildView(label_button_); - LabelButton* styled_button = - new LabelButton(this, ASCIIToUTF16("Styled Button")); - styled_button->SetStyle(Button::STYLE_BUTTON); - container->AddChildView(styled_button); + styled_button_ = new LabelButton(this, ASCIIToUTF16("Styled Button")); + styled_button_->SetStyle(Button::STYLE_BUTTON); + container->AddChildView(styled_button_); - LabelButton* disabled_button = - new LabelButton(this, ASCIIToUTF16("Disabled Button")); - disabled_button->SetStyle(Button::STYLE_BUTTON); - disabled_button->SetState(Button::STATE_DISABLED); - container->AddChildView(disabled_button); + disabled_button_ = new LabelButton(this, ASCIIToUTF16("Disabled Button")); + disabled_button_->SetStyle(Button::STYLE_BUTTON); + disabled_button_->SetState(Button::STATE_DISABLED); + container->AddChildView(disabled_button_); container->AddChildView(new BlueButton(this, ASCIIToUTF16("Blue Button"))); @@ -78,7 +72,8 @@ void ButtonExample::CreateExampleView(View* container) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); image_button_ = new ImageButton(this); - image_button_->SetFocusable(true); + image_button_->SetFocusForPlatform(); + image_button_->set_request_focus_on_press(true); image_button_->SetImage(ImageButton::STATE_NORMAL, rb.GetImageNamed(IDR_CLOSE).ToImageSkia()); image_button_->SetImage(ImageButton::STATE_HOVERED, @@ -88,41 +83,51 @@ void ButtonExample::CreateExampleView(View* container) { container->AddChildView(image_button_); } -void ButtonExample::LabelButtonPressed(const ui::Event& event) { +void ButtonExample::LabelButtonPressed(LabelButton* label_button, + const ui::Event& event) { PrintStatus("Label Button Pressed! count: %d", ++count_); if (event.IsControlDown()) { if (event.IsShiftDown()) { - label_button_->SetText(ASCIIToUTF16( - label_button_->GetText().empty() + label_button->SetText(ASCIIToUTF16( + label_button->GetText().empty() ? kLongText - : label_button_->GetText().length() > 50 ? kLabelButton : "")); + : label_button->GetText().length() > 50 ? kLabelButton : "")); } else if (event.IsAltDown()) { - label_button_->SetImage(Button::STATE_NORMAL, - label_button_->GetImage(Button::STATE_NORMAL).isNull() ? - *icon_ : gfx::ImageSkia()); + label_button->SetImage( + Button::STATE_NORMAL, + label_button->GetImage(Button::STATE_NORMAL).isNull() + ? *icon_ + : gfx::ImageSkia()); } else { static int alignment = 0; - label_button_->SetHorizontalAlignment( + label_button->SetHorizontalAlignment( static_cast<gfx::HorizontalAlignment>(++alignment % 3)); } } else if (event.IsShiftDown()) { if (event.IsAltDown()) { - label_button_->SetFocusable(!label_button_->IsFocusable()); + // Toggle focusability. + label_button_->IsAccessibilityFocusable() + ? label_button_->SetFocusBehavior(View::FocusBehavior::NEVER) + : label_button_->SetFocusForPlatform(); } else { - label_button_->SetStyle(static_cast<Button::ButtonStyle>( - (label_button_->style() + 1) % Button::STYLE_COUNT)); + label_button->SetStyle(static_cast<Button::ButtonStyle>( + (label_button->style() + 1) % Button::STYLE_COUNT)); } } else if (event.IsAltDown()) { - label_button_->SetIsDefault(!label_button_->is_default()); + label_button->SetIsDefault(!label_button->is_default()); } else { - label_button_->SetMinSize(gfx::Size()); + label_button->SetMinSize(gfx::Size()); } example_view()->GetLayoutManager()->Layout(example_view()); } void ButtonExample::ButtonPressed(Button* sender, const ui::Event& event) { if (sender == label_button_) - LabelButtonPressed(event); + LabelButtonPressed(label_button_, event); + else if (sender == styled_button_) + LabelButtonPressed(styled_button_, event); + else if (sender == disabled_button_) + LabelButtonPressed(disabled_button_, event); else PrintStatus("Image Button Pressed! count: %d", ++count_); } diff --git a/chromium/ui/views/examples/button_example.h b/chromium/ui/views/examples/button_example.h index 566d3f09bf2..956759cf412 100644 --- a/chromium/ui/views/examples/button_example.h +++ b/chromium/ui/views/examples/button_example.h @@ -27,19 +27,21 @@ class VIEWS_EXAMPLES_EXPORT ButtonExample : public ExampleBase, void CreateExampleView(View* container) override; private: - void LabelButtonPressed(const ui::Event& event); + void LabelButtonPressed(LabelButton* label_button, const ui::Event& event); // ButtonListener: void ButtonPressed(Button* sender, const ui::Event& event) override; // Example buttons. - LabelButton* label_button_; - ImageButton* image_button_; + LabelButton* label_button_ = nullptr; + LabelButton* styled_button_ = nullptr; + LabelButton* disabled_button_ = nullptr; + ImageButton* image_button_ = nullptr; - const gfx::ImageSkia* icon_; + const gfx::ImageSkia* icon_ = nullptr; // The number of times the buttons are pressed. - int count_; + int count_ = 0; DISALLOW_COPY_AND_ASSIGN(ButtonExample); }; diff --git a/chromium/ui/views/examples/combobox_example.cc b/chromium/ui/views/examples/combobox_example.cc index 4c4fdb300b9..aedc8fbdef7 100644 --- a/chromium/ui/views/examples/combobox_example.cc +++ b/chromium/ui/views/examples/combobox_example.cc @@ -49,9 +49,8 @@ void ComboboxExample::CreateExampleView(View* container) { disabled_combobox_->SetSelectedIndex(4); disabled_combobox_->SetEnabled(false); - action_combobox_ = new Combobox(&combobox_model_); + action_combobox_ = new Combobox(&combobox_model_, Combobox::STYLE_ACTION); action_combobox_->set_listener(this); - action_combobox_->SetStyle(Combobox::STYLE_ACTION); // Note: STYLE_ACTION comboboxes always have the first item selected by // default. diff --git a/chromium/ui/views/examples/examples.gyp b/chromium/ui/views/examples/examples.gyp index 50790ad639a..4038d615027 100644 --- a/chromium/ui/views/examples/examples.gyp +++ b/chromium/ui/views/examples/examples.gyp @@ -19,6 +19,7 @@ '../../events/events.gyp:events', '../../gfx/gfx.gyp:gfx', '../../gfx/gfx.gyp:gfx_geometry', + '../../gfx/gfx.gyp:gfx_range', '../../gfx/gfx.gyp:gfx_vector_icons', '../../resources/ui_resources.gyp:ui_resources', '../../resources/ui_resources.gyp:ui_test_pak', @@ -161,6 +162,7 @@ 'target_name': 'views_examples_with_content_exe', 'type': 'executable', 'dependencies': [ + '../resources/views_resources.gyp:views_resources', '../../views_content_client/views_content_client.gyp:views_content_client', 'views_examples_with_content_lib', ], diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc index 11096a781c1..d3889a89a95 100644 --- a/chromium/ui/views/examples/examples_main.cc +++ b/chromium/ui/views/examples/examples_main.cc @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> + #include "base/at_exit.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/i18n/icu_util.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/power_monitor/power_monitor.h" @@ -13,11 +16,12 @@ #include "base/run_loop.h" #include "build/build_config.h" #include "ui/base/ime/input_method_initializer.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" #include "ui/compositor/test/in_process_context_factory.h" -#include "ui/gfx/screen.h" -#include "ui/gl/gl_surface.h" +#include "ui/display/screen.h" +#include "ui/gl/init/gl_factory.h" #include "ui/views/examples/example_base.h" #include "ui/views/examples/examples_window.h" #include "ui/views/test/desktop_test_views_delegate.h" @@ -55,11 +59,11 @@ int main(int argc, char** argv) { gfx::InitializeThreadedX11(); #endif - gfx::GLSurface::InitializeOneOff(); + gl::init::InitializeGLOneOff(); // The ContextFactory must exist before any Compositors are created. bool context_factory_for_test = false; - scoped_ptr<ui::InProcessContextFactory> context_factory( + std::unique_ptr<ui::InProcessContextFactory> context_factory( new ui::InProcessContextFactory(context_factory_for_test, nullptr)); context_factory->set_use_test_surface(false); @@ -73,18 +77,19 @@ int main(int argc, char** argv) { CHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); - base::PowerMonitor power_monitor(make_scoped_ptr( - new base::PowerMonitorDeviceSource)); + base::PowerMonitor power_monitor( + base::WrapUnique(new base::PowerMonitorDeviceSource)); #if defined(OS_WIN) gfx::win::MaybeInitializeDirectWrite(); #endif #if defined(USE_AURA) - aura::Env::CreateInstance(true); + std::unique_ptr<aura::Env> env = aura::Env::CreateInstance(); aura::Env::GetInstance()->set_context_factory(context_factory.get()); #endif ui::InitializeInputMethodForTesting(); + ui::MaterialDesignController::Initialize(); { views::DesktopTestViewsDelegate views_delegate; @@ -92,13 +97,14 @@ int main(int argc, char** argv) { wm::WMState wm_state; #endif #if !defined(OS_CHROMEOS) && defined(USE_AURA) - scoped_ptr<gfx::Screen> desktop_screen(views::CreateDesktopScreen()); - gfx::Screen::SetScreenInstance(desktop_screen.get()); + std::unique_ptr<display::Screen> desktop_screen( + views::CreateDesktopScreen()); + display::Screen::SetScreenInstance(desktop_screen.get()); #endif views::examples::ShowExamplesWindow( views::examples::QUIT_ON_CLOSE, nullptr, - scoped_ptr<ScopedVector<views::examples::ExampleBase>>()); + std::unique_ptr<ScopedVector<views::examples::ExampleBase>>()); base::RunLoop().Run(); @@ -108,7 +114,7 @@ int main(int argc, char** argv) { ui::ShutdownInputMethod(); #if defined(USE_AURA) - aura::Env::DeleteInstance(); + env.reset(); #endif return 0; diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc index c391b7e2b6d..57be047069c 100644 --- a/chromium/ui/views/examples/examples_window.cc +++ b/chromium/ui/views/examples/examples_window.cc @@ -47,7 +47,7 @@ namespace views { namespace examples { -typedef scoped_ptr<ScopedVector<ExampleBase> > ScopedExamples; +typedef std::unique_ptr<ScopedVector<ExampleBase>> ScopedExamples; namespace { @@ -186,7 +186,7 @@ class ExamplesWindowContents : public WidgetDelegateView, void WindowClosing() override { instance_ = NULL; if (operation_ == QUIT_ON_CLOSE) - base::MessageLoopForUI::current()->QuitWhenIdle(); + base::MessageLoop::current()->QuitWhenIdle(); } gfx::Size GetPreferredSize() const override { return gfx::Size(800, 300); } diff --git a/chromium/ui/views/examples/examples_window.h b/chromium/ui/views/examples/examples_window.h index 339389502f5..d35b8fc9a9d 100644 --- a/chromium/ui/views/examples/examples_window.h +++ b/chromium/ui/views/examples/examples_window.h @@ -5,7 +5,8 @@ #ifndef UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_H_ #define UI_VIEWS_EXAMPLES_EXAMPLES_WINDOW_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "base/memory/scoped_vector.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/examples/views_examples_export.h" @@ -30,7 +31,7 @@ enum Operation { VIEWS_EXAMPLES_EXPORT void ShowExamplesWindow( Operation operation, gfx::NativeWindow window_context, - scoped_ptr<ScopedVector<ExampleBase> > extra_examples); + std::unique_ptr<ScopedVector<ExampleBase>> extra_examples); } // namespace examples } // namespace views diff --git a/chromium/ui/views/examples/examples_window_with_content.cc b/chromium/ui/views/examples/examples_window_with_content.cc index 87d30b7b193..a2843a76aae 100644 --- a/chromium/ui/views/examples/examples_window_with_content.cc +++ b/chromium/ui/views/examples/examples_window_with_content.cc @@ -15,7 +15,7 @@ namespace examples { void ShowExamplesWindowWithContent(Operation operation, content::BrowserContext* browser_context, gfx::NativeWindow window_context) { - scoped_ptr<ScopedVector<ExampleBase> > extra_examples( + std::unique_ptr<ScopedVector<ExampleBase>> extra_examples( new ScopedVector<ExampleBase>); extra_examples->push_back(new WebViewExample(browser_context)); ShowExamplesWindow(operation, window_context, std::move(extra_examples)); diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc index 98ea080ac08..6683626e376 100644 --- a/chromium/ui/views/examples/label_example.cc +++ b/chromium/ui/views/examples/label_example.cc @@ -5,6 +5,7 @@ #include "ui/views/examples/label_example.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/views/background.h" @@ -210,7 +211,7 @@ Combobox* LabelExample::AddCombobox(GridLayout* layout, layout->StartRow(0, 0); layout->AddView(new Label(base::ASCIIToUTF16(name))); ExampleComboboxModel* model = new ExampleComboboxModel(strings, count); - example_combobox_models_.push_back(make_scoped_ptr(model)); + example_combobox_models_.push_back(base::WrapUnique(model)); Combobox* combobox = new Combobox(model); combobox->SetSelectedIndex(0); combobox->set_listener(this); diff --git a/chromium/ui/views/examples/label_example.h b/chromium/ui/views/examples/label_example.h index 3f58fff39c5..80b0d9f8b57 100644 --- a/chromium/ui/views/examples/label_example.h +++ b/chromium/ui/views/examples/label_example.h @@ -55,7 +55,7 @@ class VIEWS_EXAMPLES_EXPORT LabelExample : public ExampleBase, Textfield* textfield_; Combobox* alignment_; Combobox* elide_behavior_; - std::vector<scoped_ptr<ExampleComboboxModel>> example_combobox_models_; + std::vector<std::unique_ptr<ExampleComboboxModel>> example_combobox_models_; Checkbox* multiline_; Checkbox* shadows_; Label* custom_label_; diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc index 166a792a847..378c90a76bc 100644 --- a/chromium/ui/views/examples/menu_example.cc +++ b/chromium/ui/views/examples/menu_example.cc @@ -51,7 +51,7 @@ class ExampleMenuModel : public ui::SimpleMenuModel, COMMAND_GO_HOME, }; - scoped_ptr<ui::SimpleMenuModel> submenu_; + std::unique_ptr<ui::SimpleMenuModel> submenu_; std::set<int> checked_fruits_; int current_encoding_command_id_; @@ -71,8 +71,8 @@ class ExampleMenuButton : public MenuButton, public MenuButtonListener { ui::SimpleMenuModel* GetMenuModel(); - scoped_ptr<ExampleMenuModel> menu_model_; - scoped_ptr<MenuRunner> menu_runner_; + std::unique_ptr<ExampleMenuModel> menu_model_; + std::unique_ptr<MenuRunner> menu_runner_; DISALLOW_COPY_AND_ASSIGN(ExampleMenuButton); }; diff --git a/chromium/ui/views/examples/multiline_example.cc b/chromium/ui/views/examples/multiline_example.cc index d01b31e2d91..c6971adee33 100644 --- a/chromium/ui/views/examples/multiline_example.cc +++ b/chromium/ui/views/examples/multiline_example.cc @@ -106,6 +106,11 @@ class MultilineExample::RenderTextView : public View { InvalidateLayout(); } + void SetMaxLines(int max_lines) { + render_text_->SetMaxLines(max_lines); + render_text_->SetElideBehavior(max_lines ? gfx::ELIDE_TAIL : gfx::NO_ELIDE); + } + private: void OnBoundsChanged(const gfx::Rect& previous_bounds) override { gfx::Rect bounds = GetLocalBounds(); @@ -113,7 +118,7 @@ class MultilineExample::RenderTextView : public View { render_text_->SetDisplayRect(bounds); } - scoped_ptr<gfx::RenderText> render_text_; + std::unique_ptr<gfx::RenderText> render_text_; DISALLOW_COPY_AND_ASSIGN(RenderTextView); }; @@ -123,8 +128,8 @@ MultilineExample::MultilineExample() render_text_view_(NULL), label_(NULL), textfield_(NULL), - label_checkbox_(NULL) { -} + label_checkbox_(NULL), + elision_checkbox_(NULL) {} MultilineExample::~MultilineExample() { } @@ -147,6 +152,11 @@ void MultilineExample::CreateExampleView(View* container) { label_checkbox_->set_listener(this); label_checkbox_->set_request_focus_on_press(false); + elision_checkbox_ = new Checkbox(ASCIIToUTF16("elide text?")); + elision_checkbox_->SetChecked(false); + elision_checkbox_->set_listener(this); + elision_checkbox_->set_request_focus_on_press(false); + textfield_ = new Textfield(); textfield_->set_controller(this); textfield_->SetText(kTestString); @@ -169,6 +179,9 @@ void MultilineExample::CreateExampleView(View* container) { layout->AddView(label_); layout->StartRow(0, 0); + layout->AddView(elision_checkbox_); + + layout->StartRow(0, 0); layout->AddView(new Label(ASCIIToUTF16("Sample Text:"))); layout->AddView(textfield_); } @@ -183,9 +196,12 @@ void MultilineExample::ContentsChanged(Textfield* sender, } void MultilineExample::ButtonPressed(Button* sender, const ui::Event& event) { - DCHECK_EQ(sender, label_checkbox_); - label_->SetText(label_checkbox_->checked() ? textfield_->text() : - base::string16()); + if (sender == label_checkbox_) { + label_->SetText(label_checkbox_->checked() ? textfield_->text() + : base::string16()); + } else if (sender == elision_checkbox_) { + render_text_view_->SetMaxLines(elision_checkbox_->checked() ? 3 : 0); + } container()->Layout(); container()->SchedulePaint(); } diff --git a/chromium/ui/views/examples/multiline_example.h b/chromium/ui/views/examples/multiline_example.h index a4c3ba56ea0..4bb5b61ffe5 100644 --- a/chromium/ui/views/examples/multiline_example.h +++ b/chromium/ui/views/examples/multiline_example.h @@ -45,6 +45,9 @@ class VIEWS_EXAMPLES_EXPORT MultilineExample : public ExampleBase, // Checkbox to enable and disable text rendering in |label_|. Checkbox* label_checkbox_; + // Checkbox to toggle text elision in |render_text_view_|. + Checkbox* elision_checkbox_; + DISALLOW_COPY_AND_ASSIGN(MultilineExample); }; diff --git a/chromium/ui/views/examples/tree_view_example.cc b/chromium/ui/views/examples/tree_view_example.cc index 5da97f755bb..68f99e2fa8c 100644 --- a/chromium/ui/views/examples/tree_view_example.cc +++ b/chromium/ui/views/examples/tree_view_example.cc @@ -47,11 +47,14 @@ void TreeViewExample::CreateExampleView(View* container) { tree_view_->SetModel(&model_); tree_view_->SetController(this); add_ = new LabelButton(this, ASCIIToUTF16("Add")); - add_->SetFocusable(true); + add_->SetFocusForPlatform(); + add_->set_request_focus_on_press(true); remove_ = new LabelButton(this, ASCIIToUTF16("Remove")); - remove_->SetFocusable(true); + remove_->SetFocusForPlatform(); + remove_->set_request_focus_on_press(true); change_title_ = new LabelButton(this, ASCIIToUTF16("Change Title")); - change_title_->SetFocusable(true); + change_title_->SetFocusForPlatform(); + change_title_->set_request_focus_on_press(true); GridLayout* layout = new GridLayout(container); container->SetLayoutManager(layout); diff --git a/chromium/ui/views/examples/tree_view_example.h b/chromium/ui/views/examples/tree_view_example.h index 9ef57603823..fb0ccf93db6 100644 --- a/chromium/ui/views/examples/tree_view_example.h +++ b/chromium/ui/views/examples/tree_view_example.h @@ -15,6 +15,7 @@ namespace views { +class LabelButton; class MenuRunner; class TreeView; @@ -70,15 +71,15 @@ class VIEWS_EXAMPLES_EXPORT TreeViewExample TreeView* tree_view_; // Control buttons to modify the model. - Button* add_; - Button* remove_; - Button* change_title_; + LabelButton* add_; + LabelButton* remove_; + LabelButton* change_title_; typedef ui::TreeNodeWithValue<int> NodeType; ui::TreeNodeModel<NodeType> model_; - scoped_ptr<MenuRunner> context_menu_runner_; + std::unique_ptr<MenuRunner> context_menu_runner_; DISALLOW_COPY_AND_ASSIGN(TreeViewExample); }; diff --git a/chromium/ui/views/examples/widget_example.cc b/chromium/ui/views/examples/widget_example.cc index 0165de3f9dc..71bd71be41a 100644 --- a/chromium/ui/views/examples/widget_example.cc +++ b/chromium/ui/views/examples/widget_example.cc @@ -87,7 +87,8 @@ void WidgetExample::BuildButton(View* container, const std::string& label, int tag) { LabelButton* button = new LabelButton(this, ASCIIToUTF16(label)); - button->SetFocusable(true); + button->SetFocusForPlatform(); + button->set_request_focus_on_press(true); button->set_tag(tag); container->AddChildView(button); } diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc index c84c3152734..bd6b0dc19fe 100644 --- a/chromium/ui/views/focus/focus_manager.cc +++ b/chromium/ui/views/focus/focus_manager.cc @@ -35,7 +35,8 @@ FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate) accelerator_manager_(new ui::AcceleratorManager), shortcut_handling_suspended_(false), focus_change_reason_(kReasonDirectFocusChange), - is_changing_focus_(false) { + is_changing_focus_(false), + keyboard_accessible_(false) { DCHECK(widget_); stored_focused_view_storage_id_ = ViewStorage::GetInstance()->CreateStorageID(); @@ -297,6 +298,16 @@ View* FocusManager::GetNextFocusableView(View* original_starting_view, return NULL; } +void FocusManager::SetKeyboardAccessible(bool keyboard_accessible) { + if (keyboard_accessible == keyboard_accessible_) + return; + + keyboard_accessible_ = keyboard_accessible; + // Disabling keyboard accessibility may cause the focused view to become not + // focusable. Hence advance focus if necessary. + AdvanceFocusIfNecessary(); +} + void FocusManager::SetFocusedViewWithReason( View* view, FocusChangeReason reason) { if (focused_view_ == view) @@ -341,9 +352,9 @@ void FocusManager::AdvanceFocusIfNecessary() { // If widget is active and focused view is not focusable, advance focus or, // if not possible, clear focus. - if (focused_view_ && !focused_view_->IsAccessibilityFocusable()) { + if (focused_view_ && !IsFocusable(focused_view_)) { AdvanceFocus(false); - if (focused_view_ && !focused_view_->IsAccessibilityFocusable()) + if (focused_view_ && !IsFocusable(focused_view_)) ClearFocus(); } } @@ -393,9 +404,11 @@ bool FocusManager::RestoreFocusedView() { focus_change_reason_ = kReasonFocusRestore; } } - return true; + // The |keyboard_accessible_| mode may have changed while the widget was + // inactive. + AdvanceFocusIfNecessary(); } - return false; + return view && view == focused_view_; } void FocusManager::SetStoredFocusView(View* focus_view) { @@ -489,15 +502,6 @@ bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) { return false; } -ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator( - const ui::Accelerator& accelerator) const { - ui::AcceleratorTarget* target = - accelerator_manager_->GetCurrentTarget(accelerator); - if (!target && delegate_.get()) - target = delegate_->GetCurrentTargetForAccelerator(accelerator); - return target; -} - bool FocusManager::HasPriorityHandler( const ui::Accelerator& accelerator) const { return accelerator_manager_->HasPriorityHandler(accelerator); @@ -542,4 +546,16 @@ bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) { return false; } +bool FocusManager::IsFocusable(View* view) const { + DCHECK(view); + +// |keyboard_accessible_| is only used on Mac. +#if defined(OS_MACOSX) + return keyboard_accessible_ ? view->IsAccessibilityFocusable() + : view->IsFocusable(); +#else + return view->IsAccessibilityFocusable(); +#endif +} + } // namespace views diff --git a/chromium/ui/views/focus/focus_manager.h b/chromium/ui/views/focus/focus_manager.h index 6d5195e45e6..99ca6e67726 100644 --- a/chromium/ui/views/focus/focus_manager.h +++ b/chromium/ui/views/focus/focus_manager.h @@ -7,9 +7,9 @@ #include <list> #include <map> +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator_manager.h" @@ -201,7 +201,8 @@ class VIEWS_EXPORT FocusManager { // Restore the view saved with a previous call to StoreFocusedView(). Used // when the widget becomes active. Returns true when the previous view was - // successfully refocused - otherwise false. + // successfully refocused. In case the stored view is no longer focusable, + // it advances focus and returns false. bool RestoreFocusedView(); // Sets the |view| to be restored when calling RestoreFocusView. This is used @@ -277,12 +278,6 @@ class VIEWS_EXPORT FocusManager { void AddFocusChangeListener(FocusChangeListener* listener); void RemoveFocusChangeListener(FocusChangeListener* listener); - // Returns the AcceleratorTarget that should be activated for the specified - // keyboard accelerator, or NULL if no view is registered for that keyboard - // accelerator. - ui::AcceleratorTarget* GetCurrentTargetForAccelerator( - const ui::Accelerator& accelerator) const; - // Whether the given |accelerator| has a priority handler associated with it. bool HasPriorityHandler(const ui::Accelerator& accelerator) const; @@ -325,6 +320,12 @@ class VIEWS_EXPORT FocusManager { bool reverse, bool dont_loop); + bool keyboard_accessible() const { return keyboard_accessible_; } + + // Updates |keyboard_accessible_| to the given value and advances focus if + // necessary. + void SetKeyboardAccessible(bool keyboard_accessible); + private: // Returns the focusable view found in the FocusTraversable specified starting // at the specified view. This traverses down along the FocusTraversable @@ -338,6 +339,10 @@ class VIEWS_EXPORT FocusManager { // and should not be processed further. bool ProcessArrowKeyTraversal(const ui::KeyEvent& event); + // Whether |view| is currently focusable as per the platform's interpretation + // of |keyboard_accesible_|. + bool IsFocusable(View* view) const; + // Whether arrow key traversal is enabled. static bool arrow_key_traversal_enabled_; @@ -346,13 +351,13 @@ class VIEWS_EXPORT FocusManager { // The object which handles an accelerator when |accelerator_manager_| doesn't // handle it. - scoped_ptr<FocusManagerDelegate> delegate_; + std::unique_ptr<FocusManagerDelegate> delegate_; // The view that currently is focused. View* focused_view_; // The AcceleratorManager this FocusManager is associated with. - scoped_ptr<ui::AcceleratorManager> accelerator_manager_; + std::unique_ptr<ui::AcceleratorManager> accelerator_manager_; // Keeps track of whether shortcut handling is currently suspended. bool shortcut_handling_suspended_; @@ -370,6 +375,15 @@ class VIEWS_EXPORT FocusManager { // See description above getter. bool is_changing_focus_; + // This is true if full keyboard accessibility is needed. This causes + // IsAccessibilityFocusable() to be checked rather than IsFocusable(). This + // can be set depending on platform constraints. FocusSearch uses this in + // addition to its own accessibility mode, which handles accessibility at the + // FocusTraversable level. Currently only used on Mac, when Full Keyboard + // access is enabled. + // Default value is false. + bool keyboard_accessible_; + DISALLOW_COPY_AND_ASSIGN(FocusManager); }; diff --git a/chromium/ui/views/focus/focus_manager_delegate.h b/chromium/ui/views/focus/focus_manager_delegate.h index ca9bd71a55c..e6122c3c93c 100644 --- a/chromium/ui/views/focus/focus_manager_delegate.h +++ b/chromium/ui/views/focus/focus_manager_delegate.h @@ -26,12 +26,6 @@ class VIEWS_EXPORT FocusManagerDelegate { // target, and so on. // Returns true if an accelerator was activated. virtual bool ProcessAccelerator(const ui::Accelerator& accelerator) = 0; - - // Returns the AcceleratorTarget that should be activated for the specified - // keyboard accelerator, or NULL if no view is registered for that keyboard - // accelerator. - virtual ui::AcceleratorTarget* GetCurrentTargetForAccelerator( - const ui::Accelerator& accelerator) const = 0; }; } // namespace views diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc index 1c4f3502dbd..c37b77f2822 100644 --- a/chromium/ui/views/focus/focus_manager_unittest.cc +++ b/chromium/ui/views/focus/focus_manager_unittest.cc @@ -43,7 +43,7 @@ class SimpleTestView : public View { public: SimpleTestView(std::vector<FocusTestEvent>* event_list, int view_id) : event_list_(event_list) { - SetFocusable(true); + SetFocusBehavior(FocusBehavior::ALWAYS); set_id(view_id); } @@ -95,9 +95,9 @@ TEST_F(FocusManagerTest, ViewFocusCallbacks) { TEST_F(FocusManagerTest, FocusChangeListener) { View* view1 = new View(); - view1->SetFocusable(true); + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); View* view2 = new View(); - view2->SetFocusable(true); + view2->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(view1); GetContentsView()->AddChildView(view2); @@ -135,11 +135,11 @@ TEST_F(FocusManagerTest, WidgetFocusChangeListener) { params.bounds = gfx::Rect(10, 10, 100, 100); params.parent = GetWidget()->GetNativeView(); - scoped_ptr<Widget> widget1(new Widget); + std::unique_ptr<Widget> widget1(new Widget); widget1->Init(params); widget1->Show(); - scoped_ptr<Widget> widget2(new Widget); + std::unique_ptr<Widget> widget2(new Widget); widget2->Init(params); widget2->Show(); @@ -198,10 +198,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { TestAcceleratorTarget escape_target(true); EXPECT_EQ(return_target.accelerator_count(), 0); EXPECT_EQ(escape_target.accelerator_count(), 0); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); // Register targets. focus_manager->RegisterAccelerator(return_accelerator, @@ -211,12 +207,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { ui::AcceleratorManager::kNormalPriority, &escape_target); - // Checks if the correct target is registered. - EXPECT_EQ(&return_target, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - EXPECT_EQ(&escape_target, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); - // Hitting the return key. EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); EXPECT_EQ(return_target.accelerator_count(), 1); @@ -233,8 +223,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { focus_manager->RegisterAccelerator(return_accelerator, ui::AcceleratorManager::kNormalPriority, &return_target2); - EXPECT_EQ(&return_target2, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); // Hitting the return key; return_target2 has the priority. EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); @@ -247,9 +235,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { focus_manager->RegisterAccelerator(return_accelerator, ui::AcceleratorManager::kNormalPriority, &return_target3); - EXPECT_EQ(&return_target3, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - // Hitting the return key. // Since the event handler of return_target3 returns false, return_target2 // should be called too. @@ -260,8 +245,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { // Unregister return_target2. focus_manager->UnregisterAccelerator(return_accelerator, &return_target2); - EXPECT_EQ(&return_target3, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); // Hitting the return key. return_target3 and return_target should be called. EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); @@ -274,12 +257,6 @@ TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) { focus_manager->UnregisterAccelerator(return_accelerator, &return_target3); focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target); - // Now there is no target registered. - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); - // Hitting the return key and the escape key. Nothing should happen. EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); EXPECT_EQ(return_target.accelerator_count(), 2); @@ -297,16 +274,12 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { TestAcceleratorTarget escape_target_normal(true); EXPECT_EQ(escape_target_high.accelerator_count(), 0); EXPECT_EQ(escape_target_normal.accelerator_count(), 0); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); // Register high priority target. focus_manager->RegisterAccelerator(escape_accelerator, ui::AcceleratorManager::kHighPriority, &escape_target_high); - EXPECT_EQ(&escape_target_high, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key. @@ -321,8 +294,6 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { // Checks if the correct target is registered (same as before, the high // priority one). - EXPECT_EQ(&escape_target_high, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key. @@ -332,8 +303,6 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { // Unregister the high priority accelerator. focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target_high); - EXPECT_EQ(&escape_target_normal, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key. @@ -345,8 +314,6 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { focus_manager->RegisterAccelerator(escape_accelerator, ui::AcceleratorManager::kHighPriority, &escape_target_high); - EXPECT_EQ(&escape_target_high, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key. @@ -357,8 +324,6 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { // Unregister the normal priority accelerator. focus_manager->UnregisterAccelerator( escape_accelerator, &escape_target_normal); - EXPECT_EQ(&escape_target_high, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_TRUE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key. @@ -368,8 +333,6 @@ TEST_F(FocusManagerTest, HighPriorityHandlers) { // Unregister the high priority accelerator. focus_manager->UnregisterAccelerator(escape_accelerator, &escape_target_high); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(escape_accelerator)); EXPECT_FALSE(focus_manager->HasPriorityHandler(escape_accelerator)); // Hit the escape key (no change, no targets registered). @@ -449,21 +412,15 @@ TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) { ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); SelfUnregisteringAcceleratorTarget target(return_accelerator, focus_manager); EXPECT_EQ(target.accelerator_count(), 0); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); // Register the target. focus_manager->RegisterAccelerator(return_accelerator, ui::AcceleratorManager::kNormalPriority, &target); - EXPECT_EQ(&target, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); // Hitting the return key. The target will be unregistered. EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); EXPECT_EQ(target.accelerator_count(), 1); - EXPECT_EQ(NULL, - focus_manager->GetCurrentTargetForAccelerator(return_accelerator)); // Hitting the return key again; nothing should happen. EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); @@ -602,17 +559,17 @@ TEST_F(FocusManagerTest, FocusInAboutToRequestFocusFromTabTraversal) { // Create 3 views focuses the 3 and advances to the second. The 2nd views // implementation of AboutToRequestFocusFromTabTraversal() focuses the first. views::View* v1 = new View; - v1->SetFocusable(true); + v1->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(v1); FocusInAboutToRequestFocusFromTabTraversalView* v2 = new FocusInAboutToRequestFocusFromTabTraversalView; - v2->SetFocusable(true); + v2->SetFocusBehavior(View::FocusBehavior::ALWAYS); v2->set_view_to_focus(v1); GetContentsView()->AddChildView(v2); views::View* v3 = new View; - v3->SetFocusable(true); + v3->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(v3); v3->RequestFocus(); @@ -625,22 +582,22 @@ TEST_F(FocusManagerTest, RotatePaneFocus) { GetContentsView()->AddChildView(pane1); views::View* v1 = new View; - v1->SetFocusable(true); + v1->SetFocusBehavior(View::FocusBehavior::ALWAYS); pane1->AddChildView(v1); views::View* v2 = new View; - v2->SetFocusable(true); + v2->SetFocusBehavior(View::FocusBehavior::ALWAYS); pane1->AddChildView(v2); views::AccessiblePaneView* pane2 = new AccessiblePaneView(); GetContentsView()->AddChildView(pane2); views::View* v3 = new View; - v3->SetFocusable(true); + v3->SetFocusBehavior(View::FocusBehavior::ALWAYS); pane2->AddChildView(v3); views::View* v4 = new View; - v4->SetFocusable(true); + v4->SetFocusBehavior(View::FocusBehavior::ALWAYS); pane2->AddChildView(v4); std::vector<views::View*> panes; @@ -695,11 +652,11 @@ TEST_F(FocusManagerTest, RotatePaneFocus) { // Verifies the stored focus view tracks the focused view. TEST_F(FocusManagerTest, ImplicitlyStoresFocus) { views::View* v1 = new View; - v1->SetFocusable(true); + v1->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(v1); views::View* v2 = new View; - v2->SetFocusable(true); + v2->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(v2); // Verify a focus request on |v1| implicitly updates the stored focus view. @@ -753,7 +710,7 @@ TEST_F(FocusManagerArrowKeyTraversalTest, ArrowKeyTraversal) { std::vector<views::View*> v; for (size_t i = 0; i < 2; ++i) { views::View* view = new View; - view->SetFocusable(true); + view->SetFocusBehavior(View::FocusBehavior::ALWAYS); GetContentsView()->AddChildView(view); v.push_back(view); } @@ -784,21 +741,98 @@ TEST_F(FocusManagerArrowKeyTraversalTest, ArrowKeyTraversal) { } TEST_F(FocusManagerTest, StoreFocusedView) { - View view; - GetFocusManager()->SetFocusedView(&view); + View* view = new View; + // Add view to the view hierarchy and make it focusable. + GetWidget()->GetRootView()->AddChildView(view); + view->SetFocusBehavior(View::FocusBehavior::ALWAYS); + + GetFocusManager()->SetFocusedView(view); GetFocusManager()->StoreFocusedView(false); EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); - EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView()); + EXPECT_EQ(view, GetFocusManager()->GetStoredFocusView()); // Repeat with |true|. - GetFocusManager()->SetFocusedView(&view); + GetFocusManager()->SetFocusedView(view); GetFocusManager()->StoreFocusedView(true); EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView()); EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); - EXPECT_EQ(&view, GetFocusManager()->GetStoredFocusView()); + EXPECT_EQ(view, GetFocusManager()->GetStoredFocusView()); +} + +#if defined(OS_MACOSX) +// Test that the correct view is restored if full keyboard access is changed. +TEST_F(FocusManagerTest, StoreFocusedViewFullKeyboardAccess) { + View* view1 = new View; + View* view2 = new View; + View* view3 = new View; + + // Make view1 focusable in accessibility mode, view2 not focusable and view3 + // always focusable. + view1->SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); + view2->SetFocusBehavior(View::FocusBehavior::NEVER); + view3->SetFocusBehavior(View::FocusBehavior::ALWAYS); + + // Add views to the view hierarchy + GetWidget()->GetRootView()->AddChildView(view1); + GetWidget()->GetRootView()->AddChildView(view2); + GetWidget()->GetRootView()->AddChildView(view3); + + view1->RequestFocus(); + EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); + GetFocusManager()->StoreFocusedView(true); + EXPECT_EQ(nullptr, GetFocusManager()->GetFocusedView()); + + // Turn off full keyboard access mode and restore focused view. Since view1 is + // no longer focusable, view3 should have focus. + GetFocusManager()->SetKeyboardAccessible(false); + EXPECT_FALSE(GetFocusManager()->RestoreFocusedView()); + EXPECT_EQ(view3, GetFocusManager()->GetFocusedView()); + + GetFocusManager()->StoreFocusedView(false); + EXPECT_EQ(nullptr, GetFocusManager()->GetFocusedView()); + + // Turn on full keyboard access mode and restore focused view. Since view3 is + // still focusable, view3 should have focus. + GetFocusManager()->SetKeyboardAccessible(true); + EXPECT_TRUE(GetFocusManager()->RestoreFocusedView()); + EXPECT_EQ(view3, GetFocusManager()->GetFocusedView()); } +// Test that View::RequestFocus() respects full keyboard access mode. +TEST_F(FocusManagerTest, RequestFocus) { + View* view1 = new View(); + View* view2 = new View(); + + // Make view1 always focusable, view2 only focusable in accessibility mode. + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); + view2->SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); + + // Adds views to the view hierarchy. + GetWidget()->GetRootView()->AddChildView(view1); + GetWidget()->GetRootView()->AddChildView(view2); + + // Verify view1 can always get focus via View::RequestFocus, while view2 can + // only get focus in full keyboard accessibility mode. + EXPECT_TRUE(GetFocusManager()->keyboard_accessible()); + view1->RequestFocus(); + EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); + view2->RequestFocus(); + EXPECT_EQ(view2, GetFocusManager()->GetFocusedView()); + + // Toggle full keyboard accessibility. + GetFocusManager()->SetKeyboardAccessible(false); + + GetFocusManager()->ClearFocus(); + EXPECT_NE(view1, GetFocusManager()->GetFocusedView()); + view1->RequestFocus(); + EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); + view2->RequestFocus(); + EXPECT_EQ(view1, GetFocusManager()->GetFocusedView()); +} + +#endif + namespace { // Trivial WidgetDelegate implementation that allows setting return value of @@ -834,12 +868,12 @@ class AdvanceFocusWidgetDelegate : public WidgetDelegate { TEST_F(FocusManagerTest, AdvanceFocusStaysInWidget) { // Add |widget_view| as a child of the Widget. View* widget_view = new View; - widget_view->SetFocusable(true); + widget_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget_view->SetBounds(20, 0, 20, 20); GetContentsView()->AddChildView(widget_view); // Create a widget with two views, focus the second. - scoped_ptr<AdvanceFocusWidgetDelegate> delegate; + std::unique_ptr<AdvanceFocusWidgetDelegate> delegate; Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.child = true; @@ -850,10 +884,10 @@ TEST_F(FocusManagerTest, AdvanceFocusStaysInWidget) { params.delegate = delegate.get(); child_widget.Init(params); View* view1 = new View; - view1->SetFocusable(true); + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); view1->SetBounds(0, 0, 20, 20); View* view2 = new View; - view2->SetFocusable(true); + view2->SetFocusBehavior(View::FocusBehavior::ALWAYS); view2->SetBounds(20, 0, 20, 20); child_widget.client_view()->AddChildView(view1); child_widget.client_view()->AddChildView(view2); diff --git a/chromium/ui/views/focus/focus_search.cc b/chromium/ui/views/focus/focus_search.cc index a7ede3b0bf3..e91a701fd10 100644 --- a/chromium/ui/views/focus/focus_search.cc +++ b/chromium/ui/views/focus/focus_search.cc @@ -6,6 +6,7 @@ #include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_search.h" #include "ui/views/view.h" +#include "ui/views/widget/widget.h" namespace views { @@ -13,6 +14,12 @@ FocusSearch::FocusSearch(View* root, bool cycle, bool accessibility_mode) : root_(root), cycle_(cycle), accessibility_mode_(accessibility_mode) { +#if defined(OS_MACOSX) + // On Mac, only the keyboard accessibility mode defined in FocusManager is + // used. No special accessibility mode should be applicable for a + // FocusTraversable. + accessibility_mode_ = false; +#endif } View* FocusSearch::FindNextFocusableView(View* starting_view, @@ -99,7 +106,13 @@ bool FocusSearch::IsViewFocusableCandidate(View* v, int skip_group_id) { } bool FocusSearch::IsFocusable(View* v) { - if (accessibility_mode_) + DCHECK(root_); + // Sanity Check. Currently the FocusManager keyboard accessibility mode is + // only used on Mac, for which |accessibility_mode_| is false. + DCHECK(!(accessibility_mode_ && + root_->GetWidget()->GetFocusManager()->keyboard_accessible())); + if (accessibility_mode_ || + root_->GetWidget()->GetFocusManager()->keyboard_accessible()) return v && v->IsAccessibilityFocusable(); return v && v->IsFocusable(); } diff --git a/chromium/ui/views/focus/focus_search.h b/chromium/ui/views/focus/focus_search.h index dd139187c6a..9da7df45ae9 100644 --- a/chromium/ui/views/focus/focus_search.h +++ b/chromium/ui/views/focus/focus_search.h @@ -87,7 +87,8 @@ class VIEWS_EXPORT FocusSearch { bool IsViewFocusableCandidate(View* v, int skip_group_id); // Convenience method; returns true if a view is not NULL and is focusable - // (checking IsAccessibilityFocusable() if |accessibility_mode_| is true). + // (checking IsAccessibilityFocusable() if |accessibility_mode_| is true or + // the associated FocusManager has keyboard accessibility enabled). bool IsFocusable(View* v); // Returns the view selected for the group of the selected view. If the view diff --git a/chromium/ui/views/focus/focus_traversal_unittest.cc b/chromium/ui/views/focus/focus_traversal_unittest.cc index f1bee540cc4..4bc43614590 100644 --- a/chromium/ui/views/focus/focus_traversal_unittest.cc +++ b/chromium/ui/views/focus/focus_traversal_unittest.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/focus/focus_manager.h" - #include <stddef.h> #include "base/macros.h" @@ -23,6 +21,7 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/tabbed_pane/tabbed_pane.h" #include "ui/views/controls/textfield/textfield.h" +#include "ui/views/focus/focus_manager.h" #include "ui/views/test/focus_manager_test.h" #include "ui/views/widget/root_view.h" #include "ui/views/widget/widget.h" @@ -134,7 +133,7 @@ class BorderView : public NativeViewHost { public: explicit BorderView(View* child) : child_(child), widget_(NULL) { DCHECK(child); - SetFocusable(false); + SetFocusBehavior(FocusBehavior::NEVER); } ~BorderView() override {} @@ -202,6 +201,24 @@ class FocusTraversalTest : public FocusManagerTest { } protected: + // Helper function to advance focus multiple times in a loop. |traversal_ids| + // is an array of view ids of length |N|. |reverse| denotes the direction in + // which focus should be advanced. + template <size_t N> + void AdvanceEntireFocusLoop(const int (&traversal_ids)[N], bool reverse) { + for (size_t i = 0; i < 3; ++i) { + for (size_t j = 0; j < N; j++) { + SCOPED_TRACE(testing::Message() << "reverse:" << reverse << " i:" << i + << " j:" << j); + GetFocusManager()->AdvanceFocus(reverse); + View* focused_view = GetFocusManager()->GetFocusedView(); + EXPECT_NE(nullptr, focused_view); + if (focused_view) + EXPECT_EQ(traversal_ids[reverse ? N - j - 1 : j], focused_view->id()); + } + } + } + TabbedPane* style_tab_; BorderView* search_border_view_; DummyComboboxModel combobox_model_; @@ -543,7 +560,7 @@ void FocusTraversalTest::InitContentView() { y += 60; contents = new View(); - contents->SetFocusable(true); + contents->SetFocusBehavior(View::FocusBehavior::ALWAYS); contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE)); contents->set_id(kThumbnailContainerID); button = new LabelButton(NULL, ASCIIToUTF16("Star")); @@ -577,32 +594,74 @@ TEST_F(FocusTraversalTest, NormalTraversal) { kSearchTextfieldID, kSearchButtonID, kHelpLinkID, kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID }; + SCOPED_TRACE("NormalTraversal"); + // Let's traverse the whole focus hierarchy (several times, to make sure it // loops OK). GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, false); // Let's traverse in reverse order. GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, true); +} + +#if defined(OS_MACOSX) +// Test focus traversal with full keyboard access off on Mac. +TEST_F(FocusTraversalTest, NormalTraversalMac) { + GetFocusManager()->SetKeyboardAccessible(false); + + // Now only views with FocusBehavior of ALWAYS will be focusable. + const int kTraversalIDs[] = {kAppleTextfieldID, kOrangeTextfieldID, + kBananaTextfieldID, kKiwiTextfieldID, + kStyleTextEditID, kSearchTextfieldID, + kThumbnailContainerID}; + + SCOPED_TRACE("NormalTraversalMac"); + + // Let's traverse the whole focus hierarchy (several times, to make sure it + // loops OK). + GetFocusManager()->ClearFocus(); + AdvanceEntireFocusLoop(kTraversalIDs, false); + + // Let's traverse in reverse order. + GetFocusManager()->ClearFocus(); + AdvanceEntireFocusLoop(kTraversalIDs, true); } +// Test toggling full keyboard access correctly changes the focused view on Mac. +TEST_F(FocusTraversalTest, FullKeyboardToggle) { + // Give focus to kTopCheckBoxID . + FindViewByID(kTopCheckBoxID)->RequestFocus(); + EXPECT_EQ(kTopCheckBoxID, GetFocusManager()->GetFocusedView()->id()); + + // Turn off full keyboard access. Focus should move to next view with ALWAYS + // focus behavior. + GetFocusManager()->SetKeyboardAccessible(false); + EXPECT_EQ(kAppleTextfieldID, GetFocusManager()->GetFocusedView()->id()); + + // Turning on full keyboard access should not change the focused view. + GetFocusManager()->SetKeyboardAccessible(true); + EXPECT_EQ(kAppleTextfieldID, GetFocusManager()->GetFocusedView()->id()); + + // Give focus to kSearchButtonID. + FindViewByID(kSearchButtonID)->RequestFocus(); + EXPECT_EQ(kSearchButtonID, GetFocusManager()->GetFocusedView()->id()); + + // Turn off full keyboard access. Focus should move to next view with ALWAYS + // focus behavior. + GetFocusManager()->SetKeyboardAccessible(false); + EXPECT_EQ(kThumbnailContainerID, GetFocusManager()->GetFocusedView()->id()); + + // See focus advances correctly in both directions. + GetFocusManager()->AdvanceFocus(false); + EXPECT_EQ(kAppleTextfieldID, GetFocusManager()->GetFocusedView()->id()); + + GetFocusManager()->AdvanceFocus(true); + EXPECT_EQ(kThumbnailContainerID, GetFocusManager()->GetFocusedView()->id()); +} +#endif // OS_MACOSX + TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { const int kDisabledIDs[] = { kBananaTextfieldID, kFruitCheckBoxID, kComboboxID, kAsparagusButtonID, @@ -619,6 +678,8 @@ TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { kSearchButtonID, kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID }; + SCOPED_TRACE("TraversalWithNonEnabledViews"); + // Let's disable some views. for (size_t i = 0; i < arraysize(kDisabledIDs); i++) { View* v = FindViewByID(kDisabledIDs[i]); @@ -626,30 +687,13 @@ TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) { v->SetEnabled(false); } - View* focused_view; // Let's do one traversal (several times, to make sure it loops ok). GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, false); // Same thing in reverse. GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, true); } TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { @@ -666,6 +710,7 @@ TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { kItalicCheckBoxID, kUnderlinedCheckBoxID, kStyleHelpLinkID, kStyleTextEditID, kSearchTextfieldID, kSearchButtonID, kHelpLinkID }; + SCOPED_TRACE("TraversalWithInvisibleViews"); // Let's make some views invisible. for (size_t i = 0; i < arraysize(kInvisibleIDs); i++) { @@ -674,30 +719,13 @@ TEST_F(FocusTraversalTest, TraversalWithInvisibleViews) { v->SetVisible(false); } - View* focused_view; // Let's do one traversal (several times, to make sure it loops ok). GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, false); // Same thing in reverse. GetFocusManager()->ClearFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kTraversalIDs, true); } TEST_F(FocusTraversalTest, PaneTraversal) { @@ -710,32 +738,18 @@ TEST_F(FocusTraversalTest, PaneTraversal) { kOrangeTextfieldID, kBananaTextfieldID, kKiwiTextfieldID, kFruitButtonID, kFruitCheckBoxID, kComboboxID }; + SCOPED_TRACE("PaneTraversal"); + FocusSearch focus_search_left(left_container_, true, false); left_container_->EnablePaneFocus(&focus_search_left); FindViewByID(kComboboxID)->RequestFocus(); // Traverse the focus hierarchy within the pane several times. - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kLeftTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kLeftTraversalIDs, false); // Traverse in reverse order. FindViewByID(kAppleTextfieldID)->RequestFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kLeftTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kLeftTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kLeftTraversalIDs, true); // Now test the right container, but this time with accessibility mode. // Make some links not focusable, but mark one of them as @@ -747,34 +761,19 @@ TEST_F(FocusTraversalTest, PaneTraversal) { FocusSearch focus_search_right(right_container_, true, true); right_container_->EnablePaneFocus(&focus_search_right); - FindViewByID(kRosettaLinkID)->SetFocusable(false); - FindViewByID(kStupeurEtTremblementLinkID)->SetFocusable(false); - FindViewByID(kDinerGameLinkID)->SetAccessibilityFocusable(true); - FindViewByID(kDinerGameLinkID)->SetFocusable(false); + FindViewByID(kRosettaLinkID)->SetFocusBehavior(View::FocusBehavior::NEVER); + FindViewByID(kStupeurEtTremblementLinkID) + ->SetFocusBehavior(View::FocusBehavior::NEVER); + FindViewByID(kDinerGameLinkID) + ->SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); FindViewByID(kAsterixLinkID)->RequestFocus(); // Traverse the focus hierarchy within the pane several times. - for (int i = 0; i < 3; ++i) { - for (size_t j = 0; j < arraysize(kRightTraversalIDs); j++) { - GetFocusManager()->AdvanceFocus(false); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kRightTraversalIDs, false); // Traverse in reverse order. FindViewByID(kBroccoliButtonID)->RequestFocus(); - for (int i = 0; i < 3; ++i) { - for (int j = arraysize(kRightTraversalIDs) - 1; j >= 0; --j) { - GetFocusManager()->AdvanceFocus(true); - View* focused_view = GetFocusManager()->GetFocusedView(); - EXPECT_TRUE(focused_view != NULL); - if (focused_view) - EXPECT_EQ(kRightTraversalIDs[j], focused_view->id()); - } - } + AdvanceEntireFocusLoop(kRightTraversalIDs, true); } class FocusTraversalNonFocusableTest : public FocusManagerTest { diff --git a/chromium/ui/views/layout/box_layout_unittest.cc b/chromium/ui/views/layout/box_layout_unittest.cc index 0ef2fbad808..4b4fec21abc 100644 --- a/chromium/ui/views/layout/box_layout_unittest.cc +++ b/chromium/ui/views/layout/box_layout_unittest.cc @@ -18,7 +18,7 @@ class BoxLayoutTest : public testing::Test { public: void SetUp() override { host_.reset(new View); } - scoped_ptr<View> host_; + std::unique_ptr<View> host_; }; } // namespace diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h index d795d7c488a..6eb3c269ff9 100644 --- a/chromium/ui/views/linux_ui/linux_ui.h +++ b/chromium/ui/views/linux_ui/linux_ui.h @@ -80,6 +80,9 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory, static LinuxUI* instance(); virtual void Initialize() = 0; + // TODO(varkha): This should not be necessary once Material Design is on + // unconditionally. + virtual void MaterialDesignControllerReady() = 0; // Returns a themed image per theme_provider.h virtual gfx::Image GetThemeImageNamed(int id) const = 0; @@ -118,7 +121,7 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory, virtual bool IsStatusIconSupported() const = 0; // Create a native status icon. - virtual scoped_ptr<StatusIconLinux> CreateLinuxStatusIcon( + virtual std::unique_ptr<StatusIconLinux> CreateLinuxStatusIcon( const gfx::ImageSkia& image, const base::string16& tool_tip) const = 0; @@ -129,9 +132,9 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory, const std::string& content_type, int size) const = 0; // Builds a Border which paints the native button style. - virtual scoped_ptr<Border> CreateNativeBorder( + virtual std::unique_ptr<Border> CreateNativeBorder( views::LabelButton* owning_button, - scoped_ptr<views::LabelButtonBorder> border) = 0; + std::unique_ptr<views::LabelButtonBorder> border) = 0; // Notifies the observer about changes about how window buttons should be // laid out. If the order is anything other than the default min,max,close on diff --git a/chromium/ui/views/mouse_watcher.cc b/chromium/ui/views/mouse_watcher.cc index c28005fdc54..686cb071d93 100644 --- a/chromium/ui/views/mouse_watcher.cc +++ b/chromium/ui/views/mouse_watcher.cc @@ -83,7 +83,7 @@ class MouseWatcher::Observer : public ui::EventHandler { private: MouseWatcher* mouse_watcher_; - scoped_ptr<views::EventMonitor> event_monitor_; + std::unique_ptr<views::EventMonitor> event_monitor_; // A factory that is used to construct a delayed callback to the listener. base::WeakPtrFactory<Observer> notify_listener_factory_; diff --git a/chromium/ui/views/mouse_watcher.h b/chromium/ui/views/mouse_watcher.h index 89e13584a74..4737d81d1b6 100644 --- a/chromium/ui/views/mouse_watcher.h +++ b/chromium/ui/views/mouse_watcher.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_MOUSE_WATCHER_H_ #define UI_VIEWS_MOUSE_WATCHER_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/views_export.h" @@ -78,13 +79,13 @@ class VIEWS_EXPORT MouseWatcher { void NotifyListener(); // Host we're listening for events over. - scoped_ptr<MouseWatcherHost> host_; + std::unique_ptr<MouseWatcherHost> host_; // Our listener. MouseWatcherListener* listener_; // Does the actual work of listening for mouse events. - scoped_ptr<Observer> observer_; + std::unique_ptr<Observer> observer_; // See description above setter. base::TimeDelta notify_on_exit_time_; diff --git a/chromium/ui/views/mouse_watcher_view_host.cc b/chromium/ui/views/mouse_watcher_view_host.cc index ac02b3cf4bf..b6856e03863 100644 --- a/chromium/ui/views/mouse_watcher_view_host.cc +++ b/chromium/ui/views/mouse_watcher_view_host.cc @@ -4,7 +4,7 @@ #include "ui/views/mouse_watcher_view_host.h" -#include "ui/gfx/screen.h" +#include "ui/display/screen.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -49,8 +49,8 @@ bool MouseWatcherViewHost::IsMouseOverWindow() { if (!widget) return false; - return gfx::Screen::GetScreen()->GetWindowUnderCursor() == - widget->GetNativeWindow(); + return display::Screen::GetScreen()->IsWindowUnderCursor( + widget->GetNativeWindow()); } } // namespace views diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn index a9005760549..4fdfca356ea 100644 --- a/chromium/ui/views/mus/BUILD.gn +++ b/chromium/ui/views/mus/BUILD.gn @@ -5,6 +5,7 @@ import("//build/config/features.gni") import("//build/config/ui.gni") import("//mojo/public/mojo_application.gni") +import("//mojo/public/mojo_application_manifest.gni") import("//testing/test.gni") import("//tools/grit/repack.gni") @@ -16,6 +17,8 @@ component("mus") { "aura_init.h", "display_converter.cc", "display_converter.h", + "display_list.cc", + "display_list.h", "input_method_mus.cc", "input_method_mus.h", "mus_export.h", @@ -57,8 +60,6 @@ component("mus") { "//components/mus/gles2:lib", "//components/mus/public/cpp", "//components/mus/public/interfaces", - "//components/resource_provider/public/cpp", - "//components/resource_provider/public/interfaces", "//mojo/converters/geometry", "//mojo/converters/ime", "//mojo/converters/input_events", @@ -66,32 +67,33 @@ component("mus") { "//mojo/platform_handle:for_component", "//mojo/public/c/system:for_component", "//mojo/public/cpp/bindings", - "//mojo/shell/public/cpp", - "//mojo/shell/public/interfaces", + "//services/catalog/public/cpp", + "//services/shell/public/cpp", + "//services/shell/public/interfaces", "//skia", "//third_party/icu", "//ui/aura", "//ui/compositor", + "//ui/display", "//ui/events", "//ui/events:events_base", + "//ui/events/devices", "//ui/gfx", "//ui/gfx/geometry", "//ui/gl", + "//ui/mojo/display", "//ui/mojo/ime:interfaces_cpp_sources", - "//ui/mojo/init", "//ui/native_theme", "//ui/platform_window", "//ui/views", "//ui/wm", ] - data_deps = [ - "//components/resource_provider", - ] - if (is_linux && !is_android) { deps += [ "//components/font_service/public/cpp" ] - data_deps += [ "//components/font_service" ] + data_deps = [ + "//components/font_service", + ] } } @@ -127,11 +129,36 @@ group("for_shared_library") { } } -group("tests") { +source_set("test_support") { testonly = true + sources = [ + "../test/native_widget_factory_mus.cc", + "../views_test_suite.cc", + "../views_test_suite.h", + "views_mus_test_suite.cc", + "views_mus_test_suite.h", + ] + deps = [ - ":views_mus_unittests", + ":mus", + "//base", + "//base/test:test_support", + "//components/mus/common:mus_common", + "//services/shell/background:lib", + "//services/shell/background/tests:test_support", + "//services/shell/public/cpp:sources", + "//testing/gtest", + "//ui/aura", + "//ui/gl:test_support", + "//ui/resources", + "//ui/resources:ui_test_pak", + "//ui/views", + "//ui/views:test_support_internal", + ] + + data_deps = [ + "//ui/resources:ui_test_pak_data", ] } @@ -142,30 +169,26 @@ test("views_mus_unittests") { # TODO(sky): add more files. sources = [ - "../run_all_unittests.cc", - "../run_all_unittests.h", - "../test/native_widget_factory_mus.cc", "../view_targeter_unittest.cc", "../widget/native_widget_unittest.cc", "../widget/widget_unittest.cc", + "display_list_unittest.cc", "native_widget_mus_unittest.cc", - "platform_test_helper_mus.cc", "run_all_unittests_mus.cc", + "screen_mus_unittest.cc", + "window_manager_connection_unittest.cc", ] deps = [ ":mus", + ":test_support", "//base", "//base:i18n", - "//base/test:test_support", "//cc", "//components/mus/public/cpp", + "//components/mus/public/cpp/tests:unittest_support", "//components/mus/public/interfaces", - "//mojo/shell/background:lib", - "//mojo/shell/background:main", - "//mojo/shell/background/tests:test_support", - "//mojo/shell/public/cpp:sources", - "//mojo/shell/runner/host:lib", + "//services/shell/background:main", # Provides main(). "//skia", "//testing/gtest", "//third_party/icu", @@ -182,10 +205,7 @@ test("views_mus_unittests") { "//ui/events/platform", "//ui/gfx:test_support", "//ui/gfx/geometry", - "//ui/gl:test_support", - "//ui/resources", "//ui/strings", - "//ui/touch_selection", "//ui/views", "//ui/views:test_support_internal", "//ui/wm", @@ -193,15 +213,10 @@ test("views_mus_unittests") { ] data_deps = [ + ":unittests_manifest", "//mash/wm", ] - # TODO(thakis): This should be a data_deps on //ui/resources:ui_test_pak, but - # that has no effect. (See similar TODOs elsewhere ui_test.pak is listed) - data = [ - "$root_out_dir/ui_test.pak", - ] - if (is_win) { deps += [ "//build/win:default_exe_manifest", @@ -228,6 +243,66 @@ test("views_mus_unittests") { } } +# Tests that must run sequentially because they access system-wide features +# like capture. +test("views_mus_interactive_ui_tests") { + testonly = true + + configs += [ "//build/config:precompiled_headers" ] + + sources = [ + "../widget/widget_interactive_uitest.cc", + "interactive_ui_tests_mus.cc", + ] + + deps = [ + ":mus", + ":test_support", + "//base", + "//services/shell/background:main", # Provides main(). + "//ui/aura", + "//ui/base", + "//ui/base/ime", + "//ui/events:events_base", + "//ui/events:test_support", + "//ui/gl:test_support", + "//ui/touch_selection", + "//ui/views", + "//ui/views:test_support_internal", + "//ui/wm", + ] + + data_deps = [ + ":interactive_ui_tests_manifest", + "//mash/wm", + ] + + if (is_win) { + deps += [ + "//build/win:default_exe_manifest", + "//third_party/iaccessible2", + "//third_party/wtl", + ] + libs = [ + "imm32.lib", + "oleacc.lib", + "comctl32.lib", + ] + } +} + +mojo_application_manifest("unittests_manifest") { + type = "exe" + application_name = "views_mus_unittests" + source = "unittests_manifest.json" +} + +mojo_application_manifest("interactive_ui_tests_manifest") { + type = "exe" + application_name = "views_mus_interactive_ui_tests" + source = "interactive_ui_tests_manifest.json" +} + group("for_component") { public_deps = [ ":mus", diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS index a6ef8809458..9f23b5b7592 100644 --- a/chromium/ui/views/mus/DEPS +++ b/chromium/ui/views/mus/DEPS @@ -5,11 +5,11 @@ include_rules = [ "+components/bitmap_uploader", "+components/gpu", "+components/mus", - "+components/resource_provider", - "+mojo/shell/public", "+mojo/cc", "+mojo/converters", "+mojo/public", + "+services/catalog/public", + "+services/shell/public", "+skia", "+ui/aura", "+ui/base", @@ -17,14 +17,14 @@ include_rules = [ "+ui/events", "+ui/gfx", "+ui/gl", + "+ui/mojo/display", "+ui/mojo/ime", - "+ui/mojo/init", "+ui/platform_window", "+ui/wm", ] specific_include_rules = { - "platform_test_helper_mus.cc": [ - "+mojo/shell/background", + "views_mus_test_suite.cc": [ + "+services/shell/background", ], } diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc index 2b08108882e..5335188700b 100644 --- a/chromium/ui/views/mus/aura_init.cc +++ b/chromium/ui/views/mus/aura_init.cc @@ -10,10 +10,11 @@ #include "base/macros.h" #include "base/path_service.h" #include "build/build_config.h" -#include "components/resource_provider/public/cpp/resource_loader.h" -#include "mojo/shell/public/cpp/connector.h" +#include "services/catalog/public/cpp/resource_loader.h" +#include "services/shell/public/cpp/connector.h" #include "ui/aura/env.h" #include "ui/base/ime/input_method_initializer.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" #include "ui/views/views_delegate.h" @@ -50,11 +51,12 @@ class MusViewsDelegate : public ViewsDelegate { } // namespace -AuraInit::AuraInit(mojo::Connector* connector, const std::string& resource_file) +AuraInit::AuraInit(shell::Connector* connector, + const std::string& resource_file) : resource_file_(resource_file), + env_(aura::Env::CreateInstance()), views_delegate_(new MusViewsDelegate) { - aura::Env::CreateInstance(false); - + ui::MaterialDesignController::Initialize(); InitializeResources(connector); ui::InitializeInputMethodForTesting(); @@ -72,15 +74,16 @@ AuraInit::~AuraInit() { #endif } -void AuraInit::InitializeResources(mojo::Connector* connector) { +void AuraInit::InitializeResources(shell::Connector* connector) { if (ui::ResourceBundle::HasSharedInstance()) return; - resource_provider::ResourceLoader resource_loader( - connector, GetResourcePaths(resource_file_)); - CHECK(resource_loader.BlockUntilLoaded()); - CHECK(resource_loader.loaded()); + catalog::ResourceLoader loader; + filesystem::mojom::DirectoryPtr directory; + connector->ConnectToInterface("mojo:catalog", &directory); + CHECK(loader.OpenFiles(std::move(directory), + GetResourcePaths(resource_file_))); ui::RegisterPathProvider(); - base::File pak_file = resource_loader.ReleaseFile(resource_file_); + base::File pak_file = loader.TakeFile(resource_file_); base::File pak_file_2 = pak_file.Duplicate(); ui::ResourceBundle::InitSharedInstanceWithPakFileRegion( std::move(pak_file), base::MemoryMappedFile::Region::kWholeFile); @@ -89,7 +92,7 @@ void AuraInit::InitializeResources(mojo::Connector* connector) { // Initialize the skia font code to go ask fontconfig underneath. #if defined(OS_LINUX) && !defined(OS_ANDROID) - font_loader_ = skia::AdoptRef(new font_service::FontLoader(connector)); + font_loader_ = sk_make_sp<font_service::FontLoader>(connector); SkFontConfigInterface::SetGlobal(font_loader_.get()); #endif diff --git a/chromium/ui/views/mus/aura_init.h b/chromium/ui/views/mus/aura_init.h index 521acac91ee..9330845f17b 100644 --- a/chromium/ui/views/mus/aura_init.h +++ b/chromium/ui/views/mus/aura_init.h @@ -5,19 +5,23 @@ #ifndef UI_VIEWS_MUS_AURA_INIT_H_ #define UI_VIEWS_MUS_AURA_INIT_H_ +#include <memory> #include <string> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "build/build_config.h" -#include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkRefCnt.h" #include "ui/views/mus/mus_export.h" +namespace aura { +class Env; +} + namespace font_service { class FontLoader; } -namespace mojo { +namespace shell { class Connector; } @@ -28,19 +32,20 @@ class ViewsDelegate; // |resource_file| is the path to the apk file containing the resources. class VIEWS_MUS_EXPORT AuraInit { public: - AuraInit(mojo::Connector* connector, const std::string& resource_file); + AuraInit(shell::Connector* connector, const std::string& resource_file); ~AuraInit(); private: - void InitializeResources(mojo::Connector* connector); + void InitializeResources(shell::Connector* connector); #if defined(OS_LINUX) && !defined(OS_ANDROID) - skia::RefPtr<font_service::FontLoader> font_loader_; + sk_sp<font_service::FontLoader> font_loader_; #endif const std::string resource_file_; - scoped_ptr<ViewsDelegate> views_delegate_; + std::unique_ptr<aura::Env> env_; + std::unique_ptr<ViewsDelegate> views_delegate_; DISALLOW_COPY_AND_ASSIGN(AuraInit); }; diff --git a/chromium/ui/views/mus/display_converter.cc b/chromium/ui/views/mus/display_converter.cc index fce58f6a114..0a66aa62ff2 100644 --- a/chromium/ui/views/mus/display_converter.cc +++ b/chromium/ui/views/mus/display_converter.cc @@ -11,14 +11,14 @@ namespace views { -std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window) { +std::vector<display::Display> GetDisplaysFromWindow(mus::Window* window) { static int64_t synthesized_display_id = 2000; - gfx::Display display; + display::Display display; display.set_id(synthesized_display_id++); display.SetScaleAndBounds( window->viewport_metrics().device_pixel_ratio, gfx::Rect(window->viewport_metrics().size_in_pixels.To<gfx::Size>())); - std::vector<gfx::Display> displays; + std::vector<display::Display> displays; displays.push_back(display); return displays; } diff --git a/chromium/ui/views/mus/display_converter.h b/chromium/ui/views/mus/display_converter.h index 6e61bf395db..74de33d5400 100644 --- a/chromium/ui/views/mus/display_converter.h +++ b/chromium/ui/views/mus/display_converter.h @@ -7,7 +7,7 @@ #include <vector> -#include "ui/gfx/display.h" +#include "ui/display/display.h" #include "ui/views/mus/mus_export.h" namespace mus { @@ -16,8 +16,8 @@ class Window; namespace views { -std::vector<gfx::Display> VIEWS_MUS_EXPORT GetDisplaysFromWindow( - mus::Window* window); +std::vector<display::Display> VIEWS_MUS_EXPORT +GetDisplaysFromWindow(mus::Window* window); } // namespace views diff --git a/chromium/ui/views/mus/display_list.cc b/chromium/ui/views/mus/display_list.cc new file mode 100644 index 00000000000..5be844ca52f --- /dev/null +++ b/chromium/ui/views/mus/display_list.cc @@ -0,0 +1,109 @@ +// Copyright 2016 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 "ui/views/mus/display_list.h" + +#include "ui/display/display_finder.h" +#include "ui/display/display_observer.h" + +namespace views { + +DisplayList::DisplayList() {} + +DisplayList::~DisplayList() {} + +void DisplayList::AddObserver(display::DisplayObserver* observer) { + observers_.AddObserver(observer); +} + +void DisplayList::RemoveObserver(display::DisplayObserver* observer) { + observers_.RemoveObserver(observer); +} + +DisplayList::Displays::const_iterator DisplayList::FindDisplayById( + int64_t id) const { + for (auto iter = displays_.begin(); iter != displays_.end(); ++iter) { + if (iter->id() == id) + return iter; + } + return displays_.end(); +} + +DisplayList::Displays::iterator DisplayList::FindDisplayById(int64_t id) { + for (auto iter = displays_.begin(); iter != displays_.end(); ++iter) { + if (iter->id() == id) + return iter; + } + return displays_.end(); +} + +DisplayList::Displays::const_iterator DisplayList::GetPrimaryDisplayIterator() + const { + return primary_display_index_ == -1 + ? displays_.end() + : displays_.begin() + primary_display_index_; +} + +void DisplayList::UpdateDisplay(const display::Display& display, Type type) { + auto iter = FindDisplayById(display.id()); + DCHECK(iter != displays_.end()); + + display::Display* local_display = &(*iter); + uint32_t changed_values = 0; + if (type == Type::PRIMARY && + static_cast<int>(iter - displays_.begin()) != + static_cast<int>(GetPrimaryDisplayIterator() - displays_.begin())) { + primary_display_index_ = static_cast<int>(iter - displays_.begin()); + // ash::DisplayManager only notifies for the Display gaining primary, not + // the one losing it. + changed_values |= display::DisplayObserver::DISPLAY_METRIC_PRIMARY; + } + if (local_display->bounds() != display.bounds()) { + local_display->set_bounds(display.bounds()); + changed_values |= display::DisplayObserver::DISPLAY_METRIC_BOUNDS; + } + if (local_display->work_area() != display.work_area()) { + local_display->set_work_area(display.work_area()); + changed_values |= display::DisplayObserver::DISPLAY_METRIC_WORK_AREA; + } + if (local_display->rotation() != display.rotation()) { + local_display->set_rotation(display.rotation()); + changed_values |= display::DisplayObserver::DISPLAY_METRIC_ROTATION; + } + if (local_display->device_scale_factor() != display.device_scale_factor()) { + local_display->set_device_scale_factor(display.device_scale_factor()); + changed_values |= + display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR; + } + FOR_EACH_OBSERVER(display::DisplayObserver, observers_, + OnDisplayMetricsChanged(*local_display, changed_values)); +} + +void DisplayList::AddDisplay(const display::Display& display, Type type) { + DCHECK(displays_.end() == FindDisplayById(display.id())); + displays_.push_back(display); + if (type == Type::PRIMARY) + primary_display_index_ = static_cast<int>(displays_.size()) - 1; + FOR_EACH_OBSERVER(display::DisplayObserver, observers_, + OnDisplayAdded(display)); +} + +void DisplayList::RemoveDisplay(int64_t id) { + auto iter = FindDisplayById(id); + DCHECK(displays_.end() != iter); + if (primary_display_index_ == static_cast<int>(iter - displays_.begin())) { + // We expect the primary to change before removing it. The only case we + // allow removal of the primary is if it is the list display. + DCHECK_EQ(1u, displays_.size()); + primary_display_index_ = -1; + } else if (primary_display_index_ > + static_cast<int>(iter - displays_.begin())) { + primary_display_index_--; + } + const display::Display display = *iter; + displays_.erase(iter); + FOR_EACH_OBSERVER(display::DisplayObserver, observers_, + OnDisplayRemoved(display)); +} +} // namespace views diff --git a/chromium/ui/views/mus/display_list.h b/chromium/ui/views/mus/display_list.h new file mode 100644 index 00000000000..19b0ac97f11 --- /dev/null +++ b/chromium/ui/views/mus/display_list.h @@ -0,0 +1,69 @@ +// Copyright 2016 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 UI_VIEWS_MUS_DISPLAY_LIST_H_ +#define UI_VIEWS_MUS_DISPLAY_LIST_H_ + +#include <stdint.h> + +#include <vector> + +#include "base/observer_list.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "ui/display/display.h" +#include "ui/views/mus/mus_export.h" + +namespace display { +class Display; +class DisplayObserver; +} + +namespace views { + +// Maintains an ordered list of display::Displays as well as operations to add, +// remove and update said list. Additionally maintains display::DisplayObservers +// and updates them as appropriate. +class VIEWS_MUS_EXPORT DisplayList { + public: + using Displays = std::vector<display::Display>; + + enum class Type { + PRIMARY, + NOT_PRIMARY, + }; + + DisplayList(); + ~DisplayList(); + + void AddObserver(display::DisplayObserver* observer); + void RemoveObserver(display::DisplayObserver* observer); + + const Displays& displays() const { return displays_; } + + Displays::const_iterator FindDisplayById(int64_t id) const; + Displays::iterator FindDisplayById(int64_t id); + + Displays::const_iterator GetPrimaryDisplayIterator() const; + + // Updates the cached id based on display.id() as well as whether the Display + // is the primary display. + void UpdateDisplay(const display::Display& display, Type type); + + // Adds a new Display. + void AddDisplay(const display::Display& display, Type type); + + // Removes the Display with the specified id. + void RemoveDisplay(int64_t id); + + private: + std::vector<display::Display> displays_; + int primary_display_index_ = -1; + base::ObserverList<display::DisplayObserver> observers_; + + DISALLOW_COPY_AND_ASSIGN(DisplayList); +}; + +} // namespace views + +#endif // UI_VIEWS_MUS_DISPLAY_LIST_H_ diff --git a/chromium/ui/views/mus/display_list_unittest.cc b/chromium/ui/views/mus/display_list_unittest.cc new file mode 100644 index 00000000000..93cdc81e608 --- /dev/null +++ b/chromium/ui/views/mus/display_list_unittest.cc @@ -0,0 +1,113 @@ +// Copyright 2016 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 "ui/views/mus/display_list.h" + +#include <string> +#include <vector> + +#include "base/strings/string_number_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/display/display.h" +#include "ui/display/display_observer.h" + +using display::Display; + +namespace views { +namespace { + +class DisplayObserverImpl : public display::DisplayObserver { + public: + DisplayObserverImpl() {} + ~DisplayObserverImpl() override {} + + std::string GetAndClearChanges() { + std::string changes; + std::swap(changes, changes_); + return changes; + } + + private: + static void AddPartChange(uint32_t changed, + uint32_t part, + const std::string& description, + std::string* changed_string) { + if ((changed & part) != part) + return; + + *changed_string += " "; + *changed_string += description; + } + + void AddChange(const std::string& change) { + if (!changes_.empty()) + changes_ += "\n"; + changes_ += change; + } + + void OnDisplayAdded(const Display& new_display) override { + AddChange("Added id=" + base::Int64ToString(new_display.id())); + } + void OnDisplayRemoved(const Display& old_display) override { + AddChange("Removed id=" + base::Int64ToString(old_display.id())); + } + void OnDisplayMetricsChanged(const Display& display, + uint32_t changed_metrics) override { + std::string parts; + AddPartChange(changed_metrics, DISPLAY_METRIC_BOUNDS, "bounds", &parts); + AddPartChange(changed_metrics, DISPLAY_METRIC_WORK_AREA, "work_area", + &parts); + AddPartChange(changed_metrics, DISPLAY_METRIC_DEVICE_SCALE_FACTOR, + "scale_factor", &parts); + AddPartChange(changed_metrics, DISPLAY_METRIC_ROTATION, "rotation", &parts); + AddPartChange(changed_metrics, DISPLAY_METRIC_PRIMARY, "primary", &parts); + + AddChange("Changed id=" + base::Int64ToString(display.id()) + parts); + } + + std::string changes_; + + DISALLOW_COPY_AND_ASSIGN(DisplayObserverImpl); +}; + +TEST(DisplayListTest, AddUpdateRemove) { + DisplayList display_list; + DisplayObserverImpl observer; + display_list.AddObserver(&observer); + display_list.AddDisplay(display::Display(2, gfx::Rect(0, 0, 801, 802)), + DisplayList::Type::PRIMARY); + EXPECT_EQ("Added id=2", observer.GetAndClearChanges()); + + // Update the bounds. + { + display::Display updated_display = *(display_list.displays().begin()); + updated_display.set_bounds(gfx::Rect(0, 0, 803, 802)); + display_list.UpdateDisplay(updated_display, DisplayList::Type::PRIMARY); + EXPECT_EQ("Changed id=2 bounds", observer.GetAndClearChanges()); + } + + // Add another. + display_list.AddDisplay(display::Display(3, gfx::Rect(0, 0, 809, 802)), + DisplayList::Type::NOT_PRIMARY); + EXPECT_EQ("Added id=3", observer.GetAndClearChanges()); + ASSERT_EQ(2u, display_list.displays().size()); + EXPECT_EQ(2, display_list.displays()[0].id()); + EXPECT_EQ(3, display_list.displays()[1].id()); + EXPECT_EQ(2, display_list.GetPrimaryDisplayIterator()->id()); + + // Make the second the primary. + display_list.UpdateDisplay(display_list.displays()[1], + DisplayList::Type::PRIMARY); + EXPECT_EQ("Changed id=3 primary", observer.GetAndClearChanges()); + EXPECT_EQ(3, display_list.GetPrimaryDisplayIterator()->id()); + + // Delete the first. + display_list.RemoveDisplay(2); + ASSERT_EQ(1u, display_list.displays().size()); + EXPECT_EQ("Removed id=2", observer.GetAndClearChanges()); + EXPECT_EQ(3, display_list.GetPrimaryDisplayIterator()->id()); +} + +} // namespace +} // namespace views diff --git a/chromium/ui/views/mus/interactive_ui_tests_manifest.json b/chromium/ui/views/mus/interactive_ui_tests_manifest.json new file mode 100644 index 00000000000..a0b81fcb72e --- /dev/null +++ b/chromium/ui/views/mus/interactive_ui_tests_manifest.json @@ -0,0 +1,10 @@ +{ + "manifest_version": 1, + "name": "mojo:views_mus_interactive_ui_tests", + "display_name": "Views Mus Interactive UI Tests", + "capabilities": { + "required": { + "*": { "classes": [ "app" ] } + } + } +} diff --git a/chromium/ui/views/mus/interactive_ui_tests_mus.cc b/chromium/ui/views/mus/interactive_ui_tests_mus.cc new file mode 100644 index 00000000000..4181166def3 --- /dev/null +++ b/chromium/ui/views/mus/interactive_ui_tests_mus.cc @@ -0,0 +1,9 @@ +// Copyright 2016 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 "ui/views/mus/views_mus_test_suite.h" + +int MasterProcessMain(int argc, char** argv) { + return views::ViewsMusTestSuite(argc, argv).RunTestsSerially(); +} diff --git a/chromium/ui/views/mus/native_widget_mus.cc b/chromium/ui/views/mus/native_widget_mus.cc index 70dd986d2c6..46a3ede494c 100644 --- a/chromium/ui/views/mus/native_widget_mus.cc +++ b/chromium/ui/views/mus/native_widget_mus.cc @@ -4,13 +4,19 @@ #include "ui/views/mus/native_widget_mus.h" +#include "base/callback.h" #include "base/macros.h" -#include "base/thread_task_runner_handle.h" +#include "base/message_loop/message_loop.h" +#include "base/threading/thread_task_runner_handle.h" #include "components/mus/public/cpp/property_type_converters.h" #include "components/mus/public/cpp/window.h" #include "components/mus/public/cpp/window_observer.h" #include "components/mus/public/cpp/window_property.h" #include "components/mus/public/cpp/window_tree_connection.h" +#include "components/mus/public/interfaces/cursor.mojom.h" +#include "components/mus/public/interfaces/window_manager.mojom.h" +#include "components/mus/public/interfaces/window_manager_constants.mojom.h" +#include "components/mus/public/interfaces/window_tree.mojom.h" #include "mojo/converters/geometry/geometry_type_converters.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/window_tree_client.h" @@ -20,8 +26,10 @@ #include "ui/aura/window.h" #include "ui/aura/window_property.h" #include "ui/base/hit_test.h" +#include "ui/events/event.h" #include "ui/gfx/canvas.h" #include "ui/native_theme/native_theme_aura.h" +#include "ui/platform_window/platform_window_delegate.h" #include "ui/views/mus/platform_window_mus.h" #include "ui/views/mus/surface_context_factory.h" #include "ui/views/mus/window_manager_constants_converters.h" @@ -32,11 +40,15 @@ #include "ui/views/window/custom_frame_view.h" #include "ui/wm/core/base_focus_rules.h" #include "ui/wm/core/capture_controller.h" +#include "ui/wm/core/cursor_manager.h" #include "ui/wm/core/default_screen_position_client.h" #include "ui/wm/core/focus_controller.h" +#include "ui/wm/core/native_cursor_manager.h" DECLARE_WINDOW_PROPERTY_TYPE(mus::Window*); +using mus::mojom::EventResult; + namespace views { namespace { @@ -44,17 +56,19 @@ DEFINE_WINDOW_PROPERTY_KEY(mus::Window*, kMusWindow, nullptr); MUS_DEFINE_WINDOW_PROPERTY_KEY(NativeWidgetMus*, kNativeWidgetMusKey, nullptr); -// TODO: figure out what this should be. +// This ensures that only the top-level aura Window can be activated. class FocusRulesImpl : public wm::BaseFocusRules { public: - FocusRulesImpl() {} + explicit FocusRulesImpl(aura::Window* root) : root_(root) {} ~FocusRulesImpl() override {} bool SupportsChildActivation(aura::Window* window) const override { - return true; + return root_ == window; } private: + aura::Window* root_; + DISALLOW_COPY_AND_ASSIGN(FocusRulesImpl); }; @@ -108,6 +122,88 @@ class NativeWidgetMusWindowTreeClient : public aura::client::WindowTreeClient { DISALLOW_COPY_AND_ASSIGN(NativeWidgetMusWindowTreeClient); }; +// A screen position client that applies the offset of the mus::Window. +class ScreenPositionClientMus : public wm::DefaultScreenPositionClient { + public: + explicit ScreenPositionClientMus(mus::Window* mus_window) + : mus_window_(mus_window) {} + ~ScreenPositionClientMus() override {} + + // wm::DefaultScreenPositionClient: + void ConvertPointToScreen(const aura::Window* window, + gfx::Point* point) override { + wm::DefaultScreenPositionClient::ConvertPointToScreen(window, point); + gfx::Rect mus_bounds = mus_window_->GetBoundsInRoot(); + point->Offset(-mus_bounds.x(), -mus_bounds.y()); + } + void ConvertPointFromScreen(const aura::Window* window, + gfx::Point* point) override { + gfx::Rect mus_bounds = mus_window_->GetBoundsInRoot(); + point->Offset(mus_bounds.x(), mus_bounds.y()); + wm::DefaultScreenPositionClient::ConvertPointFromScreen(window, point); + } + + private: + mus::Window* mus_window_; + + DISALLOW_COPY_AND_ASSIGN(ScreenPositionClientMus); +}; + +class NativeCursorManagerMus : public wm::NativeCursorManager { + public: + explicit NativeCursorManagerMus(mus::Window* mus_window) + : mus_window_(mus_window) {} + ~NativeCursorManagerMus() override {} + + // wm::NativeCursorManager: + void SetDisplay(const display::Display& display, + wm::NativeCursorManagerDelegate* delegate) override { + // We ignore this entirely, as cursor are set on the client. + } + + void SetCursor(gfx::NativeCursor cursor, + wm::NativeCursorManagerDelegate* delegate) override { + mus_window_->SetPredefinedCursor(mus::mojom::Cursor(cursor.native_type())); + delegate->CommitCursor(cursor); + } + + void SetVisibility(bool visible, + wm::NativeCursorManagerDelegate* delegate) override { + delegate->CommitVisibility(visible); + + if (visible) + SetCursor(delegate->GetCursor(), delegate); + else + mus_window_->SetPredefinedCursor(mus::mojom::Cursor::NONE); + } + + void SetCursorSet(ui::CursorSetType cursor_set, + wm::NativeCursorManagerDelegate* delegate) override { + // TODO(erg): For now, ignore the difference between SET_NORMAL and + // SET_LARGE here. This feels like a thing that mus should decide instead. + // + // Also, it's NOTIMPLEMENTED() in the desktop version!? Including not + // acknowledging the call in the delegate. + NOTIMPLEMENTED(); + } + + void SetMouseEventsEnabled( + bool enabled, + wm::NativeCursorManagerDelegate* delegate) override { + // TODO(erg): How do we actually implement this? + // + // Mouse event dispatch is potentially done in a different process, + // definitely in a different mojo service. Each app is fairly locked down. + delegate->CommitMouseEventsEnabled(enabled); + NOTIMPLEMENTED(); + } + + private: + mus::Window* mus_window_; + + DISALLOW_COPY_AND_ASSIGN(NativeCursorManagerMus); +}; + // As the window manager renderers the non-client decorations this class does // very little but honor the client area insets from the window manager. class ClientSideNonClientFrameView : public NonClientFrameView { @@ -146,15 +242,15 @@ class ClientSideNonClientFrameView : public NonClientFrameView { void ResetWindowControls() override { // TODO(sky): push to wm? } - void UpdateWindowIcon() override { - // NOTIMPLEMENTED(); - } - void UpdateWindowTitle() override { - // NOTIMPLEMENTED(); - } - void SizeConstraintsChanged() override { - // NOTIMPLEMENTED(); - } + + // These have no implementation. The Window Manager handles the actual + // rendering of the icon/title. See NonClientFrameViewMash. The values + // associated with these methods are pushed to the server by the way of + // NativeWidgetMus functions. + void UpdateWindowIcon() override {} + void UpdateWindowTitle() override {} + void SizeConstraintsChanged() override {} + gfx::Size GetPreferredSize() const override { return widget_->non_client_view() ->GetWindowBoundsForClientBounds( @@ -207,19 +303,60 @@ SkBitmap AppIconFromDelegate(WidgetDelegate* delegate) { return app_icon.GetRepresentation(1.f).sk_bitmap(); } +// Handles acknowledgement of an input event, either immediately when a nested +// message loop starts, or upon destruction. +class EventAckHandler : public base::MessageLoop::NestingObserver { + public: + explicit EventAckHandler( + std::unique_ptr<base::Callback<void(EventResult)>> ack_callback) + : ack_callback_(std::move(ack_callback)) { + DCHECK(ack_callback_); + base::MessageLoop::current()->AddNestingObserver(this); + } + + ~EventAckHandler() override { + base::MessageLoop::current()->RemoveNestingObserver(this); + if (ack_callback_) { + ack_callback_->Run(handled_ ? EventResult::HANDLED + : EventResult::UNHANDLED); + } + } + + void set_handled(bool handled) { handled_ = handled; } + + // base::MessageLoop::NestingObserver: + void OnBeginNestedMessageLoop() override { + // Acknowledge the event immediately if a nested message loop starts. + // Otherwise we appear unresponsive for the life of the nested message loop. + if (ack_callback_) { + ack_callback_->Run(EventResult::HANDLED); + ack_callback_.reset(); + } + } + + private: + std::unique_ptr<base::Callback<void(EventResult)>> ack_callback_; + bool handled_ = false; + + DISALLOW_COPY_AND_ASSIGN(EventAckHandler); +}; + } // namespace class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver { public: explicit MusWindowObserver(NativeWidgetMus* native_widget_mus) - : native_widget_mus_(native_widget_mus) { - native_widget_mus_->window_->AddObserver(this); + : native_widget_mus_(native_widget_mus), + show_state_(mus::mojom::ShowState::DEFAULT) { + mus_window()->AddObserver(this); } ~MusWindowObserver() override { - native_widget_mus_->window_->RemoveObserver(this); + mus_window()->RemoveObserver(this); } + mus::mojom::ShowState show_state() { return show_state_; } + // mus::WindowObserver: void OnWindowVisibilityChanging(mus::Window* window) override { native_widget_mus_->OnMusWindowVisibilityChanging(window); @@ -227,9 +364,76 @@ class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver { void OnWindowVisibilityChanged(mus::Window* window) override { native_widget_mus_->OnMusWindowVisibilityChanged(window); } + void OnWindowBoundsChanged(mus::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override { + platform_window_delegate()->OnBoundsChanged(new_bounds); + } + void OnWindowPredefinedCursorChanged(mus::Window* window, + mus::mojom::Cursor cursor) override { + DCHECK_EQ(window, mus_window()); + native_widget_mus_->set_last_cursor(cursor); + } + void OnWindowSharedPropertyChanged( + mus::Window* window, + const std::string& name, + const std::vector<uint8_t>* old_data, + const std::vector<uint8_t>* new_data) override { + if (name != mus::mojom::WindowManager::kShowState_Property) + return; + mus::mojom::ShowState show_state = + static_cast<mus::mojom::ShowState>(window->GetSharedProperty<int32_t>( + mus::mojom::WindowManager::kShowState_Property)); + if (show_state == show_state_) + return; + show_state_ = show_state; + ui::PlatformWindowState state = ui::PLATFORM_WINDOW_STATE_UNKNOWN; + switch (show_state_) { + case mus::mojom::ShowState::MINIMIZED: + state = ui::PLATFORM_WINDOW_STATE_MINIMIZED; + break; + case mus::mojom::ShowState::MAXIMIZED: + state = ui::PLATFORM_WINDOW_STATE_MAXIMIZED; + break; + case mus::mojom::ShowState::DEFAULT: + case mus::mojom::ShowState::INACTIVE: + case mus::mojom::ShowState::NORMAL: + case mus::mojom::ShowState::DOCKED: + // TODO(sky): support docked. + state = ui::PLATFORM_WINDOW_STATE_NORMAL; + break; + case mus::mojom::ShowState::FULLSCREEN: + state = ui::PLATFORM_WINDOW_STATE_FULLSCREEN; + break; + } + platform_window_delegate()->OnWindowStateChanged(state); + } + void OnWindowDestroyed(mus::Window* window) override { + DCHECK_EQ(mus_window(), window); + platform_window_delegate()->OnClosed(); + } + void OnWindowFocusChanged(mus::Window* gained_focus, + mus::Window* lost_focus) override { + if (gained_focus == mus_window()) + platform_window_delegate()->OnActivationChanged(true); + else if (lost_focus == mus_window()) + platform_window_delegate()->OnActivationChanged(false); + } + void OnRequestClose(mus::Window* window) override { + platform_window_delegate()->OnCloseRequest(); + } private: + mus::Window* mus_window() { return native_widget_mus_->window(); } + WindowTreeHostMus* window_tree_host() { + return native_widget_mus_->window_tree_host(); + } + ui::PlatformWindowDelegate* platform_window_delegate() { + return native_widget_mus_->window_tree_host(); + } + NativeWidgetMus* native_widget_mus_; + mus::mojom::ShowState show_state_; DISALLOW_COPY_AND_ASSIGN(MusWindowObserver); }; @@ -238,16 +442,18 @@ class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver { // NativeWidgetMus, public: NativeWidgetMus::NativeWidgetMus(internal::NativeWidgetDelegate* delegate, - mojo::Connector* connector, + shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type) : window_(window), + last_cursor_(mus::mojom::Cursor::CURSOR_NULL), native_widget_delegate_(delegate), surface_type_(surface_type), - show_state_before_fullscreen_(ui::PLATFORM_WINDOW_STATE_UNKNOWN), + show_state_before_fullscreen_(mus::mojom::ShowState::DEFAULT), ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET), content_(new aura::Window(this)), close_widget_factory_(this) { + window_->set_input_event_handler(this); mus_window_observer_.reset(new MusWindowObserver(this)); // TODO(fsamuel): Figure out lifetime of |window_|. @@ -262,7 +468,7 @@ NativeWidgetMus::NativeWidgetMus(internal::NativeWidgetDelegate* delegate, // For Chrome, we need the GpuProcessTransportFactory so that renderer and // browser pixels are composited into a single backing // SoftwareOutputDeviceMus. - if (!default_context_factory) { + if (!default_context_factory && connector) { context_factory_.reset( new SurfaceContextFactory(connector, window_, surface_type_)); aura::Env::GetInstance()->set_context_factory(context_factory_.get()); @@ -272,10 +478,14 @@ NativeWidgetMus::NativeWidgetMus(internal::NativeWidgetDelegate* delegate, } NativeWidgetMus::~NativeWidgetMus() { - if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) + if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) { + DCHECK(!window_); delete native_widget_delegate_; - else + } else { + if (window_) + window_->set_input_event_handler(nullptr); CloseNow(); + } } // static @@ -292,6 +502,17 @@ void NativeWidgetMus::NotifyFrameChanged( } } +// static +Widget* NativeWidgetMus::GetWidgetForWindow(mus::Window* window) { + if (!window) + return nullptr; + NativeWidgetMus* native_widget = + window->GetLocalProperty(kNativeWidgetMusKey); + if (!native_widget) + return nullptr; + return native_widget->GetWidget(); +} + aura::Window* NativeWidgetMus::GetRootWindow() { return window_tree_host_->window(); } @@ -305,6 +526,8 @@ void NativeWidgetMus::OnPlatformWindowClosed() { window_tree_host_->RemoveObserver(this); window_tree_host_.reset(); + cursor_manager_.reset(); // Uses |window_|. + mus_window_observer_.reset(nullptr); window_ = nullptr; @@ -348,10 +571,18 @@ void NativeWidgetMus::UpdateClientArea() { void NativeWidgetMus::ConfigurePropertiesForNewWindow( const Widget::InitParams& init_params, std::map<std::string, std::vector<uint8_t>>* properties) { + properties->insert(init_params.mus_properties.begin(), + init_params.mus_properties.end()); if (!init_params.bounds.IsEmpty()) { (*properties)[mus::mojom::WindowManager::kUserSetBounds_Property] = mojo::ConvertTo<std::vector<uint8_t>>(init_params.bounds); } + if (!init_params.name.empty()) { + (*properties)[mus::mojom::WindowManager::kName_Property] = + mojo::ConvertTo<std::vector<uint8_t>>(init_params.name); + } + (*properties)[mus::mojom::WindowManager::kAlwaysOnTop_Property] = + mojo::ConvertTo<std::vector<uint8_t>>(init_params.keep_on_top); if (!Widget::RequiresNonClientView(init_params.type)) return; @@ -387,16 +618,27 @@ void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) { window_tree_host_->InitHost(); window_tree_host_->window()->SetProperty(kMusWindow, window_); - focus_client_.reset(new wm::FocusController(new FocusRulesImpl)); + focus_client_.reset( + new wm::FocusController(new FocusRulesImpl(window_tree_host_->window()))); aura::client::SetFocusClient(window_tree_host_->window(), focus_client_.get()); aura::client::SetActivationClient(window_tree_host_->window(), focus_client_.get()); - screen_position_client_.reset(new wm::DefaultScreenPositionClient()); + screen_position_client_.reset(new ScreenPositionClientMus(window_)); aura::client::SetScreenPositionClient(window_tree_host_->window(), screen_position_client_.get()); + // TODO(erg): Remove this check when mash/wm/frame/move_event_handler.cc's + // direct usage of mus::Window::SetPredefinedCursor() is switched to a + // private method on WindowManagerClient. + if (surface_type_ == mus::mojom::SurfaceType::DEFAULT) { + cursor_manager_.reset(new wm::CursorManager( + base::WrapUnique(new NativeCursorManagerMus(window_)))); + aura::client::SetCursorClient(window_tree_host_->window(), + cursor_manager_.get()); + } + window_tree_client_.reset( new NativeWidgetMusWindowTreeClient(window_tree_host_->window())); window_tree_host_->window()->AddPreTargetHandler(focus_client_.get()); @@ -421,6 +663,9 @@ void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) { parent_mus->AddTransientWindow(window_); } + if (params.parent_mus) + params.parent_mus->AddChild(window_); + // TODO(sky): deal with show state. if (!params.bounds.size().IsEmpty()) SetBounds(params.bounds); @@ -600,8 +845,12 @@ gfx::Rect NativeWidgetMus::GetRestoredBounds() const { return GetWindowBoundsInScreen(); } +std::string NativeWidgetMus::GetWorkspace() const { + return std::string(); +} + void NativeWidgetMus::SetBounds(const gfx::Rect& bounds) { - if (!window_tree_host_) + if (!(window_ && window_tree_host_)) return; gfx::Size size(bounds.size()); @@ -611,6 +860,7 @@ void NativeWidgetMus::SetBounds(const gfx::Rect& bounds) { size.SetToMin(max_size); size.SetToMax(min_size); window_tree_host_->SetBounds(gfx::Rect(bounds.origin(), size)); + window_->SetBounds(gfx::Rect(bounds.origin(), size)); } void NativeWidgetMus::SetSize(const gfx::Size& size) { @@ -657,10 +907,11 @@ void NativeWidgetMus::Show() { } void NativeWidgetMus::Hide() { - if (!window_tree_host_) + if (!(window_ && window_tree_host_)) return; window_tree_host_->Hide(); + window_->SetVisible(false); GetNativeWindow()->Hide(); } @@ -670,14 +921,17 @@ void NativeWidgetMus::ShowMaximizedWithBounds( } void NativeWidgetMus::ShowWithWindowState(ui::WindowShowState state) { - if (!window_tree_host_) + if (!(window_ && window_tree_host_)) return; window_tree_host_->Show(); + window_->SetVisible(true); GetNativeWindow()->Show(); - if (state != ui::SHOW_STATE_INACTIVE) - Activate(); - GetWidget()->SetInitialFocus(state); + if (native_widget_delegate_->CanActivate()) { + if (state != ui::SHOW_STATE_INACTIVE) + Activate(); + GetWidget()->SetInitialFocus(state); + } } bool NativeWidgetMus::IsVisible() const { @@ -686,8 +940,10 @@ bool NativeWidgetMus::IsVisible() const { } void NativeWidgetMus::Activate() { - if (window_tree_host_) - window_tree_host_->platform_window()->Activate(); + if (window_) + window_->SetFocus(); + static_cast<aura::client::ActivationClient*>(focus_client_.get()) + ->ActivateWindow(content_); } void NativeWidgetMus::Deactivate() { @@ -702,60 +958,65 @@ bool NativeWidgetMus::IsActive() const { } void NativeWidgetMus::SetAlwaysOnTop(bool always_on_top) { - // NOTIMPLEMENTED(); + if (window_) { + window_->SetSharedProperty<bool>( + mus::mojom::WindowManager::kAlwaysOnTop_Property, always_on_top); + } } bool NativeWidgetMus::IsAlwaysOnTop() const { - // NOTIMPLEMENTED(); - return false; + return window_ && + window_->HasSharedProperty( + mus::mojom::WindowManager::kAlwaysOnTop_Property) && + window_->GetSharedProperty<bool>( + mus::mojom::WindowManager::kAlwaysOnTop_Property); } void NativeWidgetMus::SetVisibleOnAllWorkspaces(bool always_visible) { - // NOTIMPLEMENTED(); + // Not needed for chromeos. } void NativeWidgetMus::Maximize() { - if (window_tree_host_) - window_tree_host_->platform_window()->Maximize(); + SetShowState(mus::mojom::ShowState::MAXIMIZED); } void NativeWidgetMus::Minimize() { - if (window_tree_host_) - window_tree_host_->platform_window()->Minimize(); + SetShowState(mus::mojom::ShowState::MINIMIZED); } bool NativeWidgetMus::IsMaximized() const { - return window_tree_host_ && - window_tree_host_->show_state() == ui::PLATFORM_WINDOW_STATE_MAXIMIZED; + return mus_window_observer_ && + mus_window_observer_->show_state() == mus::mojom::ShowState::MAXIMIZED; } bool NativeWidgetMus::IsMinimized() const { - return window_tree_host_ && - window_tree_host_->show_state() == ui::PLATFORM_WINDOW_STATE_MINIMIZED; + return mus_window_observer_ && + mus_window_observer_->show_state() == mus::mojom::ShowState::MINIMIZED; } void NativeWidgetMus::Restore() { - if (window_tree_host_) - window_tree_host_->platform_window()->Restore(); + SetShowState(mus::mojom::ShowState::NORMAL); } void NativeWidgetMus::SetFullscreen(bool fullscreen) { if (!window_tree_host_ || IsFullscreen() == fullscreen) return; if (fullscreen) { - show_state_before_fullscreen_ = window_tree_host_->show_state(); + show_state_before_fullscreen_ = mus_window_observer_->show_state(); window_tree_host_->platform_window()->ToggleFullscreen(); } else { switch (show_state_before_fullscreen_) { - case ui::PLATFORM_WINDOW_STATE_MAXIMIZED: + case mus::mojom::ShowState::MAXIMIZED: Maximize(); break; - case ui::PLATFORM_WINDOW_STATE_MINIMIZED: + case mus::mojom::ShowState::MINIMIZED: Minimize(); break; - case ui::PLATFORM_WINDOW_STATE_UNKNOWN: - case ui::PLATFORM_WINDOW_STATE_NORMAL: - case ui::PLATFORM_WINDOW_STATE_FULLSCREEN: + case mus::mojom::ShowState::DEFAULT: + case mus::mojom::ShowState::NORMAL: + case mus::mojom::ShowState::INACTIVE: + case mus::mojom::ShowState::FULLSCREEN: + case mus::mojom::ShowState::DOCKED: // TODO(sad): This may not be sufficient. Restore(); break; @@ -764,9 +1025,8 @@ void NativeWidgetMus::SetFullscreen(bool fullscreen) { } bool NativeWidgetMus::IsFullscreen() const { - return window_tree_host_ && - window_tree_host_->show_state() == - ui::PLATFORM_WINDOW_STATE_FULLSCREEN; + return mus_window_observer_ && + mus_window_observer_->show_state() == mus::mojom::ShowState::FULLSCREEN; } void NativeWidgetMus::SetOpacity(unsigned char opacity) { @@ -793,16 +1053,18 @@ void NativeWidgetMus::SchedulePaintInRect(const gfx::Rect& rect) { } void NativeWidgetMus::SetCursor(gfx::NativeCursor cursor) { - if (!window_tree_host_) + if (!window_) return; + // TODO(erg): In aura, our incoming cursor is really two // parts. cursor.native_type() is an integer for standard cursors and is all // we support right now. If native_type() == kCursorCustom, than we should // also send an image, but as the cursor code is currently written, the image // is in a platform native format that's already uploaded to the window // server. - window_tree_host_->platform_window()->SetCursorById( - mus::mojom::Cursor(cursor.native_type())); + mus::mojom::Cursor new_cursor = mus::mojom::Cursor(cursor.native_type()); + if (last_cursor_ != new_cursor) + window_->SetPredefinedCursor(new_cursor); } bool NativeWidgetMus::IsMouseEventsEnabled() const { @@ -817,6 +1079,10 @@ void NativeWidgetMus::ClearNativeFocus() { window_ ? window_->connection()->GetFocusedWindow() : nullptr; if (focused && window_->Contains(focused) && focused != window_) window_->SetFocus(); + // Move aura-focus back to |content_|, so that the Widget still receives + // events correctly. + aura::client::GetFocusClient(content_)->ResetFocusWithinActiveWindow( + content_); } gfx::Rect NativeWidgetMus::GetWorkAreaBoundsInScreen() const { @@ -876,6 +1142,10 @@ void NativeWidgetMus::RepostNativeEvent(gfx::NativeEvent native_event) { // NOTIMPLEMENTED(); } +std::string NativeWidgetMus::GetName() const { + return window_->GetName(); +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetMus, aura::WindowDelegate implementation: @@ -951,6 +1221,14 @@ void NativeWidgetMus::GetHitTestMask(gfx::Path* mask) const { native_widget_delegate_->GetHitTestMask(mask); } +void NativeWidgetMus::SetShowState(mus::mojom::ShowState show_state) { + if (!window_) + return; + window_->SetSharedProperty<int32_t>( + mus::mojom::WindowManager::kShowState_Property, + static_cast<int32_t>(show_state)); +} + void NativeWidgetMus::OnKeyEvent(ui::KeyEvent* event) { if (event->is_char()) { // If a ui::InputMethod object is attached to the root window, character @@ -998,11 +1276,34 @@ void NativeWidgetMus::OnHostCloseRequested(const aura::WindowTreeHost* host) { GetWidget()->Close(); } +void NativeWidgetMus::OnWindowInputEvent( + mus::Window* view, + const ui::Event& event_in, + std::unique_ptr<base::Callback<void(EventResult)>>* ack_callback) { + // Take ownership of the callback, indicating that we will handle it. + EventAckHandler ack_handler(std::move(*ack_callback)); + + std::unique_ptr<ui::Event> event = ui::Event::Clone(event_in); + // TODO(markdittmer): This should be this->OnEvent(event.get()), but that + // can't happen until IME is refactored out of in WindowTreeHostMus. + platform_window_delegate()->DispatchEvent(event.get()); + // NOTE: |this| may be deleted. + + ack_handler.set_handled(event->handled()); + // |ack_handler| acks the event on destruction if necessary. +} + void NativeWidgetMus::OnMusWindowVisibilityChanging(mus::Window* window) { - native_widget_delegate_->OnNativeWidgetVisibilityChanging(!window->visible()); + if (window == window_) { + native_widget_delegate_->OnNativeWidgetVisibilityChanging( + !window->visible()); + } } void NativeWidgetMus::OnMusWindowVisibilityChanged(mus::Window* window) { + if (window != window_) + return; + if (window->visible()) { window_tree_host_->Show(); GetNativeWindow()->Show(); diff --git a/chromium/ui/views/mus/native_widget_mus.h b/chromium/ui/views/mus/native_widget_mus.h index 3419c064e05..7532719db35 100644 --- a/chromium/ui/views/mus/native_widget_mus.h +++ b/chromium/ui/views/mus/native_widget_mus.h @@ -8,16 +8,19 @@ #include <stdint.h> #include <map> +#include <memory> #include <string> +#include "base/callback.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "components/mus/public/cpp/input_event_handler.h" #include "components/mus/public/interfaces/window_tree.mojom.h" #include "ui/aura/window_delegate.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/platform_window/platform_window_delegate.h" #include "ui/views/mus/mus_export.h" +#include "ui/views/mus/window_tree_host_mus.h" #include "ui/views/widget/native_widget_private.h" namespace aura { @@ -29,23 +32,31 @@ class WindowTreeClient; class Window; } -namespace mojo { -class Connector; -} - namespace mus { class Window; class WindowTreeConnection; +namespace mojom { +enum class Cursor; +enum class EventResult; +} +} + +namespace shell { +class Connector; +} + +namespace ui { +class Event; } namespace wm { +class CursorManager; class FocusController; } namespace views { class SurfaceContextFactory; class WidgetDelegate; -class WindowTreeHostMus; // An implementation of NativeWidget that binds to a mus::Window. Because Aura // is used extensively within Views code, this code uses aura and binds to the @@ -53,12 +64,14 @@ class WindowTreeHostMus; // aura::Window in a hierarchy is created without a delegate by the // aura::WindowTreeHost, we must create a child aura::Window in this class // (content_) and attach it to the root. -class VIEWS_MUS_EXPORT NativeWidgetMus : public internal::NativeWidgetPrivate, - public aura::WindowDelegate, - public aura::WindowTreeHostObserver { +class VIEWS_MUS_EXPORT NativeWidgetMus + : public internal::NativeWidgetPrivate, + public aura::WindowDelegate, + public aura::WindowTreeHostObserver, + public NON_EXPORTED_BASE(mus::InputEventHandler) { public: NativeWidgetMus(internal::NativeWidgetDelegate* delegate, - mojo::Connector* connector, + shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type); ~NativeWidgetMus() override; @@ -72,7 +85,11 @@ class VIEWS_MUS_EXPORT NativeWidgetMus : public internal::NativeWidgetPrivate, // Notifies all widgets the frame constants changed in some way. static void NotifyFrameChanged(mus::WindowTreeConnection* connection); + // Returns the widget for a mus::Window, or null if there is none. + static Widget* GetWidgetForWindow(mus::Window* window); + mus::Window* window() { return window_; } + WindowTreeHostMus* window_tree_host() { return window_tree_host_.get(); } aura::Window* GetRootWindow(); @@ -116,6 +133,7 @@ class VIEWS_MUS_EXPORT NativeWidgetMus : public internal::NativeWidgetPrivate, gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; void SetBounds(const gfx::Rect& bounds) override; void SetSize(const gfx::Size& size) override; void StackAbove(gfx::NativeView native_view) override; @@ -168,6 +186,7 @@ class VIEWS_MUS_EXPORT NativeWidgetMus : public internal::NativeWidgetPrivate, bool IsTranslucentWindowOpacitySupported() const override; void OnSizeConstraintsChanged() override; void RepostNativeEvent(gfx::NativeEvent native_event) override; + std::string GetName() const override; // Overridden from aura::WindowDelegate: gfx::Size GetMinimumSize() const override; @@ -198,34 +217,51 @@ class VIEWS_MUS_EXPORT NativeWidgetMus : public internal::NativeWidgetPrivate, // Overridden from aura::WindowTreeHostObserver: void OnHostCloseRequested(const aura::WindowTreeHost* host) override; - private: + // Overridden from mus::InputEventHandler: + void OnWindowInputEvent( + mus::Window* view, + const ui::Event& event, + std::unique_ptr<base::Callback<void(mus::mojom::EventResult)>>* + ack_callback) override; + +private: + friend class NativeWidgetMusTest; class MusWindowObserver; + ui::PlatformWindowDelegate* platform_window_delegate() { + return window_tree_host(); + } + + void set_last_cursor(mus::mojom::Cursor cursor) { last_cursor_ = cursor; } + void SetShowState(mus::mojom::ShowState show_state); + void OnMusWindowVisibilityChanging(mus::Window* window); void OnMusWindowVisibilityChanged(mus::Window* window); mus::Window* window_; + mus::mojom::Cursor last_cursor_; internal::NativeWidgetDelegate* native_widget_delegate_; const mus::mojom::SurfaceType surface_type_; - ui::PlatformWindowState show_state_before_fullscreen_; + mus::mojom::ShowState show_state_before_fullscreen_; // See class documentation for Widget in widget.h for a note about ownership. Widget::InitParams::Ownership ownership_; // Functions with the same name require the mus::WindowObserver to be in // a separate class. - scoped_ptr<MusWindowObserver> mus_window_observer_; + std::unique_ptr<MusWindowObserver> mus_window_observer_; // Aura configuration. - scoped_ptr<SurfaceContextFactory> context_factory_; - scoped_ptr<WindowTreeHostMus> window_tree_host_; + std::unique_ptr<SurfaceContextFactory> context_factory_; + std::unique_ptr<WindowTreeHostMus> window_tree_host_; aura::Window* content_; - scoped_ptr<wm::FocusController> focus_client_; - scoped_ptr<aura::client::DefaultCaptureClient> capture_client_; - scoped_ptr<aura::client::WindowTreeClient> window_tree_client_; - scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_; + std::unique_ptr<wm::FocusController> focus_client_; + std::unique_ptr<aura::client::DefaultCaptureClient> capture_client_; + std::unique_ptr<aura::client::WindowTreeClient> window_tree_client_; + std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_; + std::unique_ptr<wm::CursorManager> cursor_manager_; base::WeakPtrFactory<NativeWidgetMus> close_widget_factory_; DISALLOW_COPY_AND_ASSIGN(NativeWidgetMus); diff --git a/chromium/ui/views/mus/native_widget_mus_unittest.cc b/chromium/ui/views/mus/native_widget_mus_unittest.cc index 78155814861..e4b7fb34c63 100644 --- a/chromium/ui/views/mus/native_widget_mus_unittest.cc +++ b/chromium/ui/views/mus/native_widget_mus_unittest.cc @@ -4,27 +4,68 @@ #include "ui/views/mus/native_widget_mus.h" +#include "base/callback.h" #include "base/macros.h" #include "components/mus/public/cpp/property_type_converters.h" +#include "components/mus/public/cpp/tests/window_tree_client_impl_private.h" #include "components/mus/public/cpp/window.h" #include "components/mus/public/cpp/window_property.h" +#include "components/mus/public/cpp/window_tree_connection.h" #include "components/mus/public/interfaces/window_manager.mojom.h" +#include "components/mus/public/interfaces/window_tree.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/aura/window.h" +#include "ui/events/event.h" +#include "ui/events/test/test_event_handler.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/skia_util.h" +#include "ui/views/controls/native/native_view_host.h" #include "ui/views/test/focus_manager_test.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_observer.h" +#include "ui/wm/public/activation_client.h" + +using mus::mojom::EventResult; namespace views { namespace { +// A view that reports any mouse press as handled. +class HandleMousePressView : public View { + public: + HandleMousePressView() {} + ~HandleMousePressView() override {} + + // View: + bool OnMousePressed(const ui::MouseEvent& event) override { return true; } + + private: + DISALLOW_COPY_AND_ASSIGN(HandleMousePressView); +}; + +// A view that deletes a widget on mouse press. +class DeleteWidgetView : public View { + public: + explicit DeleteWidgetView(std::unique_ptr<Widget>* widget_ptr) + : widget_ptr_(widget_ptr) {} + ~DeleteWidgetView() override {} + + // View: + bool OnMousePressed(const ui::MouseEvent& event) override { + widget_ptr_->reset(); + return true; + } + + private: + std::unique_ptr<Widget>* widget_ptr_; + DISALLOW_COPY_AND_ASSIGN(DeleteWidgetView); +}; + // Returns a small colored bitmap. SkBitmap MakeBitmap(SkColor color) { SkBitmap bitmap; @@ -80,14 +121,16 @@ class TestWidgetDelegate : public WidgetDelegateView { DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); }; +} // namespace + class NativeWidgetMusTest : public ViewsTestBase { public: NativeWidgetMusTest() {} ~NativeWidgetMusTest() override {} // Creates a test widget. Takes ownership of |delegate|. - scoped_ptr<Widget> CreateWidget(TestWidgetDelegate* delegate) { - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> CreateWidget(TestWidgetDelegate* delegate) { + std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.delegate = delegate; params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -96,14 +139,42 @@ class NativeWidgetMusTest : public ViewsTestBase { return widget; } + int ack_callback_count() { return ack_callback_count_; } + + void AckCallback(mus::mojom::EventResult result) { + ack_callback_count_++; + EXPECT_EQ(mus::mojom::EventResult::HANDLED, result); + } + + // Returns a mouse pressed event inside the widget. Tests that place views + // within the widget that respond to the event must be constructed within the + // widget coordinate space such that they respond correctly. + std::unique_ptr<ui::MouseEvent> CreateMouseEvent() { + return base::WrapUnique(new ui::MouseEvent( + ui::ET_MOUSE_PRESSED, gfx::Point(50, 50), gfx::Point(50, 50), + base::TimeDelta(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); + } + + // Simulates an input event to the NativeWidget. + void OnWindowInputEvent( + NativeWidgetMus* native_widget, + const ui::Event& event, + std::unique_ptr<base::Callback<void(mus::mojom::EventResult)>>* + ack_callback) { + native_widget->OnWindowInputEvent(native_widget->window(), event, + ack_callback); + } + private: + int ack_callback_count_ = 0; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetMusTest); }; // Tests communication of activation and focus between Widget and // NativeWidgetMus. TEST_F(NativeWidgetMusTest, OnActivationChanged) { - scoped_ptr<Widget> widget(CreateWidget(nullptr)); + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); widget->Show(); // Track activation, focus and blur events. @@ -132,11 +203,31 @@ TEST_F(NativeWidgetMusTest, OnActivationChanged) { WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener); } +// Tests that showing a non-activatable widget does not activate it. +// TODO(jamescook): Remove this test when widget_interactive_uittests.cc runs +// under mus. +TEST_F(NativeWidgetMusTest, ShowNonActivatableWidget) { + Widget widget; + WidgetActivationObserver activation_observer(&widget); + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_BUBBLE); + params.activatable = Widget::InitParams::ACTIVATABLE_NO; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = gfx::Rect(10, 20, 100, 200); + widget.Init(params); + widget.Show(); + + // The widget is not currently active. + EXPECT_FALSE(widget.IsActive()); + + // The widget was never active. + EXPECT_EQ(0u, activation_observer.changes().size()); +} + // Tests that a window with an icon sets the mus::Window icon property. TEST_F(NativeWidgetMusTest, AppIcon) { // Create a Widget with a bitmap as the icon. SkBitmap source_bitmap = MakeBitmap(SK_ColorRED); - scoped_ptr<Widget> widget( + std::unique_ptr<Widget> widget( CreateWidget(new TestWidgetDelegate(source_bitmap))); // The mus::Window has the icon property. @@ -155,7 +246,7 @@ TEST_F(NativeWidgetMusTest, AppIcon) { // property. TEST_F(NativeWidgetMusTest, NoAppIcon) { // Create a Widget without a special icon. - scoped_ptr<Widget> widget(CreateWidget(nullptr)); + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); // The mus::Window does not have an icon property. mus::Window* window = @@ -170,7 +261,7 @@ TEST_F(NativeWidgetMusTest, ChangeAppIcon) { // Create a Widget with an icon. SkBitmap bitmap1 = MakeBitmap(SK_ColorRED); TestWidgetDelegate* delegate = new TestWidgetDelegate(bitmap1); - scoped_ptr<Widget> widget(CreateWidget(delegate)); + std::unique_ptr<Widget> widget(CreateWidget(delegate)); // Update the icon to a new image. SkBitmap bitmap2 = MakeBitmap(SK_ColorGREEN); @@ -186,12 +277,163 @@ TEST_F(NativeWidgetMusTest, ChangeAppIcon) { } TEST_F(NativeWidgetMusTest, ValidLayerTree) { - scoped_ptr<Widget> widget(CreateWidget(nullptr)); + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); View* content = new View; content->SetPaintToLayer(true); widget->GetContentsView()->AddChildView(content); EXPECT_TRUE(widget->GetNativeWindow()->layer()->Contains(content->layer())); } -} // namespace +// Tests that the internal name is propagated from the Widget to the +// mus::Window. +TEST_F(NativeWidgetMusTest, GetName) { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.name = "MyWidget"; + widget.Init(params); + mus::Window* window = + static_cast<NativeWidgetMus*>(widget.native_widget_private())->window(); + EXPECT_EQ("MyWidget", window->GetName()); +} + +// Verifies changing the visibility of a child mus::Window doesn't change the +// visibility of the parent. +TEST_F(NativeWidgetMusTest, ChildVisibilityDoesntEffectParent) { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(params); + widget.Show(); + mus::Window* window = + static_cast<NativeWidgetMus*>(widget.native_widget_private())->window(); + ASSERT_TRUE(window->visible()); + + // Create a child window, make it visible and parent it to the Widget's + // window. + mus::Window* child_window = window->connection()->NewWindow(); + child_window->SetVisible(true); + window->AddChild(child_window); + + // Hide the child, this should not impact the visibility of the parent. + child_window->SetVisible(false); + EXPECT_TRUE(window->visible()); +} + +// Tests that child aura::Windows cannot be activated. +TEST_F(NativeWidgetMusTest, FocusChildAuraWindow) { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(params); + + View* focusable = new View; + focusable->SetFocusBehavior(View::FocusBehavior::ALWAYS); + widget.GetContentsView()->AddChildView(focusable); + + NativeViewHost* native_host = new NativeViewHost; + widget.GetContentsView()->AddChildView(native_host); + + std::unique_ptr<aura::Window> window(new aura::Window(nullptr)); + window->Init(ui::LayerType::LAYER_SOLID_COLOR); + native_host->SetBounds(5, 10, 20, 30); + native_host->Attach(window.get()); + widget.Show(); + window->Show(); + widget.SetBounds(gfx::Rect(10, 20, 30, 40)); + + // Sanity check that the |window| is a descendent of the Widget's window. + ASSERT_TRUE(widget.GetNativeView()->Contains(window->parent())); + + // Focusing the child window should not activate it. + window->Focus(); + EXPECT_TRUE(window->HasFocus()); + aura::Window* active_window = + aura::client::GetActivationClient(window.get()->GetRootWindow()) + ->GetActiveWindow(); + EXPECT_NE(window.get(), active_window); + EXPECT_EQ(widget.GetNativeView(), active_window); + + // Moving focus to a child View should move focus away from |window|, and to + // the Widget's window instead. + focusable->RequestFocus(); + EXPECT_FALSE(window->HasFocus()); + EXPECT_TRUE(widget.GetNativeView()->HasFocus()); + active_window = + aura::client::GetActivationClient(window.get()->GetRootWindow()) + ->GetActiveWindow(); + EXPECT_EQ(widget.GetNativeView(), active_window); +} + +TEST_F(NativeWidgetMusTest, WidgetReceivesEvent) { + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); + widget->Show(); + + View* content = new HandleMousePressView; + content->SetBounds(10, 20, 90, 180); + widget->GetContentsView()->AddChildView(content); + + ui::test::TestEventHandler handler; + content->AddPreTargetHandler(&handler); + + std::unique_ptr<ui::MouseEvent> mouse = CreateMouseEvent(); + NativeWidgetMus* native_widget = + static_cast<NativeWidgetMus*>(widget->native_widget_private()); + mus::WindowTreeClientImplPrivate test_api(native_widget->window()); + test_api.CallOnWindowInputEvent(native_widget->window(), *mouse); + EXPECT_EQ(1, handler.num_mouse_events()); +} + +// Tests that an incoming UI event is acked with the handled status. +TEST_F(NativeWidgetMusTest, EventAcked) { + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); + widget->Show(); + + View* content = new HandleMousePressView; + content->SetBounds(10, 20, 90, 180); + widget->GetContentsView()->AddChildView(content); + + // Dispatch an input event to the window and view. + std::unique_ptr<ui::MouseEvent> event = CreateMouseEvent(); + std::unique_ptr<base::Callback<void(EventResult)>> ack_callback( + new base::Callback<void(EventResult)>(base::Bind( + &NativeWidgetMusTest::AckCallback, base::Unretained(this)))); + OnWindowInputEvent( + static_cast<NativeWidgetMus*>(widget->native_widget_private()), + *event, + &ack_callback); + + // The test took ownership of the callback and called it. + EXPECT_FALSE(ack_callback); + EXPECT_EQ(1, ack_callback_count()); +} + +// Tests that a window that is deleted during event handling properly acks the +// event. +TEST_F(NativeWidgetMusTest, EventAckedWithWindowDestruction) { + std::unique_ptr<Widget> widget(CreateWidget(nullptr)); + widget->Show(); + + View* content = new DeleteWidgetView(&widget); + content->SetBounds(10, 20, 90, 180); + widget->GetContentsView()->AddChildView(content); + + // Dispatch an input event to the window and view. + std::unique_ptr<ui::MouseEvent> event = CreateMouseEvent(); + std::unique_ptr<base::Callback<void(EventResult)>> ack_callback( + new base::Callback<void(EventResult)>(base::Bind( + &NativeWidgetMusTest::AckCallback, base::Unretained(this)))); + OnWindowInputEvent( + static_cast<NativeWidgetMus*>(widget->native_widget_private()), + *event, + &ack_callback); + + // The widget was deleted. + EXPECT_FALSE(widget.get()); + + // The test took ownership of the callback and called it. + EXPECT_FALSE(ack_callback); + EXPECT_EQ(1, ack_callback_count()); +} + } // namespace views diff --git a/chromium/ui/views/mus/platform_test_helper_mus.cc b/chromium/ui/views/mus/platform_test_helper_mus.cc deleted file mode 100644 index 80e6a74a1ec..00000000000 --- a/chromium/ui/views/mus/platform_test_helper_mus.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2016 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 "ui/views/test/platform_test_helper.h" - -#include "base/command_line.h" -#include "base/run_loop.h" -#include "mojo/shell/background/background_shell.h" -#include "mojo/shell/background/tests/test_catalog_store.h" -#include "mojo/shell/public/cpp/connector.h" -#include "mojo/shell/public/cpp/shell_client.h" -#include "mojo/shell/public/cpp/shell_connection.h" -#include "ui/aura/env.h" -#include "ui/views/mus/window_manager_connection.h" -#include "ui/views/views_delegate.h" - -using mojo::shell::BackgroundShell; - -namespace views { -namespace { - -const char kTestName[] = "mojo:test-app"; - -class DefaultShellClient : public mojo::ShellClient { - public: - DefaultShellClient() {} - ~DefaultShellClient() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(DefaultShellClient); -}; - -scoped_ptr<mojo::shell::TestCatalogStore> BuildTestCatalogStore() { - scoped_ptr<base::ListValue> apps(new base::ListValue); - apps->Append( - mojo::shell::BuildPermissiveSerializedAppInfo(kTestName, "test")); - return make_scoped_ptr(new mojo::shell::TestCatalogStore(std::move(apps))); -} - -class PlatformTestHelperMus : public PlatformTestHelper { - public: - PlatformTestHelperMus() { - background_shell_.reset(new BackgroundShell); - scoped_ptr<BackgroundShell::InitParams> init_params( - new BackgroundShell::InitParams); - init_params->catalog_store = BuildTestCatalogStore(); - background_shell_->Init(std::move(init_params)); - shell_client_.reset(new DefaultShellClient); - shell_connection_.reset(new mojo::ShellConnection( - shell_client_.get(), - background_shell_->CreateShellClientRequest(kTestName))); - - // TODO(rockot): Remove this RunLoop. http://crbug.com/594852. - base::RunLoop wait_loop; - shell_connection_->set_initialize_handler(wait_loop.QuitClosure()); - wait_loop.Run(); - - // ui/views/mus requires a WindowManager running, for now use the desktop - // one. - mojo::Connector* connector = shell_connection_->connector(); - connector->Connect("mojo:desktop_wm"); - WindowManagerConnection::Create(connector); - - // On X we need to reset the ContextFactory before every NativeWidgetMus - // is created. - // TODO(sad): this is a hack, figure out a better solution. - ViewsDelegate::GetInstance()->set_native_widget_factory(base::Bind( - &PlatformTestHelperMus::CreateNativeWidgetMus, base::Unretained(this), - std::map<std::string, std::vector<uint8_t>>())); - } - - ~PlatformTestHelperMus() override { - WindowManagerConnection::Reset(); - // |app_| has a reference to us, destroy it while we are still valid. - shell_connection_.reset(); - } - - bool IsMus() const override { return true; } - - private: - NativeWidget* CreateNativeWidgetMus( - const std::map<std::string, std::vector<uint8_t>>& props, - const Widget::InitParams& init_params, - internal::NativeWidgetDelegate* delegate) { - ui::ContextFactory* factory = aura::Env::GetInstance()->context_factory(); - aura::Env::GetInstance()->set_context_factory(nullptr); - NativeWidget* result = - WindowManagerConnection::Get()->CreateNativeWidgetMus( - props, init_params, delegate); - aura::Env::GetInstance()->set_context_factory(factory); - return result; - } - - scoped_ptr<BackgroundShell> background_shell_; - scoped_ptr<mojo::ShellConnection> shell_connection_; - scoped_ptr<DefaultShellClient> shell_client_; - - DISALLOW_COPY_AND_ASSIGN(PlatformTestHelperMus); -}; - -} // namespace - -// static -scoped_ptr<PlatformTestHelper> PlatformTestHelper::Create() { - return make_scoped_ptr(new PlatformTestHelperMus); -} - -} // namespace views diff --git a/chromium/ui/views/mus/platform_window_mus.cc b/chromium/ui/views/mus/platform_window_mus.cc index d42a9a77908..d9dc54b0759 100644 --- a/chromium/ui/views/mus/platform_window_mus.cc +++ b/chromium/ui/views/mus/platform_window_mus.cc @@ -14,25 +14,24 @@ #include "ui/platform_window/platform_window_delegate.h" #include "ui/views/mus/window_manager_connection.h" +using mus::mojom::EventResult; + namespace views { namespace { + static uint32_t accelerated_widget_count = 1; } // namespace PlatformWindowMus::PlatformWindowMus(ui::PlatformWindowDelegate* delegate, - mojo::Connector* connector, + shell::Connector* connector, mus::Window* mus_window) : delegate_(delegate), mus_window_(mus_window), - show_state_(mus::mojom::ShowState::RESTORED), - last_cursor_(mus::mojom::Cursor::CURSOR_NULL), mus_window_destroyed_(false) { DCHECK(delegate_); DCHECK(mus_window_); - mus_window_->AddObserver(this); - mus_window_->set_input_event_handler(this); // We need accelerated widget numbers to be different for each // window and fit in the smallest sizeof(AcceleratedWidget) uint32_t @@ -47,52 +46,27 @@ PlatformWindowMus::PlatformWindowMus(ui::PlatformWindowDelegate* delegate, delegate_->OnAcceleratedWidgetAvailable( accelerated_widget, mus_window_->viewport_metrics().device_pixel_ratio); - bitmap_uploader_.reset(new bitmap_uploader::BitmapUploader(mus_window_)); - bitmap_uploader_->Init(connector); - prop_.reset(new ui::ViewProp( - accelerated_widget, bitmap_uploader::kBitmapUploaderForAcceleratedWidget, - bitmap_uploader_.get())); -} - -PlatformWindowMus::~PlatformWindowMus() { - if (!mus_window_) - return; - mus_window_->RemoveObserver(this); - mus_window_->set_input_event_handler(nullptr); - if (!mus_window_destroyed_) - mus_window_->Destroy(); -} - -void PlatformWindowMus::Activate() { - mus_window_->SetFocus(); -} - -void PlatformWindowMus::SetCursorById(mus::mojom::Cursor cursor) { - if (last_cursor_ != cursor) { - // The ui::PlatformWindow interface uses ui::PlatformCursor at this level, - // instead of ui::Cursor. All of the cursor abstractions in ui right now are - // sort of leaky; despite being nominally cross platform, they all drop down - // to platform types almost immediately, which makes them unusable as - // transport types. - mus_window_->SetPredefinedCursor(cursor); + if (connector) { + bitmap_uploader_.reset(new bitmap_uploader::BitmapUploader(mus_window_)); + bitmap_uploader_->Init(connector); + prop_.reset( + new ui::ViewProp(accelerated_widget, + bitmap_uploader::kBitmapUploaderForAcceleratedWidget, + bitmap_uploader_.get())); } } -void PlatformWindowMus::Show() { - mus_window_->SetVisible(true); -} +PlatformWindowMus::~PlatformWindowMus() {} -void PlatformWindowMus::Hide() { - mus_window_->SetVisible(false); -} +void PlatformWindowMus::Show() {} + +void PlatformWindowMus::Hide() {} void PlatformWindowMus::Close() { NOTIMPLEMENTED(); } -void PlatformWindowMus::SetBounds(const gfx::Rect& bounds) { - mus_window_->SetBounds(bounds); -} +void PlatformWindowMus::SetBounds(const gfx::Rect& bounds) {} gfx::Rect PlatformWindowMus::GetBounds() { return mus_window_->bounds(); @@ -114,17 +88,11 @@ void PlatformWindowMus::ToggleFullscreen() { NOTIMPLEMENTED(); } -void PlatformWindowMus::Maximize() { - SetShowState(mus::mojom::ShowState::MAXIMIZED); -} +void PlatformWindowMus::Maximize() {} -void PlatformWindowMus::Minimize() { - SetShowState(mus::mojom::ShowState::MINIMIZED); -} +void PlatformWindowMus::Minimize() {} -void PlatformWindowMus::Restore() { - SetShowState(mus::mojom::ShowState::RESTORED); -} +void PlatformWindowMus::Restore() {} void PlatformWindowMus::SetCursor(ui::PlatformCursor cursor) { NOTIMPLEMENTED(); @@ -142,96 +110,4 @@ ui::PlatformImeController* PlatformWindowMus::GetPlatformImeController() { return nullptr; } -void PlatformWindowMus::SetShowState(mus::mojom::ShowState show_state) { - mus_window_->SetSharedProperty<int32_t>( - mus::mojom::WindowManager::kShowState_Property, - static_cast<int32_t>(show_state)); -} - -void PlatformWindowMus::OnWindowDestroyed(mus::Window* window) { - DCHECK_EQ(mus_window_, window); - mus_window_destroyed_ = true; -#ifndef NDEBUG - weak_factory_.reset(new base::WeakPtrFactory<PlatformWindowMus>(this)); - base::WeakPtr<PlatformWindowMus> weak_ptr = weak_factory_->GetWeakPtr(); -#endif - delegate_->OnClosed(); - // |this| has been destroyed at this point. -#ifndef NDEBUG - DCHECK(!weak_ptr); -#endif -} - -void PlatformWindowMus::OnWindowBoundsChanged(mus::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - delegate_->OnBoundsChanged(new_bounds); -} - -void PlatformWindowMus::OnWindowFocusChanged(mus::Window* gained_focus, - mus::Window* lost_focus) { - if (gained_focus == mus_window_) - delegate_->OnActivationChanged(true); - else if (lost_focus == mus_window_) - delegate_->OnActivationChanged(false); -} - -void PlatformWindowMus::OnWindowPredefinedCursorChanged( - mus::Window* window, - mus::mojom::Cursor cursor) { - DCHECK_EQ(window, mus_window_); - last_cursor_ = cursor; -} - -void PlatformWindowMus::OnWindowSharedPropertyChanged( - mus::Window* window, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) { - if (name != mus::mojom::WindowManager::kShowState_Property) - return; - mus::mojom::ShowState show_state = - static_cast<mus::mojom::ShowState>(window->GetSharedProperty<int32_t>( - mus::mojom::WindowManager::kShowState_Property)); - if (show_state == show_state_) - return; - show_state_ = show_state; - ui::PlatformWindowState state = ui::PLATFORM_WINDOW_STATE_UNKNOWN; - switch (show_state_) { - case mus::mojom::ShowState::MINIMIZED: - state = ui::PLATFORM_WINDOW_STATE_MINIMIZED; - break; - case mus::mojom::ShowState::MAXIMIZED: - state = ui::PLATFORM_WINDOW_STATE_MAXIMIZED; - break; - case mus::mojom::ShowState::RESTORED: - state = ui::PLATFORM_WINDOW_STATE_NORMAL; - break; - case mus::mojom::ShowState::IMMERSIVE: - case mus::mojom::ShowState::PRESENTATION: - // This may not be sufficient. - state = ui::PLATFORM_WINDOW_STATE_FULLSCREEN; - break; - } - delegate_->OnWindowStateChanged(state); -} - -void PlatformWindowMus::OnRequestClose(mus::Window* window) { - delegate_->OnCloseRequest(); -} - -void PlatformWindowMus::OnWindowInputEvent( - mus::Window* view, - const ui::Event& event, - scoped_ptr<base::Callback<void(bool)>>* ack_callback) { - // It's possible dispatching the event will spin a nested message loop. Ack - // the callback now, otherwise we appear unresponsive for the life of the - // nested message loop. - (*ack_callback)->Run(true); - ack_callback->reset(); - // TODO(moshayedi): Avoid cloning after updating PlatformWindowDelegate to - // accept constant pointers. - delegate_->DispatchEvent(ui::Event::Clone(event).get()); -} - } // namespace views diff --git a/chromium/ui/views/mus/platform_window_mus.h b/chromium/ui/views/mus/platform_window_mus.h index ba206713f08..c17b9c80b04 100644 --- a/chromium/ui/views/mus/platform_window_mus.h +++ b/chromium/ui/views/mus/platform_window_mus.h @@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "components/mus/public/cpp/input_event_handler.h" #include "components/mus/public/cpp/window_observer.h" #include "ui/platform_window/platform_window.h" #include "ui/views/mus/mus_export.h" @@ -20,31 +19,26 @@ namespace bitmap_uploader { class BitmapUploader; } -namespace mojo { +namespace shell { class Connector; } namespace ui { -class Event; class ViewProp; } namespace views { +// This class has been marked for deletion. Its implementation is being rolled +// into views::NativeWidgetMus. See crbug.com/609555 for details. class VIEWS_MUS_EXPORT PlatformWindowMus - : public NON_EXPORTED_BASE(ui::PlatformWindow), - public mus::WindowObserver, - public NON_EXPORTED_BASE(mus::InputEventHandler) { + : public NON_EXPORTED_BASE(ui::PlatformWindow) { public: PlatformWindowMus(ui::PlatformWindowDelegate* delegate, - mojo::Connector* connector, + shell::Connector* connector, mus::Window* mus_window); ~PlatformWindowMus() override; - void Activate(); - - void SetCursorById(mus::mojom::Cursor cursor); - // ui::PlatformWindow: void Show() override; void Hide() override; @@ -64,42 +58,18 @@ class VIEWS_MUS_EXPORT PlatformWindowMus ui::PlatformImeController* GetPlatformImeController() override; private: - void SetShowState(mus::mojom::ShowState show_state); - - // mus::WindowObserver: - void OnWindowDestroyed(mus::Window* window) override; - void OnWindowBoundsChanged(mus::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - void OnWindowFocusChanged(mus::Window* gained_focus, - mus::Window* lost_focus) override; - void OnWindowPredefinedCursorChanged(mus::Window* window, - mus::mojom::Cursor cursor) override; - void OnWindowSharedPropertyChanged( - mus::Window* window, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) override; - void OnRequestClose(mus::Window* window) override; - - // mus::InputEventHandler: - void OnWindowInputEvent( - mus::Window* view, - const ui::Event& event, - scoped_ptr<base::Callback<void(bool)>>* ack_callback) override; + friend class PlatformWindowMusTest; ui::PlatformWindowDelegate* delegate_; mus::Window* mus_window_; - mus::mojom::ShowState show_state_; - mus::mojom::Cursor last_cursor_; // True if OnWindowDestroyed() has been received. bool mus_window_destroyed_; - scoped_ptr<bitmap_uploader::BitmapUploader> bitmap_uploader_; - scoped_ptr<ui::ViewProp> prop_; + std::unique_ptr<bitmap_uploader::BitmapUploader> bitmap_uploader_; + std::unique_ptr<ui::ViewProp> prop_; #ifndef NDEBUG - scoped_ptr<base::WeakPtrFactory<PlatformWindowMus>> weak_factory_; + std::unique_ptr<base::WeakPtrFactory<PlatformWindowMus>> weak_factory_; #endif DISALLOW_COPY_AND_ASSIGN(PlatformWindowMus); diff --git a/chromium/ui/views/mus/run_all_unittests_mus.cc b/chromium/ui/views/mus/run_all_unittests_mus.cc index 4de8cdb1839..05e4f0c82a2 100644 --- a/chromium/ui/views/mus/run_all_unittests_mus.cc +++ b/chromium/ui/views/mus/run_all_unittests_mus.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/run_all_unittests.h" +#include "ui/views/mus/views_mus_test_suite.h" int MasterProcessMain(int argc, char** argv) { - return views::RunAllUnittests(argc, argv); + return views::ViewsMusTestSuite(argc, argv).RunTests(); } diff --git a/chromium/ui/views/mus/screen_mus.cc b/chromium/ui/views/mus/screen_mus.cc index 855f475674e..227170606ae 100644 --- a/chromium/ui/views/mus/screen_mus.cc +++ b/chromium/ui/views/mus/screen_mus.cc @@ -5,51 +5,18 @@ #include "ui/views/mus/screen_mus.h" #include "mojo/converters/geometry/geometry_type_converters.h" -#include "mojo/shell/public/cpp/connection.h" -#include "mojo/shell/public/cpp/connector.h" -#include "ui/gfx/display_finder.h" -#include "ui/gfx/display_observer.h" +#include "services/shell/public/cpp/connection.h" +#include "services/shell/public/cpp/connector.h" +#include "ui/aura/window.h" +#include "ui/display/display_finder.h" +#include "ui/display/display_observer.h" +#include "ui/mojo/display/display_type_converters.h" #include "ui/views/mus/screen_mus_delegate.h" #include "ui/views/mus/window_manager_frame_values.h" namespace mojo { template <> -struct TypeConverter<gfx::Display, mus::mojom::DisplayPtr> { - static gfx::Display Convert(const mus::mojom::DisplayPtr& input) { - gfx::Display result(input->id, input->bounds.To<gfx::Rect>()); - result.set_work_area(input->work_area.To<gfx::Rect>()); - result.set_device_scale_factor(input->device_pixel_ratio); - switch (input->rotation) { - case mus::mojom::Rotation::VALUE_0: - result.set_rotation(gfx::Display::ROTATE_0); - break; - case mus::mojom::Rotation::VALUE_90: - result.set_rotation(gfx::Display::ROTATE_90); - break; - case mus::mojom::Rotation::VALUE_180: - result.set_rotation(gfx::Display::ROTATE_180); - break; - case mus::mojom::Rotation::VALUE_270: - result.set_rotation(gfx::Display::ROTATE_270); - break; - } - switch (input->touch_support) { - case mus::mojom::TouchSupport::UNKNOWN: - result.set_touch_support(gfx::Display::TOUCH_SUPPORT_UNKNOWN); - break; - case mus::mojom::TouchSupport::AVAILABLE: - result.set_touch_support(gfx::Display::TOUCH_SUPPORT_AVAILABLE); - break; - case mus::mojom::TouchSupport::UNAVAILABLE: - result.set_touch_support(gfx::Display::TOUCH_SUPPORT_UNAVAILABLE); - break; - } - return result; - } -}; - -template <> struct TypeConverter<views::WindowManagerFrameValues, mus::mojom::FrameDecorationValuesPtr> { static views::WindowManagerFrameValues Convert( @@ -69,13 +36,13 @@ namespace views { ScreenMus::ScreenMus(ScreenMusDelegate* delegate) : delegate_(delegate), - primary_display_index_(0), - display_manager_observer_binding_(this) {} + display_manager_observer_binding_(this) { +} ScreenMus::~ScreenMus() {} -void ScreenMus::Init(mojo::Connector* connector) { - gfx::Screen::SetScreenInstance(this); +void ScreenMus::Init(shell::Connector* connector) { + display::Screen::SetScreenInstance(this); connector->ConnectToInterface("mojo:mus", &display_manager_); @@ -86,70 +53,52 @@ void ScreenMus::Init(mojo::Connector* connector) { // // TODO(rockot): Do something better here. This should not have to block tasks // from running on the calling thread. http://crbug.com/594852. - display_manager_observer_binding_.WaitForIncomingMethodCall(); - - // The WaitForIncomingMethodCall() should have supplied the set of Displays. - DCHECK(displays_.size()); -} - -int ScreenMus::FindDisplayIndexById(int64_t id) const { - for (size_t i = 0; i < displays_.size(); ++i) { - if (displays_[i].id() == id) - return static_cast<int>(i); + bool success = display_manager_observer_binding_.WaitForIncomingMethodCall(); + + // The WaitForIncomingMethodCall() should have supplied the set of Displays, + // unless mus is going down, in which case encountered_error() is true, or the + // call to WaitForIncomingMethodCall() failed. + if (display_list_.displays().empty()) { + DCHECK(display_manager_.encountered_error() || !success); + // In this case we install a default display and assume the process is + // going to exit shortly so that the real value doesn't matter. + display_list_.AddDisplay( + display::Display(0xFFFFFFFF, gfx::Rect(0, 0, 801, 802)), + DisplayList::Type::PRIMARY); } - return -1; } -void ScreenMus::ProcessDisplayChanged(const gfx::Display& changed_display, +void ScreenMus::ProcessDisplayChanged(const display::Display& changed_display, bool is_primary) { - const int display_index = FindDisplayIndexById(changed_display.id()); - if (display_index == -1) { - displays_.push_back(changed_display); - if (is_primary) - primary_display_index_ = static_cast<int>(displays_.size()) - 1; - FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, - OnDisplayAdded(changed_display)); + if (display_list_.FindDisplayById(changed_display.id()) == + display_list_.displays().end()) { + display_list_.AddDisplay(changed_display, + is_primary ? DisplayList::Type::PRIMARY + : DisplayList::Type::NOT_PRIMARY); return; } - - gfx::Display* local_display = &displays_[display_index]; - uint32_t changed_values = 0; - if (is_primary && display_index != primary_display_index_) { - primary_display_index_ = display_index; - // ash::DisplayManager only notifies for the Display gaining primary, not - // the one losing it. - changed_values |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY; - } - if (local_display->bounds() != changed_display.bounds()) { - local_display->set_bounds(changed_display.bounds()); - changed_values |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS; - } - if (local_display->work_area() != changed_display.work_area()) { - local_display->set_work_area(changed_display.work_area()); - changed_values |= gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA; - } - if (local_display->rotation() != changed_display.rotation()) { - local_display->set_rotation(changed_display.rotation()); - changed_values |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION; - } - if (local_display->device_scale_factor() != - changed_display.device_scale_factor()) { - local_display->set_device_scale_factor( - changed_display.device_scale_factor()); - changed_values |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR; - } - FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, - OnDisplayMetricsChanged(*local_display, changed_values)); + display_list_.UpdateDisplay( + changed_display, + is_primary ? DisplayList::Type::PRIMARY : DisplayList::Type::NOT_PRIMARY); } gfx::Point ScreenMus::GetCursorScreenPoint() { - NOTIMPLEMENTED(); - return gfx::Point(); + if (!delegate_) { + // TODO(erg): If we need the cursor point in the window manager, we'll need + // to make |delegate_| required. It only recently changed to be optional. + NOTIMPLEMENTED(); + return gfx::Point(); + } + + return delegate_->GetCursorScreenPoint(); } -gfx::NativeWindow ScreenMus::GetWindowUnderCursor() { - NOTIMPLEMENTED(); - return nullptr; +bool ScreenMus::IsWindowUnderCursor(gfx::NativeWindow window) { + if (!window) + return false; + + return window->IsVisible() && + window->GetBoundsInScreen().Contains(GetCursorScreenPoint()); } gfx::NativeWindow ScreenMus::GetWindowAtScreenPoint(const gfx::Point& point) { @@ -157,81 +106,86 @@ gfx::NativeWindow ScreenMus::GetWindowAtScreenPoint(const gfx::Point& point) { return nullptr; } -gfx::Display ScreenMus::GetPrimaryDisplay() const { - return displays_[primary_display_index_]; +display::Display ScreenMus::GetPrimaryDisplay() const { + return *display_list_.GetPrimaryDisplayIterator(); } -gfx::Display ScreenMus::GetDisplayNearestWindow(gfx::NativeView view) const { +display::Display ScreenMus::GetDisplayNearestWindow( + gfx::NativeView view) const { //NOTIMPLEMENTED(); - return GetPrimaryDisplay(); + return *display_list_.GetPrimaryDisplayIterator(); } -gfx::Display ScreenMus::GetDisplayNearestPoint(const gfx::Point& point) const { - return *gfx::FindDisplayNearestPoint(displays_, point); +display::Display ScreenMus::GetDisplayNearestPoint( + const gfx::Point& point) const { + return *display::FindDisplayNearestPoint(display_list_.displays(), point); } int ScreenMus::GetNumDisplays() const { - return static_cast<int>(displays_.size()); + return static_cast<int>(display_list_.displays().size()); } -std::vector<gfx::Display> ScreenMus::GetAllDisplays() const { - return displays_; +std::vector<display::Display> ScreenMus::GetAllDisplays() const { + return display_list_.displays(); } -gfx::Display ScreenMus::GetDisplayMatching(const gfx::Rect& match_rect) const { - const gfx::Display* match = - gfx::FindDisplayWithBiggestIntersection(displays_, match_rect); +display::Display ScreenMus::GetDisplayMatching( + const gfx::Rect& match_rect) const { + const display::Display* match = display::FindDisplayWithBiggestIntersection( + display_list_.displays(), match_rect); return match ? *match : GetPrimaryDisplay(); } -void ScreenMus::AddObserver(gfx::DisplayObserver* observer) { - observers_.AddObserver(observer); +void ScreenMus::AddObserver(display::DisplayObserver* observer) { + display_list_.AddObserver(observer); } -void ScreenMus::RemoveObserver(gfx::DisplayObserver* observer) { - observers_.RemoveObserver(observer); +void ScreenMus::RemoveObserver(display::DisplayObserver* observer) { + display_list_.RemoveObserver(observer); } -void ScreenMus::OnDisplays(mojo::Array<mus::mojom::DisplayPtr> displays) { +void ScreenMus::OnDisplays( + mojo::Array<mus::mojom::DisplayPtr> transport_displays) { // This should only be called once from Init() before any observers have been // added. - DCHECK(displays_.empty()); - displays_ = displays.To<std::vector<gfx::Display>>(); + DCHECK(display_list_.displays().empty()); + std::vector<display::Display> displays = + transport_displays.To<std::vector<display::Display>>(); for (size_t i = 0; i < displays.size(); ++i) { - if (displays[i]->is_primary) { - primary_display_index_ = static_cast<int>(i); + const bool is_primary = transport_displays[i]->is_primary; + display_list_.AddDisplay(displays[i], is_primary + ? DisplayList::Type::PRIMARY + : DisplayList::Type::NOT_PRIMARY); + if (is_primary) { // TODO(sky): Make WindowManagerFrameValues per display. WindowManagerFrameValues frame_values = - displays[i]->frame_decoration_values.To<WindowManagerFrameValues>(); + transport_displays[i] + ->frame_decoration_values.To<WindowManagerFrameValues>(); WindowManagerFrameValues::SetInstance(frame_values); } } + DCHECK(!display_list_.displays().empty()); } void ScreenMus::OnDisplaysChanged( mojo::Array<mus::mojom::DisplayPtr> transport_displays) { for (size_t i = 0; i < transport_displays.size(); ++i) { const bool is_primary = transport_displays[i]->is_primary; - ProcessDisplayChanged(transport_displays[i].To<gfx::Display>(), is_primary); + ProcessDisplayChanged(transport_displays[i].To<display::Display>(), + is_primary); if (is_primary) { WindowManagerFrameValues frame_values = transport_displays[i] ->frame_decoration_values.To<WindowManagerFrameValues>(); WindowManagerFrameValues::SetInstance(frame_values); - delegate_->OnWindowManagerFrameValuesChanged(); + if (delegate_) + delegate_->OnWindowManagerFrameValuesChanged(); } } } void ScreenMus::OnDisplayRemoved(int64_t id) { - const int index = FindDisplayIndexById(id); - DCHECK_NE(-1, index); - // Another display must become primary before the existing primary is - // removed. - DCHECK_NE(index, primary_display_index_); - const gfx::Display display = displays_[index]; - FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_, - OnDisplayRemoved(display)); + display_list_.RemoveDisplay(id); } } // namespace views diff --git a/chromium/ui/views/mus/screen_mus.h b/chromium/ui/views/mus/screen_mus.h index a6800afd72e..ddd9c14077d 100644 --- a/chromium/ui/views/mus/screen_mus.h +++ b/chromium/ui/views/mus/screen_mus.h @@ -11,11 +11,12 @@ #include "base/run_loop.h" #include "components/mus/public/interfaces/display.mojom.h" #include "mojo/public/cpp/bindings/binding.h" -#include "ui/gfx/display.h" -#include "ui/gfx/screen.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/views/mus/display_list.h" #include "ui/views/mus/mus_export.h" -namespace mojo { +namespace shell { class Connector; } @@ -25,47 +26,48 @@ class ScreenMusDelegate; // Screen implementation backed by mus::mojom::DisplayManager. class VIEWS_MUS_EXPORT ScreenMus - : public gfx::Screen, + : public display::Screen, public NON_EXPORTED_BASE(mus::mojom::DisplayManagerObserver) { public: + // |delegate| can be nullptr. explicit ScreenMus(ScreenMusDelegate* delegate); ~ScreenMus() override; - void Init(mojo::Connector* connector); + void Init(shell::Connector* connector); private: - int FindDisplayIndexById(int64_t id) const; - // Invoked when a display changed in some weay, including being added. // If |is_primary| is true, |changed_display| is the primary display. - void ProcessDisplayChanged(const gfx::Display& changed_display, + void ProcessDisplayChanged(const display::Display& changed_display, bool is_primary); - // gfx::Screen: + // display::Screen: gfx::Point GetCursorScreenPoint() override; - gfx::NativeWindow GetWindowUnderCursor() override; + bool IsWindowUnderCursor(gfx::NativeWindow window) override; gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override; - gfx::Display GetPrimaryDisplay() const override; - gfx::Display GetDisplayNearestWindow(gfx::NativeView view) const override; - gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const override; + display::Display GetPrimaryDisplay() const override; + display::Display GetDisplayNearestWindow(gfx::NativeView view) const override; + display::Display GetDisplayNearestPoint( + const gfx::Point& point) const override; int GetNumDisplays() const override; - std::vector<gfx::Display> GetAllDisplays() const override; - gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override; - void AddObserver(gfx::DisplayObserver* observer) override; - void RemoveObserver(gfx::DisplayObserver* observer) override; + std::vector<display::Display> GetAllDisplays() const override; + display::Display GetDisplayMatching( + const gfx::Rect& match_rect) const override; + void AddObserver(display::DisplayObserver* observer) override; + void RemoveObserver(display::DisplayObserver* observer) override; // mus::mojom::DisplayManager: - void OnDisplays(mojo::Array<mus::mojom::DisplayPtr> displays) override; - void OnDisplaysChanged(mojo::Array<mus::mojom::DisplayPtr> display) override; + void OnDisplays( + mojo::Array<mus::mojom::DisplayPtr> transport_displays) override; + void OnDisplaysChanged( + mojo::Array<mus::mojom::DisplayPtr> transport_displays) override; void OnDisplayRemoved(int64_t id) override; - ScreenMusDelegate* delegate_; + ScreenMusDelegate* delegate_; // Can be nullptr. mus::mojom::DisplayManagerPtr display_manager_; - std::vector<gfx::Display> displays_; - int primary_display_index_; mojo::Binding<mus::mojom::DisplayManagerObserver> display_manager_observer_binding_; - base::ObserverList<gfx::DisplayObserver> observers_; + DisplayList display_list_; DISALLOW_COPY_AND_ASSIGN(ScreenMus); }; diff --git a/chromium/ui/views/mus/screen_mus_delegate.h b/chromium/ui/views/mus/screen_mus_delegate.h index 4c7940088c5..1db1b67faaa 100644 --- a/chromium/ui/views/mus/screen_mus_delegate.h +++ b/chromium/ui/views/mus/screen_mus_delegate.h @@ -7,6 +7,10 @@ #include "ui/views/mus/mus_export.h" +namespace gfx { +class Point; +} + namespace views { // Screen implementation backed by mus::mojom::DisplayManager. @@ -14,7 +18,9 @@ class VIEWS_MUS_EXPORT ScreenMusDelegate { public: virtual void OnWindowManagerFrameValuesChanged() = 0; - protected: + virtual gfx::Point GetCursorScreenPoint() = 0; + +protected: virtual ~ScreenMusDelegate() {} }; diff --git a/chromium/ui/views/mus/screen_mus_unittest.cc b/chromium/ui/views/mus/screen_mus_unittest.cc new file mode 100644 index 00000000000..1d71fbaa4a4 --- /dev/null +++ b/chromium/ui/views/mus/screen_mus_unittest.cc @@ -0,0 +1,32 @@ +// Copyright 2016 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 "ui/views/mus/screen_mus.h" + +#include "base/command_line.h" +#include "ui/display/display_switches.h" +#include "ui/display/screen.h" +#include "ui/views/mus/window_manager_connection.h" +#include "ui/views/test/scoped_views_test_helper.h" +#include "ui/views/test/views_test_base.h" + +namespace views { +namespace { + +TEST(ScreenMusTest, ConsistentDisplayInHighDPI) { + base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kForceDeviceScaleFactor, "2"); + ScopedViewsTestHelper test_helper; + display::Screen* screen = display::Screen::GetScreen(); + std::vector<display::Display> displays = screen->GetAllDisplays(); + ASSERT_FALSE(displays.empty()); + for (const display::Display& display : displays) { + EXPECT_EQ(2.f, display.device_scale_factor()); + EXPECT_EQ(display.work_area(), display.bounds()); + } +} + +} // namespace +} // namespace views diff --git a/chromium/ui/views/mus/surface_binding.cc b/chromium/ui/views/mus/surface_binding.cc index e33e3247bd7..a3dc98fb730 100644 --- a/chromium/ui/views/mus/surface_binding.cc +++ b/chromium/ui/views/mus/surface_binding.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/lazy_instance.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/threading/thread_local.h" #include "cc/output/compositor_frame.h" #include "cc/output/output_surface.h" @@ -26,7 +27,7 @@ #include "mojo/converters/geometry/geometry_type_converters.h" #include "mojo/converters/surfaces/surfaces_type_converters.h" #include "mojo/public/cpp/bindings/binding.h" -#include "mojo/shell/public/cpp/connector.h" +#include "services/shell/public/cpp/connector.h" #include "ui/views/mus/window_tree_host_mus.h" namespace views { @@ -41,10 +42,10 @@ namespace views { class SurfaceBinding::PerConnectionState : public base::RefCounted<PerConnectionState> { public: - static PerConnectionState* Get(mojo::Connector* connector, + static PerConnectionState* Get(shell::Connector* connector, mus::WindowTreeConnection* connection); - scoped_ptr<cc::OutputSurface> CreateOutputSurface( + std::unique_ptr<cc::OutputSurface> CreateOutputSurface( mus::Window* window, mus::mojom::SurfaceType type); @@ -54,7 +55,7 @@ class SurfaceBinding::PerConnectionState friend class base::RefCounted<PerConnectionState>; - PerConnectionState(mojo::Connector* connector, + PerConnectionState(shell::Connector* connector, mus::WindowTreeConnection* connection); ~PerConnectionState(); @@ -63,7 +64,7 @@ class SurfaceBinding::PerConnectionState static base::LazyInstance< base::ThreadLocalPointer<ConnectionToStateMap>>::Leaky window_states; - mojo::Connector* connector_; + shell::Connector* connector_; mus::WindowTreeConnection* connection_; // Set of state needed to create an OutputSurface. @@ -79,7 +80,7 @@ base::LazyInstance<base::ThreadLocalPointer< // static SurfaceBinding::PerConnectionState* SurfaceBinding::PerConnectionState::Get( - mojo::Connector* connector, + shell::Connector* connector, mus::WindowTreeConnection* connection) { ConnectionToStateMap* window_map = window_states.Pointer()->Get(); if (!window_map) { @@ -93,10 +94,12 @@ SurfaceBinding::PerConnectionState* SurfaceBinding::PerConnectionState::Get( return (*window_map)[connection]; } -scoped_ptr<cc::OutputSurface> +std::unique_ptr<cc::OutputSurface> SurfaceBinding::PerConnectionState::CreateOutputSurface( mus::Window* window, mus::mojom::SurfaceType surface_type) { + if (gpu_.encountered_error()) + return nullptr; // TODO(sky): figure out lifetime here. Do I need to worry about the return // value outliving this? mus::mojom::CommandBufferPtr cb; @@ -104,12 +107,12 @@ SurfaceBinding::PerConnectionState::CreateOutputSurface( scoped_refptr<cc::ContextProvider> context_provider( new mus::ContextProvider(cb.PassInterface().PassHandle())); - return make_scoped_ptr(new mus::OutputSurface( + return base::WrapUnique(new mus::OutputSurface( context_provider, window->RequestSurface(surface_type))); } SurfaceBinding::PerConnectionState::PerConnectionState( - mojo::Connector* connector, + shell::Connector* connector, mus::WindowTreeConnection* connection) : connector_(connector), connection_(connection) {} @@ -126,11 +129,17 @@ SurfaceBinding::PerConnectionState::~PerConnectionState() { void SurfaceBinding::PerConnectionState::Init() { connector_->ConnectToInterface("mojo:mus", &gpu_); + + // TODO(sad): If connection is lost (e.g. if gpu crashes), then the + // connections need to be restored. https://crbug.com/613366 + // TODO(rockot|yzshen): It is necessary to install a connection-error handler, + // even if the handler doesn't actually do anything. https://crbug.com/613371 + gpu_.set_connection_error_handler([]{}); } // SurfaceBinding -------------------------------------------------------------- -SurfaceBinding::SurfaceBinding(mojo::Connector* connector, +SurfaceBinding::SurfaceBinding(shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type) : window_(window), @@ -139,7 +148,7 @@ SurfaceBinding::SurfaceBinding(mojo::Connector* connector, SurfaceBinding::~SurfaceBinding() {} -scoped_ptr<cc::OutputSurface> SurfaceBinding::CreateOutputSurface() { +std::unique_ptr<cc::OutputSurface> SurfaceBinding::CreateOutputSurface() { return state_->CreateOutputSurface(window_, surface_type_); } diff --git a/chromium/ui/views/mus/surface_binding.h b/chromium/ui/views/mus/surface_binding.h index 2c6c5b68a33..2e04c3d488a 100644 --- a/chromium/ui/views/mus/surface_binding.h +++ b/chromium/ui/views/mus/surface_binding.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_MUS_SURFACE_BINDING_H_ #define UI_VIEWS_MUS_SURFACE_BINDING_H_ +#include <memory> + #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "components/mus/public/interfaces/window_tree.mojom.h" #include "ui/views/mus/mus_export.h" @@ -15,14 +16,14 @@ namespace cc { class OutputSurface; } -namespace mojo { -class Connector; -} - namespace mus { class Window; } +namespace shell { +class Connector; +} + namespace views { // SurfaceBinding is responsible for managing the connections necessary to @@ -32,14 +33,14 @@ namespace views { // connection. class VIEWS_MUS_EXPORT SurfaceBinding { public: - SurfaceBinding(mojo::Connector* connector, + SurfaceBinding(shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type); ~SurfaceBinding(); // Creates an OutputSurface that renders to the Window supplied to the // constructor. - scoped_ptr<cc::OutputSurface> CreateOutputSurface(); + std::unique_ptr<cc::OutputSurface> CreateOutputSurface(); private: class PerConnectionState; diff --git a/chromium/ui/views/mus/surface_context_factory.cc b/chromium/ui/views/mus/surface_context_factory.cc index bb27a08fb06..316d14e3c27 100644 --- a/chromium/ui/views/mus/surface_context_factory.cc +++ b/chromium/ui/views/mus/surface_context_factory.cc @@ -4,11 +4,12 @@ #include "ui/views/mus/surface_context_factory.h" +#include "base/memory/ptr_util.h" #include "cc/output/output_surface.h" #include "cc/resources/shared_bitmap_manager.h" #include "cc/surfaces/surface_id_allocator.h" #include "components/mus/public/cpp/window.h" -#include "mojo/shell/public/interfaces/connector.mojom.h" +#include "services/shell/public/interfaces/connector.mojom.h" #include "ui/compositor/reflector.h" #include "ui/gl/gl_bindings.h" @@ -27,7 +28,7 @@ class FakeReflector : public ui::Reflector { } // namespace SurfaceContextFactory::SurfaceContextFactory( - mojo::Connector* connector, + shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type) : surface_binding_(connector, window, surface_type), @@ -38,14 +39,17 @@ SurfaceContextFactory::~SurfaceContextFactory() {} void SurfaceContextFactory::CreateOutputSurface( base::WeakPtr<ui::Compositor> compositor) { // NOTIMPLEMENTED(); - compositor->SetOutputSurface(surface_binding_.CreateOutputSurface()); + std::unique_ptr<cc::OutputSurface> surface = + surface_binding_.CreateOutputSurface(); + if (surface) + compositor->SetOutputSurface(std::move(surface)); } -scoped_ptr<ui::Reflector> SurfaceContextFactory::CreateReflector( +std::unique_ptr<ui::Reflector> SurfaceContextFactory::CreateReflector( ui::Compositor* mirroed_compositor, ui::Layer* mirroring_layer) { // NOTIMPLEMENTED(); - return make_scoped_ptr(new FakeReflector); + return base::WrapUnique(new FakeReflector); } void SurfaceContextFactory::RemoveReflector(ui::Reflector* reflector) { @@ -86,12 +90,17 @@ cc::TaskGraphRunner* SurfaceContextFactory::GetTaskGraphRunner() { return raster_thread_helper_.task_graph_runner(); } -scoped_ptr<cc::SurfaceIdAllocator> +std::unique_ptr<cc::SurfaceIdAllocator> SurfaceContextFactory::CreateSurfaceIdAllocator() { - return make_scoped_ptr( + return base::WrapUnique( new cc::SurfaceIdAllocator(next_surface_id_namespace_++)); } +cc::SurfaceManager* SurfaceContextFactory::GetSurfaceManager() { + // NOTIMPLEMENTED(); + return nullptr; +} + void SurfaceContextFactory::ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) { // NOTIMPLEMENTED(); diff --git a/chromium/ui/views/mus/surface_context_factory.h b/chromium/ui/views/mus/surface_context_factory.h index 6399d5a011b..61701e63e74 100644 --- a/chromium/ui/views/mus/surface_context_factory.h +++ b/chromium/ui/views/mus/surface_context_factory.h @@ -27,7 +27,7 @@ namespace views { class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory { public: - SurfaceContextFactory(mojo::Connector* connector, + SurfaceContextFactory(shell::Connector* connector, mus::Window* window, mus::mojom::SurfaceType surface_type); ~SurfaceContextFactory() override; @@ -35,7 +35,7 @@ class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory { private: // ContextFactory: void CreateOutputSurface(base::WeakPtr<ui::Compositor> compositor) override; - scoped_ptr<ui::Reflector> CreateReflector( + std::unique_ptr<ui::Reflector> CreateReflector( ui::Compositor* mirrored_compositor, ui::Layer* mirroring_layer) override; void RemoveReflector(ui::Reflector* reflector) override; @@ -47,9 +47,13 @@ class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory { cc::SharedBitmapManager* GetSharedBitmapManager() override; gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; cc::TaskGraphRunner* GetTaskGraphRunner() override; - scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override; + std::unique_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override; + cc::SurfaceManager* GetSurfaceManager() override; void ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) override; + void SetAuthoritativeVSyncInterval(ui::Compositor* compositor, + base::TimeDelta interval) override {} + void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {} SurfaceBinding surface_binding_; uint32_t next_surface_id_namespace_; diff --git a/chromium/ui/views/mus/unittests_manifest.json b/chromium/ui/views/mus/unittests_manifest.json new file mode 100644 index 00000000000..23ef6e3fd84 --- /dev/null +++ b/chromium/ui/views/mus/unittests_manifest.json @@ -0,0 +1,10 @@ +{ + "manifest_version": 1, + "name": "mojo:views_mus_unittests", + "display_name": "Views Mus Unittests", + "capabilities": { + "required": { + "*": { "classes": [ "app" ] } + } + } +} diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc new file mode 100644 index 00000000000..a101f3b19be --- /dev/null +++ b/chromium/ui/views/mus/views_mus_test_suite.cc @@ -0,0 +1,160 @@ +// Copyright 2016 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 "ui/views/mus/views_mus_test_suite.h" + +#include <memory> + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/simple_thread.h" +#include "base/threading/thread.h" +#include "components/mus/common/switches.h" +#include "services/shell/background/background_shell.h" +#include "services/shell/public/cpp/connector.h" +#include "services/shell/public/cpp/shell_client.h" +#include "services/shell/public/cpp/shell_connection.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/mus/window_manager_connection.h" +#include "ui/views/test/platform_test_helper.h" +#include "ui/views/views_delegate.h" + +namespace views { +namespace { + +void EnsureCommandLineSwitch(const std::string& name) { + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (!cmd_line->HasSwitch(name)) + cmd_line->AppendSwitch(name); +} + +class DefaultShellClient : public shell::ShellClient { + public: + DefaultShellClient() {} + ~DefaultShellClient() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultShellClient); +}; + +class PlatformTestHelperMus : public PlatformTestHelper { + public: + PlatformTestHelperMus() { + ViewsDelegate::GetInstance()->set_native_widget_factory(base::Bind( + &WindowManagerConnection::CreateNativeWidgetMus, + base::Unretained(WindowManagerConnection::Get()), + std::map<std::string, std::vector<uint8_t>>())); + } + ~PlatformTestHelperMus() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(PlatformTestHelperMus); +}; + +std::unique_ptr<PlatformTestHelper> CreatePlatformTestHelper( + shell::Connector* connector, + const shell::Identity& identity) { + if (!WindowManagerConnection::Exists()) + WindowManagerConnection::Create(connector, identity); + return base::WrapUnique(new PlatformTestHelperMus); +} + +} // namespace + +class ShellConnection { + public: + ShellConnection() : thread_("Persistent shell connections") { + base::WaitableEvent wait(false, false); + base::Thread::Options options; + thread_.StartWithOptions(options); + thread_.task_runner()->PostTask( + FROM_HERE, base::Bind(&ShellConnection::SetUpConnections, + base::Unretained(this), &wait)); + wait.Wait(); + + // WindowManagerConnection cannot be created from here yet, although the + // connector and identity are available at this point. This is because + // WindowManagerConnection needs a ViewsDelegate and a MessageLoop to have + // been installed first. So delay the creation until the necessary + // dependencies have been met. + PlatformTestHelper::set_factory(base::Bind( + &CreatePlatformTestHelper, shell_connector_.get(), shell_identity_)); + } + + ~ShellConnection() { + if (views::WindowManagerConnection::Exists()) + views::WindowManagerConnection::Reset(); + base::WaitableEvent wait(false, false); + thread_.task_runner()->PostTask( + FROM_HERE, base::Bind(&ShellConnection::TearDownConnections, + base::Unretained(this), &wait)); + wait.Wait(); + } + + private: + void SetUpConnections(base::WaitableEvent* wait) { + background_shell_.reset(new shell::BackgroundShell); + background_shell_->Init(nullptr); + shell_client_.reset(new DefaultShellClient); + shell_connection_.reset(new shell::ShellConnection( + shell_client_.get(), + background_shell_->CreateShellClientRequest(GetTestName()))); + + // ui/views/mus requires a WindowManager running, for now use the desktop + // one. + shell::Connector* connector = shell_connection_->connector(); + connector->Connect("mojo:desktop_wm"); + shell_connector_ = connector->Clone(); + shell_identity_ = shell_connection_->identity(); + wait->Signal(); + } + + void TearDownConnections(base::WaitableEvent* wait) { + shell_connection_.reset(); + wait->Signal(); + } + + // Returns the name of the test executable, e.g. "exe:views_mus_unittests". + std::string GetTestName() { + base::FilePath executable = base::CommandLine::ForCurrentProcess() + ->GetProgram() + .BaseName() + .RemoveExtension(); + return std::string("exe:") + executable.MaybeAsASCII(); + } + + base::Thread thread_; + std::unique_ptr<shell::BackgroundShell> background_shell_; + std::unique_ptr<shell::ShellConnection> shell_connection_; + std::unique_ptr<DefaultShellClient> shell_client_; + std::unique_ptr<shell::Connector> shell_connector_; + shell::Identity shell_identity_; + + DISALLOW_COPY_AND_ASSIGN(ShellConnection); +}; + +ViewsMusTestSuite::ViewsMusTestSuite(int argc, char** argv) + : ViewsTestSuite(argc, argv) {} + +ViewsMusTestSuite::~ViewsMusTestSuite() {} + +void ViewsMusTestSuite::Initialize() { + PlatformTestHelper::SetIsMus(); + // Let other mojo apps know that we're running in tests. Do this with a + // command line flag to avoid making blocking calls to other processes for + // setup for tests (e.g. to unlock the screen in the window manager). + EnsureCommandLineSwitch(mus::switches::kUseTestConfig); + + ViewsTestSuite::Initialize(); + shell_connections_.reset(new ShellConnection); +} + +void ViewsMusTestSuite::Shutdown() { + shell_connections_.reset(); + ViewsTestSuite::Shutdown(); +} + +} // namespace views diff --git a/chromium/ui/views/mus/views_mus_test_suite.h b/chromium/ui/views/mus/views_mus_test_suite.h new file mode 100644 index 00000000000..0f801bf1a84 --- /dev/null +++ b/chromium/ui/views/mus/views_mus_test_suite.h @@ -0,0 +1,34 @@ +// Copyright 2016 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 UI_VIEWS_MUS_VIEWS_MUS_TEST_SUITE_H_ +#define UI_VIEWS_MUS_VIEWS_MUS_TEST_SUITE_H_ + +#include <memory> + +#include "base/macros.h" +#include "ui/views/views_test_suite.h" + +namespace views { + +class ShellConnection; + +class ViewsMusTestSuite : public ViewsTestSuite { + public: + ViewsMusTestSuite(int argc, char** argv); + ~ViewsMusTestSuite() override; + + private: + // ViewsTestSuite: + void Initialize() override; + void Shutdown() override; + + std::unique_ptr<ShellConnection> shell_connections_; + + DISALLOW_COPY_AND_ASSIGN(ViewsMusTestSuite); +}; + +} // namespace views + +#endif // UI_VIEWS_MUS_VIEWS_MUS_TEST_SUITE_H_ diff --git a/chromium/ui/views/mus/window_manager_connection.cc b/chromium/ui/views/mus/window_manager_connection.cc index fc41913602f..a76ffa6ebd4 100644 --- a/chromium/ui/views/mus/window_manager_connection.cc +++ b/chromium/ui/views/mus/window_manager_connection.cc @@ -8,13 +8,19 @@ #include "base/lazy_instance.h" #include "base/threading/thread_local.h" +#include "components/mus/public/cpp/property_type_converters.h" +#include "components/mus/public/cpp/window.h" +#include "components/mus/public/cpp/window_property.h" #include "components/mus/public/cpp/window_tree_connection.h" +#include "components/mus/public/interfaces/event_matcher.mojom.h" #include "components/mus/public/interfaces/window_tree.mojom.h" #include "mojo/converters/geometry/geometry_type_converters.h" -#include "mojo/shell/public/cpp/connection.h" -#include "mojo/shell/public/cpp/connector.h" +#include "services/shell/public/cpp/connection.h" +#include "services/shell/public/cpp/connector.h" +#include "ui/events/devices/device_data_manager.h" #include "ui/views/mus/native_widget_mus.h" #include "ui/views/mus/screen_mus.h" +#include "ui/views/pointer_watcher.h" #include "ui/views/views_delegate.h" namespace views { @@ -30,9 +36,10 @@ base::LazyInstance<WindowManagerConnectionPtr>::Leaky lazy_tls_ptr = } // namespace // static -void WindowManagerConnection::Create(mojo::Connector* connector) { +void WindowManagerConnection::Create(shell::Connector* connector, + const shell::Identity& identity) { DCHECK(!lazy_tls_ptr.Pointer()->Get()); - lazy_tls_ptr.Pointer()->Set(new WindowManagerConnection(connector)); + lazy_tls_ptr.Pointer()->Set(new WindowManagerConnection(connector, identity)); } // static @@ -64,18 +71,50 @@ NativeWidget* WindowManagerConnection::CreateNativeWidgetMus( internal::NativeWidgetDelegate* delegate) { std::map<std::string, std::vector<uint8_t>> properties = props; NativeWidgetMus::ConfigurePropertiesForNewWindow(init_params, &properties); + properties[mus::mojom::WindowManager::kAppID_Property] = + mojo::ConvertTo<std::vector<uint8_t>>(identity_.name()); return new NativeWidgetMus(delegate, connector_, NewWindow(properties), mus::mojom::SurfaceType::DEFAULT); } -WindowManagerConnection::WindowManagerConnection(mojo::Connector* connector) - : connector_(connector), window_tree_connection_(nullptr) { +void WindowManagerConnection::AddPointerWatcher(PointerWatcher* watcher) { + bool had_watcher = HasPointerWatcher(); + pointer_watchers_.AddObserver(watcher); + if (!had_watcher) { + // Start a watcher for pointer down. + // TODO(jamescook): Extend event observers to handle multiple event types. + mus::mojom::EventMatcherPtr matcher = mus::mojom::EventMatcher::New(); + matcher->type_matcher = mus::mojom::EventTypeMatcher::New(); + matcher->type_matcher->type = mus::mojom::EventType::POINTER_DOWN; + window_tree_connection_->SetEventObserver(std::move(matcher)); + } +} + +void WindowManagerConnection::RemovePointerWatcher(PointerWatcher* watcher) { + pointer_watchers_.RemoveObserver(watcher); + if (!HasPointerWatcher()) { + // Last PointerWatcher removed, stop the event observer. + window_tree_connection_->SetEventObserver(nullptr); + } +} + +WindowManagerConnection::WindowManagerConnection( + shell::Connector* connector, + const shell::Identity& identity) + : connector_(connector), + identity_(identity), + window_tree_connection_(nullptr) { window_tree_connection_.reset( mus::WindowTreeConnection::Create(this, connector_)); screen_.reset(new ScreenMus(this)); screen_->Init(connector); + // TODO(sad): We should have a DeviceDataManager implementation that talks to + // a mojo service to learn about the input-devices on the system. + // http://crbug.com/601981 + ui::DeviceDataManager::CreateInstance(); + ViewsDelegate::GetInstance()->set_native_widget_factory(base::Bind( &WindowManagerConnection::CreateNativeWidgetMus, base::Unretained(this), @@ -86,6 +125,16 @@ WindowManagerConnection::~WindowManagerConnection() { // ~WindowTreeConnection calls back to us (we're the WindowTreeDelegate), // destroy it while we are still valid. window_tree_connection_.reset(); + + ui::DeviceDataManager::DeleteInstance(); +} + +bool WindowManagerConnection::HasPointerWatcher() { + // Check to see if we really have any observers left. This doesn't use + // base::ObserverList<>::might_have_observers() because that returns true + // during iteration over the list even when the last observer is removed. + base::ObserverList<PointerWatcher>::Iterator iterator(&pointer_watchers_); + return !!iterator.GetNext(); } void WindowManagerConnection::OnEmbed(mus::Window* root) {} @@ -93,9 +142,38 @@ void WindowManagerConnection::OnEmbed(mus::Window* root) {} void WindowManagerConnection::OnConnectionLost( mus::WindowTreeConnection* connection) {} +void WindowManagerConnection::OnEventObserved(const ui::Event& event, + mus::Window* target) { + if (!event.IsLocatedEvent()) + return; + Widget* target_widget = nullptr; + if (target) { + mus::Window* root = target->GetRoot(); + target_widget = NativeWidgetMus::GetWidgetForWindow(root); + } + + // The mojo input events type converter uses the event root_location field + // to store screen coordinates. Screen coordinates really should be returned + // separately. See http://crbug.com/608547 + gfx::Point location_in_screen = event.AsLocatedEvent()->root_location(); + if (event.type() == ui::ET_MOUSE_PRESSED) { + FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_, + OnMousePressed(*event.AsMouseEvent(), location_in_screen, + target_widget)); + } else if (event.type() == ui::ET_TOUCH_PRESSED) { + FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_, + OnTouchPressed(*event.AsTouchEvent(), location_in_screen, + target_widget)); + } +} + void WindowManagerConnection::OnWindowManagerFrameValuesChanged() { if (window_tree_connection_) NativeWidgetMus::NotifyFrameChanged(window_tree_connection_.get()); } +gfx::Point WindowManagerConnection::GetCursorScreenPoint() { + return window_tree_connection_->GetCursorScreenPoint(); +} + } // namespace views diff --git a/chromium/ui/views/mus/window_manager_connection.h b/chromium/ui/views/mus/window_manager_connection.h index 69059893346..049e09509af 100644 --- a/chromium/ui/views/mus/window_manager_connection.h +++ b/chromium/ui/views/mus/window_manager_connection.h @@ -7,19 +7,23 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" #include "components/mus/public/cpp/window_tree_delegate.h" +#include "services/shell/public/cpp/identity.h" #include "ui/views/mus/mus_export.h" #include "ui/views/mus/screen_mus_delegate.h" #include "ui/views/widget/widget.h" -namespace mojo { +namespace shell { class Connector; } namespace views { class NativeWidget; +class PointerWatcher; class ScreenMus; namespace internal { class NativeWidgetDelegate; @@ -37,14 +41,15 @@ class VIEWS_MUS_EXPORT WindowManagerConnection : public NON_EXPORTED_BASE(mus::WindowTreeDelegate), public ScreenMusDelegate { public: - static void Create(mojo::Connector* connector); + static void Create(shell::Connector* connector, + const shell::Identity& identity); static WindowManagerConnection* Get(); static bool Exists(); // Destroys the singleton instance. static void Reset(); - mojo::Connector* connector() { return connector_; } + shell::Connector* connector() { return connector_; } mus::Window* NewWindow(const std::map<std::string, std::vector<uint8_t>>& properties); @@ -54,20 +59,34 @@ class VIEWS_MUS_EXPORT WindowManagerConnection const Widget::InitParams& init_params, internal::NativeWidgetDelegate* delegate); + void AddPointerWatcher(PointerWatcher* watcher); + void RemovePointerWatcher(PointerWatcher* watcher); + private: - explicit WindowManagerConnection(mojo::Connector* connector); + friend class WindowManagerConnectionTest; + + WindowManagerConnection(shell::Connector* connector, + const shell::Identity& identity); ~WindowManagerConnection() override; + // Returns true if there is one or more pointer watchers for this client. + bool HasPointerWatcher(); + // mus::WindowTreeDelegate: void OnEmbed(mus::Window* root) override; void OnConnectionLost(mus::WindowTreeConnection* connection) override; + void OnEventObserved(const ui::Event& event, mus::Window* target) override; // ScreenMusDelegate: void OnWindowManagerFrameValuesChanged() override; - - mojo::Connector* connector_; - scoped_ptr<ScreenMus> screen_; - scoped_ptr<mus::WindowTreeConnection> window_tree_connection_; + gfx::Point GetCursorScreenPoint() override; + + shell::Connector* connector_; + shell::Identity identity_; + std::unique_ptr<ScreenMus> screen_; + std::unique_ptr<mus::WindowTreeConnection> window_tree_connection_; + // Must be empty on destruction. + base::ObserverList<PointerWatcher, true> pointer_watchers_; DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection); }; diff --git a/chromium/ui/views/mus/window_manager_connection_unittest.cc b/chromium/ui/views/mus/window_manager_connection_unittest.cc new file mode 100644 index 00000000000..8d86447c5be --- /dev/null +++ b/chromium/ui/views/mus/window_manager_connection_unittest.cc @@ -0,0 +1,118 @@ +// Copyright 2016 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 "ui/views/mus/window_manager_connection.h" + +#include <memory> + +#include "base/message_loop/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event.h" +#include "ui/views/pointer_watcher.h" +#include "ui/views/test/scoped_views_test_helper.h" + +namespace views { +namespace { + +class TestPointerWatcher : public PointerWatcher { + public: + TestPointerWatcher() {} + ~TestPointerWatcher() override {} + + bool mouse_pressed() const { return mouse_pressed_; } + bool touch_pressed() const { return touch_pressed_; } + + void Reset() { + mouse_pressed_ = false; + touch_pressed_ = false; + } + + // PointerWatcher: + void OnMousePressed(const ui::MouseEvent& event, + const gfx::Point& location_in_screen, + Widget* target) override { + mouse_pressed_ = true; + } + void OnTouchPressed(const ui::TouchEvent& event, + const gfx::Point& location_in_screen, + Widget* target) override { + touch_pressed_ = true; + } + + private: + bool mouse_pressed_ = false; + bool touch_pressed_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestPointerWatcher); +}; + +} // namespace + +class WindowManagerConnectionTest : public testing::Test { + public: + WindowManagerConnectionTest() {} + ~WindowManagerConnectionTest() override {} + + void OnEventObserved(const ui::Event& event) { + WindowManagerConnection::Get()->OnEventObserved(event, nullptr); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WindowManagerConnectionTest); +}; + +TEST_F(WindowManagerConnectionTest, PointerWatcher) { + base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); + ScopedViewsTestHelper helper; + WindowManagerConnection* connection = WindowManagerConnection::Get(); + ASSERT_TRUE(connection); + ui::MouseEvent mouse_pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + base::TimeDelta(), ui::EF_NONE, 0); + ui::TouchEvent touch_pressed(ui::ET_TOUCH_PRESSED, gfx::Point(), 1, + base::TimeDelta()); + ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); + + // PointerWatchers receive mouse events. + TestPointerWatcher watcher1; + connection->AddPointerWatcher(&watcher1); + OnEventObserved(mouse_pressed); + EXPECT_TRUE(watcher1.mouse_pressed()); + watcher1.Reset(); + + // PointerWatchers receive touch events. + OnEventObserved(touch_pressed); + EXPECT_TRUE(watcher1.touch_pressed()); + watcher1.Reset(); + + // PointerWatchers do not trigger for key events. + OnEventObserved(key_pressed); + EXPECT_FALSE(watcher1.mouse_pressed()); + EXPECT_FALSE(watcher1.touch_pressed()); + watcher1.Reset(); + + // Two PointerWatchers can both receive a single observed event. + TestPointerWatcher watcher2; + connection->AddPointerWatcher(&watcher2); + OnEventObserved(mouse_pressed); + EXPECT_TRUE(watcher1.mouse_pressed()); + EXPECT_TRUE(watcher2.mouse_pressed()); + watcher1.Reset(); + watcher2.Reset(); + + // Removing the first PointerWatcher stops sending events to it. + connection->RemovePointerWatcher(&watcher1); + OnEventObserved(mouse_pressed); + EXPECT_FALSE(watcher1.mouse_pressed()); + EXPECT_TRUE(watcher2.mouse_pressed()); + watcher1.Reset(); + watcher2.Reset(); + + // Removing the last PointerWatcher stops sending events to it. + connection->RemovePointerWatcher(&watcher2); + OnEventObserved(mouse_pressed); + EXPECT_FALSE(watcher1.mouse_pressed()); + EXPECT_FALSE(watcher1.touch_pressed()); +} + +} // namespace views diff --git a/chromium/ui/views/mus/window_tree_host_mus.cc b/chromium/ui/views/mus/window_tree_host_mus.cc index 2880c0bf480..e360eb05b46 100644 --- a/chromium/ui/views/mus/window_tree_host_mus.cc +++ b/chromium/ui/views/mus/window_tree_host_mus.cc @@ -4,6 +4,7 @@ #include "ui/views/mus/window_tree_host_mus.h" +#include "base/memory/ptr_util.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/events/event.h" @@ -16,13 +17,12 @@ namespace views { //////////////////////////////////////////////////////////////////////////////// // WindowTreeHostMus, public: -WindowTreeHostMus::WindowTreeHostMus(mojo::Connector* connector, +WindowTreeHostMus::WindowTreeHostMus(shell::Connector* connector, NativeWidgetMus* native_widget, mus::Window* window) - : native_widget_(native_widget), - show_state_(ui::PLATFORM_WINDOW_STATE_UNKNOWN) { + : native_widget_(native_widget) { SetPlatformWindow( - make_scoped_ptr(new PlatformWindowMus(this, connector, window))); + base::WrapUnique(new PlatformWindowMus(this, connector, window))); // The location of events is already transformed, and there is no way to // correctly determine the reverse transform. So, don't attempt to transform // event locations, else the root location is wrong. @@ -58,10 +58,6 @@ void WindowTreeHostMus::OnClosed() { native_widget_->OnPlatformWindowClosed(); } -void WindowTreeHostMus::OnWindowStateChanged(ui::PlatformWindowState state) { - show_state_ = state; -} - void WindowTreeHostMus::OnActivationChanged(bool active) { if (active) GetInputMethod()->OnFocus(); diff --git a/chromium/ui/views/mus/window_tree_host_mus.h b/chromium/ui/views/mus/window_tree_host_mus.h index 0bffe25ea13..30da7ed2d3f 100644 --- a/chromium/ui/views/mus/window_tree_host_mus.h +++ b/chromium/ui/views/mus/window_tree_host_mus.h @@ -11,14 +11,14 @@ class SkBitmap; -namespace mojo { -class Connector; -} - namespace mus { class Window; } +namespace shell { +class Connector; +} + namespace views { class InputMethodMUS; @@ -27,25 +27,22 @@ class PlatformWindowMus; class VIEWS_MUS_EXPORT WindowTreeHostMus : public aura::WindowTreeHostPlatform { public: - WindowTreeHostMus(mojo::Connector* connector, + WindowTreeHostMus(shell::Connector* connector, NativeWidgetMus* native_widget, mus::Window* window); ~WindowTreeHostMus() override; PlatformWindowMus* platform_window(); - ui::PlatformWindowState show_state() const { return show_state_; } private: // aura::WindowTreeHostPlatform: void DispatchEvent(ui::Event* event) override; void OnClosed() override; - void OnWindowStateChanged(ui::PlatformWindowState new_state) override; void OnActivationChanged(bool active) override; void OnCloseRequest() override; NativeWidgetMus* native_widget_; - scoped_ptr<InputMethodMUS> input_method_; - ui::PlatformWindowState show_state_; + std::unique_ptr<InputMethodMUS> input_method_; DISALLOW_COPY_AND_ASSIGN(WindowTreeHostMus); }; diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc index 9a677956f84..d48a7ef2ef5 100644 --- a/chromium/ui/views/painter.cc +++ b/chromium/ui/views/painter.cc @@ -4,9 +4,11 @@ #include "ui/views/painter.h" +#include <memory> + #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" @@ -149,9 +151,9 @@ class GradientPainter : public Painter { // If |horizontal_| is true then the gradient is painted horizontally. bool horizontal_; // The gradient colors. - scoped_ptr<SkColor[]> colors_; + std::unique_ptr<SkColor[]> colors_; // The relative positions of the corresponding gradient colors. - scoped_ptr<SkScalar[]> pos_; + std::unique_ptr<SkScalar[]> pos_; // The number of elements in |colors_| and |pos_|. size_t count_; @@ -216,7 +218,7 @@ class ImagePainter : public Painter { void Paint(gfx::Canvas* canvas, const gfx::Size& size) override; private: - scoped_ptr<gfx::NineImagePainter> nine_painter_; + std::unique_ptr<gfx::NineImagePainter> nine_painter_; DISALLOW_COPY_AND_ASSIGN(ImagePainter); }; @@ -256,7 +258,8 @@ Painter::~Painter() { void Painter::PaintPainterAt(gfx::Canvas* canvas, Painter* painter, const gfx::Rect& rect) { - DCHECK(canvas && painter); + DCHECK(canvas); + DCHECK(painter); canvas->Save(); canvas->Translate(rect.OffsetFromOrigin()); painter->Paint(canvas, rect.size()); @@ -313,21 +316,21 @@ Painter* Painter::CreateImageGridPainter(const int image_ids[]) { } // static -scoped_ptr<Painter> Painter::CreateDashedFocusPainter() { - return make_scoped_ptr(new DashedFocusPainter(gfx::Insets())); +std::unique_ptr<Painter> Painter::CreateDashedFocusPainter() { + return base::WrapUnique(new DashedFocusPainter(gfx::Insets())); } // static -scoped_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets( +std::unique_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets( const gfx::Insets& insets) { - return make_scoped_ptr(new DashedFocusPainter(insets)); + return base::WrapUnique(new DashedFocusPainter(insets)); } // static -scoped_ptr<Painter> Painter::CreateSolidFocusPainter( +std::unique_ptr<Painter> Painter::CreateSolidFocusPainter( SkColor color, const gfx::Insets& insets) { - return make_scoped_ptr(new SolidFocusPainter(color, insets)); + return base::WrapUnique(new SolidFocusPainter(color, insets)); } // HorizontalPainter ---------------------------------------------------------- diff --git a/chromium/ui/views/painter.h b/chromium/ui/views/painter.h index 76cc996f50c..cffe1c166b4 100644 --- a/chromium/ui/views/painter.h +++ b/chromium/ui/views/painter.h @@ -7,9 +7,10 @@ #include <stddef.h> +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/nine_image_painter_factory.h" #include "ui/views/views_export.h" @@ -77,11 +78,12 @@ class VIEWS_EXPORT Painter { static Painter* CreateImageGridPainter(const int image_ids[]); // Factory methods for creating painters intended for rendering focus. - static scoped_ptr<Painter> CreateDashedFocusPainter(); - static scoped_ptr<Painter> CreateDashedFocusPainterWithInsets( + static std::unique_ptr<Painter> CreateDashedFocusPainter(); + static std::unique_ptr<Painter> CreateDashedFocusPainterWithInsets( + const gfx::Insets& insets); + static std::unique_ptr<Painter> CreateSolidFocusPainter( + SkColor color, const gfx::Insets& insets); - static scoped_ptr<Painter> CreateSolidFocusPainter(SkColor color, - const gfx::Insets& insets); // Returns the minimum size this painter can paint without obvious graphical // problems (e.g. overlapping images). diff --git a/chromium/ui/views/pointer_watcher.h b/chromium/ui/views/pointer_watcher.h new file mode 100644 index 00000000000..2abc4cb42d2 --- /dev/null +++ b/chromium/ui/views/pointer_watcher.h @@ -0,0 +1,42 @@ +// Copyright 2016 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 UI_VIEWS_POINTER_WATCHER_H_ +#define UI_VIEWS_POINTER_WATCHER_H_ + +#include "ui/views/views_export.h" + +namespace gfx { +class Point; +} + +namespace ui { +class MouseEvent; +class TouchEvent; +} + +namespace views { +class Widget; + +// An interface for read-only observation of pointer events (in particular, the +// events cannot be marked as handled). Only certain event types are supported. +// The |target| is the top-level widget that will receive the event, if any. +// NOTE: On mus this allows observation of events outside of windows owned +// by the current process, in which case the |target| will be null. On mus +// event.target() is always null. +class VIEWS_EXPORT PointerWatcher { + public: + virtual ~PointerWatcher() {} + + virtual void OnMousePressed(const ui::MouseEvent& event, + const gfx::Point& location_in_screen, + Widget* target) = 0; + virtual void OnTouchPressed(const ui::TouchEvent& event, + const gfx::Point& location_in_screen, + Widget* target) = 0; +}; + +} // namespace views + +#endif // UI_VIEWS_POINTER_WATCHER_H_ diff --git a/chromium/ui/views/run_all_unittests.cc b/chromium/ui/views/run_all_unittests.cc deleted file mode 100644 index 922343bdc91..00000000000 --- a/chromium/ui/views/run_all_unittests.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 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 "base/bind.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/test/launcher/unit_test_launcher.h" -#include "base/test/test_suite.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_paths.h" -#include "ui/gl/test/gl_surface_test_support.h" - -#if defined(USE_AURA) -#include "ui/aura/env.h" -#endif - -namespace views { - -class ViewTestSuite : public base::TestSuite { - public: - ViewTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {} - - protected: - void Initialize() override { - base::TestSuite::Initialize(); - gfx::GLSurfaceTestSupport::InitializeOneOff(); - ui::RegisterPathProvider(); - - base::FilePath ui_test_pak_path; - ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); - ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); -#if defined(USE_AURA) - aura::Env::CreateInstance(true); -#endif - } - - void Shutdown() override { -#if defined(USE_AURA) - aura::Env::DeleteInstance(); -#endif - ui::ResourceBundle::CleanupSharedInstance(); - base::TestSuite::Shutdown(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ViewTestSuite); -}; - -int RunAllUnittests(int argc, char** argv) { - ViewTestSuite test_suite(argc, argv); - - return base::LaunchUnitTests( - argc, argv, base::Bind(&ViewTestSuite::Run, - base::Unretained(&test_suite))); -} - -} // namespace views diff --git a/chromium/ui/views/run_all_unittests.h b/chromium/ui/views/run_all_unittests.h deleted file mode 100644 index 43239f80772..00000000000 --- a/chromium/ui/views/run_all_unittests.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 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 UI_VIEWS_RUN_ALL_UNITTESTS_H_ -#define UI_VIEWS_RUN_ALL_UNITTESTS_H_ - -namespace views { - -int RunAllUnittests(int argc, char** argv); - -} // namespace - -#endif // UI_VIEWS_RUN_ALL_UNITTESTS_H_ diff --git a/chromium/ui/views/run_all_unittests_main.cc b/chromium/ui/views/run_all_unittests_main.cc index 5b26c760050..f3b39f0e557 100644 --- a/chromium/ui/views/run_all_unittests_main.cc +++ b/chromium/ui/views/run_all_unittests_main.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/views/run_all_unittests.h" +#include "ui/views/views_test_suite.h" int main(int argc, char** argv) { - views::RunAllUnittests(argc, argv); + return views::ViewsTestSuite(argc, argv).RunTests(); } diff --git a/chromium/ui/views/style/mac/combobox_background_mac.cc b/chromium/ui/views/style/mac/combobox_background_mac.cc index 31997b15b78..1a97a7e412a 100644 --- a/chromium/ui/views/style/mac/combobox_background_mac.cc +++ b/chromium/ui/views/style/mac/combobox_background_mac.cc @@ -7,35 +7,39 @@ #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRRect.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/scoped_canvas.h" #include "ui/native_theme/native_theme_mac.h" -#include "ui/views/controls/combobox/combobox.h" #include "ui/views/view.h" +using ui::NativeThemeMac; + namespace views { -ComboboxBackgroundMac::ComboboxBackgroundMac() {} +ComboboxBackgroundMac::ComboboxBackgroundMac(int container_width) + : container_width_(container_width) {} ComboboxBackgroundMac::~ComboboxBackgroundMac() {} void ComboboxBackgroundMac::Paint(gfx::Canvas* canvas, View* view) const { - DCHECK_EQ(view->GetClassName(), Combobox::kViewClassName); - Combobox* combobox = static_cast<Combobox*>(view); + gfx::RectF bounds(view->GetLocalBounds()); + gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, view->bounds()); - gfx::RectF bounds(combobox->GetLocalBounds()); // Inset the left side far enough to draw only the arrow button, and inset the // other three sides by half a pixel so the edge of the background doesn't // paint outside the border. - bounds.Inset(bounds.width() - combobox->GetArrowButtonWidth(), 0.5, 0.5, 0.5); + bounds.Inset(bounds.width() - container_width_, 0.5, 0.5, 0.5); - ui::NativeTheme::State state = ui::NativeTheme::kNormal; - if (!combobox->enabled()) - state = ui::NativeTheme::kDisabled; + // TODO(tapted): Check whether the Widget is active, and use the NORMAL + // BackgroundType if it is inactive. Handling this properly also requires the + // control to observe the Widget for activation changes and invalidate. + NativeThemeMac::ButtonBackgroundType type = + NativeThemeMac::ButtonBackgroundType::HIGHLIGHTED; + if (!view->enabled()) + type = NativeThemeMac::ButtonBackgroundType::DISABLED; SkPaint paint; paint.setShader( - ui::NativeThemeMac::GetButtonBackgroundShader( - state, - bounds.height())); + NativeThemeMac::GetButtonBackgroundShader(type, bounds.height())); paint.setStyle(SkPaint::kFill_Style); paint.setAntiAlias(true); diff --git a/chromium/ui/views/style/mac/combobox_background_mac.h b/chromium/ui/views/style/mac/combobox_background_mac.h index 5be50858d75..353deab74d7 100644 --- a/chromium/ui/views/style/mac/combobox_background_mac.h +++ b/chromium/ui/views/style/mac/combobox_background_mac.h @@ -23,12 +23,17 @@ namespace views { // Mac look and feel. class ComboboxBackgroundMac : public Background { public: - ComboboxBackgroundMac(); + // The |container_width| argument is the width of the "arrows" section from + // the diagram above, including any necessary padding around the actual arrow. + explicit ComboboxBackgroundMac(int container_width); ~ComboboxBackgroundMac() override; // Background: void Paint(gfx::Canvas* canvas, View* view) const override; + private: + int container_width_; + DISALLOW_COPY_AND_ASSIGN(ComboboxBackgroundMac); }; diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac.cc b/chromium/ui/views/style/mac/dialog_button_border_mac.cc index 366fbc28e9c..232c66d9ce8 100644 --- a/chromium/ui/views/style/mac/dialog_button_border_mac.cc +++ b/chromium/ui/views/style/mac/dialog_button_border_mac.cc @@ -5,116 +5,62 @@ #include "ui/views/style/mac/dialog_button_border_mac.h" #include "base/logging.h" -#include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDrawLooper.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/gfx/canvas.h" +#include "ui/native_theme/native_theme_mac.h" #include "ui/views/border.h" #include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/button/label_button.h" + +using ui::NativeThemeMac; namespace views { namespace { -// Type to map button states to a corresponding SkColor. -typedef const SkColor ColorByState[Button::STATE_COUNT]; - -// If a state is added, ColorByState will silently fill with zeros, so assert. -static_assert(Button::STATE_COUNT == 4, - "DialogButtonBorderMac assumes 4 button states."); - // Corner radius of rounded rectangles. const SkScalar kCornerRadius = 2; +const SkScalar kFocusCornerRadius = 4; +const SkScalar kFocusRingThickness = 3; -// Vertical offset of the drop shadow and the inner highlight shadow. -const SkScalar kShadowOffsetY = 1; - -// Shadow blur radius of the inner highlight shadow. -const double kInnerShadowBlurRadius = 2.0; +const SkColor kDefaultBorderColor = SkColorSetARGB(0xF2, 0xBA, 0xBA, 0xBA); +const SkColor kHighlightedBorderColor = SkColorSetARGB(0xFF, 0x52, 0x76, 0xFF); +const SkColor kFocusRingColor = SkColorSetARGB(0x80, 0x3B, 0x9A, 0xFC); // Default border insets, to provide text padding. -const int kPaddingX = 14; -const int kPaddingY = 4; - -sk_sp<SkShader> CreateButtonGradient(int height, - Button::ButtonState state) { - ColorByState start = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED}; - ColorByState end = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE}; - - SkPoint gradient_points[2]; - gradient_points[0].iset(0, 0); - gradient_points[1].iset(0, height); +const int kPaddingX = 19; +const int kPaddingY = 7; - SkColor gradient_colors[] = {start[state], start[state], end[state]}; - SkScalar gradient_positions[] = {0.0, 0.38, 1.0}; - - return SkGradientShader::MakeLinear( - gradient_points, gradient_colors, gradient_positions, 3, - SkShader::kClamp_TileMode); -} - -void DrawConstrainedButtonBackground(const SkRect& button_rect, - SkCanvas* canvas, - Button::ButtonState button_state) { +void DrawDialogButtonBackground(const SkRect& button_rect, + SkCanvas* canvas, + const LabelButton& button) { // Extend the size of the SkRect so the border stroke is drawn over it on all // sides. SkRect rect(button_rect); rect.fRight += 1; rect.fBottom += 1; - SkPaint paint; - - // Drop Shadow. - ColorByState shadow = {0x14000000, 0x1F000000, 0x00000000, 0x00000000}; - const double blur = 0.0; - std::vector<gfx::ShadowValue> shadows( - 1, gfx::ShadowValue(gfx::Vector2d(0, kShadowOffsetY), blur, - shadow[button_state])); - paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); + NativeThemeMac::ButtonBackgroundType type = + NativeThemeMac::ButtonBackgroundType::NORMAL; + if (!button.enabled() || button.state() == Button::STATE_DISABLED) + type = NativeThemeMac::ButtonBackgroundType::DISABLED; + else if (button.state() == Button::STATE_PRESSED) + type = NativeThemeMac::ButtonBackgroundType::PRESSED; + else if (DialogButtonBorderMac::ShouldRenderDefault(button)) + type = NativeThemeMac::ButtonBackgroundType::HIGHLIGHTED; // Background. - paint.setShader(CreateButtonGradient(rect.height(), button_state)); + SkPaint paint; + paint.setShader( + NativeThemeMac::GetButtonBackgroundShader(type, rect.height())); paint.setStyle(SkPaint::kFill_Style); paint.setFlags(SkPaint::kAntiAlias_Flag); canvas->drawRoundRect(rect, kCornerRadius, kCornerRadius, paint); } -// Draws an inner box shadow inside a rounded rectangle of size |rect|. The -// technique: draw a black "ring" around the outside of the button cell. Then -// clip out everything except the shadow it casts. Works similar to Blink's -// GraphicsContext::drawInnerShadow(). -void DrawRoundRectInnerShadow(const SkRect& rect, - SkCanvas* canvas, - SkColor shadow_color) { - const gfx::Vector2d shadow_offset(0, kShadowOffsetY); - SkRect outer(rect); - outer.outset(abs(shadow_offset.x()) + kInnerShadowBlurRadius, - abs(shadow_offset.y()) + kInnerShadowBlurRadius); - - SkPath path; - path.addRect(outer); - path.setFillType(SkPath::kEvenOdd_FillType); - path.addRoundRect(rect, kCornerRadius, kCornerRadius); // Poke a hole. - - // Inset the clip to cater for the border stroke. - SkPath clip; - clip.addRoundRect(rect.makeInset(0.5, 0.5), kCornerRadius, kCornerRadius); - - SkPaint paint; - std::vector<gfx::ShadowValue> shadows( - 1, gfx::ShadowValue(shadow_offset, kInnerShadowBlurRadius, shadow_color)); - paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(SK_ColorBLACK); // Note: Entirely clipped. - - canvas->save(); - canvas->clipPath(clip, SkRegion::kIntersect_Op, true /* antialias */); - canvas->drawPath(path, paint); - canvas->restore(); -} - } // namespace DialogButtonBorderMac::DialogButtonBorderMac() { @@ -123,39 +69,56 @@ DialogButtonBorderMac::DialogButtonBorderMac() { DialogButtonBorderMac::~DialogButtonBorderMac() {} +// static +bool DialogButtonBorderMac::ShouldRenderDefault(const LabelButton& button) { + // TODO(tapted): Check whether the Widget is active, and only return true here + // if it is. Plumbing this requires default buttons to also observe Widget + // activations to ensure text and background colors are properly invalidated. + return button.is_default(); +} + void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) { + // Actually, |view| should be a LabelButton as well, but don't rely too much + // on RTTI. DCHECK(CustomButton::AsCustomButton(&view)); - const CustomButton& button = static_cast<const CustomButton&>(view); + const LabelButton& button = static_cast<const LabelButton&>(view); SkCanvas* canvas_skia = canvas->sk_canvas(); // Inset all sides for the rounded rectangle stroke. Inset again to make room - // for the shadows (while keeping the text centered). + // for the shadows and static focus ring (while keeping the text centered). SkRect sk_rect = gfx::RectToSkRect(view.GetLocalBounds()); - sk_rect.inset(2.0, 2.0); + sk_rect.inset(kFocusRingThickness, kFocusRingThickness); - DrawConstrainedButtonBackground(sk_rect, canvas_skia, button.state()); + DrawDialogButtonBackground(sk_rect, canvas_skia, button); // Offset so that strokes are contained within the pixel boundary. sk_rect.offset(0.5, 0.5); - ColorByState highlight = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000}; - DrawRoundRectInnerShadow(sk_rect, canvas_skia, highlight[button.state()]); - // Border or focus ring. + // Border and focus ring. + SkColor border_color = kDefaultBorderColor; + if (button.state() == Button::STATE_PRESSED || ShouldRenderDefault(button)) + border_color = kHighlightedBorderColor; + SkPaint paint; - ColorByState border = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000}; - const SkColor focus_border = {0xFF5DA5FF}; - paint.setStrokeWidth(1); paint.setStyle(SkPaint::kStroke_Style); paint.setFlags(SkPaint::kAntiAlias_Flag); - if (button.HasFocus() && button.state() != Button::STATE_PRESSED) - paint.setColor(focus_border); - else - paint.setColor(border[button.state()]); + paint.setStrokeWidth(1); + paint.setColor(border_color); canvas_skia->drawRoundRect(sk_rect, kCornerRadius, kCornerRadius, paint); + + if (button.HasFocus()) { + paint.setStrokeWidth(kFocusRingThickness); + paint.setColor(kFocusRingColor); + sk_rect.inset(-1, -1); + canvas_skia->drawRoundRect(sk_rect, kFocusCornerRadius, kFocusCornerRadius, + paint); + } } gfx::Size DialogButtonBorderMac::GetMinimumSize() const { - return gfx::Size(100, 30); + // Overridden by PlatformStyle. Here, just ensure the minimum size is + // consistent with the padding. + return gfx::Size(2 * kPaddingX, 2 * kPaddingY); } } // namespace views diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac.h b/chromium/ui/views/style/mac/dialog_button_border_mac.h index a45bc48e574..b10b09a9b7e 100644 --- a/chromium/ui/views/style/mac/dialog_button_border_mac.h +++ b/chromium/ui/views/style/mac/dialog_button_border_mac.h @@ -11,6 +11,8 @@ namespace views { +class LabelButton; + // Skia port of the default button style used for dialogs on Chrome Mac. // Originally provided by ConstrainedWindowButton, which used Quartz-backed // Cocoa drawing routines. @@ -19,6 +21,9 @@ class VIEWS_EXPORT DialogButtonBorderMac : public LabelButtonBorder { DialogButtonBorderMac(); ~DialogButtonBorderMac() override; + // Whether the given |button| should get a highlighted background. + static bool ShouldRenderDefault(const LabelButton& button); + // views::Border: void Paint(const View& view, gfx::Canvas* canvas) override; gfx::Size GetMinimumSize() const override; diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc b/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc index 471715b7613..950697481e1 100644 --- a/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc +++ b/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc @@ -5,6 +5,7 @@ #include "ui/views/style/mac/dialog_button_border_mac.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/compositor/canvas_painter.h" @@ -26,11 +27,11 @@ class TestLabelButton : public LabelButton { void set_provide_custom_border(bool value) { provide_custom_border_ = value; } // LabelButton: - scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const override { + std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override { if (!provide_custom_border_) return LabelButton::CreateDefaultBorder(); - return make_scoped_ptr(new LabelButtonAssetBorder(style())); + return base::WrapUnique(new LabelButtonAssetBorder(style())); } private: @@ -113,12 +114,9 @@ TEST_F(DialogButtonBorderMacTest, DrawMinimumSize) { EXPECT_LE(border_min_size.width(), view_preferred_size.width()); EXPECT_LE(border_min_size.height(), view_preferred_size.height()); - // Calling SetStyle(STYLE_BUTTON) sets a default minimum height that is larger - // than the border minimum height. Override that to match the border. - button.SetMinSize(gfx::Size()); - view_preferred_size = button.GetPreferredSize(); - EXPECT_EQ(border_min_size.width(), view_preferred_size.width()); - EXPECT_EQ(border_min_size.height(), view_preferred_size.height()); + // Note that Mac's PlatformStyle specifies a minimum button size, but it + // shouldn't be larger than the size of the button's label plus border insets. + // If it was, a Button::SetMinSize() call would be needed here to override it. button.SizeToPreferredSize(); EXPECT_EQ(view_preferred_size.width(), button.width()); @@ -147,19 +145,24 @@ TEST_F(DialogButtonBorderMacTest, DrawMinimumSize) { // Test drawing with some text. The usual case. TEST_F(DialogButtonBorderMacTest, DrawWithLabel) { - TestLabelButton button("Label Text That Exceeds the Minimum Button Size"); + TestLabelButton button(""); button.SetStyle(Button::STYLE_BUTTON); button.SimulateAddToWidget(); EXPECT_TRUE(BorderIsDialogButton(button)); - button.SetMinSize(gfx::Size()); button.SizeToPreferredSize(); + const gfx::Size no_label_size = button.size(); - // Long label, so the button width should be greater than in DrawMinimumSize. - const gfx::Size border_min_size = DialogButtonBorderMacSize(); - EXPECT_LT(border_min_size.width(), button.width()); - EXPECT_EQ(border_min_size.height(), button.height()); + button.SetText( + base::ASCIIToUTF16("Label Text That Exceeds the Minimum Button Size")); + button.SizeToPreferredSize(); + + // Long label, so the button width should be greater than the empty button. + EXPECT_LT(no_label_size.width(), button.width()); + + // The height shouldn't change. + EXPECT_EQ(no_label_size.height(), button.height()); TestPaintAllStates(&button, true); } diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc index 6719c9ba46b..e74281cdc88 100644 --- a/chromium/ui/views/style/platform_style.cc +++ b/chromium/ui/views/style/platform_style.cc @@ -4,9 +4,12 @@ #include "ui/views/style/platform_style.h" +#include "base/memory/ptr_util.h" #include "build/build_config.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/shadow_value.h" +#include "ui/native_theme/native_theme.h" #include "ui/resources/grit/ui_resources.h" #include "ui/views/background.h" #include "ui/views/controls/button/label_button.h" @@ -14,10 +17,28 @@ #include "ui/views/controls/focusable_border.h" #include "ui/views/controls/scrollbar/native_scroll_bar.h" +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#define DESKTOP_LINUX +#endif + namespace views { +namespace { + +#if !defined(DESKTOP_LINUX) && !defined(OS_MACOSX) +// Default text and shadow colors for STYLE_BUTTON. +const SkColor kStyleButtonTextColor = SK_ColorBLACK; +const SkColor kStyleButtonShadowColor = SK_ColorWHITE; +#endif + +} // namespace #if !defined(OS_MACOSX) +const int PlatformStyle::kMinLabelButtonWidth = 70; +const int PlatformStyle::kMinLabelButtonHeight = 33; +const bool PlatformStyle::kDefaultLabelButtonHasBoldFont = true; +const bool PlatformStyle::kTextfieldDragVerticallyDragsToEnd = false; + // static gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled, Combobox::Style style) { @@ -26,38 +47,66 @@ gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled, } // static -scoped_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() { - return make_scoped_ptr(new FocusableBorder()); +std::unique_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() { + return base::WrapUnique(new FocusableBorder()); } // static -scoped_ptr<Background> PlatformStyle::CreateComboboxBackground() { +std::unique_ptr<Background> PlatformStyle::CreateComboboxBackground( + int shoulder_width) { return nullptr; } // static -scoped_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder( +std::unique_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder( Button::ButtonStyle style) { if (!ui::MaterialDesignController::IsModeMaterial() || style != Button::STYLE_TEXTBUTTON) { - return make_scoped_ptr(new LabelButtonAssetBorder(style)); + return base::WrapUnique(new LabelButtonAssetBorder(style)); } - scoped_ptr<LabelButtonBorder> border(new views::LabelButtonBorder()); + std::unique_ptr<LabelButtonBorder> border(new views::LabelButtonBorder()); border->set_insets(views::LabelButtonAssetBorder::GetDefaultInsetsForStyle( Button::STYLE_TEXTBUTTON)); return border; } // static -scoped_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { - return make_scoped_ptr(new NativeScrollBar(is_horizontal)); +std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { + return base::WrapUnique(new NativeScrollBar(is_horizontal)); +} + +// static +SkColor PlatformStyle::TextColorForButton( + const ButtonColorByState& color_by_state, + const LabelButton& button) { + return color_by_state[button.state()]; +} + +#endif // OS_MACOSX + +#if !defined(DESKTOP_LINUX) && !defined(OS_MACOSX) +// static +void PlatformStyle::ApplyLabelButtonTextStyle( + Label* label, + ButtonColorByState* color_by_state) { + ButtonColorByState& colors = *color_by_state; + colors[Button::STATE_NORMAL] = kStyleButtonTextColor; + colors[Button::STATE_HOVERED] = kStyleButtonTextColor; + colors[Button::STATE_PRESSED] = kStyleButtonTextColor; + + const ui::NativeTheme* theme = label->GetNativeTheme(); + label->SetBackgroundColor( + theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonBackgroundColor)); + label->SetAutoColorReadabilityEnabled(false); + label->SetShadows(gfx::ShadowValues( + 1, gfx::ShadowValue(gfx::Vector2d(0, 1), 0, kStyleButtonShadowColor))); } #endif -#if !defined(OS_LINUX) || defined(OS_CHROMEOS) +#if !defined(DESKTOP_LINUX) // static -scoped_ptr<Border> PlatformStyle::CreateThemedLabelButtonBorder( +std::unique_ptr<Border> PlatformStyle::CreateThemedLabelButtonBorder( LabelButton* button) { return button->CreateDefaultBorder(); } diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h index 3103691642a..3a6392622d4 100644 --- a/chromium/ui/views/style/platform_style.h +++ b/chromium/ui/views/style/platform_style.h @@ -5,22 +5,39 @@ #ifndef UI_VIEWS_STYLE_PLATFORM_STYLE_H_ #define UI_VIEWS_STYLE_PLATFORM_STYLE_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/combobox/combobox.h" +#include "ui/views/views_export.h" namespace views { class Border; class FocusableBorder; +class Label; class LabelButton; class LabelButtonBorder; class ScrollBar; // Cross-platform API for providing platform-specific styling for toolkit-views. -class PlatformStyle { +class VIEWS_EXPORT PlatformStyle { public: + // Type used by LabelButton to map button states to text colors. + using ButtonColorByState = SkColor[Button::STATE_COUNT]; + + // Minimum size for platform-styled buttons (Button::STYLE_BUTTON). + static const int kMinLabelButtonWidth; + static const int kMinLabelButtonHeight; + + // Whether dialog-default buttons are given a bold font style. + static const bool kDefaultLabelButtonHasBoldFont; + + // Whether dragging vertically above or below a textfield's bounds selects to + // the left or right end of the text from the cursor, respectively. + static const bool kTextfieldDragVerticallyDragsToEnd; + // Creates an ImageSkia containing the image to use for the combobox arrow. // The |is_enabled| argument is true if the control the arrow is for is // enabled, and false if the control is disabled. The |style| argument is the @@ -29,21 +46,33 @@ class PlatformStyle { Combobox::Style style); // Creates the appropriate border for a focusable Combobox. - static scoped_ptr<FocusableBorder> CreateComboboxBorder(); + static std::unique_ptr<FocusableBorder> CreateComboboxBorder(); // Creates the appropriate background for a Combobox. - static scoped_ptr<Background> CreateComboboxBackground(); + static std::unique_ptr<Background> CreateComboboxBackground( + int shoulder_width); // Creates the default label button border for the given |style|. Used when a // custom default border is not provided for a particular LabelButton class. - static scoped_ptr<LabelButtonBorder> CreateLabelButtonBorder( + static std::unique_ptr<LabelButtonBorder> CreateLabelButtonBorder( Button::ButtonStyle style); - // Applies the current system theme to the default border created by |button|. - static scoped_ptr<Border> CreateThemedLabelButtonBorder(LabelButton* button); - // Creates the default scrollbar for the given orientation. - static scoped_ptr<ScrollBar> CreateScrollBar(bool is_horizontal); + static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal); + + // Returns the current text color for the current button state. + static SkColor TextColorForButton(const ButtonColorByState& color_by_state, + const LabelButton& button); + + // Applies platform styles to |label| and fills |color_by_state| with the text + // colors for normal, pressed, hovered, and disabled states, if the colors for + // Button::STYLE_BUTTON buttons differ from those provided by ui::NativeTheme. + static void ApplyLabelButtonTextStyle(Label* label, + ButtonColorByState* color_by_state); + + // Applies the current system theme to the default border created by |button|. + static std::unique_ptr<Border> CreateThemedLabelButtonBorder( + LabelButton* button); private: DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformStyle); diff --git a/chromium/ui/views/style/platform_style_linux.cc b/chromium/ui/views/style/platform_style_linux.cc index 36e3de58f4d..3e644c4be45 100644 --- a/chromium/ui/views/style/platform_style_linux.cc +++ b/chromium/ui/views/style/platform_style_linux.cc @@ -11,7 +11,7 @@ namespace views { // static -scoped_ptr<Border> PlatformStyle::CreateThemedLabelButtonBorder( +std::unique_ptr<Border> PlatformStyle::CreateThemedLabelButtonBorder( LabelButton* button) { views::LinuxUI* linux_ui = views::LinuxUI::instance(); if (linux_ui) @@ -19,4 +19,12 @@ scoped_ptr<Border> PlatformStyle::CreateThemedLabelButtonBorder( return button->CreateDefaultBorder(); } +void PlatformStyle::ApplyLabelButtonTextStyle(Label* label, + ButtonColorByState* colors) { + // TODO(erg): This is disabled on desktop linux because of the binary asset + // confusion. These details should either be pushed into ui::NativeThemeWin + // or should be obsoleted by rendering buttons with paint calls instead of + // with static assets. http://crbug.com/350498 +} + } // namespace views diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm index cbe9be51ce1..5e06da5d281 100644 --- a/chromium/ui/views/style/platform_style_mac.mm +++ b/chromium/ui/views/style/platform_style_mac.mm @@ -4,6 +4,7 @@ #include "ui/views/style/platform_style.h" +#include "base/memory/ptr_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icons.h" @@ -17,6 +18,11 @@ namespace views { +const int PlatformStyle::kMinLabelButtonWidth = 32; +const int PlatformStyle::kMinLabelButtonHeight = 30; +const bool PlatformStyle::kDefaultLabelButtonHasBoldFont = false; +const bool PlatformStyle::kTextfieldDragVerticallyDragsToEnd = true; + // static gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled, Combobox::Style style) { @@ -33,27 +39,52 @@ gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled, } // static -scoped_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() { - return make_scoped_ptr(new FocusableRoundedBorder); +std::unique_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() { + return base::WrapUnique(new FocusableRoundedBorder); } // static -scoped_ptr<Background> PlatformStyle::CreateComboboxBackground() { - return make_scoped_ptr(new ComboboxBackgroundMac); +std::unique_ptr<Background> PlatformStyle::CreateComboboxBackground( + int shoulder_width) { + return base::WrapUnique(new ComboboxBackgroundMac(shoulder_width)); } // static -scoped_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder( +std::unique_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder( Button::ButtonStyle style) { if (style == Button::STYLE_BUTTON) - return make_scoped_ptr(new DialogButtonBorderMac()); + return base::WrapUnique(new DialogButtonBorderMac()); + + return base::WrapUnique(new LabelButtonAssetBorder(style)); +} + +// static +std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { + return base::WrapUnique(new CocoaScrollBar(is_horizontal)); +} - return make_scoped_ptr(new LabelButtonAssetBorder(style)); +// static +SkColor PlatformStyle::TextColorForButton( + const ButtonColorByState& color_by_state, + const LabelButton& button) { + Button::ButtonState state = button.state(); + if (button.style() == Button::STYLE_BUTTON && + DialogButtonBorderMac::ShouldRenderDefault(button)) { + // For convenience, we currently assume Mac wants the color corresponding to + // the pressed state for default buttons. + state = Button::STATE_PRESSED; + } + return color_by_state[state]; } // static -scoped_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { - return make_scoped_ptr(new CocoaScrollBar(is_horizontal)); +void PlatformStyle::ApplyLabelButtonTextStyle( + views::Label* label, + ButtonColorByState* color_by_state) { + const ui::NativeTheme* theme = label->GetNativeTheme(); + ButtonColorByState& colors = *color_by_state; + colors[Button::STATE_PRESSED] = + theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHighlightColor); } } // namespace views diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc index c0e4ef943a6..8508ffc55aa 100644 --- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc +++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc @@ -16,7 +16,6 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image.h" #include "ui/gfx/path.h" -#include "ui/gfx/screen.h" #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/resources/grit/views_resources.h" @@ -126,7 +125,7 @@ gfx::Image* GetHandleImage(ui::SelectionBound::Type bound_type) { case ui::SelectionBound::RIGHT: return GetRightHandleImage(); default: - NOTREACHED() << "Invalid touch handle bound type."; + NOTREACHED() << "Invalid touch handle bound type: " << bound_type; return nullptr; }; } @@ -241,7 +240,7 @@ class TouchSelectionControllerImpl::EditingHandleView widget_->SetContentsView(this); aura::Window* window = widget_->GetNativeWindow(); - window->SetEventTargeter(scoped_ptr<ui::EventTargeter>( + window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>( new TouchHandleWindowTargeter(window, this))); // We are owned by the TouchSelectionControllerImpl. @@ -250,6 +249,10 @@ class TouchSelectionControllerImpl::EditingHandleView ~EditingHandleView() override { SetWidgetVisible(false, false); } + ui::SelectionBound::Type selection_bound_type() { + return selection_bound_.type(); + } + // Overridden from views::WidgetDelegateView: bool WidgetHasHitTestMask() const override { return true; } @@ -337,7 +340,11 @@ class TouchSelectionControllerImpl::EditingHandleView widget_->Hide(); } - void SetBoundInScreen(const ui::SelectionBound& bound) { + // If |is_visible| is true, this will update the widget and trigger a repaint + // if necessary. Otherwise this will only update the internal state: + // |selection_bound_| and |image_|, so that the state is valid for the time + // this becomes visible. + void SetBoundInScreen(const ui::SelectionBound& bound, bool is_visible) { bool update_bound_type = false; // Cursor handle should always have the bound type CENTER DCHECK(!is_cursor_handle_ || bound.type() == ui::SelectionBound::CENTER); @@ -354,8 +361,13 @@ class TouchSelectionControllerImpl::EditingHandleView if (update_bound_type) { selection_bound_.set_type(bound.type()); image_ = GetHandleImage(bound.type()); - SchedulePaint(); + if (is_visible) + SchedulePaint(); } + + if (!is_visible) + return; + selection_bound_.SetEdge(bound.edge_top(), bound.edge_bottom()); widget_->SetBounds(GetSelectionWidgetBounds(selection_bound_)); @@ -376,7 +388,7 @@ class TouchSelectionControllerImpl::EditingHandleView } private: - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; TouchSelectionControllerImpl* controller_; // In local coordinates @@ -493,7 +505,7 @@ void TouchSelectionControllerImpl::SelectionChanged() { // If the new location of this handle is out of client view, its widget // should not get hidden, since it should still receive touch events. // Hence, we are not using |SetHandleBound()| method here. - dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped); + dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped, true); // Temporary fix for selection handle going outside a window. On a webpage, // the page should scroll if the selection handle is dragged outside the @@ -593,8 +605,7 @@ void TouchSelectionControllerImpl::SetHandleBound( const ui::SelectionBound& bound, const ui::SelectionBound& bound_in_screen) { handle->SetWidgetVisible(ShouldShowHandleFor(bound), false); - if (handle->IsWidgetVisible()) - handle->SetBoundInScreen(bound_in_screen); + handle->SetBoundInScreen(bound_in_screen, handle->IsWidgetVisible()); } bool TouchSelectionControllerImpl::ShouldShowHandleFor( @@ -740,6 +751,11 @@ gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { return cursor_handle_->GetWidget()->GetNativeView(); } +ui::SelectionBound::Type +TouchSelectionControllerImpl::GetSelectionHandle1Type() { + return selection_handle_1_->selection_bound_type(); +} + gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() { return selection_handle_1_->GetBoundsInScreen(); } diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.h b/chromium/ui/views/touchui/touch_selection_controller_impl.h index 006b89782dc..1580bfb1f5c 100644 --- a/chromium/ui/views/touchui/touch_selection_controller_impl.h +++ b/chromium/ui/views/touchui/touch_selection_controller_impl.h @@ -110,6 +110,7 @@ class VIEWS_EXPORT TouchSelectionControllerImpl // Convenience methods for testing. gfx::NativeView GetCursorHandleNativeView(); + ui::SelectionBound::Type GetSelectionHandle1Type(); gfx::Rect GetSelectionHandle1Bounds(); gfx::Rect GetSelectionHandle2Bounds(); gfx::Rect GetCursorHandleBounds(); @@ -122,9 +123,9 @@ class VIEWS_EXPORT TouchSelectionControllerImpl ui::TouchEditable* client_view_; Widget* client_widget_; - scoped_ptr<EditingHandleView> selection_handle_1_; - scoped_ptr<EditingHandleView> selection_handle_2_; - scoped_ptr<EditingHandleView> cursor_handle_; + std::unique_ptr<EditingHandleView> selection_handle_1_; + std::unique_ptr<EditingHandleView> selection_handle_2_; + std::unique_ptr<EditingHandleView> cursor_handle_; bool command_executed_; base::TimeTicks selection_start_time_; diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc index 3bdbbd5f6c5..602795aec8f 100644 --- a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc +++ b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc @@ -181,6 +181,10 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { return GetSelectionController()->GetCursorHandleNativeView(); } + ui::SelectionBound::Type GetSelectionHandle1Type() { + return GetSelectionController()->GetSelectionHandle1Type(); + } + gfx::Rect GetSelectionHandle1Bounds() { return GetSelectionController()->GetSelectionHandle1Bounds(); } @@ -269,13 +273,43 @@ class TouchSelectionControllerImplTest : public ViewsTestBase { } } + // Sets up a textfield with a long text string such that it doesn't all fit + // into the textfield. Then selects the text - the first handle is expected + // to be invisible. |selection_start| is the position of the first handle. + void SetupSelectionInvisibleHandle(uint32_t selection_start) { + // Create a textfield with lots of text in it. + CreateTextfield(); + std::string some_text("some text"); + std::string textfield_text; + for (int i = 0; i < 10; ++i) + textfield_text += some_text; + textfield_->SetText(ASCIIToUTF16(textfield_text)); + + // Tap the textfield to invoke selection. + ui::GestureEventDetails details(ui::ET_GESTURE_TAP); + details.set_tap_count(1); + ui::GestureEvent tap(0, 0, 0, base::TimeDelta(), details); + textfield_->OnGestureEvent(&tap); + + // Select some text such that one handle is hidden. + textfield_->SelectRange(gfx::Range( + selection_start, static_cast<uint32_t>(textfield_text.length()))); + + // Check that one selection handle is hidden. + EXPECT_FALSE(IsSelectionHandle1Visible()); + EXPECT_TRUE(IsSelectionHandle2Visible()); + EXPECT_EQ(gfx::Range(selection_start, + static_cast<uint32_t>(textfield_text.length())), + textfield_->GetSelectedRange()); + } + Widget* textfield_widget_; Widget* widget_; Textfield* textfield_; - scoped_ptr<TextfieldTestApi> textfield_test_api_; - scoped_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_; - scoped_ptr<aura::test::TestCursorClient> test_cursor_client_; + std::unique_ptr<TextfieldTestApi> textfield_test_api_; + std::unique_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_; + std::unique_ptr<aura::test::TestCursorClient> test_cursor_client_; private: DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerImplTest); @@ -539,29 +573,8 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { TEST_F(TouchSelectionControllerImplTest, HiddenSelectionHandleRetainsCursorPosition) { - // Create a textfield with lots of text in it. - CreateTextfield(); - std::string textfield_text("some text"); - for (int i = 0; i < 10; ++i) - textfield_text += textfield_text; - textfield_->SetText(ASCIIToUTF16(textfield_text)); - - // Tap the textfield to invoke selection. - ui::GestureEventDetails details(ui::ET_GESTURE_TAP); - details.set_tap_count(1); - ui::GestureEvent tap(0, 0, 0, base::TimeDelta(), details); - textfield_->OnGestureEvent(&tap); - - // Select some text such that one handle is hidden. - textfield_->SelectRange( - gfx::Range(10u, static_cast<uint32_t>(textfield_text.length()))); - - // Check that one selection handle is hidden. - EXPECT_FALSE(IsSelectionHandle1Visible()); - EXPECT_TRUE(IsSelectionHandle2Visible()); - EXPECT_EQ( - gfx::Range(10u, static_cast<uint32_t>(textfield_text.length())), - textfield_->GetSelectedRange()); + static const uint32_t selection_start = 10u; + SetupSelectionInvisibleHandle(selection_start); // Drag the visible handle around and make sure the selection end point of the // invisible handle does not change. @@ -576,6 +589,24 @@ TEST_F(TouchSelectionControllerImplTest, } } +// Tests that we can handle the hidden handle getting exposed as a result of a +// drag and that it maintains the correct orientation when exposed. +TEST_F(TouchSelectionControllerImplTest, HiddenSelectionHandleExposed) { + static const uint32_t selection_start = 0u; + SetupSelectionInvisibleHandle(selection_start); + + // Drag the handle until the selection shrinks such that the other handle + // becomes visible. + while (!IsSelectionHandle1Visible()) { + static const int drag_diff = -10; + SimulateSelectionHandleDrag(gfx::Vector2d(drag_diff, 0), 2); + } + + // Confirm that the exposed handle maintains the LEFT orientation + // (and does not reset to ui::SelectionBound::Type::CENTER). + EXPECT_EQ(ui::SelectionBound::Type::LEFT, GetSelectionHandle1Type()); +} + TEST_F(TouchSelectionControllerImplTest, DoubleTapInTextfieldWithCursorHandleShouldSelectText) { CreateTextfield(); @@ -685,8 +716,9 @@ TEST_F(TouchSelectionControllerImplTest, CreateWidget(); TestTouchEditable touch_editable(widget_->GetNativeView()); - scoped_ptr<ui::TouchEditingControllerDeprecated> touch_selection_controller( - ui::TouchEditingControllerDeprecated::Create(&touch_editable)); + std::unique_ptr<ui::TouchEditingControllerDeprecated> + touch_selection_controller( + ui::TouchEditingControllerDeprecated::Create(&touch_editable)); touch_editable.set_bounds(gfx::Rect(0, 0, 100, 20)); diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc index d5928a3353d..b506f787de5 100644 --- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc +++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc @@ -16,7 +16,7 @@ #include "ui/gfx/geometry/size.h" #include "ui/gfx/text_utils.h" #include "ui/strings/grit/ui_strings.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/layout/box_layout.h" @@ -37,8 +37,8 @@ const int kEllipsesButtonTag = -1; } // namespace // A bubble that contains actions available for the selected text. An object of -// this type, as a BubbleDelegateView, manages its own lifetime. -class TouchSelectionMenuRunnerViews::Menu : public BubbleDelegateView, +// this type, as a BubbleDialogDelegateView, manages its own lifetime. +class TouchSelectionMenuRunnerViews::Menu : public BubbleDialogDelegateView, public ButtonListener { public: Menu(TouchSelectionMenuRunnerViews* owner, @@ -51,7 +51,7 @@ class TouchSelectionMenuRunnerViews::Menu : public BubbleDelegateView, static bool IsMenuAvailable(const ui::TouchSelectionMenuClient* client); // Closes the menu. This will eventually self-destroy the object. - void Close(); + void CloseMenu(); private: friend class TouchSelectionMenuRunnerViews::TestApi; @@ -68,9 +68,10 @@ class TouchSelectionMenuRunnerViews::Menu : public BubbleDelegateView, // Helper to disconnect this menu object from its owning menu runner. void DisconnectOwner(); - // BubbleDelegateView: + // BubbleDialogDelegateView: void OnPaint(gfx::Canvas* canvas) override; void WindowClosing() override; + int GetDialogButtons() const override; // ButtonListener: void ButtonPressed(Button* sender, const ui::Event& event) override; @@ -86,7 +87,7 @@ TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner, const gfx::Rect& anchor_rect, const gfx::Size& handle_image_size, aura::Window* context) - : BubbleDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER), + : BubbleDialogDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER), owner_(owner), client_(client) { DCHECK(owner_); @@ -117,7 +118,7 @@ TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner, adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height()); SetAnchorRect(adjusted_anchor_rect); - BubbleDelegateView::CreateBubble(this); + BubbleDialogDelegateView::CreateBubble(this); GetWidget()->Show(); } @@ -159,8 +160,7 @@ Button* TouchSelectionMenuRunnerViews::Menu::CreateButton( gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr); LabelButton* button = new LabelButton(this, label); button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight)); - button->SetFocusable(true); - button->set_request_focus_on_press(false); + button->SetFocusForPlatform(); const gfx::FontList& font_list = ui::ResourceBundle::GetSharedInstance().GetFontList( ui::ResourceBundle::SmallFont); @@ -170,7 +170,7 @@ Button* TouchSelectionMenuRunnerViews::Menu::CreateButton( return button; } -void TouchSelectionMenuRunnerViews::Menu::Close() { +void TouchSelectionMenuRunnerViews::Menu::CloseMenu() { DisconnectOwner(); // Closing the widget will self-destroy this object. Widget* widget = GetWidget(); @@ -185,7 +185,7 @@ void TouchSelectionMenuRunnerViews::Menu::DisconnectOwner() { } void TouchSelectionMenuRunnerViews::Menu::OnPaint(gfx::Canvas* canvas) { - BubbleDelegateView::OnPaint(canvas); + BubbleDialogDelegateView::OnPaint(canvas); // Draw separator bars. for (int i = 0; i < child_count() - 1; ++i) { @@ -198,15 +198,19 @@ void TouchSelectionMenuRunnerViews::Menu::OnPaint(gfx::Canvas* canvas) { void TouchSelectionMenuRunnerViews::Menu::WindowClosing() { DCHECK(!owner_ || owner_->menu_ == this); - BubbleDelegateView::WindowClosing(); + BubbleDialogDelegateView::WindowClosing(); if (owner_) DisconnectOwner(); } +int TouchSelectionMenuRunnerViews::Menu::GetDialogButtons() const { + return ui::DIALOG_BUTTON_NONE; +} + void TouchSelectionMenuRunnerViews::Menu::ButtonPressed( Button* sender, const ui::Event& event) { - Close(); + CloseMenu(); if (sender->tag() != kEllipsesButtonTag) client_->ExecuteCommand(sender->tag(), event.flags()); else @@ -264,7 +268,7 @@ void TouchSelectionMenuRunnerViews::CloseMenu() { return; // Closing the menu sets |menu_| to nullptr and eventually deletes the object. - menu_->Close(); + menu_->CloseMenu(); DCHECK(!menu_); } diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.h b/chromium/ui/views/touchui/touch_selection_menu_runner_views.h index 03a8967afa5..0ce40600a99 100644 --- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.h +++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ #define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/touch_selection/touch_selection_menu_runner.h" #include "ui/views/views_export.h" diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc index d733034153b..be3bbf5b7ed 100644 --- a/chromium/ui/views/view.cc +++ b/chromium/ui/views/view.cc @@ -8,11 +8,12 @@ #include <algorithm> #include <cmath> +#include <memory> #include <utility> #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -32,6 +33,7 @@ #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" #include "ui/compositor/transform_recorder.h" +#include "ui/display/screen.h" #include "ui/events/event_target_iterator.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/point3_f.h" @@ -39,7 +41,6 @@ #include "ui/gfx/interpolated_transform.h" #include "ui/gfx/path.h" #include "ui/gfx/scoped_canvas.h" -#include "ui/gfx/screen.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/transform.h" #include "ui/native_theme/native_theme.h" @@ -114,8 +115,7 @@ View::View() registered_accelerator_count_(0), next_focusable_view_(NULL), previous_focusable_view_(NULL), - focusable_(false), - accessibility_focusable_(false), + focus_behavior_(FocusBehavior::NEVER), context_menu_controller_(NULL), drag_controller_(NULL), native_view_accessibility_(NULL) { @@ -479,8 +479,8 @@ void View::SetPaintToLayer(bool paint_to_layer) { } } -scoped_ptr<ui::Layer> View::RecreateLayer() { - scoped_ptr<ui::Layer> old_layer = LayerOwner::RecreateLayer(); +std::unique_ptr<ui::Layer> View::RecreateLayer() { + std::unique_ptr<ui::Layer> old_layer = LayerOwner::RecreateLayer(); Widget* widget = GetWidget(); if (widget) widget->UpdateRootLayers(); @@ -858,7 +858,7 @@ void View::set_background(Background* b) { background_.reset(b); } -void View::SetBorder(scoped_ptr<Border> b) { +void View::SetBorder(std::unique_ptr<Border> b) { border_ = std::move(b); } @@ -953,7 +953,7 @@ bool View::IsMouseHovered() const { if (!GetWidget()->IsMouseEventsEnabled()) return false; - gfx::Point cursor_pos(gfx::Screen::GetScreen()->GetCursorScreenPoint()); + gfx::Point cursor_pos(display::Screen::GetScreen()->GetCursorScreenPoint()); ConvertPointFromScreen(this, &cursor_pos); return HitTestPoint(cursor_pos); } @@ -1066,9 +1066,9 @@ const ui::InputMethod* View::GetInputMethod() const { : nullptr; } -scoped_ptr<ViewTargeter> -View::SetEventTargeter(scoped_ptr<ViewTargeter> targeter) { - scoped_ptr<ViewTargeter> old_targeter = std::move(targeter_); +std::unique_ptr<ViewTargeter> View::SetEventTargeter( + std::unique_ptr<ViewTargeter> targeter) { + std::unique_ptr<ViewTargeter> old_targeter = std::move(targeter_); targeter_ = std::move(targeter); return old_targeter; } @@ -1090,8 +1090,8 @@ ui::EventTarget* View::GetParentTarget() { return parent_; } -scoped_ptr<ui::EventTargetIterator> View::GetChildIterator() const { - return make_scoped_ptr(new ui::EventTargetIteratorImpl<View>(children_)); +std::unique_ptr<ui::EventTargetIterator> View::GetChildIterator() const { + return base::WrapUnique(new ui::EventTargetIteratorImpl<View>(children_)); } ui::EventTargeter* View::GetEventTargeter() { @@ -1198,28 +1198,20 @@ void View::SetNextFocusableView(View* view) { next_focusable_view_ = view; } -void View::SetFocusable(bool focusable) { - if (focusable_ == focusable) +void View::SetFocusBehavior(FocusBehavior focus_behavior) { + if (focus_behavior_ == focus_behavior) return; - focusable_ = focusable; + focus_behavior_ = focus_behavior; AdvanceFocusIfNecessary(); } bool View::IsFocusable() const { - return focusable_ && enabled_ && IsDrawn(); + return focus_behavior_ == FocusBehavior::ALWAYS && enabled_ && IsDrawn(); } bool View::IsAccessibilityFocusable() const { - return (focusable_ || accessibility_focusable_) && enabled_ && IsDrawn(); -} - -void View::SetAccessibilityFocusable(bool accessibility_focusable) { - if (accessibility_focusable_ == accessibility_focusable) - return; - - accessibility_focusable_ = accessibility_focusable; - AdvanceFocusIfNecessary(); + return focus_behavior_ != FocusBehavior::NEVER && enabled_ && IsDrawn(); } FocusManager* View::GetFocusManager() { @@ -1234,8 +1226,13 @@ const FocusManager* View::GetFocusManager() const { void View::RequestFocus() { FocusManager* focus_manager = GetFocusManager(); - if (focus_manager && IsFocusable()) - focus_manager->SetFocusedView(this); + if (focus_manager) { + bool focusable = focus_manager->keyboard_accessible() + ? IsAccessibilityFocusable() + : IsFocusable(); + if (focusable) + focus_manager->SetFocusedView(this); + } } bool View::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { @@ -1808,7 +1805,7 @@ void View::DoRemoveChildView(View* view, if (i == children_.end()) return; - scoped_ptr<View> view_to_be_deleted; + std::unique_ptr<View> view_to_be_deleted; if (update_focus_cycle) { View* next_focusable = view->next_focusable_view_; View* prev_focusable = view->previous_focusable_view_; @@ -2086,9 +2083,7 @@ void View::CreateLayer() { SetLayer(new ui::Layer()); layer()->set_delegate(this); -#if !defined(NDEBUG) layer()->set_name(GetClassName()); -#endif UpdateParentLayers(); UpdateLayerVisibility(); diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h index a85ef3dfa00..6b45c6313ba 100644 --- a/chromium/ui/views/view.h +++ b/chromium/ui/views/view.h @@ -9,6 +9,7 @@ #include <algorithm> #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -17,7 +18,6 @@ #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.h" #include "ui/base/accelerators/accelerator.h" @@ -116,6 +116,18 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, public: typedef std::vector<View*> Views; + enum class FocusBehavior { + // Use when the View is never focusable. Default. + NEVER, + + // Use when the View is to be focusable both in regular and accessibility + // mode. + ALWAYS, + + // Use when the View is focusable only during accessibility mode. + ACCESSIBLE_ONLY, + }; + struct ViewHierarchyChangedDetails { ViewHierarchyChangedDetails() : is_add(false), @@ -314,7 +326,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, void SetPaintToLayer(bool paint_to_layer); // Overridden from ui::LayerOwner: - scoped_ptr<ui::Layer> RecreateLayer() override; + std::unique_ptr<ui::Layer> RecreateLayer() override; // RTL positioning ----------------------------------------------------------- @@ -504,7 +516,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, Background* background() { return background_.get(); } // The border object is owned by this object and may be NULL. - virtual void SetBorder(scoped_ptr<Border> b); + virtual void SetBorder(std::unique_ptr<Border> b); const Border* border() const { return border_.get(); } Border* border() { return border_.get(); } @@ -700,7 +712,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Sets a new ViewTargeter for the view, and returns the previous // ViewTargeter. - scoped_ptr<ViewTargeter> SetEventTargeter(scoped_ptr<ViewTargeter> targeter); + std::unique_ptr<ViewTargeter> SetEventTargeter( + std::unique_ptr<ViewTargeter> targeter); // Returns the ViewTargeter installed on |this| if one exists, // otherwise returns the ViewTargeter installed on our root view. @@ -712,7 +725,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Overridden from ui::EventTarget: bool CanAcceptEvent(const ui::Event& event) override; ui::EventTarget* GetParentTarget() override; - scoped_ptr<ui::EventTargetIterator> GetChildIterator() const override; + std::unique_ptr<ui::EventTargetIterator> GetChildIterator() const override; ui::EventTargeter* GetEventTargeter() override; void ConvertEventToTarget(ui::EventTarget* target, ui::LocatedEvent* event) override; @@ -766,25 +779,16 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // IMPORTANT NOTE: loops in the focus hierarchy are not supported. void SetNextFocusableView(View* view); - // Sets whether this view is capable of taking focus. It will clear focus if - // the focused view is set to be non-focusable. - // Note that this is false by default so that a view used as a container does - // not get the focus. - void SetFocusable(bool focusable); + // Sets |focus_behavior| and advances focus if necessary. + void SetFocusBehavior(FocusBehavior focus_behavior); - // Returns true if this view is |focusable_|, |enabled_| and drawn. + // Returns true if this view is focusable, |enabled_| and drawn. bool IsFocusable() const; // Return whether this view is focusable when the user requires full keyboard // access, even though it may not be normally focusable. bool IsAccessibilityFocusable() const; - // Set whether this view can be made focusable if the user requires - // full keyboard access, even though it's not normally focusable. It will - // clear focus if the focused view is set to be non-focusable. - // Note that this is false by default. - void SetAccessibilityFocusable(bool 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. @@ -1140,9 +1144,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Focus --------------------------------------------------------------------- - // Returns last value passed to SetFocusable(). Use IsFocusable() to determine - // if a view can take focus right now. - bool focusable() const { return focusable_; } + // Returns last set focus behavior. + FocusBehavior focus_behavior() const { return focus_behavior_; } // Override to be notified when focus has changed either to or from this View. virtual void OnFocus(); @@ -1191,7 +1194,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // NativeTheme --------------------------------------------------------------- - // Invoked when the NativeTheme associated with this View changes. + // Invoked when the NativeTheme associated with this View changes, including + // when one first becomes available (after the view is added to a widget + // hierarchy). virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) {} // Debugging ----------------------------------------------------------------- @@ -1482,7 +1487,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, bool registered_for_visible_bounds_notification_; // List of descendants wanting notification when their visible bounds change. - scoped_ptr<Views> descendants_to_notify_; + std::unique_ptr<Views> descendants_to_notify_; // Transformations ----------------------------------------------------------- @@ -1497,7 +1502,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // 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_; + std::unique_ptr<LayoutManager> layout_manager_; // Whether this View's layer should be snapped to the pixel boundary. bool snap_layer_to_pixel_boundary_; @@ -1505,10 +1510,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Painting ------------------------------------------------------------------ // Background - scoped_ptr<Background> background_; + std::unique_ptr<Background> background_; // Border. - scoped_ptr<Border> border_; + std::unique_ptr<Border> border_; // Cached output of painting to be reused in future frames until invalidated. ui::PaintCache paint_cache_; @@ -1532,7 +1537,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // 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_; + std::unique_ptr<std::vector<ui::Accelerator>> accelerators_; size_t registered_accelerator_count_; // Focus --------------------------------------------------------------------- @@ -1543,12 +1548,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // 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_; + // The focus behavior of the view in regular and accessibility mode. + FocusBehavior focus_behavior_; // Context menus ------------------------------------------------------------- @@ -1561,7 +1562,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Input -------------------------------------------------------------------- - scoped_ptr<ViewTargeter> targeter_; + std::unique_ptr<ViewTargeter> targeter_; // Accessibility ------------------------------------------------------------- diff --git a/chromium/ui/views/view_targeter_unittest.cc b/chromium/ui/views/view_targeter_unittest.cc index 33a23729662..ea579d59f93 100644 --- a/chromium/ui/views/view_targeter_unittest.cc +++ b/chromium/ui/views/view_targeter_unittest.cc @@ -5,6 +5,7 @@ #include "ui/views/view_targeter.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "ui/events/event_targeter.h" #include "ui/events/event_utils.h" #include "ui/gfx/path.h" @@ -133,7 +134,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) { content->AddChildView(child); child->AddChildView(grandchild); - grandchild->SetFocusable(true); + grandchild->SetFocusBehavior(View::FocusBehavior::ALWAYS); grandchild->RequestFocus(); internal::RootView* root_view = @@ -617,7 +618,7 @@ TEST_F(ViewTargeterTest, HitTestCallsOnView) { v2->SetBoundsRect(v2_bounds); root_view->AddChildView(v2); ViewTargeter* view_targeter = new ViewTargeter(v2); - v2->SetEventTargeter(make_scoped_ptr(view_targeter)); + v2->SetEventTargeter(base::WrapUnique(view_targeter)); gfx::Point v1_centerpoint = v1_bounds.CenterPoint(); gfx::Point v2_centerpoint = v2_bounds.CenterPoint(); diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc index 4b50b319ad2..89e3c1bb94d 100644 --- a/chromium/ui/views/view_unittest.cc +++ b/chromium/ui/views/view_unittest.cc @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/view.h" + #include <stddef.h> #include <map> +#include <memory> #include "base/i18n/rtl.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/rand_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -39,7 +41,6 @@ #include "ui/views/controls/textfield/textfield.h" #include "ui/views/focus/view_storage.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/view.h" #include "ui/views/widget/native_widget.h" #include "ui/views/widget/root_view.h" #include "ui/views/window/dialog_client_view.h" @@ -238,7 +239,7 @@ class TestView : public View { views::View::Blur(); } - bool focusable() const { return View::focusable(); } + FocusBehavior focus_behavior() const { return View::focus_behavior(); } void set_can_process_events_within_subtree(bool can_process) { can_process_events_within_subtree_ = can_process; @@ -385,7 +386,7 @@ TEST_F(ViewTest, MouseEvent) { TestView* v2 = new TestView(); v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -448,7 +449,7 @@ TEST_F(ViewTest, DeleteOnPressed) { v1->Reset(); v2->Reset(); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -2113,7 +2114,7 @@ TEST_F(ViewTest, HandleAccelerator) { 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); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 100, 100); @@ -2192,7 +2193,7 @@ TEST_F(ViewTest, ActivateAccelerator) { 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); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 100, 100); @@ -2255,7 +2256,7 @@ TEST_F(ViewTest, HiddenViewWithAccelerator) { view->AddAccelerator(return_accelerator); EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 100, 100); @@ -2283,7 +2284,7 @@ TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) { view->AddAccelerator(return_accelerator); EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(0, 0, 100, 100); @@ -2429,13 +2430,13 @@ class ToplevelWidgetObserverView : public View { // Test that a view can track the current top level widget by overriding // View::ViewHierarchyChanged() and View::NativeViewHierarchyChanged(). TEST_F(ViewTest, MAYBE_NativeViewHierarchyChanged) { - scoped_ptr<Widget> toplevel1(new Widget); + std::unique_ptr<Widget> toplevel1(new Widget); Widget::InitParams toplevel1_params = CreateParams(Widget::InitParams::TYPE_POPUP); toplevel1_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; toplevel1->Init(toplevel1_params); - scoped_ptr<Widget> toplevel2(new Widget); + std::unique_ptr<Widget> toplevel2(new Widget); Widget::InitParams toplevel2_params = CreateParams(Widget::InitParams::TYPE_POPUP); toplevel2_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -2676,7 +2677,7 @@ TEST_F(ViewTest, TransformEvent) { TEST_F(ViewTest, TransformVisibleBound) { gfx::Rect viewport_bounds(0, 0, 100, 100); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = viewport_bounds; @@ -2733,7 +2734,7 @@ class VisibleBoundsView : public View { TEST_F(ViewTest, OnVisibleBoundsChanged) { gfx::Rect viewport_bounds(0, 0, 100, 100); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = viewport_bounds; @@ -2835,7 +2836,7 @@ TEST_F(ViewTest, AddAndRemoveSchedulePaints) { // We have to put the View hierarchy into a Widget or no paints will be // scheduled. - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = viewport_bounds; @@ -2855,7 +2856,7 @@ TEST_F(ViewTest, AddAndRemoveSchedulePaints) { parent_view->scheduled_paint_rects_.clear(); parent_view->RemoveChildView(child_view); - scoped_ptr<View> child_deleter(child_view); + std::unique_ptr<View> child_deleter(child_view); ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size()); EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front()); @@ -3051,7 +3052,7 @@ TEST_F(ViewTest, ConversionsWithTransform) { // Tests conversion methods to and from screen coordinates. TEST_F(ViewTest, ConversionsToFromScreen) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -3077,7 +3078,7 @@ TEST_F(ViewTest, ConversionsToFromScreen) { // Tests conversion methods for rectangles. TEST_F(ViewTest, ConvertRectWithTransform) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 650, 650); @@ -3192,7 +3193,7 @@ TEST_F(ViewTest, ViewHierarchyChanged) { ObserverView* v3 = new ObserverView(); // Add |v3| to |v2|. - scoped_ptr<ObserverView> v2(new ObserverView()); + std::unique_ptr<ObserverView> v2(new ObserverView()); v2->AddChildView(v3); // Make sure both |v2| and |v3| receive the ViewHierarchyChanged() @@ -3425,9 +3426,9 @@ TEST_F(ViewTest, ReorderChildren) { child->AddChildView(foo2); View* foo3 = new View(); child->AddChildView(foo3); - foo1->SetFocusable(true); - foo2->SetFocusable(true); - foo3->SetFocusable(true); + foo1->SetFocusBehavior(View::FocusBehavior::ALWAYS); + foo2->SetFocusBehavior(View::FocusBehavior::ALWAYS); + foo3->SetFocusBehavior(View::FocusBehavior::ALWAYS); ASSERT_EQ(0, child->GetIndexOf(foo1)); ASSERT_EQ(1, child->GetIndexOf(foo2)); @@ -3572,10 +3573,11 @@ TEST_F(ViewTest, AdvanceFocusIfNecessaryForUnfocusableView) { widget.Init(params); View* view1 = new View(); - view1->SetFocusable(true); + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); + widget.GetRootView()->AddChildView(view1); View* view2 = new View(); - view2->SetFocusable(true); + view2->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget.GetRootView()->AddChildView(view2); FocusManager* focus_manager = widget.GetFocusManager(); @@ -3604,7 +3606,7 @@ TEST_F(ViewTest, AdvanceFocusIfNecessaryForUnfocusableView) { // Set the focused view as not focusable and check if the next view gets // focused. - view1->SetFocusable(false); + view1->SetFocusBehavior(View::FocusBehavior::NEVER); EXPECT_EQ(view2, focus_manager->GetFocusedView()); } @@ -4207,15 +4209,15 @@ TEST_F(ViewLayerTest, ReorderUnderWidget) { TEST_F(ViewLayerTest, AcquireLayer) { View* content = new View; widget()->SetContentsView(content); - scoped_ptr<View> c1(new View); + std::unique_ptr<View> c1(new View); c1->SetPaintToLayer(true); EXPECT_TRUE(c1->layer()); content->AddChildView(c1.get()); - scoped_ptr<ui::Layer> layer(c1->AcquireLayer()); + std::unique_ptr<ui::Layer> layer(c1->AcquireLayer()); EXPECT_EQ(layer.get(), c1->layer()); - scoped_ptr<ui::Layer> layer2(c1->RecreateLayer()); + std::unique_ptr<ui::Layer> layer2(c1->RecreateLayer()); EXPECT_NE(c1->layer(), layer2.get()); // Destroy view before destroying layer. @@ -4224,7 +4226,7 @@ TEST_F(ViewLayerTest, AcquireLayer) { // Verify the z-order of the layers as a result of calling RecreateLayer(). TEST_F(ViewLayerTest, RecreateLayerZOrder) { - scoped_ptr<View> v(new View()); + std::unique_ptr<View> v(new View()); v->SetPaintToLayer(true); View* v1 = new View(); @@ -4240,7 +4242,7 @@ TEST_F(ViewLayerTest, RecreateLayerZOrder) { EXPECT_EQ(v1->layer(), child_layers_pre[0]); EXPECT_EQ(v2->layer(), child_layers_pre[1]); - scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); + std::unique_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|. // for |v1| and |v2|. @@ -4272,7 +4274,7 @@ TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) { EXPECT_EQ(v1->layer(), child_layers_pre[0]); EXPECT_EQ(v2->layer(), child_layers_pre[1]); - scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); + std::unique_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|. const std::vector<ui::Layer*>& child_layers_post = root_layer->children(); @@ -4298,7 +4300,7 @@ TEST_F(ViewLayerTest, RecreateLayerMovesNonViewChildren) { v.layer()->Add(&layer); v.layer()->StackAtBottom(&layer); - scoped_ptr<ui::Layer> old_layer(v.RecreateLayer()); + std::unique_ptr<ui::Layer> old_layer(v.RecreateLayer()); // All children should be moved from old layer to new layer. ASSERT_TRUE(old_layer.get() != NULL); @@ -4362,17 +4364,19 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) { TEST_F(ViewTest, FocusableAssertions) { // View subclasses may change insets based on whether they are focusable, // which effects the preferred size. To avoid preferred size changing around - // these Views need to key off the last value set to SetFocusable(), not + // these Views need to key off the last value set to SetFocusBehavior(), not // whether the View is focusable right now. For this reason it's important - // that focusable() return the last value passed to SetFocusable and not - // whether the View is focusable right now. + // that the return value of focus_behavior() depends on the last value passed + // to SetFocusBehavior and not whether the View is focusable right now. TestView view; - view.SetFocusable(true); - EXPECT_TRUE(view.focusable()); + view.SetFocusBehavior(View::FocusBehavior::ALWAYS); + EXPECT_EQ(View::FocusBehavior::ALWAYS, view.focus_behavior()); view.SetEnabled(false); - EXPECT_TRUE(view.focusable()); - view.SetFocusable(false); - EXPECT_FALSE(view.focusable()); + EXPECT_EQ(View::FocusBehavior::ALWAYS, view.focus_behavior()); + view.SetFocusBehavior(View::FocusBehavior::NEVER); + EXPECT_EQ(View::FocusBehavior::NEVER, view.focus_behavior()); + view.SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY); + EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, view.focus_behavior()); } // Verifies when a view is deleted it is removed from ViewStorage. @@ -4404,7 +4408,7 @@ TEST_F(ViewTest, OnNativeThemeChanged) { // new native theme notification. test_view->AddChildView(test_view_child); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(params); @@ -4444,7 +4448,7 @@ TEST_F(ViewTest, ScopedTargetHandlerReceivesEvents) { TestView* v = new TestView(); v->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 350, 350); diff --git a/chromium/ui/views/view_unittest_aura.cc b/chromium/ui/views/view_unittest_aura.cc index 568a29cf264..b1e7b2fee60 100644 --- a/chromium/ui/views/view_unittest_aura.cc +++ b/chromium/ui/views/view_unittest_aura.cc @@ -4,7 +4,8 @@ #include "ui/views/view.h" -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/aura/window.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_tree_owner.h" @@ -120,8 +121,8 @@ TEST_F(ViewAuraTest, RecreateLayersWithWindows) { EXPECT_EQ(v7_layer, old_w1_root_sublayers[2]); { - scoped_ptr<ui::LayerTreeOwner> cloned_owner( - wm::RecreateLayers(w1->GetNativeView())); + std::unique_ptr<ui::LayerTreeOwner> cloned_owner( + wm::RecreateLayers(w1->GetNativeView(), nullptr)); EXPECT_EQ(w1_layer, cloned_owner->root()); EXPECT_NE(w1_layer, w1->GetNativeView()->layer()); diff --git a/chromium/ui/views/views.gyp b/chromium/ui/views/views.gyp index 6f2243320b9..b57a8158d63 100644 --- a/chromium/ui/views/views.gyp +++ b/chromium/ui/views/views.gyp @@ -16,16 +16,16 @@ 'animation/bounds_animator.h', 'animation/button_ink_drop_delegate.cc', 'animation/button_ink_drop_delegate.h', - 'animation/ink_drop_animation.cc', - 'animation/ink_drop_animation.h', - 'animation/ink_drop_animation_controller.h', - 'animation/ink_drop_animation_controller_factory.cc', - 'animation/ink_drop_animation_controller_factory.h', - 'animation/ink_drop_animation_controller_impl.cc', - 'animation/ink_drop_animation_controller_impl.h', + 'animation/ink_drop_ripple.cc', + 'animation/ink_drop_ripple.h', + 'animation/ink_drop.h', + 'animation/ink_drop_factory.cc', + 'animation/ink_drop_factory.h', + 'animation/ink_drop_impl.cc', + 'animation/ink_drop_impl.h', 'animation/ink_drop_animation_ended_reason.cc', 'animation/ink_drop_animation_ended_reason.h', - 'animation/ink_drop_animation_observer.h', + 'animation/ink_drop_ripple_observer.h', 'animation/ink_drop_delegate.h', 'animation/ink_drop_host.h', 'animation/ink_drop_host_view.cc', @@ -39,18 +39,16 @@ 'animation/ink_drop_state.h', 'animation/scroll_animator.cc', 'animation/scroll_animator.h', - 'animation/flood_fill_ink_drop_animation.cc', - 'animation/flood_fill_ink_drop_animation.h', - 'animation/square_ink_drop_animation.cc', - 'animation/square_ink_drop_animation.h', + 'animation/flood_fill_ink_drop_ripple.cc', + 'animation/flood_fill_ink_drop_ripple.h', + 'animation/square_ink_drop_ripple.cc', + 'animation/square_ink_drop_ripple.h', 'background.cc', 'background.h', 'border.cc', 'border.h', 'bubble/bubble_border.cc', 'bubble/bubble_border.h', - 'bubble/bubble_delegate.cc', - 'bubble/bubble_delegate.h', 'bubble/bubble_dialog_delegate.cc', 'bubble/bubble_dialog_delegate.h', 'bubble/bubble_frame_view.cc', @@ -284,6 +282,7 @@ 'native_theme_delegate.h', 'painter.cc', 'painter.h', + 'pointer_watcher.h', 'rect_based_targeting_utils.cc', 'rect_based_targeting_utils.h', 'repeat_controller.cc', @@ -313,6 +312,8 @@ 'view_targeter_delegate.h', 'views_delegate.cc', 'views_delegate.h', + 'views_export.h', + 'views_exports.cc', 'views_switches.cc', 'views_switches.h', 'views_touch_selection_controller_factory.h', @@ -490,18 +491,19 @@ 'widget/desktop_aura/desktop_window_tree_host_ozone.cc', ], 'views_test_support_sources': [ - 'animation/test/flood_fill_ink_drop_animation_test_api.cc', - 'animation/test/flood_fill_ink_drop_animation_test_api.h', - 'animation/test/ink_drop_animation_test_api.cc', - 'animation/test/ink_drop_animation_test_api.h', - 'animation/test/ink_drop_animation_controller_impl_test_api.cc', - 'animation/test/ink_drop_animation_controller_impl_test_api.h', + 'animation/test/flood_fill_ink_drop_ripple_test_api.cc', + 'animation/test/flood_fill_ink_drop_ripple_test_api.h', + 'animation/test/ink_drop_ripple_test_api.cc', + 'animation/test/ink_drop_ripple_test_api.h', + 'animation/test/ink_drop_impl_test_api.cc', + 'animation/test/ink_drop_impl_test_api.h', 'animation/test/ink_drop_hover_test_api.cc', 'animation/test/ink_drop_hover_test_api.h', - 'animation/test/square_ink_drop_animation_test_api.cc', - 'animation/test/square_ink_drop_animation_test_api.h', - 'animation/test/test_ink_drop_animation_observer.cc', - 'animation/test/test_ink_drop_animation_observer.h', + 'animation/test/ink_drop_utils.cc', + 'animation/test/square_ink_drop_ripple_test_api.cc', + 'animation/test/square_ink_drop_ripple_test_api.h', + 'animation/test/test_ink_drop_ripple_observer.cc', + 'animation/test/test_ink_drop_ripple_observer.h', 'animation/test/test_ink_drop_animation_observer_helper.h', 'animation/test/test_ink_drop_host.cc', 'animation/test/test_ink_drop_host.h', @@ -523,6 +525,8 @@ 'test/focus_manager_test.h', 'test/menu_runner_test_api.cc', 'test/menu_runner_test_api.h', + 'test/menu_test_utils.cc', + 'test/menu_test_utils.h', 'test/native_widget_factory.cc', 'test/native_widget_factory.h', 'test/scoped_views_test_helper.cc', @@ -557,8 +561,8 @@ 'test/widget_test_aura.cc', ], 'views_test_support_desktop_aura_x11_sources': [ - 'test/desktop_screen_x11_test_api.h', 'test/desktop_screen_x11_test_api.cc', + 'test/desktop_screen_x11_test_api.h', 'test/ui_controls_factory_desktop_aurax11.cc', 'test/ui_controls_factory_desktop_aurax11.h', ], @@ -567,13 +571,12 @@ 'accessibility/native_view_accessibility_win_unittest.cc', 'accessible_pane_view_unittest.cc', 'animation/bounds_animator_unittest.cc', - 'animation/ink_drop_animation_controller_factory_unittest.cc', - 'animation/ink_drop_animation_controller_impl_unittest.cc', - 'animation/ink_drop_animation_unittest.cc', + 'animation/ink_drop_factory_unittest.cc', + 'animation/ink_drop_impl_unittest.cc', + 'animation/ink_drop_ripple_unittest.cc', 'animation/ink_drop_hover_unittest.cc', - 'animation/square_ink_drop_animation_unittest.cc', + 'animation/square_ink_drop_ripple_unittest.cc', 'bubble/bubble_border_unittest.cc', - 'bubble/bubble_delegate_unittest.cc', 'bubble/bubble_dialog_delegate_unittest.cc', 'bubble/bubble_frame_view_unittest.cc', 'bubble/bubble_window_targeter_unittest.cc', @@ -616,14 +619,14 @@ 'layout/box_layout_unittest.cc', 'layout/grid_layout_unittest.cc', 'rect_based_targeting_utils_unittest.cc', - 'run_all_unittests.cc', - 'run_all_unittests.h', 'run_all_unittests_main.cc', 'style/mac/dialog_button_border_mac_unittest.cc', 'view_model_unittest.cc', 'view_model_utils_unittest.cc', 'view_targeter_unittest.cc', 'view_unittest.cc', + 'views_test_suite.cc', + 'views_test_suite.h', 'widget/native_widget_mac_unittest.mm', 'widget/native_widget_unittest.cc', 'widget/root_view_unittest.cc', @@ -679,6 +682,7 @@ '../events/platform/events_platform.gyp:events_platform', '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', + '../gfx/gfx.gyp:gfx_range', '../gfx/gfx.gyp:gfx_vector_icons', '../native_theme/native_theme.gyp:native_theme', '../resources/ui_resources.gyp:ui_resources', @@ -770,6 +774,8 @@ '../../build/linux/system.gyp:x11', '../../build/linux/system.gyp:xrandr', '../events/devices/events_devices.gyp:events_devices', + '../events/devices/x11/events_devices_x11.gyp:events_devices_x11', + '../events/keycodes/events_keycodes.gyp:keycodes_x11', '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', '../gfx/x/gfx_x11.gyp:gfx_x11', ], @@ -794,6 +800,7 @@ 'sources': [ '<@(views_desktop_aura_x11_sources)' ], 'dependencies': [ '../../build/linux/system.gyp:xext', + '../../ui/base/x/ui_base_x.gyp:ui_base_x', ], }], ['OS == "win"', { @@ -836,6 +843,7 @@ '../events/platform/events_platform.gyp:events_platform', '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', + '../gfx/gfx.gyp:gfx_range', 'resources/views_resources.gyp:views_resources', 'views', ], @@ -846,8 +854,8 @@ '<@(views_test_support_sources)', # These are not listed in views_test_support_sources as they are not # used by the gn target that pulls in views_test_support_sources. - 'test/default_platform_test_helper.cc', 'test/native_widget_factory_desktop.cc', + 'test/platform_test_helper.cc', 'test/platform_test_helper.h', ], 'conditions': [ @@ -887,6 +895,7 @@ '../events/events.gyp:events_test_support', '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', + '../gfx/gfx.gyp:gfx_range', '../native_theme/native_theme.gyp:native_theme', '../resources/ui_resources.gyp:ui_resources', '../resources/ui_resources.gyp:ui_test_pak', @@ -1019,9 +1028,9 @@ ], 'sources': [ 'cocoa/bridged_native_widget_interactive_uitest.mm', - 'run_all_unittests.cc', - 'run_all_unittests.h', 'run_all_unittests_main.cc', + 'views_test_suite.cc', + 'views_test_suite.h', 'widget/native_widget_mac_interactive_uitest.mm', ], 'conditions': [ diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h index c0e24cfe86c..54b5c4383e8 100644 --- a/chromium/ui/views/views_delegate.h +++ b/chromium/ui/views/views_delegate.h @@ -197,10 +197,10 @@ class VIEWS_EXPORT ViewsDelegate { ViewsDelegate(); private: - scoped_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_; + std::unique_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_; #if defined(USE_AURA) - scoped_ptr<TouchSelectionMenuRunnerViews> touch_selection_menu_runner_; + std::unique_ptr<TouchSelectionMenuRunnerViews> touch_selection_menu_runner_; #endif NativeWidgetFactory native_widget_factory_; diff --git a/chromium/ui/views/views_exports.cc b/chromium/ui/views/views_exports.cc new file mode 100644 index 00000000000..f1ba3f5336e --- /dev/null +++ b/chromium/ui/views/views_exports.cc @@ -0,0 +1,10 @@ +// Copyright 2016 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. + +// This file is for including headers that are not included in any other .cc +// files contained within the ui/views module. We need to include these here so +// that linker will know to include the symbols, defined by these headers, in +// the resulting dynamic library. + +#include "ui/views/pointer_watcher.h" diff --git a/chromium/ui/views/views_test_suite.cc b/chromium/ui/views/views_test_suite.cc new file mode 100644 index 00000000000..a7e7c13db09 --- /dev/null +++ b/chromium/ui/views/views_test_suite.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2012 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 "ui/views/views_test_suite.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/path_service.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/ui_base_paths.h" +#include "ui/gl/test/gl_surface_test_support.h" + +#if defined(USE_AURA) +#include <memory> + +#include "ui/aura/env.h" +#endif + +namespace views { + +ViewsTestSuite::ViewsTestSuite(int argc, char** argv) + : base::TestSuite(argc, argv), argc_(argc), argv_(argv) {} + +ViewsTestSuite::~ViewsTestSuite() {} + +int ViewsTestSuite::RunTests() { + return base::LaunchUnitTests( + argc_, argv_, base::Bind(&ViewsTestSuite::Run, base::Unretained(this))); +} + +int ViewsTestSuite::RunTestsSerially() { + return base::LaunchUnitTestsSerially( + argc_, argv_, base::Bind(&ViewsTestSuite::Run, base::Unretained(this))); +} + +void ViewsTestSuite::Initialize() { + base::TestSuite::Initialize(); + gfx::GLSurfaceTestSupport::InitializeOneOff(); + ui::RegisterPathProvider(); + + base::FilePath ui_test_pak_path; + ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); + ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); +#if defined(USE_AURA) + env_ = aura::Env::CreateInstance(); +#endif +} + +void ViewsTestSuite::Shutdown() { +#if defined(USE_AURA) + env_.reset(); +#endif + ui::ResourceBundle::CleanupSharedInstance(); + base::TestSuite::Shutdown(); +} + +} // namespace views diff --git a/chromium/ui/views/views_test_suite.h b/chromium/ui/views/views_test_suite.h new file mode 100644 index 00000000000..7a03f29e714 --- /dev/null +++ b/chromium/ui/views/views_test_suite.h @@ -0,0 +1,45 @@ +// Copyright 2016 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 UI_VIEWS_VIEWS_TEST_SUITE_H_ +#define UI_VIEWS_VIEWS_TEST_SUITE_H_ + +#include "base/test/test_suite.h" + +#if defined(USE_AURA) +#include <memory> +#endif + +namespace aura { +class Env; +} + +namespace views { + +class ViewsTestSuite : public base::TestSuite { + public: + ViewsTestSuite(int argc, char** argv); + ~ViewsTestSuite() override; + + int RunTests(); + int RunTestsSerially(); + + protected: + // base::TestSuite: + void Initialize() override; + void Shutdown() override; + + private: +#if defined(USE_AURA) + std::unique_ptr<aura::Env> env_; +#endif + int argc_; + char** argv_; + + DISALLOW_COPY_AND_ASSIGN(ViewsTestSuite); +}; + +} // namespace + +#endif // UI_VIEWS_VIEWS_TEST_SUITE_H_ diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h index ff116bc81a0..3e30e133bf6 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h @@ -5,14 +5,15 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CURSOR_LOADER_UPDATER_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/views/views_export.h" namespace aura { class RootWindow; } -namespace gfx { +namespace display { class Display; } @@ -30,7 +31,7 @@ class VIEWS_EXPORT DesktopCursorLoaderUpdater { // Creates a new DesktopCursorLoaderUpdater, or NULL if the platform doesn't // support one. - static scoped_ptr<DesktopCursorLoaderUpdater> Create(); + static std::unique_ptr<DesktopCursorLoaderUpdater> Create(); // Called when a CursorLoader is created. virtual void OnCreate(float device_scale_factor, @@ -38,7 +39,7 @@ class VIEWS_EXPORT DesktopCursorLoaderUpdater { // Called when the display has changed (as we may need to reload the cursor // assets in response to a device scale factor or rotation change). - virtual void OnDisplayUpdated(const gfx::Display& display, + virtual void OnDisplayUpdated(const display::Display& display, ui::CursorLoader* loader) = 0; }; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc index 11fc3f1e1cc..2d0063b6944 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc @@ -7,10 +7,11 @@ #include <stddef.h> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/cursor/cursor_loader.h" #include "ui/base/cursor/cursors_aura.h" -#include "ui/gfx/display.h" +#include "ui/display/display.h" namespace views { namespace { @@ -62,14 +63,15 @@ void DesktopCursorLoaderUpdaterAuraLinux::OnCreate( } void DesktopCursorLoaderUpdaterAuraLinux::OnDisplayUpdated( - const gfx::Display& display, + const display::Display& display, ui::CursorLoader* loader) { LoadImageCursors(display.device_scale_factor(), loader); } // static -scoped_ptr<DesktopCursorLoaderUpdater> DesktopCursorLoaderUpdater::Create() { - return make_scoped_ptr(new DesktopCursorLoaderUpdaterAuraLinux); +std::unique_ptr<DesktopCursorLoaderUpdater> +DesktopCursorLoaderUpdater::Create() { + return base::WrapUnique(new DesktopCursorLoaderUpdaterAuraLinux); } } // namespace views diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h index d0be0944fab..65490dd8c6c 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h @@ -18,7 +18,7 @@ class DesktopCursorLoaderUpdaterAuraLinux : public DesktopCursorLoaderUpdater { // Overridden from DesktopCursorLoaderUpdater: void OnCreate(float device_scale_factor, ui::CursorLoader* loader) override; - void OnDisplayUpdated(const gfx::Display& display, + void OnDisplayUpdated(const display::Display& display, ui::CursorLoader* loader) override; }; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc index eadc1ca49e1..249bb08aa3b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc @@ -7,7 +7,8 @@ namespace views { // static -scoped_ptr<DesktopCursorLoaderUpdater> DesktopCursorLoaderUpdater::Create() { +std::unique_ptr<DesktopCursorLoaderUpdater> +DesktopCursorLoaderUpdater::Create() { return nullptr; } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc index e9907e2a275..c133595c123 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc @@ -4,13 +4,14 @@ #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h" +#include <X11/Xatom.h> #include <stddef.h> #include <stdint.h> -#include <X11/Xatom.h> #include "base/event_types.h" #include "base/lazy_instance.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram_macros.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -24,11 +25,11 @@ #include "ui/base/x/selection_utils.h" #include "ui/base/x/x11_foreign_window_manager.h" #include "ui/base/x/x11_util.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/platform/platform_event_source.h" #include "ui/gfx/image/image_skia.h" -#include "ui/gfx/screen.h" #include "ui/views/controls/image_view.h" #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h" #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" @@ -838,9 +839,9 @@ void DesktopDragDropClientAuraX11::OnMoveLoopEnded() { end_move_loop_timer_.Stop(); } -scoped_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop( +std::unique_ptr<X11MoveLoop> DesktopDragDropClientAuraX11::CreateMoveLoop( X11MoveLoopDelegate* delegate) { - return make_scoped_ptr(new X11WholeScreenMoveLoop(this)); + return base::WrapUnique(new X11WholeScreenMoveLoop(this)); } XID DesktopDragDropClientAuraX11::FindWindowFor( @@ -952,8 +953,8 @@ void DesktopDragDropClientAuraX11::EndMoveLoop() { void DesktopDragDropClientAuraX11::DragTranslate( const gfx::Point& root_window_location, - scoped_ptr<ui::OSExchangeData>* data, - scoped_ptr<ui::DropTargetEvent>* event, + std::unique_ptr<ui::OSExchangeData>* data, + std::unique_ptr<ui::DropTargetEvent>* event, aura::client::DragDropDelegate** delegate) { gfx::Point root_location = root_window_location; root_window_->GetHost()->ConvertPointFromNativeScreen(&root_location); @@ -1065,8 +1066,8 @@ void DesktopDragDropClientAuraX11::CompleteXdndPosition( ::Window source_window, const gfx::Point& screen_point) { int drag_operation = ui::DragDropTypes::DRAG_NONE; - scoped_ptr<ui::OSExchangeData> data; - scoped_ptr<ui::DropTargetEvent> drop_target_event; + std::unique_ptr<ui::OSExchangeData> data; + std::unique_ptr<ui::DropTargetEvent> drop_target_event; DragDropDelegate* delegate = NULL; DragTranslate(screen_point, &data, &drop_target_event, &delegate); if (delegate) @@ -1186,8 +1187,8 @@ void DesktopDragDropClientAuraX11::CreateDragWidget( params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.accept_events = false; - gfx::Point location = - gfx::Screen::GetScreen()->GetCursorScreenPoint() - drag_widget_offset_; + gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint() - + drag_widget_offset_; params.bounds = gfx::Rect(location, image.size()); widget->set_focus_on_creation(false); widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h index 65dc403ddf2..9fec7bbe020 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h @@ -6,12 +6,13 @@ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_AURAX11_H_ #include <X11/Xlib.h> + +#include <memory> #include <set> #include <vector> #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" #include "ui/aura/window_observer.h" @@ -106,7 +107,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 // The following methods are virtual for the sake of testing. // Creates a move loop. - virtual scoped_ptr<X11MoveLoop> CreateMoveLoop( + virtual std::unique_ptr<X11MoveLoop> CreateMoveLoop( X11MoveLoopDelegate* delegate); // Finds the topmost X11 window at |screen_point| and returns it if it is @@ -148,8 +149,8 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 // the underlying aura::Window representation, as moves internal to the X11 // window can cause internal drag leave and enter messages. void DragTranslate(const gfx::Point& root_window_location, - scoped_ptr<ui::OSExchangeData>* data, - scoped_ptr<ui::DropTargetEvent>* event, + std::unique_ptr<ui::OSExchangeData>* data, + std::unique_ptr<ui::DropTargetEvent>* event, aura::client::DragDropDelegate** delegate); // Called when we need to notify the current aura::Window that we're no @@ -201,7 +202,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 // A nested message loop that notifies this object of events through the // X11MoveLoopDelegate interface. - scoped_ptr<X11MoveLoop> move_loop_; + std::unique_ptr<X11MoveLoop> move_loop_; aura::Window* root_window_; @@ -214,7 +215,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 // Target side information. class X11DragContext; - scoped_ptr<X11DragContext> target_current_context_; + std::unique_ptr<X11DragContext> target_current_context_; // The modifier state for the most recent mouse move. int current_modifier_state_; @@ -238,7 +239,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 // If we would send an XdndPosition message while we're waiting for an // XdndStatus response, we need to cache the latest details we'd send. - scoped_ptr<std::pair<gfx::Point, unsigned long> > next_position_message_; + std::unique_ptr<std::pair<gfx::Point, unsigned long>> next_position_message_; // Reprocesses the most recent mouse move event if the mouse has not moved // in a while in case the window stacking order has changed and @@ -275,7 +276,7 @@ class VIEWS_EXPORT DesktopDragDropClientAuraX11 base::OneShotTimer end_move_loop_timer_; // Widget that the user drags around. May be NULL. - scoped_ptr<Widget> drag_widget_; + std::unique_ptr<Widget> drag_widget_; // The offset of |drag_widget_| relative to the mouse position. gfx::Vector2d drag_widget_offset_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc index 29105c2c366..55e1b03726b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <map> +#include <memory> #include <vector> // Include views_test_base.h first because the definition of None in X.h @@ -10,7 +11,7 @@ #include "ui/views/test/views_test_base.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" @@ -119,7 +120,7 @@ class SimpleTestDragDropClient : public DesktopDragDropClientAuraX11 { private: // DesktopDragDropClientAuraX11: - scoped_ptr<X11MoveLoop> CreateMoveLoop( + std::unique_ptr<X11MoveLoop> CreateMoveLoop( X11MoveLoopDelegate* delegate) override; XID FindWindowFor(const gfx::Point& screen_point) override; @@ -281,10 +282,10 @@ bool SimpleTestDragDropClient::IsMoveLoopRunning() { return loop_->IsRunning(); } -scoped_ptr<X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop( +std::unique_ptr<X11MoveLoop> SimpleTestDragDropClient::CreateMoveLoop( X11MoveLoopDelegate* delegate) { loop_ = new TestMoveLoop(delegate); - return make_scoped_ptr(loop_); + return base::WrapUnique(loop_); } XID SimpleTestDragDropClient::FindWindowFor(const gfx::Point& screen_point) { @@ -427,11 +428,11 @@ class DesktopDragDropClientAuraX11Test : public ViewsTestBase { } private: - scoped_ptr<TestDragDropClient> client_; - scoped_ptr<DesktopNativeCursorManager> cursor_manager_; + std::unique_ptr<TestDragDropClient> client_; + std::unique_ptr<DesktopNativeCursorManager> cursor_manager_; // The widget used to initiate drags. - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11Test); }; @@ -869,11 +870,11 @@ class DesktopDragDropClientAuraX11ChromeSourceTargetTest } private: - scoped_ptr<SimpleTestDragDropClient> client_; - scoped_ptr<DesktopNativeCursorManager> cursor_manager_; + std::unique_ptr<SimpleTestDragDropClient> client_; + std::unique_ptr<DesktopNativeCursorManager> cursor_manager_; // The widget used to initiate drags. - scoped_ptr<Widget> widget_; + std::unique_ptr<Widget> widget_; DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientAuraX11ChromeSourceTargetTest); }; @@ -884,7 +885,7 @@ void ChromeSourceTargetStep2(SimpleTestDragDropClient* client, int modifier_flags) { EXPECT_TRUE(client->IsMoveLoopRunning()); - scoped_ptr<Widget> target_widget(new Widget); + std::unique_ptr<Widget> target_widget(new Widget); Widget::InitParams target_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); target_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; target_params.native_widget = diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc index 6931bd51863..875763dad35 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc @@ -62,8 +62,8 @@ DWORD DesktopDropTargetWin::OnDragEnter(IDataObject* data_object, DWORD key_state, POINT position, DWORD effect) { - scoped_ptr<OSExchangeData> data; - scoped_ptr<ui::DropTargetEvent> event; + std::unique_ptr<OSExchangeData> data; + std::unique_ptr<ui::DropTargetEvent> event; DragDropDelegate* delegate; // Translate will call OnDragEntered. Translate(data_object, key_state, position, effect, &data, &event, &delegate); @@ -76,8 +76,8 @@ DWORD DesktopDropTargetWin::OnDragOver(IDataObject* data_object, POINT position, DWORD effect) { int drag_operation = ui::DragDropTypes::DRAG_NONE; - scoped_ptr<OSExchangeData> data; - scoped_ptr<ui::DropTargetEvent> event; + std::unique_ptr<OSExchangeData> data; + std::unique_ptr<ui::DropTargetEvent> event; DragDropDelegate* delegate; Translate(data_object, key_state, position, effect, &data, &event, &delegate); if (delegate) @@ -94,8 +94,8 @@ DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object, POINT position, DWORD effect) { int drag_operation = ui::DragDropTypes::DRAG_NONE; - scoped_ptr<OSExchangeData> data; - scoped_ptr<ui::DropTargetEvent> event; + std::unique_ptr<OSExchangeData> data; + std::unique_ptr<ui::DropTargetEvent> event; DragDropDelegate* delegate; Translate(data_object, key_state, position, effect, &data, &event, &delegate); if (delegate) { @@ -123,8 +123,8 @@ void DesktopDropTargetWin::Translate( DWORD key_state, POINT position, DWORD effect, - scoped_ptr<OSExchangeData>* data, - scoped_ptr<ui::DropTargetEvent>* event, + std::unique_ptr<OSExchangeData>* data, + std::unique_ptr<ui::DropTargetEvent>* event, DragDropDelegate** delegate) { gfx::Point location(position.x, position.y); gfx::Point root_location = location; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h index 24059b6f64c..b7fcf6c8a78 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.h @@ -5,8 +5,9 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTIOP_DROP_TARGET_WIN_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTIOP_DROP_TARGET_WIN_H_ +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/aura/window_observer.h" #include "ui/base/dragdrop/drop_target_win.h" @@ -57,8 +58,8 @@ class DesktopDropTargetWin : public ui::DropTargetWin, DWORD key_state, POINT cursor_position, DWORD effect, - scoped_ptr<ui::OSExchangeData>* data, - scoped_ptr<ui::DropTargetEvent>* event, + std::unique_ptr<ui::OSExchangeData>* data, + std::unique_ptr<ui::DropTargetEvent>* event, aura::client::DragDropDelegate** delegate); void NotifyDragLeave(); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h index 2af191b445f..bb6cbd2d5f5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_factory_ozone.h @@ -7,9 +7,12 @@ #include "ui/views/views_export.h" +namespace display { +class Screen; +} + namespace gfx { class Rect; -class Screen; } namespace views { @@ -39,7 +42,7 @@ class VIEWS_EXPORT DesktopFactoryOzone { // Delegates implementation of DesktopScreen externally to // Ozone implementation. - virtual gfx::Screen* CreateDesktopScreen() = 0; + virtual display::Screen* CreateDesktopScreen() = 0; private: static DesktopFactoryOzone* impl_; // not owned diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc index 35cce8d5354..8b306f5e5ef 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules_unittest.cc @@ -17,8 +17,8 @@ namespace views { namespace { -scoped_ptr<Widget> CreateDesktopWidget() { - scoped_ptr<Widget> widget(new Widget); +std::unique_ptr<Widget> CreateDesktopWidget() { + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = Widget::InitParams( Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); @@ -37,8 +37,8 @@ TEST_F(DesktopFocusRulesTest, DontFocusWindowsInOtherHierarchies) { // Two widgets (each with a DesktopNativeWidgetAura). |w2| has a child Window // |w2_child| that is not focusable. |w2_child|'s has a transient parent in // |w1|. - scoped_ptr<views::Widget> w1(CreateDesktopWidget()); - scoped_ptr<views::Widget> w2(CreateDesktopWidget()); + std::unique_ptr<views::Widget> w1(CreateDesktopWidget()); + std::unique_ptr<views::Widget> w2(CreateDesktopWidget()); aura::test::TestWindowDelegate w2_child_delegate; w2_child_delegate.set_can_focus(false); aura::Window* w2_child = new aura::Window(&w2_child_delegate); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc index 2f9dc0d4be4..ea8df16d00d 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc @@ -14,7 +14,7 @@ namespace views { DesktopNativeCursorManager::DesktopNativeCursorManager( - scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater) + std::unique_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater) : cursor_loader_updater_(std::move(cursor_loader_updater)), cursor_loader_(ui::CursorLoader::Create()) { if (cursor_loader_updater_.get()) @@ -39,7 +39,7 @@ void DesktopNativeCursorManager::RemoveHost(aura::WindowTreeHost* host) { } void DesktopNativeCursorManager::SetDisplay( - const gfx::Display& display, + const display::Display& display, wm::NativeCursorManagerDelegate* delegate) { cursor_loader_->UnloadAll(); cursor_loader_->set_rotation(display.rotation()); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h index 552a1b8f114..d059c87453b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h @@ -5,11 +5,11 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_ +#include <memory> #include <set> #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/views/views_export.h" #include "ui/wm/core/native_cursor_manager.h" @@ -35,7 +35,7 @@ class VIEWS_EXPORT DesktopNativeCursorManager : public wm::NativeCursorManager { public: DesktopNativeCursorManager( - scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater); + std::unique_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater); ~DesktopNativeCursorManager() override; // Builds a cursor and sets the internal platform representation. The return @@ -50,7 +50,7 @@ class VIEWS_EXPORT DesktopNativeCursorManager private: // Overridden from wm::NativeCursorManager: - void SetDisplay(const gfx::Display& display, + void SetDisplay(const display::Display& display, wm::NativeCursorManagerDelegate* delegate) override; void SetCursor(gfx::NativeCursor cursor, wm::NativeCursorManagerDelegate* delegate) override; @@ -66,8 +66,8 @@ class VIEWS_EXPORT DesktopNativeCursorManager typedef std::set<aura::WindowTreeHost*> Hosts; Hosts hosts_; - scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater_; - scoped_ptr<ui::CursorLoader> cursor_loader_; + std::unique_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater_; + std::unique_ptr<ui::CursorLoader> cursor_loader_; DISALLOW_COPY_AND_ASSIGN(DesktopNativeCursorManager); }; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index f69b839d73a..99809d17f38 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -19,12 +19,11 @@ #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" #include "ui/compositor/layer.h" +#include "ui/display/screen.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/display.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size_conversions.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme.h" #include "ui/views/corewm/tooltip.h" #include "ui/views/corewm/tooltip_controller.h" @@ -401,6 +400,7 @@ void DesktopNativeWidgetAura::InitNativeWidget( const Widget::InitParams& params) { ownership_ = params.ownership; widget_type_ = params.type; + name_ = params.name; NativeWidgetAura::RegisterNativeWidgetForWindow(this, content_window_); // Animations on TYPE_WINDOW are handled by the OS. Additionally if we animate @@ -458,7 +458,7 @@ void DesktopNativeWidgetAura::InitNativeWidget( } if (!cursor_manager_) { cursor_manager_ = new wm::CursorManager( - scoped_ptr<wm::NativeCursorManager>(native_cursor_manager_)); + std::unique_ptr<wm::NativeCursorManager>(native_cursor_manager_)); } native_cursor_manager_->AddHost(host()); aura::client::SetCursorClient(host_->window(), cursor_manager_); @@ -675,11 +675,16 @@ gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const { desktop_window_tree_host_->GetRestoredBounds() : gfx::Rect(); } +std::string DesktopNativeWidgetAura::GetWorkspace() const { + return content_window_ ? + desktop_window_tree_host_->GetWorkspace() : std::string(); +} + void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) { if (!content_window_) return; aura::Window* root = host_->window(); - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); gfx::Rect bounds_in_pixels = screen->DIPToScreenRectInWindow(root, bounds); desktop_window_tree_host_->AsWindowTreeHost()->SetBounds(bounds_in_pixels); } @@ -946,6 +951,10 @@ void DesktopNativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) { OnEvent(native_event); } +std::string DesktopNativeWidgetAura::GetName() const { + return name_; +} + //////////////////////////////////////////////////////////////////////////////// // DesktopNativeWidgetAura, aura::WindowDelegate implementation: @@ -1152,6 +1161,11 @@ void DesktopNativeWidgetAura::OnHostResized(const aura::WindowTreeHost* host) { native_widget_delegate_->OnNativeWidgetSizeChanged(new_bounds.size()); } +void DesktopNativeWidgetAura::OnHostWorkspaceChanged( + const aura::WindowTreeHost* host) { + native_widget_delegate_->OnNativeWidgetWorkspaceChanged(); +} + void DesktopNativeWidgetAura::OnHostMoved(const aura::WindowTreeHost* host, const gfx::Point& new_origin) { TRACE_EVENT1("views", "DesktopNativeWidgetAura::OnHostMoved", diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 47f514924bf..61adcdd5730 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -5,6 +5,8 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_WIDGET_AURA_H_ +#include <string> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "ui/aura/client/focus_change_observer.h" @@ -121,6 +123,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; void SetBounds(const gfx::Rect& bounds) override; void SetSize(const gfx::Size& size) override; void StackAbove(gfx::NativeView native_view) override; @@ -173,6 +176,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura bool IsTranslucentWindowOpacitySupported() const override; void OnSizeConstraintsChanged() override; void RepostNativeEvent(gfx::NativeEvent native_event) override; + std::string GetName() const override; // Overridden from aura::WindowDelegate: gfx::Size GetMinimumSize() const override; @@ -222,6 +226,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura // Overridden from aura::WindowTreeHostObserver: void OnHostCloseRequested(const aura::WindowTreeHost* host) override; void OnHostResized(const aura::WindowTreeHost* host) override; + void OnHostWorkspaceChanged(const aura::WindowTreeHost* host) override; void OnHostMoved(const aura::WindowTreeHost* host, const gfx::Point& new_origin) override; @@ -235,13 +240,16 @@ class VIEWS_EXPORT DesktopNativeWidgetAura void RootWindowDestroyed(); - scoped_ptr<aura::WindowTreeHost> host_; + std::unique_ptr<aura::WindowTreeHost> host_; DesktopWindowTreeHost* desktop_window_tree_host_; // See class documentation for Widget in widget.h for a note about ownership. Widget::InitParams::Ownership ownership_; - scoped_ptr<DesktopCaptureClient> capture_client_; + // Internal name. + std::string name_; + + std::unique_ptr<DesktopCaptureClient> capture_client_; // Child of the root, contains |content_window_|. aura::Window* content_window_container_; @@ -253,26 +261,25 @@ class VIEWS_EXPORT DesktopNativeWidgetAura internal::NativeWidgetDelegate* native_widget_delegate_; - scoped_ptr<wm::FocusController> focus_client_; - scoped_ptr<aura::client::ScreenPositionClient> position_client_; - scoped_ptr<aura::client::DragDropClient> drag_drop_client_; - scoped_ptr<aura::client::WindowTreeClient> window_tree_client_; - scoped_ptr<DesktopEventClient> event_client_; - scoped_ptr<FocusManagerEventHandler> focus_manager_event_handler_; + std::unique_ptr<wm::FocusController> focus_client_; + std::unique_ptr<aura::client::ScreenPositionClient> position_client_; + std::unique_ptr<aura::client::DragDropClient> drag_drop_client_; + std::unique_ptr<aura::client::WindowTreeClient> window_tree_client_; + std::unique_ptr<DesktopEventClient> event_client_; + std::unique_ptr<FocusManagerEventHandler> focus_manager_event_handler_; // Toplevel event filter which dispatches to other event filters. - scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_; + std::unique_ptr<wm::CompoundEventFilter> root_window_event_filter_; - scoped_ptr<DropHelper> drop_helper_; + std::unique_ptr<DropHelper> drop_helper_; int last_drop_operation_; - scoped_ptr<corewm::TooltipController> tooltip_controller_; - scoped_ptr<TooltipManagerAura> tooltip_manager_; + std::unique_ptr<corewm::TooltipController> tooltip_controller_; + std::unique_ptr<TooltipManagerAura> tooltip_manager_; - scoped_ptr<wm::VisibilityController> visibility_controller_; + std::unique_ptr<wm::VisibilityController> visibility_controller_; - scoped_ptr<wm::WindowModalityController> - window_modality_controller_; + std::unique_ptr<wm::WindowModalityController> window_modality_controller_; bool restore_focus_on_activate_; @@ -287,11 +294,11 @@ class VIEWS_EXPORT DesktopNativeWidgetAura static wm::CursorManager* cursor_manager_; static views::DesktopNativeCursorManager* native_cursor_manager_; - scoped_ptr<wm::ShadowController> shadow_controller_; + std::unique_ptr<wm::ShadowController> shadow_controller_; // Reorders child windows of |window_| associated with a view based on the // order of the associated views in the widget's view hierarchy. - scoped_ptr<WindowReorderer> window_reorderer_; + std::unique_ptr<WindowReorderer> window_reorderer_; // See class documentation for Widget in widget.h for a note about type. Widget::InitParams::Type widget_type_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc index 86e60d31fc8..997b4e1071e 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc @@ -14,10 +14,10 @@ #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" +#include "ui/display/screen.h" #include "ui/events/event_processor.h" #include "ui/events/event_utils.h" #include "ui/events/test/event_generator.h" -#include "ui/gfx/screen.h" #include "ui/views/test/native_widget_factory.h" #include "ui/views/test/test_views.h" #include "ui/views/test/test_views_delegate.h" @@ -40,7 +40,7 @@ typedef ViewsTestBase DesktopNativeWidgetAuraTest; // Verifies creating a Widget with a parent that is not in a RootWindow doesn't // crash. TEST_F(DesktopNativeWidgetAuraTest, CreateWithParentNotInRootWindow) { - scoped_ptr<aura::Window> window(new aura::Window(NULL)); + std::unique_ptr<aura::Window> window(new aura::Window(NULL)); window->Init(ui::LAYER_NOT_DRAWN); Widget widget; Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); @@ -219,14 +219,14 @@ TEST_F(DesktopNativeWidgetAuraTest, DontAccessContentWindowDuringDestruction) { } } -void QuitNestedLoopAndCloseWidget(scoped_ptr<Widget> widget, +void QuitNestedLoopAndCloseWidget(std::unique_ptr<Widget> widget, base::Closure* quit_runloop) { quit_runloop->Run(); } // Verifies that a widget can be destroyed when running a nested message-loop. TEST_F(DesktopNativeWidgetAuraTest, WidgetCanBeDestroyedFromNestedLoop) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -432,7 +432,8 @@ TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupRepositionTest) { gfx::Rect new_pos(10, 10, 400, 400); popup_window.owned_window()->SetBoundsInScreen( - new_pos, gfx::Screen::GetScreen()->GetDisplayNearestPoint(gfx::Point())); + new_pos, + display::Screen::GetScreen()->GetDisplayNearestPoint(gfx::Point())); EXPECT_EQ(new_pos, popup_window.top_level_widget()->GetWindowBoundsInScreen()); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen.h b/chromium/ui/views/widget/desktop_aura/desktop_screen.h index 2db961d2d95..88d2ffee2d7 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen.h @@ -7,7 +7,7 @@ #include "ui/views/views_export.h" -namespace gfx { +namespace display { class Screen; } @@ -15,7 +15,7 @@ namespace views { // Creates a Screen that represents the screen of the environment that hosts // a WindowTreeHost. Caller owns the result. -VIEWS_EXPORT gfx::Screen* CreateDesktopScreen(); +VIEWS_EXPORT display::Screen* CreateDesktopScreen(); } // namespace views diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc index 9708ad88bfc..870413f84f8 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc @@ -8,7 +8,7 @@ namespace views { -gfx::Screen* CreateDesktopScreen() { +display::Screen* CreateDesktopScreen() { return DesktopFactoryOzone::GetInstance()->CreateDesktopScreen(); } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc index cf49c96fca4..6096b4e1079 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.cc @@ -34,7 +34,7 @@ DesktopScreenPositionClient::~DesktopScreenPositionClient() { void DesktopScreenPositionClient::SetBounds(aura::Window* window, const gfx::Rect& bounds, - const gfx::Display& display) { + const display::Display& display) { // TODO(jam): Use the 3rd parameter, |display|. aura::Window* root = window->GetRootWindow(); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h index 2e7bb1b9b2d..33fbdc2ef8d 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_position_client.h @@ -22,7 +22,7 @@ class VIEWS_EXPORT DesktopScreenPositionClient // aura::client::DefaultScreenPositionClient: void SetBounds(aura::Window* window, const gfx::Rect& bounds, - const gfx::Display& display) override; + const display::Display& display) override; private: aura::Window* root_window_; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc index 4df7b7ffae5..f772f64d656 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.cc @@ -8,7 +8,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" -#include "ui/gfx/display.h" +#include "ui/display/display.h" #include "ui/views/widget/desktop_aura/desktop_screen.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" @@ -26,7 +26,7 @@ DesktopScreenWin::~DesktopScreenWin() { //////////////////////////////////////////////////////////////////////////////// // DesktopScreenWin, display::win::ScreenWin implementation: -gfx::Display DesktopScreenWin::GetDisplayMatching( +display::Display DesktopScreenWin::GetDisplayMatching( const gfx::Rect& match_rect) const { return GetDisplayNearestPoint(match_rect.CenterPoint()); } @@ -43,7 +43,7 @@ gfx::NativeWindow DesktopScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { //////////////////////////////////////////////////////////////////////////////// -gfx::Screen* CreateDesktopScreen() { +display::Screen* CreateDesktopScreen() { return new DesktopScreenWin; } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h index 085ba321da1..87299feba93 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_win.h @@ -18,7 +18,8 @@ public: private: // Overridden from display::win::ScreenWin: - gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override; + display::Display GetDisplayMatching( + const gfx::Rect& match_rect) const override; HWND GetHWNDFromNativeView(gfx::NativeView window) const override; gfx::NativeWindow GetNativeWindowFromHWND(HWND hwnd) const override; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc index 6ffd94a3c89..57d5f13bc9b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc @@ -16,15 +16,15 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" #include "ui/base/layout.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/display/util/display_util.h" #include "ui/display/util/x11/edid_parser_x11.h" #include "ui/events/platform/platform_event_source.h" -#include "ui/gfx/display.h" #include "ui/gfx/font_render_params.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/native_widget_types.h" -#include "ui/gfx/screen.h" #include "ui/gfx/x/x11_types.h" #include "ui/views/linux_ui/linux_ui.h" #include "ui/views/widget/desktop_aura/desktop_screen.h" @@ -33,6 +33,11 @@ namespace { +const char* const kAtomsToCache[] = { + "_NET_WORKAREA", + nullptr +}; + // The delay to perform configuration after RRNotify. See the comment // in |Dispatch()|. const int64_t kConfigureDelayMs = 500; @@ -42,8 +47,8 @@ double GetDeviceScaleFactor() { if (views::LinuxUI::instance()) { device_scale_factor = views::LinuxUI::instance()->GetDeviceScaleFactor(); - } else if (gfx::Display::HasForceDeviceScaleFactor()) { - device_scale_factor = gfx::Display::GetForcedDeviceScaleFactor(); + } else if (display::Display::HasForceDeviceScaleFactor()) { + device_scale_factor = display::Display::GetForcedDeviceScaleFactor(); } return device_scale_factor; } @@ -56,7 +61,7 @@ gfx::Point DIPToPixelPoint(const gfx::Point& dip_point) { return gfx::ScaleToFlooredPoint(dip_point, GetDeviceScaleFactor()); } -std::vector<gfx::Display> GetFallbackDisplayList() { +std::vector<display::Display> GetFallbackDisplayList() { ::XDisplay* display = gfx::GetXDisplay(); ::Screen* screen = DefaultScreenOfDisplay(display); int width = WidthOfScreen(screen); @@ -64,15 +69,15 @@ std::vector<gfx::Display> GetFallbackDisplayList() { gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen)); gfx::Rect bounds_in_pixels(0, 0, width, height); - gfx::Display gfx_display(0, bounds_in_pixels); - if (!gfx::Display::HasForceDeviceScaleFactor() && + display::Display gfx_display(0, bounds_in_pixels); + if (!display::Display::HasForceDeviceScaleFactor() && !ui::IsDisplaySizeBlackListed(physical_size)) { const float device_scale_factor = GetDeviceScaleFactor(); DCHECK_LE(1.0f, device_scale_factor); gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels); } - return std::vector<gfx::Display>(1, gfx_display); + return std::vector<display::Display>(1, gfx_display); } } // namespace @@ -86,7 +91,9 @@ DesktopScreenX11::DesktopScreenX11() : xdisplay_(gfx::GetXDisplay()), x_root_window_(DefaultRootWindow(xdisplay_)), has_xrandr_(false), - xrandr_event_base_(0) { + xrandr_event_base_(0), + primary_display_index_(0), + atom_cache_(xdisplay_, kAtomsToCache) { // We only support 1.3+. There were library changes before this and we should // use the new interface instead of the 1.2 one. int randr_version_major = 0; @@ -120,7 +127,7 @@ DesktopScreenX11::~DesktopScreenX11() { } //////////////////////////////////////////////////////////////////////////////// -// DesktopScreenX11, gfx::Screen implementation: +// DesktopScreenX11, display::Screen implementation: gfx::Point DesktopScreenX11::GetCursorScreenPoint() { TRACE_EVENT0("views", "DesktopScreenX11::GetCursorScreenPoint()"); @@ -143,8 +150,8 @@ gfx::Point DesktopScreenX11::GetCursorScreenPoint() { return PixelToDIPPoint(gfx::Point(root_x, root_y)); } -gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() { - return GetWindowAtScreenPoint(GetCursorScreenPoint()); +bool DesktopScreenX11::IsWindowUnderCursor(gfx::NativeWindow window) { + return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window; } gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint( @@ -158,11 +165,11 @@ int DesktopScreenX11::GetNumDisplays() const { return displays_.size(); } -std::vector<gfx::Display> DesktopScreenX11::GetAllDisplays() const { +std::vector<display::Display> DesktopScreenX11::GetAllDisplays() const { return displays_; } -gfx::Display DesktopScreenX11::GetDisplayNearestWindow( +display::Display DesktopScreenX11::GetDisplayNearestWindow( gfx::NativeView window) const { if (!window) return GetPrimaryDisplay(); @@ -187,9 +194,9 @@ gfx::Display DesktopScreenX11::GetDisplayNearestWindow( return GetPrimaryDisplay(); } -gfx::Display DesktopScreenX11::GetDisplayNearestPoint( +display::Display DesktopScreenX11::GetDisplayNearestPoint( const gfx::Point& point) const { - for (std::vector<gfx::Display>::const_iterator it = displays_.begin(); + for (std::vector<display::Display>::const_iterator it = displays_.begin(); it != displays_.end(); ++it) { if (it->bounds().Contains(point)) return *it; @@ -198,11 +205,11 @@ gfx::Display DesktopScreenX11::GetDisplayNearestPoint( return GetPrimaryDisplay(); } -gfx::Display DesktopScreenX11::GetDisplayMatching( +display::Display DesktopScreenX11::GetDisplayMatching( const gfx::Rect& match_rect) const { int max_area = 0; - const gfx::Display* matching = NULL; - for (std::vector<gfx::Display>::const_iterator it = displays_.begin(); + const display::Display* matching = NULL; + for (std::vector<display::Display>::const_iterator it = displays_.begin(); it != displays_.end(); ++it) { gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect); int area = intersect.width() * intersect.height(); @@ -215,28 +222,34 @@ gfx::Display DesktopScreenX11::GetDisplayMatching( return matching ? *matching : GetPrimaryDisplay(); } -gfx::Display DesktopScreenX11::GetPrimaryDisplay() const { - return displays_.front(); +display::Display DesktopScreenX11::GetPrimaryDisplay() const { + DCHECK(!displays_.empty()); + return displays_[primary_display_index_]; } -void DesktopScreenX11::AddObserver(gfx::DisplayObserver* observer) { +void DesktopScreenX11::AddObserver(display::DisplayObserver* observer) { change_notifier_.AddObserver(observer); } -void DesktopScreenX11::RemoveObserver(gfx::DisplayObserver* observer) { +void DesktopScreenX11::RemoveObserver(display::DisplayObserver* observer) { change_notifier_.RemoveObserver(observer); } bool DesktopScreenX11::CanDispatchEvent(const ui::PlatformEvent& event) { return event->type - xrandr_event_base_ == RRScreenChangeNotify || - event->type - xrandr_event_base_ == RRNotify; + event->type - xrandr_event_base_ == RRNotify || + (event->type == PropertyNotify && + event->xproperty.window == x_root_window_ && + event->xproperty.atom == atom_cache_.GetAtom("_NET_WORKAREA")); } uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) { if (event->type - xrandr_event_base_ == RRScreenChangeNotify) { // Pass the event through to xlib. XRRUpdateConfiguration(event); - } else if (event->type - xrandr_event_base_ == RRNotify) { + } else if (event->type - xrandr_event_base_ == RRNotify || + (event->type == PropertyNotify && + event->xproperty.atom == atom_cache_.GetAtom("_NET_WORKAREA"))) { // There's some sort of observer dispatch going on here, but I don't think // it's the screen's? if (configure_timer_.get() && configure_timer_->IsRunning()) { @@ -259,7 +272,7 @@ uint32_t DesktopScreenX11::DispatchEvent(const ui::PlatformEvent& event) { // static void DesktopScreenX11::UpdateDeviceScaleFactorForTest() { DesktopScreenX11* screen = - static_cast<DesktopScreenX11*>(gfx::Screen::GetScreen()); + static_cast<DesktopScreenX11*>(display::Screen::GetScreen()); screen->ConfigureTimerFired(); } @@ -267,16 +280,17 @@ void DesktopScreenX11::UpdateDeviceScaleFactorForTest() { // DesktopScreenX11, private: DesktopScreenX11::DesktopScreenX11( - const std::vector<gfx::Display>& test_displays) + const std::vector<display::Display>& test_displays) : xdisplay_(gfx::GetXDisplay()), x_root_window_(DefaultRootWindow(xdisplay_)), has_xrandr_(false), xrandr_event_base_(0), - displays_(test_displays) { -} + displays_(test_displays), + primary_display_index_(0), + atom_cache_(xdisplay_, kAtomsToCache) {} -std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { - std::vector<gfx::Display> displays; +std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { + std::vector<display::Display> displays; gfx::XScopedPtr< XRRScreenResources, gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>> @@ -286,6 +300,9 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { return GetFallbackDisplayList(); } + primary_display_index_ = 0; + RROutput primary_display_id = XRRGetOutputPrimary(xdisplay_, x_root_window_); + bool has_work_area = false; gfx::Rect work_area_in_pixels; std::vector<int> value; @@ -322,9 +339,9 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { } gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height); - gfx::Display display(display_id, crtc_bounds); + display::Display display(display_id, crtc_bounds); - if (!gfx::Display::HasForceDeviceScaleFactor()) { + if (!display::Display::HasForceDeviceScaleFactor()) { display.SetScaleAndBounds(device_scale_factor, crtc_bounds); } @@ -342,19 +359,22 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { switch (crtc->rotation) { case RR_Rotate_0: - display.set_rotation(gfx::Display::ROTATE_0); + display.set_rotation(display::Display::ROTATE_0); break; case RR_Rotate_90: - display.set_rotation(gfx::Display::ROTATE_90); + display.set_rotation(display::Display::ROTATE_90); break; case RR_Rotate_180: - display.set_rotation(gfx::Display::ROTATE_180); + display.set_rotation(display::Display::ROTATE_180); break; case RR_Rotate_270: - display.set_rotation(gfx::Display::ROTATE_270); + display.set_rotation(display::Display::ROTATE_270); break; } + if (output_id == primary_display_id) + primary_display_index_ = displays.size(); + displays.push_back(display); } } @@ -366,13 +386,13 @@ std::vector<gfx::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() { } void DesktopScreenX11::ConfigureTimerFired() { - std::vector<gfx::Display> old_displays = displays_; + std::vector<display::Display> old_displays = displays_; SetDisplaysInternal(BuildDisplaysFromXRandRInfo()); change_notifier_.NotifyDisplaysChanged(old_displays, displays_); } void DesktopScreenX11::SetDisplaysInternal( - const std::vector<gfx::Display>& displays) { + const std::vector<display::Display>& displays) { displays_ = displays; gfx::SetFontRenderParamsDeviceScaleFactor( GetPrimaryDisplay().device_scale_factor()); @@ -380,7 +400,7 @@ void DesktopScreenX11::SetDisplaysInternal( //////////////////////////////////////////////////////////////////////////////// -gfx::Screen* CreateDesktopScreen() { +display::Screen* CreateDesktopScreen() { return new DesktopScreenX11; } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h index e96d983ccb2..03f5c6255b0 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h @@ -7,18 +7,16 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/timer/timer.h" +#include "ui/display/display_change_notifier.h" +#include "ui/display/screen.h" #include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/gfx/display_change_notifier.h" -#include "ui/gfx/screen.h" +#include "ui/gfx/x/x11_atom_cache.h" #include "ui/views/views_export.h" -namespace gfx { -class Display; -} - typedef unsigned long XID; typedef XID Window; typedef struct _XDisplay Display; @@ -31,25 +29,28 @@ class DesktopScreenX11TestApi; } // Our singleton screen implementation that talks to xrandr. -class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen, +class VIEWS_EXPORT DesktopScreenX11 : public display::Screen, public ui::PlatformEventDispatcher { public: DesktopScreenX11(); ~DesktopScreenX11() override; - // Overridden from gfx::Screen: + // Overridden from display::Screen: gfx::Point GetCursorScreenPoint() override; - gfx::NativeWindow GetWindowUnderCursor() override; + bool IsWindowUnderCursor(gfx::NativeWindow window) override; gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override; int GetNumDisplays() const override; - std::vector<gfx::Display> GetAllDisplays() const override; - gfx::Display GetDisplayNearestWindow(gfx::NativeView window) const override; - gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const override; - gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override; - gfx::Display GetPrimaryDisplay() const override; - void AddObserver(gfx::DisplayObserver* observer) override; - void RemoveObserver(gfx::DisplayObserver* observer) override; + std::vector<display::Display> GetAllDisplays() const override; + display::Display GetDisplayNearestWindow( + gfx::NativeView window) const override; + display::Display GetDisplayNearestPoint( + const gfx::Point& point) const override; + display::Display GetDisplayMatching( + const gfx::Rect& match_rect) const override; + display::Display GetPrimaryDisplay() const override; + void AddObserver(display::DisplayObserver* observer) override; + void RemoveObserver(display::DisplayObserver* observer) override; // ui::PlatformEventDispatcher: bool CanDispatchEvent(const ui::PlatformEvent& event) override; @@ -62,17 +63,17 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen, friend class test::DesktopScreenX11TestApi; // Constructor used in tests. - DesktopScreenX11(const std::vector<gfx::Display>& test_displays); + DesktopScreenX11(const std::vector<display::Display>& test_displays); // Builds a list of displays from the current screen information offered by // the X server. - std::vector<gfx::Display> BuildDisplaysFromXRandRInfo(); + std::vector<display::Display> BuildDisplaysFromXRandRInfo(); // We delay updating the display so we can coalesce events. void ConfigureTimerFired(); // Updates |displays_| and sets FontRenderParams's scale factor. - void SetDisplaysInternal(const std::vector<gfx::Display>& displays); + void SetDisplaysInternal(const std::vector<display::Display>& displays); Display* xdisplay_; ::Window x_root_window_; @@ -85,13 +86,18 @@ class VIEWS_EXPORT DesktopScreenX11 : public gfx::Screen, int xrandr_event_base_; // The display objects we present to chrome. - std::vector<gfx::Display> displays_; + std::vector<display::Display> displays_; + + // The index into displays_ that represents the primary display. + size_t primary_display_index_; // The timer to delay configuring outputs. See also the comments in // Dispatch(). - scoped_ptr<base::OneShotTimer> configure_timer_; + std::unique_ptr<base::OneShotTimer> configure_timer_; + + display::DisplayChangeNotifier change_notifier_; - gfx::DisplayChangeNotifier change_notifier_; + ui::X11AtomCache atom_cache_; DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11); }; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc index a2e2d2aed7e..82f81bad69c 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc @@ -6,16 +6,17 @@ #include <stdint.h> +#include <memory> + #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/hit_test.h" #include "ui/base/x/x11_util.h" +#include "ui/display/display_observer.h" #include "ui/events/test/event_generator.h" -#include "ui/gfx/display_observer.h" #include "ui/gfx/font_render_params.h" #include "ui/gfx/x/x11_types.h" #include "ui/views/test/views_test_base.h" @@ -56,7 +57,7 @@ const int64_t kFirstDisplay = 5321829; const int64_t kSecondDisplay = 928310; class DesktopScreenX11Test : public views::ViewsTestBase, - public gfx::DisplayObserver { + public display::DisplayObserver { public: DesktopScreenX11Test() {} ~DesktopScreenX11Test() override {} @@ -65,8 +66,9 @@ class DesktopScreenX11Test : public views::ViewsTestBase, void SetUp() override { ViewsTestBase::SetUp(); // Initialize the world to the single monitor case. - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); screen_.reset(new DesktopScreenX11(displays)); screen_->AddObserver(this); } @@ -77,14 +79,14 @@ class DesktopScreenX11Test : public views::ViewsTestBase, } protected: - std::vector<gfx::Display> changed_display_; - std::vector<gfx::Display> added_display_; - std::vector<gfx::Display> removed_display_; + std::vector<display::Display> changed_display_; + std::vector<display::Display> added_display_; + std::vector<display::Display> removed_display_; DesktopScreenX11* screen() { return screen_.get(); } - void NotifyDisplaysChanged(const std::vector<gfx::Display>& displays) { - std::vector<gfx::Display> old_displays = screen_->displays_; + void NotifyDisplaysChanged(const std::vector<display::Display>& displays) { + std::vector<display::Display> old_displays = screen_->displays_; screen_->SetDisplaysInternal(displays); screen_->change_notifier_.NotifyDisplaysChanged(old_displays, screen_->displays_); @@ -115,28 +117,29 @@ class DesktopScreenX11Test : public views::ViewsTestBase, } private: - // Overridden from gfx::DisplayObserver: - void OnDisplayAdded(const gfx::Display& new_display) override { + // Overridden from display::DisplayObserver: + void OnDisplayAdded(const display::Display& new_display) override { added_display_.push_back(new_display); } - void OnDisplayRemoved(const gfx::Display& old_display) override { + void OnDisplayRemoved(const display::Display& old_display) override { removed_display_.push_back(old_display); } - void OnDisplayMetricsChanged(const gfx::Display& display, + void OnDisplayMetricsChanged(const display::Display& display, uint32_t metrics) override { changed_display_.push_back(display); } - scoped_ptr<DesktopScreenX11> screen_; + std::unique_ptr<DesktopScreenX11> screen_; DISALLOW_COPY_AND_ASSIGN(DesktopScreenX11Test); }; TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(1u, changed_display_.size()); @@ -145,10 +148,11 @@ TEST_F(DesktopScreenX11Test, BoundsChangeSingleMonitor) { } TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(0u, changed_display_.size()); @@ -157,9 +161,11 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheRight) { } TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(1024, 0, 640, 480))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(1024, 0, 640, 480))); NotifyDisplaysChanged(displays); EXPECT_EQ(1u, changed_display_.size()); @@ -168,16 +174,18 @@ TEST_F(DesktopScreenX11Test, AddMonitorToTheLeft) { } TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); ResetDisplayChanges(); displays.clear(); - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); NotifyDisplaysChanged(displays); EXPECT_EQ(0u, changed_display_.size()); @@ -186,16 +194,18 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnRight) { } TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); ResetDisplayChanges(); displays.clear(); - displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(0, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(1u, changed_display_.size()); @@ -204,10 +214,11 @@ TEST_F(DesktopScreenX11Test, RemoveMonitorOnLeft) { } TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(kFirstDisplay, @@ -221,10 +232,11 @@ TEST_F(DesktopScreenX11Test, GetDisplayNearestPoint) { } TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(kSecondDisplay, @@ -232,10 +244,11 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingBasic) { } TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); EXPECT_EQ(kSecondDisplay, @@ -243,10 +256,11 @@ TEST_F(DesktopScreenX11Test, GetDisplayMatchingOverlap) { } TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, - gfx::Rect(640, 0, 1024, 768))); - displays.push_back(gfx::Display(kSecondDisplay, gfx::Rect(0, 0, 640, 480))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(640, 0, 1024, 768))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(0, 0, 640, 480))); NotifyDisplaysChanged(displays); // The first display in the list is always the primary, even if other @@ -256,10 +270,11 @@ TEST_F(DesktopScreenX11Test, GetPrimaryDisplay) { TEST_F(DesktopScreenX11Test, GetDisplayNearestWindow) { // Set up a two monitor situation. - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); - displays.push_back(gfx::Display(kSecondDisplay, - gfx::Rect(640, 0, 1024, 768))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); Widget* window_one = BuildTopLevelDesktopWidget(gfx::Rect(10, 10, 10, 10), @@ -369,41 +384,43 @@ TEST_F(DesktopScreenX11Test, RightClickDuringDoubleClickDoesntMaximize) { // Test that rotating the displays notifies the DisplayObservers. TEST_F(DesktopScreenX11Test, RotationChange) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + std::vector<display::Display> displays; displays.push_back( - gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + displays.push_back( + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); ResetDisplayChanges(); - displays[0].set_rotation(gfx::Display::ROTATE_90); + displays[0].set_rotation(display::Display::ROTATE_90); NotifyDisplaysChanged(displays); EXPECT_EQ(1u, changed_display_.size()); - displays[1].set_rotation(gfx::Display::ROTATE_90); + displays[1].set_rotation(display::Display::ROTATE_90); NotifyDisplaysChanged(displays); EXPECT_EQ(2u, changed_display_.size()); - displays[0].set_rotation(gfx::Display::ROTATE_270); + displays[0].set_rotation(display::Display::ROTATE_270); NotifyDisplaysChanged(displays); EXPECT_EQ(3u, changed_display_.size()); - displays[0].set_rotation(gfx::Display::ROTATE_270); + displays[0].set_rotation(display::Display::ROTATE_270); NotifyDisplaysChanged(displays); EXPECT_EQ(3u, changed_display_.size()); - displays[0].set_rotation(gfx::Display::ROTATE_0); - displays[1].set_rotation(gfx::Display::ROTATE_0); + displays[0].set_rotation(display::Display::ROTATE_0); + displays[1].set_rotation(display::Display::ROTATE_0); NotifyDisplaysChanged(displays); EXPECT_EQ(5u, changed_display_.size()); } // Test that changing the displays workarea notifies the DisplayObservers. TEST_F(DesktopScreenX11Test, WorkareaChange) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back( - gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); ResetDisplayChanges(); @@ -431,10 +448,11 @@ TEST_F(DesktopScreenX11Test, WorkareaChange) { // Test that changing the device scale factor notifies the DisplayObservers. TEST_F(DesktopScreenX11Test, DeviceScaleFactorChange) { - std::vector<gfx::Display> displays; - displays.push_back(gfx::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); + std::vector<display::Display> displays; + displays.push_back( + display::Display(kFirstDisplay, gfx::Rect(0, 0, 640, 480))); displays.push_back( - gfx::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); + display::Display(kSecondDisplay, gfx::Rect(640, 0, 1024, 768))); NotifyDisplaysChanged(displays); ResetDisplayChanges(); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h index 831557d4f66..7eee095edf7 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h @@ -5,7 +5,8 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_H_ -#include "base/memory/scoped_ptr.h" +#include <memory> + #include "ui/aura/window_event_dispatcher.h" #include "ui/base/ui_base_types.h" #include "ui/views/views_export.h" @@ -62,12 +63,12 @@ class VIEWS_EXPORT DesktopWindowTreeHost { // Creates and returns the Tooltip implementation to use. Return value is // owned by DesktopNativeWidgetAura and lives as long as // DesktopWindowTreeHost. - virtual scoped_ptr<corewm::Tooltip> CreateTooltip() = 0; + virtual std::unique_ptr<corewm::Tooltip> CreateTooltip() = 0; // Creates and returns the DragDropClient implementation to use. Return value // is owned by DesktopNativeWidgetAura and lives as long as // DesktopWindowTreeHost. - virtual scoped_ptr<aura::client::DragDropClient> CreateDragDropClient( + virtual std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) = 0; virtual void Close() = 0; @@ -89,6 +90,7 @@ class VIEWS_EXPORT DesktopWindowTreeHost { virtual gfx::Rect GetWindowBoundsInScreen() const = 0; virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0; virtual gfx::Rect GetRestoredBounds() const = 0; + virtual std::string GetWorkspace() const = 0; virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0; diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index fa9ea48b500..7591042b3c5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -4,6 +4,7 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" +#include "base/memory/ptr_util.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/aura/client/aura_constants.h" @@ -16,12 +17,13 @@ #include "ui/base/win/shell.h" #include "ui/compositor/compositor_constants.h" #include "ui/compositor/paint_context.h" +#include "ui/display/win/dpi.h" +#include "ui/display/win/screen_win.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/path.h" #include "ui/gfx/path_win.h" -#include "ui/gfx/win/dpi.h" #include "ui/native_theme/native_theme_aura.h" #include "ui/native_theme/native_theme_win.h" #include "ui/views/corewm/tooltip_win.h" @@ -140,7 +142,9 @@ void DesktopWindowTreeHostWin::Init(aura::Window* content_window, remove_standard_frame_ = params.remove_standard_frame; has_non_client_view_ = Widget::RequiresNonClientView(params.type); - gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds); + // We don't have an HWND yet, so scale relative to the nearest screen. + gfx::Rect pixel_bounds = + display::win::ScreenWin::DIPToScreenRect(nullptr, params.bounds); message_handler_->Init(parent_hwnd, pixel_bounds); if (params.force_software_compositing) { ::SetProp(GetAcceleratedWidget(), @@ -170,17 +174,17 @@ void DesktopWindowTreeHostWin::OnNativeWidgetCreated( SetWindowTransparency(); } -scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() { +std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() { DCHECK(!tooltip_); tooltip_ = new corewm::TooltipWin(GetAcceleratedWidget()); - return make_scoped_ptr(tooltip_); + return base::WrapUnique(tooltip_); } -scoped_ptr<aura::client::DragDropClient> +std::unique_ptr<aura::client::DragDropClient> DesktopWindowTreeHostWin::CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) { drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND()); - return make_scoped_ptr(drag_drop_client_); + return base::WrapUnique(drag_drop_client_); } void DesktopWindowTreeHostWin::Close() { @@ -218,7 +222,8 @@ void DesktopWindowTreeHostWin::ShowMaximizedWithBounds( const gfx::Rect& restored_bounds) { if (compositor()) compositor()->SetVisible(true); - gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds); + gfx::Rect pixel_bounds = + display::win::ScreenWin::DIPToScreenRect(GetHWND(), restored_bounds); message_handler_->ShowMaximizedWithBounds(pixel_bounds); } @@ -227,7 +232,8 @@ bool DesktopWindowTreeHostWin::IsVisible() const { } void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) { - gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size); + gfx::Size size_in_pixels = display::win::ScreenWin::DIPToScreenSize(GetHWND(), + size); gfx::Size expanded = GetExpandedWindowSize( message_handler_->window_ex_style(), size_in_pixels); window_enlargement_ = @@ -247,7 +253,8 @@ void DesktopWindowTreeHostWin::StackAtTop() { } void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) { - gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size); + gfx::Size size_in_pixels = display::win::ScreenWin::DIPToScreenSize(GetHWND(), + size); gfx::Size expanded_size; expanded_size = GetExpandedWindowSize(message_handler_->window_ex_style(), size_in_pixels); @@ -262,25 +269,29 @@ void DesktopWindowTreeHostWin::GetWindowPlacement( ui::WindowShowState* show_state) const { message_handler_->GetWindowPlacement(bounds, show_state); InsetBottomRight(bounds, window_enlargement_); - *bounds = gfx::win::ScreenToDIPRect(*bounds); + *bounds = display::win::ScreenWin::ScreenToDIPRect(GetHWND(), *bounds); } gfx::Rect DesktopWindowTreeHostWin::GetWindowBoundsInScreen() const { gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen(); InsetBottomRight(&pixel_bounds, window_enlargement_); - return gfx::win::ScreenToDIPRect(pixel_bounds); + return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds); } gfx::Rect DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() const { gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen(); InsetBottomRight(&pixel_bounds, window_enlargement_); - return gfx::win::ScreenToDIPRect(pixel_bounds); + return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds); } gfx::Rect DesktopWindowTreeHostWin::GetRestoredBounds() const { gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds(); InsetBottomRight(&pixel_bounds, window_enlargement_); - return gfx::win::ScreenToDIPRect(pixel_bounds); + return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds); +} + +std::string DesktopWindowTreeHostWin::GetWorkspace() const { + return std::string(); } gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const { @@ -290,7 +301,7 @@ gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const { MONITOR_DEFAULTTONEAREST), &monitor_info); gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork); - return gfx::win::ScreenToDIPRect(pixel_bounds); + return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds); } void DesktopWindowTreeHostWin::SetShape(SkRegion* native_region) { @@ -299,9 +310,9 @@ void DesktopWindowTreeHostWin::SetShape(SkRegion* native_region) { // See crbug.com/410593. SkRegion* shape = native_region; SkRegion device_region; - if (gfx::GetDPIScale() > 1.0) { + if (display::win::GetDPIScale() > 1.0) { shape = &device_region; - const float& scale = gfx::GetDPIScale(); + const float& scale = display::win::GetDPIScale(); std::vector<SkIRect> rects; for (SkRegion::Iterator it(*native_region); !it.done(); it.next()) { const SkIRect& rect = it.rect(); @@ -654,7 +665,8 @@ bool DesktopWindowTreeHostWin::WillProcessWorkAreaChange() const { int DesktopWindowTreeHostWin::GetNonClientComponent( const gfx::Point& point) const { - gfx::Point dip_position = gfx::win::ScreenToDIPPoint(point); + gfx::Point dip_position = display::win::ScreenWin::ClientToDIPPoint(GetHWND(), + point); return native_widget_delegate_->GetNonClientComponent(dip_position); } @@ -685,6 +697,11 @@ gfx::Size DesktopWindowTreeHostWin::GetRootViewSize() const { return GetWidget()->GetRootView()->size(); } +gfx::Size DesktopWindowTreeHostWin::DIPToScreenSize( + const gfx::Size& dip_size) const { + return display::win::ScreenWin::DIPToScreenSize(GetHWND(), dip_size); +} + void DesktopWindowTreeHostWin::ResetWindowControls() { GetWidget()->non_client_view()->ResetWindowControls(); } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index 3465112eac0..f357a5c9895 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -48,8 +48,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin void Init(aura::Window* content_window, const Widget::InitParams& params) override; void OnNativeWidgetCreated(const Widget::InitParams& params) override; - scoped_ptr<corewm::Tooltip> CreateTooltip() override; - scoped_ptr<aura::client::DragDropClient> CreateDragDropClient( + std::unique_ptr<corewm::Tooltip> CreateTooltip() override; + std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) override; void Close() override; void CloseNow() override; @@ -66,6 +66,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; gfx::Rect GetWorkAreaBoundsInScreen() const override; void SetShape(SkRegion* native_region) override; void Activate() override; @@ -146,6 +147,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin bool GetClientAreaInsets(gfx::Insets* insets) const override; void GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const override; gfx::Size GetRootViewSize() const override; + gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const override; void ResetWindowControls() override; gfx::NativeViewAccessible GetNativeViewAccessible() override; bool ShouldHandleSystemCommands() const override; @@ -205,8 +207,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin // Returns true if a modal window is active in the current root window chain. bool IsModalWindowActive() const; - scoped_ptr<HWNDMessageHandler> message_handler_; - scoped_ptr<aura::client::FocusClient> focus_client_; + std::unique_ptr<HWNDMessageHandler> message_handler_; + std::unique_ptr<aura::client::FocusClient> focus_client_; // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura // instead of providing this route back to Widget. @@ -258,7 +260,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin // whenever the cursor visibility state changes. static bool is_cursor_visible_; - scoped_ptr<aura::client::ScopedTooltipDisabler> tooltip_disabler_; + std::unique_ptr<aura::client::ScopedTooltipDisabler> tooltip_disabler_; // Indicates if current window will receive mouse events when should not // become activated. diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index cecae1ee81d..f792797e855 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc @@ -9,9 +9,12 @@ #include <X11/Xutil.h> #include <X11/extensions/XInput2.h> #include <X11/extensions/shape.h> + #include <utility> #include "base/command_line.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" @@ -26,20 +29,20 @@ #include "ui/base/ime/input_method.h" #include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util_internal.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/events/devices/x11/device_data_manager_x11.h" #include "ui/events/devices/x11/device_list_cache_x11.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event_utils.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/display.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/path.h" #include "ui/gfx/path_x11.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme.h" #include "ui/native_theme/native_theme_aura.h" #include "ui/views/corewm/tooltip_aura.h" @@ -250,7 +253,7 @@ void DesktopWindowTreeHostX11::RemoveObserver( } void DesktopWindowTreeHostX11::SwapNonClientEventHandler( - scoped_ptr<ui::EventHandler> handler) { + std::unique_ptr<ui::EventHandler> handler) { wm::CompoundEventFilter* compound_event_filter = desktop_native_widget_aura_->root_window_event_filter(); if (x11_non_client_event_filter_) @@ -307,7 +310,7 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated( // TODO(erg): Unify this code once the other consumer goes away. SwapNonClientEventHandler( - scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this))); + std::unique_ptr<ui::EventHandler>(new X11WindowEventFilter(this))); SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW && !params.remove_standard_frame); @@ -319,17 +322,17 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated( native_widget_delegate_->OnNativeWidgetCreated(true); } -scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() { - return make_scoped_ptr(new corewm::TooltipAura); +std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() { + return base::WrapUnique(new corewm::TooltipAura); } -scoped_ptr<aura::client::DragDropClient> +std::unique_ptr<aura::client::DragDropClient> DesktopWindowTreeHostX11::CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) { drag_drop_client_ = new DesktopDragDropClientAuraX11( window(), cursor_manager, xdisplay_, xwindow_); drag_drop_client_->Init(); - return make_scoped_ptr(drag_drop_client_); + return base::WrapUnique(drag_drop_client_); } void DesktopWindowTreeHostX11::Close() { @@ -561,6 +564,13 @@ gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const { return GetWindowBoundsInScreen(); } +std::string DesktopWindowTreeHostX11::GetWorkspace() const { + int workspace_id; + if (ui::GetIntProperty(xwindow_, "_NET_WM_DESKTOP", &workspace_id)) + return base::IntToString(workspace_id); + return std::string(); +} + gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const { return ToDIPRect(GetWorkAreaBoundsInPixels()); } @@ -819,8 +829,8 @@ void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) { // See https://crbug.com/361408 if (fullscreen) { restored_bounds_in_pixels_ = bounds_in_pixels_; - const gfx::Display display = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(window()); + const display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow(window()); bounds_in_pixels_ = ToPixelRect(display.bounds()); } else { bounds_in_pixels_ = restored_bounds_in_pixels_; @@ -938,10 +948,10 @@ void DesktopWindowTreeHostX11::SizeConstraintsChanged() { // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation: gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const { - gfx::Display display = gfx::Screen::GetScreen()->GetPrimaryDisplay(); + display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); if (window_mapped_) { aura::Window* win = const_cast<aura::Window*>(window()); - display = gfx::Screen::GetScreen()->GetDisplayNearestWindow(win); + display = display::Screen::GetScreen()->GetDisplayNearestWindow(win); } float scale = display.device_scale_factor(); @@ -1216,6 +1226,10 @@ void DesktopWindowTreeHostX11::InitX11Window( if (params.visible_on_all_workspaces) { state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY")); ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops); + } else if (!params.workspace.empty()) { + int workspace; + if (base::StringToInt(params.workspace, &workspace)) + ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace); } // Setting _NET_WM_STATE by sending a message to the root_window (with @@ -1286,8 +1300,8 @@ void DesktopWindowTreeHostX11::InitX11Window( gfx::Size DesktopWindowTreeHostX11::AdjustSize( const gfx::Size& requested_size_in_pixels) { - std::vector<gfx::Display> displays = - gfx::Screen::GetScreen()->GetAllDisplays(); + std::vector<display::Display> displays = + display::Screen::GetScreen()->GetAllDisplays(); // Compare against all monitor sizes. The window manager can move the window // to whichever monitor it wants. for (size_t i = 0; i < displays.size(); ++i) { @@ -1532,10 +1546,10 @@ void DesktopWindowTreeHostX11::ConvertEventToDifferentHost( ui::LocatedEvent* located_event, DesktopWindowTreeHostX11* host) { DCHECK_NE(this, host); - const gfx::Display display_src = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(window()); - const gfx::Display display_dest = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(host->window()); + const display::Display display_src = + display::Screen::GetScreen()->GetDisplayNearestWindow(window()); + const display::Display display_dest = + display::Screen::GetScreen()->GetDisplayNearestWindow(host->window()); DCHECK_EQ(display_src.device_scale_factor(), display_dest.device_scale_factor()); gfx::Vector2d offset = GetLocationOnNativeScreen() - @@ -1658,16 +1672,6 @@ void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) { // asynchronous. if (ui::X11EventSource::GetInstance()) ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_); - window_mapped_ = true; - - UpdateMinAndMaxSize(); - - // Some WMs only respect maximize hints after the window has been mapped. - // Check whether we need to re-do a maximization. - if (should_maximize_after_map_) { - Maximize(); - should_maximize_after_map_ = false; - } } void DesktopWindowTreeHostX11::SetWindowTransparency() { @@ -1881,9 +1885,21 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( break; } case MapNotify: { + window_mapped_ = true; + FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, observer_list_, OnWindowMapped(xwindow_)); + + UpdateMinAndMaxSize(); + + // Some WMs only respect maximize hints after the window has been mapped. + // Check whether we need to re-do a maximization. + if (should_maximize_after_map_) { + Maximize(); + should_maximize_after_map_ = false; + } + break; } case UnmapNotify: { @@ -1967,6 +1983,8 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( OnWMStateUpdated(); else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS")) OnFrameExtentsUpdated(); + else if (changed_atom == atom_cache_.GetAtom("_NET_WM_DESKTOP")) + OnHostWorkspaceChanged(); break; } case SelectionNotify: { diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h index 7e842fed086..6a963f8456e 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h @@ -80,7 +80,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 void RemoveObserver(views::DesktopWindowTreeHostObserverX11* observer); // Swaps the current handler for events in the non client view with |handler|. - void SwapNonClientEventHandler(scoped_ptr<ui::EventHandler> handler); + void SwapNonClientEventHandler(std::unique_ptr<ui::EventHandler> handler); // Runs the |func| callback for each content-window, and deallocates the // internal list of open windows. @@ -91,8 +91,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 void Init(aura::Window* content_window, const Widget::InitParams& params) override; void OnNativeWidgetCreated(const Widget::InitParams& params) override; - scoped_ptr<corewm::Tooltip> CreateTooltip() override; - scoped_ptr<aura::client::DragDropClient> CreateDragDropClient( + std::unique_ptr<corewm::Tooltip> CreateTooltip() override; + std::unique_ptr<aura::client::DragDropClient> CreateDragDropClient( DesktopNativeCursorManager* cursor_manager) override; void Close() override; void CloseNow() override; @@ -109,6 +109,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; gfx::Rect GetWorkAreaBoundsInScreen() const override; void SetShape(SkRegion* native_region) override; void Activate() override; @@ -300,8 +301,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 DesktopDragDropClientAuraX11* drag_drop_client_; - scoped_ptr<ui::EventHandler> x11_non_client_event_filter_; - scoped_ptr<X11DesktopWindowMoveClient> x11_window_move_client_; + std::unique_ptr<ui::EventHandler> x11_non_client_event_filter_; + std::unique_ptr<X11DesktopWindowMoveClient> x11_window_move_client_; // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura // instead of providing this route back to Widget. diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc index 7ea716cfe0e..1ac18b5b7cd 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc @@ -6,12 +6,13 @@ #include <X11/Xlib.h> +#include <memory> + // Get rid of X11 macros which conflict with gtest. #undef Bool #undef None #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "ui/aura/env.h" #include "ui/aura/window.h" @@ -81,8 +82,8 @@ class MouseMoveCounterHandler : public ui::EventHandler { }; // Creates a widget with the given bounds. -scoped_ptr<Widget> CreateWidget(const gfx::Rect& bounds) { - scoped_ptr<Widget> widget(new Widget); +std::unique_ptr<Widget> CreateWidget(const gfx::Rect& bounds) { + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.remove_standard_frame = true; @@ -156,7 +157,7 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase { // Chrome even if it not possible to deactivate the window wrt to the x server. // This behavior is required by several interactive_ui_tests. TEST_F(DesktopWindowTreeHostX11Test, Deactivate) { - scoped_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100))); + std::unique_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100))); ActivationWaiter waiter( widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); @@ -181,13 +182,13 @@ TEST_F(DesktopWindowTreeHostX11Test, Deactivate) { // Chrome synchronously switches the window that mouse events are forwarded to // when capture is changed. TEST_F(DesktopWindowTreeHostX11Test, CaptureEventForwarding) { - scoped_ptr<Widget> widget1(CreateWidget(gfx::Rect(100, 100, 100, 100))); + std::unique_ptr<Widget> widget1(CreateWidget(gfx::Rect(100, 100, 100, 100))); aura::Window* window1 = widget1->GetNativeWindow(); DesktopWindowTreeHostX11* host1 = static_cast<DesktopWindowTreeHostX11*>(window1->GetHost()); widget1->Show(); - scoped_ptr<Widget> widget2(CreateWidget(gfx::Rect(200, 100, 100, 100))); + std::unique_ptr<Widget> widget2(CreateWidget(gfx::Rect(200, 100, 100, 100))); aura::Window* window2 = widget2->GetNativeWindow(); DesktopWindowTreeHostX11* host2 = static_cast<DesktopWindowTreeHostX11*>(window2->GetHost()); @@ -255,8 +256,8 @@ TEST_F(DesktopWindowTreeHostX11Test, CaptureEventForwarding) { } TEST_F(DesktopWindowTreeHostX11Test, InputMethodFocus) { - scoped_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100))); - scoped_ptr<Textfield> textfield(new Textfield); + std::unique_ptr<Widget> widget(CreateWidget(gfx::Rect(100, 100, 100, 100))); + std::unique_ptr<Textfield> textfield(new Textfield); textfield->SetBounds(0, 0, 200, 20); widget->GetRootView()->AddChildView(textfield.get()); widget->ShowInactive(); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc index 7c2253493ac..52a3827f2bc 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <vector> - #include <stddef.h> #include <X11/extensions/shape.h> #include <X11/Xlib.h> +#include <memory> +#include <vector> + // Get rid of X11 macros which conflict with gtest. // It is necessary to include this header before the rest so that Bool can be // undefined. @@ -17,19 +18,18 @@ #include "base/command_line.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" #include "ui/base/x/x11_util.h" +#include "ui/display/display_switches.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/platform/x11/x11_event_source_glib.h" #include "ui/events/test/platform_event_source_test_api.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/path.h" -#include "ui/gfx/switches.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/x11_property_change_waiter.h" @@ -76,7 +76,7 @@ class WMStateWaiter : public X11PropertyChangeWaiter { return true; } - scoped_ptr<ui::X11AtomCache> atom_cache_; + std::unique_ptr<ui::X11AtomCache> atom_cache_; // The name of the hint to wait to get set or unset. const char* hint_; @@ -140,8 +140,8 @@ class ShapedWidgetDelegate : public WidgetDelegateView { }; // Creates a widget of size 100x100. -scoped_ptr<Widget> CreateWidget(WidgetDelegate* delegate) { - scoped_ptr<Widget> widget(new Widget); +std::unique_ptr<Widget> CreateWidget(WidgetDelegate* delegate) { + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.delegate = delegate; params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -219,7 +219,7 @@ TEST_F(DesktopWindowTreeHostX11Test, Shape) { // 1) Test setting the window shape via the NonClientFrameView. This technique // is used to get rounded corners on Chrome windows when not using the native // window frame. - scoped_ptr<Widget> widget1 = CreateWidget(new ShapedWidgetDelegate()); + std::unique_ptr<Widget> widget1 = CreateWidget(new ShapedWidgetDelegate()); widget1->Show(); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -290,7 +290,7 @@ TEST_F(DesktopWindowTreeHostX11Test, Shape) { SkRegion* shape_region = new SkRegion; shape_region->setPath(shape2, SkRegion(shape2.getBounds().round())); - scoped_ptr<Widget> widget2(CreateWidget(NULL)); + std::unique_ptr<Widget> widget2(CreateWidget(NULL)); widget2->Show(); widget2->SetShape(shape_region); ui::X11EventSource::GetInstance()->DispatchXEvents(); @@ -330,7 +330,7 @@ TEST_F(DesktopWindowTreeHostX11Test, WindowManagerTogglesFullscreen) { if (!ui::WmSupportsHint(ui::GetAtom("_NET_WM_STATE_FULLSCREEN"))) return; - scoped_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate()); + std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate()); XID xid = widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); widget->Show(); ui::X11EventSource::GetInstance()->DispatchXEvents(); diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc index 5ab84f9928e..8ec4b1e7b9a 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc @@ -43,7 +43,7 @@ X11DesktopHandler::X11DesktopHandler() : xdisplay_(gfx::GetXDisplay()), x_root_window_(DefaultRootWindow(xdisplay_)), x_active_window_(None), - wm_user_time_ms_(0), + wm_user_time_ms_(CurrentTime), current_window_(None), current_window_active_state_(NOT_ACTIVE), atom_cache_(xdisplay_, kAtomsToCache), @@ -91,6 +91,10 @@ void X11DesktopHandler::ActivateWindow(::Window window) { // If the window is not already active, send a hint to activate it if (x_active_window_ != window) { + if (wm_user_time_ms_ == CurrentTime) { + set_wm_user_time_ms( + ui::X11EventSource::GetInstance()->UpdateLastSeenServerTime()); + } XEvent xclient; memset(&xclient, 0, sizeof(xclient)); xclient.type = ClientMessage; @@ -120,6 +124,18 @@ void X11DesktopHandler::ActivateWindow(::Window window) { } } +void X11DesktopHandler::set_wm_user_time_ms(Time time_ms) { + if (time_ms != CurrentTime) { + int64_t event_time_64 = time_ms; + int64_t time_difference = wm_user_time_ms_ - event_time_64; + // Ignore timestamps that go backwards. However, X server time is a 32-bit + // millisecond counter, so if the time goes backwards by more than half the + // range of the 32-bit counter, treat it as a rollover. + if (time_difference < 0 || time_difference > (UINT32_MAX >> 1)) + wm_user_time_ms_ = time_ms; + } +} + void X11DesktopHandler::DeactivateWindow(::Window window) { if (!IsActiveWindow(window)) return; diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h index 947040e4393..47a1ff1a7ff 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h +++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h @@ -15,6 +15,7 @@ #include "base/macros.h" #include "ui/aura/env_observer.h" #include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_types.h" #include "ui/views/views_export.h" @@ -36,12 +37,8 @@ class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher, // Gets/sets the X11 server time of the most recent mouse click, touch or // key press on a Chrome window. - int wm_user_time_ms() const { - return wm_user_time_ms_; - } - void set_wm_user_time_ms(unsigned long time_ms) { - wm_user_time_ms_ = time_ms; - } + int wm_user_time_ms() const { return wm_user_time_ms_; } + void set_wm_user_time_ms(Time time_ms); // Sends a request to the window manager to activate |window|. // This method should only be called if the window is already mapped. @@ -95,7 +92,7 @@ class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher, // The X11 server time of the most recent mouse click, touch, or key press // on a Chrome window. - unsigned long wm_user_time_ms_; + Time wm_user_time_ms_; // The active window according to X11 server. ::Window current_window_; diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc index 35403700d7d..c6bcbb3e8e6 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_window_move_client.cc @@ -14,7 +14,6 @@ #include "ui/aura/window_tree_host.h" #include "ui/base/x/x11_util.h" #include "ui/events/event.h" -#include "ui/gfx/screen.h" namespace views { diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc index 46357f60f00..2bb919bb4df 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc @@ -4,11 +4,13 @@ #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" -#include <stddef.h> -#include <X11/extensions/shape.h> #include <X11/Xlib.h> #include <X11/Xregion.h> +#include <X11/extensions/shape.h> +#include <stddef.h> + #include <algorithm> +#include <memory> #include <vector> // Get rid of X11 macros which conflict with gtest. @@ -16,7 +18,6 @@ #undef None #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRegion.h" @@ -62,7 +63,7 @@ class MinimizeWaiter : public X11PropertyChangeWaiter { return true; } - scoped_ptr<ui::X11AtomCache> atom_cache_; + std::unique_ptr<ui::X11AtomCache> atom_cache_; DISALLOW_COPY_AND_ASSIGN(MinimizeWaiter); }; @@ -118,8 +119,8 @@ class X11TopmostWindowFinderTest : public ViewsTestBase { // Creates and shows a Widget with |bounds|. The caller takes ownership of // the returned widget. - scoped_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) { - scoped_ptr<Widget> toplevel(new Widget); + std::unique_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) { + std::unique_ptr<Widget> toplevel(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.native_widget = new DesktopNativeWidgetAura(toplevel.get()); @@ -226,14 +227,14 @@ TEST_F(X11TopmostWindowFinderTest, Basic) { // Avoid positioning test windows at 0x0 because window managers often have a // panel/launcher along one of the screen edges and do not allow windows to // position themselves to overlap the panel/launcher. - scoped_ptr<Widget> widget1( + std::unique_ptr<Widget> widget1( CreateAndShowWidget(gfx::Rect(100, 100, 200, 100))); aura::Window* window1 = widget1->GetNativeWindow(); XID xid1 = window1->GetHost()->GetAcceleratedWidget(); XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200)); - scoped_ptr<Widget> widget3( + std::unique_ptr<Widget> widget3( CreateAndShowWidget(gfx::Rect(100, 190, 200, 110))); aura::Window* window3 = widget3->GetNativeWindow(); XID xid3 = window3->GetHost()->GetAcceleratedWidget(); @@ -277,7 +278,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) { // Test that the minimized state is properly handled. TEST_F(X11TopmostWindowFinderTest, Minimized) { - scoped_ptr<Widget> widget1( + std::unique_ptr<Widget> widget1( CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); aura::Window* window1 = widget1->GetNativeWindow(); XID xid1 = window1->GetHost()->GetAcceleratedWidget(); @@ -316,7 +317,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) { if (!ui::IsShapeExtensionAvailable()) return; - scoped_ptr<Widget> widget1( + std::unique_ptr<Widget> widget1( CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); SkRegion* skregion1 = new SkRegion; @@ -356,7 +357,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) { if (!ui::IsShapeExtensionAvailable()) return; - scoped_ptr<Widget> widget1( + std::unique_ptr<Widget> widget1( CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); SkRegion* skregion1 = new SkRegion; @@ -377,7 +378,7 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) { if (!ui::IsShapeExtensionAvailable()) return; - scoped_ptr<Widget> widget1( + std::unique_ptr<Widget> widget1( CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); SkRegion* skregion1 = new SkRegion; diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc index eca9951d2da..cbf3f35638c 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc @@ -159,7 +159,7 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source, GrabEscKey(); - scoped_ptr<ui::ScopedEventDispatcher> old_dispatcher = + std::unique_ptr<ui::ScopedEventDispatcher> old_dispatcher = std::move(nested_dispatcher_); nested_dispatcher_ = ui::PlatformEventSource::GetInstance()->OverrideDispatcher(this); diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h index 24a909911c1..c1eb5515ef8 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h +++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h @@ -67,7 +67,7 @@ class X11WholeScreenMoveLoop : public X11MoveLoop, // Are we running a nested message loop from RunMoveLoop()? bool in_move_loop_; - scoped_ptr<ui::ScopedEventDispatcher> nested_dispatcher_; + std::unique_ptr<ui::ScopedEventDispatcher> nested_dispatcher_; // Cursor in use prior to the move loop starting. Restored when the move loop // quits. @@ -88,7 +88,7 @@ class X11WholeScreenMoveLoop : public X11MoveLoop, // pressing escape). bool canceled_; - scoped_ptr<ui::MouseEvent> last_motion_in_screen_; + std::unique_ptr<ui::MouseEvent> last_motion_in_screen_; base::WeakPtrFactory<X11WholeScreenMoveLoop> weak_factory_; DISALLOW_COPY_AND_ASSIGN(X11WholeScreenMoveLoop); diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc index c0ead5563fd..b8a4c388be2 100644 --- a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc +++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc @@ -14,10 +14,10 @@ #include "ui/aura/window_delegate.h" #include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -#include "ui/gfx/display.h" -#include "ui/gfx/screen.h" #include "ui/gfx/x/x11_types.h" #include "ui/views/linux_ui/linux_ui.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" @@ -152,7 +152,7 @@ void X11WindowEventFilter::OnClickedMaximizeButton(ui::MouseEvent* event) { return; gfx::Rect display_work_area = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(target).work_area(); + display::Screen::GetScreen()->GetDisplayNearestWindow(target).work_area(); gfx::Rect bounds = widget->GetWindowBoundsInScreen(); if (event->IsMiddleMouseButton()) { bounds.set_y(display_work_area.y()); diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc index 4f24e5caced..cbdf38294d4 100644 --- a/chromium/ui/views/widget/native_widget_aura.cc +++ b/chromium/ui/views/widget/native_widget_aura.cc @@ -5,10 +5,12 @@ #include "ui/views/widget/native_widget_aura.h" #include "base/bind.h" +#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "build/build_config.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/capture_client.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/client/screen_position_client.h" @@ -21,10 +23,11 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/ui_base_types.h" #include "ui/compositor/layer.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" -#include "ui/gfx/screen.h" #include "ui/native_theme/native_theme_aura.h" #include "ui/views/drag_utils.h" #include "ui/views/views_delegate.h" @@ -109,6 +112,8 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { window_->SetTransparent( params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW); window_->Init(params.layer_type); + // Set name after layer init so it propagates to layer. + window_->SetName(params.name); if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_NONE) SetShadowType(window_, wm::SHADOW_TYPE_NONE); else if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP) @@ -137,8 +142,9 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { // If a parent is specified but no bounds are given, // use the origin of the parent's display so that the widget // will be added to the same display as the parent. - gfx::Rect bounds = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(parent).bounds(); + gfx::Rect bounds = display::Screen::GetScreen() + ->GetDisplayNearestWindow(parent) + .bounds(); window_bounds.set_origin(bounds.origin()); } } @@ -283,8 +289,9 @@ void NativeWidgetAura::CenterWindow(const gfx::Size& size) { // When centering window, we take the intersection of the host and // the parent. We assume the root window represents the visible // rect of a single screen. - gfx::Rect work_area = - gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_).work_area(); + gfx::Rect work_area = display::Screen::GetScreen() + ->GetDisplayNearestWindow(window_) + .work_area(); aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(window_->GetRootWindow()); @@ -394,6 +401,10 @@ gfx::Rect NativeWidgetAura::GetRestoredBounds() const { return bounds; } +std::string NativeWidgetAura::GetWorkspace() const { + return std::string(); +} + void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) { if (!window_) return; @@ -403,8 +414,8 @@ void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) { aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root); if (screen_position_client) { - gfx::Display dst_display = - gfx::Screen::GetScreen()->GetDisplayMatching(bounds); + display::Display dst_display = + display::Screen::GetScreen()->GetDisplayMatching(bounds); screen_position_client->SetBounds(window_, bounds, dst_display); return; } @@ -436,7 +447,7 @@ void NativeWidgetAura::StackBelow(gfx::NativeView native_view) { void NativeWidgetAura::SetShape(SkRegion* region) { if (window_) - window_->layer()->SetAlphaShape(make_scoped_ptr(region)); + window_->layer()->SetAlphaShape(base::WrapUnique(region)); else delete region; } @@ -642,7 +653,9 @@ void NativeWidgetAura::ClearNativeFocus() { gfx::Rect NativeWidgetAura::GetWorkAreaBoundsInScreen() const { if (!window_) return gfx::Rect(); - return gfx::Screen::GetScreen()->GetDisplayNearestWindow(window_).work_area(); + return display::Screen::GetScreen() + ->GetDisplayNearestWindow(window_) + .work_area(); } Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop( @@ -737,6 +750,10 @@ void NativeWidgetAura::RepostNativeEvent(gfx::NativeEvent native_event) { OnEvent(native_event); } +std::string NativeWidgetAura::GetName() const { + return window_ ? window_->name() : std::string(); +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetAura, aura::WindowDelegate implementation: @@ -1170,5 +1187,15 @@ gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() { #endif } +// static +gfx::NativeView NativeWidgetPrivate::GetGlobalCapture( + gfx::NativeView native_view) { + aura::client::CaptureClient* capture_client = + aura::client::GetCaptureClient(native_view->GetRootWindow()); + if (!capture_client) + return nullptr; + return capture_client->GetGlobalCaptureWindow(); +} + } // namespace internal } // namespace views diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h index 9e27cca806b..65585834a64 100644 --- a/chromium/ui/views/widget/native_widget_aura.h +++ b/chromium/ui/views/widget/native_widget_aura.h @@ -5,6 +5,8 @@ #ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_ #define UI_VIEWS_WIDGET_NATIVE_WIDGET_AURA_H_ +#include <string> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "ui/aura/client/focus_change_observer.h" @@ -81,6 +83,7 @@ class VIEWS_EXPORT NativeWidgetAura gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; void SetBounds(const gfx::Rect& bounds) override; void SetSize(const gfx::Size& size) override; void StackAbove(gfx::NativeView native_view) override; @@ -133,6 +136,7 @@ class VIEWS_EXPORT NativeWidgetAura bool IsTranslucentWindowOpacitySupported() const override; void OnSizeConstraintsChanged() override; void RepostNativeEvent(gfx::NativeEvent native_event) override; + std::string GetName() const override; // Overridden from aura::WindowDelegate: gfx::Size GetMinimumSize() const override; @@ -213,13 +217,13 @@ class VIEWS_EXPORT NativeWidgetAura // The saved window state for exiting full screen state. ui::WindowShowState saved_window_state_; - scoped_ptr<TooltipManagerAura> tooltip_manager_; + std::unique_ptr<TooltipManagerAura> tooltip_manager_; // Reorders child windows of |window_| associated with a view based on the // order of the associated views in the widget's view hierarchy. - scoped_ptr<WindowReorderer> window_reorderer_; + std::unique_ptr<WindowReorderer> window_reorderer_; - scoped_ptr<DropHelper> drop_helper_; + std::unique_ptr<DropHelper> drop_helper_; int last_drop_operation_; // The following factory is used for calls to close the NativeWidgetAura diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc index 0a626ae45a1..3d2f1c3b97e 100644 --- a/chromium/ui/views/widget/native_widget_aura_unittest.cc +++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc @@ -4,9 +4,10 @@ #include "ui/views/widget/native_widget_aura.h" +#include <memory> + #include "base/command_line.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/aura_constants.h" @@ -14,10 +15,10 @@ #include "ui/aura/layout_manager.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/window.h" +#include "ui/aura/window_observer.h" #include "ui/aura/window_tree_host.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" -#include "ui/gfx/screen.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/test/widget_test.h" #include "ui/views/widget/root_view.h" @@ -78,7 +79,7 @@ class NativeWidgetAuraTest : public aura::test::AuraTestBase { } private: - scoped_ptr<wm::FocusController> focus_controller_; + std::unique_ptr<wm::FocusController> focus_controller_; TestFocusRules* test_focus_rules_; DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest); @@ -87,10 +88,10 @@ class NativeWidgetAuraTest : public aura::test::AuraTestBase { TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) { // Make a parent window larger than the host represented by // WindowEventDispatcher. - scoped_ptr<aura::Window> parent(new aura::Window(NULL)); + std::unique_ptr<aura::Window> parent(new aura::Window(nullptr)); parent->Init(ui::LAYER_NOT_DRAWN); parent->SetBounds(gfx::Rect(0, 0, 1024, 800)); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); NativeWidgetAura* window = Init(parent.get(), widget.get()); window->CenterWindow(gfx::Size(100, 100)); @@ -104,10 +105,10 @@ TEST_F(NativeWidgetAuraTest, CenterWindowLargeParent) { TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) { // Make a parent window smaller than the host represented by // WindowEventDispatcher. - scoped_ptr<aura::Window> parent(new aura::Window(NULL)); + std::unique_ptr<aura::Window> parent(new aura::Window(nullptr)); parent->Init(ui::LAYER_NOT_DRAWN); parent->SetBounds(gfx::Rect(0, 0, 480, 320)); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); NativeWidgetAura* window = Init(parent.get(), widget.get()); window->CenterWindow(gfx::Size(100, 100)); @@ -122,10 +123,10 @@ TEST_F(NativeWidgetAuraTest, CenterWindowSmallParent) { TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) { // Make a parent window smaller than the host represented by // WindowEventDispatcher and offset it slightly from the origin. - scoped_ptr<aura::Window> parent(new aura::Window(NULL)); + std::unique_ptr<aura::Window> parent(new aura::Window(nullptr)); parent->Init(ui::LAYER_NOT_DRAWN); parent->SetBounds(gfx::Rect(20, 40, 480, 320)); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); NativeWidgetAura* window = Init(parent.get(), widget.get()); window->CenterWindow(gfx::Size(500, 600)); @@ -137,11 +138,11 @@ TEST_F(NativeWidgetAuraTest, CenterWindowSmallParentNotAtOrigin) { TEST_F(NativeWidgetAuraTest, CreateMinimized) { Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = NULL; + params.parent = nullptr; params.context = root_window(); params.show_state = ui::SHOW_STATE_MINIMIZED; params.bounds.SetRect(0, 0, 1024, 800); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); widget->Init(params); widget->Show(); @@ -149,6 +150,72 @@ TEST_F(NativeWidgetAuraTest, CreateMinimized) { widget->CloseNow(); } +// A WindowObserver that counts kShowStateKey property changes. +class TestWindowObserver : public aura::WindowObserver { + public: + explicit TestWindowObserver(gfx::NativeWindow window) : window_(window) { + window_->AddObserver(this); + } + ~TestWindowObserver() override { + window_->RemoveObserver(this); + } + + // aura::WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override { + if (key != aura::client::kShowStateKey) + return; + count_++; + state_ = window_->GetProperty(aura::client::kShowStateKey); + } + + int count() const { return count_; } + ui::WindowShowState state() const { return state_; } + void Reset() { count_ = 0; } + + private: + gfx::NativeWindow window_; + int count_ = 0; + ui::WindowShowState state_ = ui::WindowShowState::SHOW_STATE_DEFAULT; + + DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); +}; + +// Tests that window transitions from normal to minimized and back do not +// involve extra show state transitions. +TEST_F(NativeWidgetAuraTest, ToggleState) { + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.parent = nullptr; + params.context = root_window(); + params.show_state = ui::SHOW_STATE_NORMAL; + params.bounds.SetRect(0, 0, 1024, 800); + Widget widget; + widget.Init(params); + std::unique_ptr<TestWindowObserver> observer( + new TestWindowObserver(widget.GetNativeWindow())); + widget.Show(); + EXPECT_FALSE(widget.IsMinimized()); + EXPECT_EQ(0, observer->count()); + EXPECT_EQ(ui::WindowShowState::SHOW_STATE_DEFAULT, observer->state()); + + widget.Minimize(); + EXPECT_TRUE(widget.IsMinimized()); + EXPECT_EQ(1, observer->count()); + EXPECT_EQ(ui::WindowShowState::SHOW_STATE_MINIMIZED, observer->state()); + observer->Reset(); + + widget.Show(); + widget.Restore(); + EXPECT_EQ(1, observer->count()); + EXPECT_EQ(ui::WindowShowState::SHOW_STATE_NORMAL, observer->state()); + + observer.reset(); + EXPECT_FALSE(widget.IsMinimized()); + widget.CloseNow(); +} + class TestLayoutManagerBase : public aura::LayoutManager { public: TestLayoutManagerBase() {} @@ -219,10 +286,10 @@ class TestWidget : public views::Widget { TEST_F(NativeWidgetAuraTest, ShowMaximizedDoesntBounceAround) { root_window()->SetBounds(gfx::Rect(0, 0, 640, 480)); root_window()->SetLayoutManager(new MaximizeLayoutManager); - scoped_ptr<TestWidget> widget(new TestWidget()); + std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.parent = NULL; + params.parent = nullptr; params.context = root_window(); params.show_state = ui::SHOW_STATE_MAXIMIZED; params.bounds = gfx::Rect(10, 10, 100, 200); @@ -276,11 +343,11 @@ TEST_F(NativeWidgetAuraTest, TestPropertiesWhenAddedToLayout) { root_window()->SetBounds(gfx::Rect(0, 0, 640, 480)); PropertyTestLayoutManager* layout_manager = new PropertyTestLayoutManager(); root_window()->SetLayoutManager(layout_manager); - scoped_ptr<TestWidget> widget(new TestWidget()); + std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.delegate = new PropertyTestWidgetDelegate(widget.get()); - params.parent = NULL; + params.parent = nullptr; params.context = root_window(); widget->Init(params); EXPECT_TRUE(layout_manager->added()); @@ -293,7 +360,7 @@ TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) { params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.context = root_window(); params.bounds.SetRect(10, 20, 300, 400); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); widget->Init(params); // For Aura, client area bounds match window bounds. @@ -349,7 +416,7 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { child->set_consume_gesture_event(false); view->SetLayoutManager(new FillLayout); view->AddChildView(child); - scoped_ptr<TestWidget> widget(new TestWidget()); + std::unique_ptr<TestWidget> widget(new TestWidget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.context = root_window(); @@ -390,7 +457,7 @@ TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { // Create two widgets: |parent| and |child|. |child| is a child of |parent|. views::View* parent_root = new views::View; - scoped_ptr<Widget> parent(new Widget()); + std::unique_ptr<Widget> parent(new Widget()); Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); parent_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -400,7 +467,7 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { parent->SetBounds(gfx::Rect(0, 0, 400, 400)); parent->Show(); - scoped_ptr<Widget> child(new Widget()); + std::unique_ptr<Widget> child(new Widget()); Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); child_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; child_params.parent = parent->GetNativeWindow(); @@ -438,7 +505,7 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { gfx::Point(70, 70))); delete view_with_layer; - view_with_layer = NULL; + view_with_layer = nullptr; EXPECT_EQ(child->GetNativeWindow(), parent->GetNativeWindow()->GetEventHandlerForPoint( @@ -452,7 +519,7 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) { // Verifies that widget->FlashFrame() sets aura::client::kDrawAttentionKey, // and activating the window clears it. TEST_F(NativeWidgetAuraTest, FlashFrame) { - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); params.context = root_window(); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; @@ -470,10 +537,10 @@ TEST_F(NativeWidgetAuraTest, FlashFrame) { } TEST_F(NativeWidgetAuraTest, NoCrashOnThemeAfterClose) { - scoped_ptr<aura::Window> parent(new aura::Window(NULL)); + std::unique_ptr<aura::Window> parent(new aura::Window(nullptr)); parent->Init(ui::LAYER_NOT_DRAWN); parent->SetBounds(gfx::Rect(0, 0, 480, 320)); - scoped_ptr<Widget> widget(new Widget()); + std::unique_ptr<Widget> widget(new Widget()); Init(parent.get(), widget.get()); widget->Show(); widget->Close(); diff --git a/chromium/ui/views/widget/native_widget_delegate.h b/chromium/ui/views/widget/native_widget_delegate.h index 033db2bf107..e6c3b84ea04 100644 --- a/chromium/ui/views/widget/native_widget_delegate.h +++ b/chromium/ui/views/widget/native_widget_delegate.h @@ -97,6 +97,9 @@ class VIEWS_EXPORT NativeWidgetDelegate { // e.g. maximize. virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) = 0; + // Called when NativeWidget changed workspaces. + virtual void OnNativeWidgetWorkspaceChanged() = 0; + // Called when the NativeWidget changes its window state. // This may happen at the same time as OnNativeWidgetSizeChanged, e.g. // maximize. diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h index 1b7deb2c801..93402a18470 100644 --- a/chromium/ui/views/widget/native_widget_mac.h +++ b/chromium/ui/views/widget/native_widget_mac.h @@ -80,6 +80,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { gfx::Rect GetWindowBoundsInScreen() const override; gfx::Rect GetClientAreaBoundsInScreen() const override; gfx::Rect GetRestoredBounds() const override; + std::string GetWorkspace() const override; void SetBounds(const gfx::Rect& bounds) override; void SetSize(const gfx::Size& size) override; void StackAbove(gfx::NativeView native_view) override; @@ -132,6 +133,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { bool IsTranslucentWindowOpacitySupported() const override; void OnSizeConstraintsChanged() override; void RepostNativeEvent(gfx::NativeEvent native_event) override; + std::string GetName() const override; protected: // Creates the NSWindow that will be passed to the BridgedNativeWidget. @@ -146,10 +148,13 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate { friend class test::HitTestNativeWidgetMac; internal::NativeWidgetDelegate* delegate_; - scoped_ptr<BridgedNativeWidget> bridge_; + std::unique_ptr<BridgedNativeWidget> bridge_; Widget::InitParams::Ownership ownership_; + // Internal name. + std::string name_; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetMac); }; diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm index 126623ff0e7..fb7fef45007 100644 --- a/chromium/ui/views/widget/native_widget_mac.mm +++ b/chromium/ui/views/widget/native_widget_mac.mm @@ -119,6 +119,7 @@ int NativeWidgetMac::SheetPositionY() { void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) { ownership_ = params.ownership; + name_ = params.name; base::scoped_nsobject<NSWindow> window([CreateNSWindow(params) retain]); [window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject. bridge_->Init(window, params); @@ -305,6 +306,10 @@ gfx::Rect NativeWidgetMac::GetRestoredBounds() const { return bridge_ ? bridge_->GetRestoredBounds() : gfx::Rect(); } +std::string NativeWidgetMac::GetWorkspace() const { + return std::string(); +} + void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) { if (bridge_) bridge_->SetBounds(bounds); @@ -371,7 +376,7 @@ void NativeWidgetMac::CloseNow() { // Notify observers while |bridged_| is still valid. delegate_->OnNativeWidgetDestroying(); // Reset |bridge_| to NULL before destroying it. - scoped_ptr<BridgedNativeWidget> bridge(std::move(bridge_)); + std::unique_ptr<BridgedNativeWidget> bridge(std::move(bridge_)); } void NativeWidgetMac::Show() { @@ -590,6 +595,10 @@ void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) { NOTIMPLEMENTED(); } +std::string NativeWidgetMac::GetName() const { + return name_; +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetMac, protected: @@ -710,6 +719,13 @@ gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() { return gfx::FontList(); } +// static +gfx::NativeView NativeWidgetPrivate::GetGlobalCapture( + gfx::NativeView native_view) { + NOTIMPLEMENTED(); + return nullptr; +} + } // namespace internal } // namespace views diff --git a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm index 528f67d42a7..c29fe0464ff 100644 --- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm +++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm @@ -11,6 +11,7 @@ #include "base/macros.h" #include "ui/base/test/ui_controls.h" #import "ui/base/test/windowed_nsnotification_observer.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/test/test_widget_observer.h" #include "ui/views/test/widget_test.h" @@ -38,7 +39,7 @@ class NativeWidgetMacInteractiveUITest } protected: - scoped_ptr<Observer> observer_; + std::unique_ptr<Observer> observer_; int activationCount_; int deactivationCount_; @@ -159,6 +160,16 @@ NSData* ViewAsTIFF(NSView* view) { return [bitmap TIFFRepresentation]; } +class TestBubbleView : public BubbleDialogDelegateView { + public: + explicit TestBubbleView(Widget* parent) { + SetAnchorView(parent->GetContentsView()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestBubbleView); +}; + } // namespace // Test that parent windows keep their traffic lights enabled when showing @@ -176,15 +187,11 @@ TEST_F(NativeWidgetMacInteractiveUITest, ParentWindowTrafficLights) { NSData* active_button_image = ViewAsTIFF(button); EXPECT_TRUE(active_button_image); - // Create an activatable frameless child. Frameless so that it doesn't have - // traffic lights of its own, and activatable so that it can take key status. - Widget* child_widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.native_widget = new NativeWidgetMac(child_widget); - params.bounds = gfx::Rect(130, 130, 100, 100); - params.parent = parent_widget->GetNativeView(); - child_widget->Init(params); - ShowKeyWindow(child_widget); + // Pop open a bubble on the parent Widget. When the visibility of Bubbles with + // an anchor View changes, BubbleDialogDelegateView::HandleVisibilityChanged() + // updates Widget::SetAlwaysRenderAsActive(..) accordingly. + ShowKeyWindow(BubbleDialogDelegateView::CreateBubble( + new TestBubbleView(parent_widget))); // Ensure the button instance is still valid. EXPECT_EQ(button, [parent standardWindowButton:NSWindowCloseButton]); @@ -199,6 +206,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, ParentWindowTrafficLights) { EXPECT_TRUE([active_button_image isEqualToData:button_image_with_child]); // Verify that activating some other random window does change the button. + // When the bubble loses activation, it will dismiss itself and update + // Widget::SetAlwaysRenderAsActive(). Widget* other_widget = CreateTopLevelPlatformWidget(); other_widget->SetBounds(gfx::Rect(200, 200, 100, 100)); ShowKeyWindow(other_widget); diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm index ba095dfbeeb..ac0740d53ed 100644 --- a/chromium/ui/views/widget/native_widget_mac_unittest.mm +++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm @@ -8,6 +8,7 @@ #import "base/mac/foundation_util.h" #import "base/mac/scoped_nsobject.h" +#import "base/mac/scoped_nsautorelease_pool.h" #import "base/mac/scoped_objc_class_swizzler.h" #include "base/macros.h" #include "base/run_loop.h" @@ -19,10 +20,12 @@ #include "third_party/skia/include/core/SkCanvas.h" #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #import "ui/base/cocoa/window_size_constants.h" +#import "ui/base/test/scoped_fake_full_keyboard_access.h" #import "ui/events/test/cocoa_test_event_utils.h" #include "ui/events/test/event_generator.h" #import "ui/gfx/mac/coordinate_conversion.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" +#import "ui/views/cocoa/bridged_content_view.h" #import "ui/views/cocoa/bridged_native_widget.h" #import "ui/views/cocoa/native_widget_mac_nswindow.h" #include "ui/views/controls/button/label_button.h" @@ -53,8 +56,10 @@ @interface NativeWidgetMacTestWindow : NativeWidgetMacNSWindow { @private int invalidateShadowCount_; + bool* deallocFlag_; } @property(readonly, nonatomic) int invalidateShadowCount; +@property(assign, nonatomic) bool* deallocFlag; @end // Used to mock BridgedContentView so that calls to drawRect: can be @@ -75,6 +80,10 @@ @interface FocusableTestNSView : NSView @end +@interface TestNativeParentWindow : NSWindow +@property(assign, nonatomic) bool* deallocFlag; +@end + namespace views { namespace test { @@ -89,7 +98,7 @@ class BridgedNativeWidgetTestApi { void SimulateFrameSwap(const gfx::Size& size) { const float kScaleFactor = 1.0f; bridge_->compositor_widget_->GotFrame( - 0, base::ScopedCFTypeRef<IOSurfaceRef>(), size, kScaleFactor); + 0, false, 0, base::ScopedCFTypeRef<IOSurfaceRef>(), size, kScaleFactor); bridge_->AcceleratedWidgetSwapCompleted(); } @@ -136,8 +145,8 @@ class NativeWidgetMacTest : public WidgetTest { NSRect ParentRect() const { return NSMakeRect(100, 100, 300, 200); } // Make a native NSWindow with the given |style_mask| to use as a parent. - NSWindow* MakeNativeParentWithStyle(int style_mask) { - native_parent_.reset([[NSWindow alloc] + TestNativeParentWindow* MakeNativeParentWithStyle(int style_mask) { + native_parent_.reset([[TestNativeParentWindow alloc] initWithContentRect:ParentRect() styleMask:style_mask backing:NSBackingStoreBuffered @@ -148,7 +157,7 @@ class NativeWidgetMacTest : public WidgetTest { } // Make a borderless, native NSWindow to use as a parent. - NSWindow* MakeNativeParent() { + TestNativeParentWindow* MakeNativeParent() { return MakeNativeParentWithStyle(NSBorderlessWindowMask); } @@ -165,9 +174,10 @@ class NativeWidgetMacTest : public WidgetTest { return widget; } - private: - base::scoped_nsobject<NSWindow> native_parent_; + protected: + base::scoped_nsobject<TestNativeParentWindow> native_parent_; + private: DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacTest); }; @@ -231,11 +241,22 @@ class NativeHostHolder { private: base::scoped_nsobject<NSView> view_; - scoped_ptr<NativeViewHost> host_; + std::unique_ptr<NativeViewHost> host_; DISALLOW_COPY_AND_ASSIGN(NativeHostHolder); }; +// This class gives public access to the protected ctor of +// BubbleDialogDelegateView. +class SimpleBubbleView : public BubbleDialogDelegateView { + public: + SimpleBubbleView() {} + ~SimpleBubbleView() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(SimpleBubbleView); +}; + // Test visibility states triggered externally. TEST_F(NativeWidgetMacTest, HideAndShowExternally) { Widget* widget = CreateTopLevelPlatformWidget(); @@ -633,6 +654,37 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) { EXPECT_EQ(0u, [[native_parent childWindows] count]); } +// Tests closing the last remaining NSWindow reference via -windowWillClose:. +// This is a regression test for http://crbug.com/616701. +TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) { + bool child_dealloced = false; + bool native_parent_dealloced = false; + { + base::mac::ScopedNSAutoreleasePool pool; + TestNativeParentWindow* native_parent = MakeNativeParent(); + [native_parent setDeallocFlag:&native_parent_dealloced]; + + NativeWidgetMacTestWindow* window; + Widget::InitParams init_params = + CreateParams(Widget::InitParams::TYPE_POPUP); + init_params.parent = [native_parent_ contentView]; + init_params.bounds = gfx::Rect(0, 0, 100, 200); + CreateWidgetWithTestWindow(init_params, &window); + [window setDeallocFlag:&child_dealloced]; + } + { + // On 10.11, closing a weak reference on the parent window works, but older + // versions of AppKit get upset if things are released inside -[NSWindow + // close]. This test tries to establish a situation where the last reference + // to the child window is released inside WidgetOwnerNSWindowAdapter:: + // OnWindowWillClose(). + base::mac::ScopedNSAutoreleasePool pool; + [native_parent_.autorelease() close]; + EXPECT_TRUE(child_dealloced); + } + EXPECT_TRUE(native_parent_dealloced); +} + // Use Native APIs to query the tooltip text that would be shown once the // tooltip delay had elapsed. base::string16 TooltipTextForWidget(Widget* widget) { @@ -1041,7 +1093,7 @@ TEST_F(NativeWidgetMacTest, NoParentDelegateDuringTeardown) { // Test the WIDGET_OWNS_NATIVE_WIDGET flow. { - scoped_ptr<Widget> parent(new Widget); + std::unique_ptr<Widget> parent(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(100, 100, 300, 200); @@ -1075,15 +1127,15 @@ TEST_F(NativeWidgetMacTest, NativeProperties) { EXPECT_FALSE([dialog_widget->GetNativeWindow() canBecomeMainWindow]); // Create a bubble widget with a parent: also shouldn't get main. - BubbleDelegateView* bubble_view = new BubbleDelegateView(); + BubbleDialogDelegateView* bubble_view = new SimpleBubbleView(); bubble_view->set_parent_window(regular_widget->GetNativeView()); - Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_view); + Widget* bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble_view); EXPECT_TRUE([bubble_widget->GetNativeWindow() canBecomeKeyWindow]); EXPECT_FALSE([bubble_widget->GetNativeWindow() canBecomeMainWindow]); // But a bubble without a parent should still be able to become main. Widget* toplevel_bubble_widget = - BubbleDelegateView::CreateBubble(new BubbleDelegateView()); + BubbleDialogDelegateView::CreateBubble(new SimpleBubbleView()); EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow() canBecomeKeyWindow]); EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow() canBecomeMainWindow]); @@ -1340,7 +1392,7 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Borderless) { // Ensure traversing NSView focus correctly updates the views::FocusManager. TEST_F(NativeWidgetMacTest, ChangeFocusOnChangeFirstResponder) { Widget* widget = CreateTopLevelPlatformWidget(); - widget->GetRootView()->SetFocusable(true); + widget->GetRootView()->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget->Show(); base::scoped_nsobject<NSView> child_view([[FocusableTestNSView alloc] @@ -1362,6 +1414,79 @@ TEST_F(NativeWidgetMacTest, ChangeFocusOnChangeFirstResponder) { widget->CloseNow(); } +// Test class for Full Keyboard Access related tests. +class NativeWidgetMacFullKeyboardAccessTest : public NativeWidgetMacTest { + public: + NativeWidgetMacFullKeyboardAccessTest() {} + + protected: + // testing::Test: + void SetUp() override { + NativeWidgetMacTest::SetUp(); + + widget_ = CreateTopLevelPlatformWidget(); + bridge_ = + NativeWidgetMac::GetBridgeForNativeWindow(widget_->GetNativeWindow()); + fake_full_keyboard_access_ = + ui::test::ScopedFakeFullKeyboardAccess::GetInstance(); + DCHECK(fake_full_keyboard_access_); + widget_->Show(); + } + + void TearDown() override { + widget_->CloseNow(); + NativeWidgetMacTest::TearDown(); + } + + Widget* widget_ = nullptr; + BridgedNativeWidget* bridge_ = nullptr; + ui::test::ScopedFakeFullKeyboardAccess* fake_full_keyboard_access_ = nullptr; +}; + +// Test that updateFullKeyboardAccess method on BridgedContentView correctly +// sets the keyboard accessibility mode on the associated focus manager. +TEST_F(NativeWidgetMacFullKeyboardAccessTest, FullKeyboardToggle) { + EXPECT_TRUE(widget_->GetFocusManager()->keyboard_accessible()); + fake_full_keyboard_access_->set_full_keyboard_access_state(false); + [bridge_->ns_view() updateFullKeyboardAccess]; + EXPECT_FALSE(widget_->GetFocusManager()->keyboard_accessible()); + fake_full_keyboard_access_->set_full_keyboard_access_state(true); + [bridge_->ns_view() updateFullKeyboardAccess]; + EXPECT_TRUE(widget_->GetFocusManager()->keyboard_accessible()); +} + +// Test that a Widget's associated FocusManager is initialized with the correct +// keyboard accessibility value. +TEST_F(NativeWidgetMacFullKeyboardAccessTest, Initialization) { + EXPECT_TRUE(widget_->GetFocusManager()->keyboard_accessible()); + + fake_full_keyboard_access_->set_full_keyboard_access_state(false); + Widget* widget2 = CreateTopLevelPlatformWidget(); + EXPECT_FALSE(widget2->GetFocusManager()->keyboard_accessible()); + widget2->CloseNow(); +} + +// Test that the correct keyboard accessibility mode is set when the window +// becomes active. +TEST_F(NativeWidgetMacFullKeyboardAccessTest, Activation) { + EXPECT_TRUE(widget_->GetFocusManager()->keyboard_accessible()); + + widget_->Hide(); + fake_full_keyboard_access_->set_full_keyboard_access_state(false); + // [bridge_->ns_view() updateFullKeyboardAccess] is not explicitly called + // since we may not receive full keyboard access toggle notifications when our + // application is inactive. + + widget_->Show(); + EXPECT_FALSE(widget_->GetFocusManager()->keyboard_accessible()); + + widget_->Hide(); + fake_full_keyboard_access_->set_full_keyboard_access_state(true); + + widget_->Show(); + EXPECT_TRUE(widget_->GetFocusManager()->keyboard_accessible()); +} + class NativeWidgetMacViewsOrderTest : public WidgetTest { public: NativeWidgetMacViewsOrderTest() {} @@ -1381,7 +1506,7 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest { const int kNativeViewCount = 3; for (int i = 0; i < kNativeViewCount; ++i) { - scoped_ptr<NativeHostHolder> holder(new NativeHostHolder()); + std::unique_ptr<NativeHostHolder> holder(new NativeHostHolder()); native_host_parent_->AddChildView(holder->host()); holder->AttachNativeView(); hosts_.push_back(std::move(holder)); @@ -1402,7 +1527,7 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest { Widget* widget_ = nullptr; View* native_host_parent_ = nullptr; NSView* compositor_view_ = nil; - std::vector<scoped_ptr<NativeHostHolder>> hosts_; + std::vector<std::unique_ptr<NativeHostHolder>> hosts_; private: DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacViewsOrderTest); @@ -1481,6 +1606,15 @@ TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) { @implementation NativeWidgetMacTestWindow @synthesize invalidateShadowCount = invalidateShadowCount_; +@synthesize deallocFlag = deallocFlag_; + +- (void)dealloc { + if (deallocFlag_) { + DCHECK(!*deallocFlag_); + *deallocFlag_ = true; + } + [super dealloc]; +} - (void)invalidateShadow { ++invalidateShadowCount_; @@ -1506,3 +1640,19 @@ TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) { return YES; } @end + +@implementation TestNativeParentWindow { + bool* deallocFlag_; +} + +@synthesize deallocFlag = deallocFlag_; + +- (void)dealloc { + if (deallocFlag_) { + DCHECK(!*deallocFlag_); + *deallocFlag_ = true; + } + [super dealloc]; +} + +@end diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h index 777eaa226a4..d52aee63249 100644 --- a/chromium/ui/views/widget/native_widget_private.h +++ b/chromium/ui/views/widget/native_widget_private.h @@ -5,6 +5,8 @@ #ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_ #define UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_ +#include <string> + #include "base/strings/string16.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/native_widget_types.h" @@ -71,6 +73,10 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { static gfx::FontList GetWindowTitleFontList(); + // Returns the NativeView with capture, otherwise NULL if there is no current + // capture set, or if |native_view| has no root. + static gfx::NativeView GetGlobalCapture(gfx::NativeView native_view); + // Initializes the NativeWidget. virtual void InitNativeWidget(const Widget::InitParams& params) = 0; @@ -165,6 +171,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { virtual gfx::Rect GetWindowBoundsInScreen() const = 0; virtual gfx::Rect GetClientAreaBoundsInScreen() const = 0; virtual gfx::Rect GetRestoredBounds() const = 0; + virtual std::string GetWorkspace() const = 0; virtual void SetBounds(const gfx::Rect& bounds) = 0; virtual void SetSize(const gfx::Size& size) = 0; virtual void StackAbove(gfx::NativeView native_view) = 0; @@ -223,6 +230,9 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget { // Repost an unhandled event to the native widget for default OS processing. virtual void RepostNativeEvent(gfx::NativeEvent native_event) = 0; + // Returns an internal name that matches the name of the associated Widget. + virtual std::string GetName() const = 0; + // Overridden from NativeWidget: internal::NativeWidgetPrivate* AsNativeWidgetPrivate() override; }; diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc index ff1294ae9f7..cbfb8c4a95d 100644 --- a/chromium/ui/views/widget/root_view.cc +++ b/chromium/ui/views/widget/root_view.cc @@ -171,7 +171,8 @@ RootView::RootView(Widget* widget) old_dispatch_target_(NULL) { AddPreTargetHandler(pre_dispatch_handler_.get()); AddPostTargetHandler(post_dispatch_handler_.get()); - SetEventTargeter(scoped_ptr<ViewTargeter>(new RootViewTargeter(this, this))); + SetEventTargeter( + std::unique_ptr<ViewTargeter>(new RootViewTargeter(this, this))); } RootView::~RootView() { diff --git a/chromium/ui/views/widget/root_view.h b/chromium/ui/views/widget/root_view.h index 58c647fccef..dea38d2be73 100644 --- a/chromium/ui/views/widget/root_view.h +++ b/chromium/ui/views/widget/root_view.h @@ -207,8 +207,8 @@ class VIEWS_EXPORT RootView : public View, // its place. bool gesture_handler_set_before_processing_; - scoped_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_; - scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_; + std::unique_ptr<internal::PreEventDispatchHandler> pre_dispatch_handler_; + std::unique_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_; // Focus --------------------------------------------------------------------- diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc index 03f672d302e..26a9b3d9495 100644 --- a/chromium/ui/views/widget/root_view_unittest.cc +++ b/chromium/ui/views/widget/root_view_unittest.cc @@ -5,6 +5,7 @@ #include "ui/views/widget/root_view.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "ui/events/event_utils.h" #include "ui/views/context_menu_controller.h" #include "ui/views/test/views_test_base.h" @@ -53,13 +54,13 @@ TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) { content->AddChildView(child); // Give focus to |child| so that it will be the target of the key event. - child->SetFocusable(true); + child->SetFocusBehavior(View::FocusBehavior::ALWAYS); child->RequestFocus(); internal::RootView* root_view = static_cast<internal::RootView*>(widget.GetRootView()); ViewTargeter* view_targeter = new ViewTargeter(root_view); - root_view->SetEventTargeter(make_scoped_ptr(view_targeter)); + root_view->SetEventTargeter(base::WrapUnique(view_targeter)); ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, ui::EF_NONE); ui::EventDispatchDetails details = root_view->OnEventFromSource(&key_event); @@ -120,7 +121,7 @@ TEST_F(RootViewTest, ContextMenuFromKeyEvent) { View* focused_view = new View; focused_view->set_context_menu_controller(&controller); widget.SetContentsView(focused_view); - focused_view->SetFocusable(true); + focused_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); focused_view->RequestFocus(); // No context menu should be shown for a keypress of 'A'. diff --git a/chromium/ui/views/widget/tooltip_manager.h b/chromium/ui/views/widget/tooltip_manager.h index e8074047340..4c27c361cee 100644 --- a/chromium/ui/views/widget/tooltip_manager.h +++ b/chromium/ui/views/widget/tooltip_manager.h @@ -11,7 +11,6 @@ #include "ui/views/views_export.h" namespace gfx { -class Display; class FontList; class Point; } // namespace gfx diff --git a/chromium/ui/views/widget/tooltip_manager_aura.cc b/chromium/ui/views/widget/tooltip_manager_aura.cc index c4bf40ea856..90b6e063933 100644 --- a/chromium/ui/views/widget/tooltip_manager_aura.cc +++ b/chromium/ui/views/widget/tooltip_manager_aura.cc @@ -9,8 +9,8 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/display/screen.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/screen.h" #include "ui/views/widget/widget.h" #include "ui/wm/public/tooltip_client.h" @@ -49,7 +49,7 @@ void TooltipManagerAura::UpdateTooltipManagerForCapture(Widget* source) { if (!screen_position_client) return; screen_position_client->ConvertPointToScreen(root_window, &screen_loc); - gfx::Screen* screen = gfx::Screen::GetScreen(); + display::Screen* screen = display::Screen::GetScreen(); aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc); if (!target) return; diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc index ffafd0d2bbb..a86fe4859ee 100644 --- a/chromium/ui/views/widget/widget.cc +++ b/chromium/ui/views/widget/widget.cc @@ -18,10 +18,10 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" +#include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/gfx/image/image_skia.h" -#include "ui/gfx/screen.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/views/event_monitor.h" #include "ui/views/focus/focus_manager.h" @@ -134,8 +134,7 @@ Widget::InitParams::InitParams(Type type) layer_type(ui::LAYER_TEXTURED), context(nullptr), force_show_in_taskbar(false), - force_software_compositing(false) { -} + force_software_compositing(false) {} Widget::InitParams::InitParams(const InitParams& other) = default; @@ -290,6 +289,12 @@ void Widget::Init(const InitParams& in_params) { TRACE_EVENT0("views", "Widget::Init"); InitParams params = in_params; + // If an internal name was not provided the class name of the contents view + // is a reasonable default. + if (params.name.empty() && params.delegate && + params.delegate->GetContentsView()) + params.name = params.delegate->GetContentsView()->GetClassName(); + params.child |= (params.type == InitParams::TYPE_CONTROL); is_top_level_ = !params.child; @@ -347,10 +352,12 @@ void Widget::Init(const InitParams& in_params) { UpdateWindowTitle(); non_client_view_->ResetWindowControls(); SetInitialBounds(params.bounds); - if (params.show_state == ui::SHOW_STATE_MAXIMIZED) + if (params.show_state == ui::SHOW_STATE_MAXIMIZED) { Maximize(); - else if (params.show_state == ui::SHOW_STATE_MINIMIZED) + } else if (params.show_state == ui::SHOW_STATE_MINIMIZED) { Minimize(); + saved_show_state_ = ui::SHOW_STATE_MINIMIZED; + } } else if (params.delegate) { SetContentsView(params.delegate->GetContentsView()); SetInitialBoundsForFramelessWindow(params.bounds); @@ -481,6 +488,10 @@ gfx::Rect Widget::GetRestoredBounds() const { return native_widget_->GetRestoredBounds(); } +std::string Widget::GetWorkspace() const { + return native_widget_->GetWorkspace(); +} + void Widget::SetBounds(const gfx::Rect& bounds) { native_widget_->SetBounds(bounds); } @@ -494,7 +505,7 @@ void Widget::CenterWindow(const gfx::Size& size) { } void Widget::SetBoundsConstrained(const gfx::Rect& bounds) { - gfx::Rect work_area = gfx::Screen::GetScreen() + gfx::Rect work_area = display::Screen::GetScreen() ->GetDisplayNearestPoint(bounds.origin()) .work_area(); if (work_area.IsEmpty()) { @@ -600,10 +611,8 @@ void Widget::Show() { !IsFullscreen()) { native_widget_->ShowMaximizedWithBounds(initial_restored_bounds_); } else { - ui::WindowShowState show_state = - IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : - IsMinimized() ? ui::SHOW_STATE_MINIMIZED : saved_show_state_; - native_widget_->ShowWithWindowState(show_state); + native_widget_->ShowWithWindowState( + IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_); } // |saved_show_state_| only applies the first time the window is shown. // If we don't reset the value the window may be shown maximized every time @@ -987,6 +996,10 @@ void Widget::OnSizeConstraintsChanged() { void Widget::OnOwnerClosing() {} +std::string Widget::GetName() const { + return native_widget_->GetName(); +} + //////////////////////////////////////////////////////////////////////////////// // Widget, NativeWidgetDelegate implementation: @@ -1100,6 +1113,8 @@ void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) { GetWindowBoundsInScreen())); } +void Widget::OnNativeWidgetWorkspaceChanged() {} + void Widget::OnNativeWidgetWindowShowStateChanged() { SaveWindowPlacementIfInitialized(); } @@ -1156,19 +1171,23 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) { // use an observer to make sure we are still alive. WidgetDeletionObserver widget_deletion_observer(this); + gfx::NativeView current_capture = + internal::NativeWidgetPrivate::GetGlobalCapture( + native_widget_->GetNativeView()); // Make sure we're still visible before we attempt capture as the mouse // press processing may have made the window hide (as happens with menus). - - // It is possible for a View to show a context menu on mouse-press. Since - // the menu does a capture and starts a nested message-loop, the release - // would go to the menu. The next click (i.e. both mouse-press and release - // events) also go to the menu. The menu (and the nested message-loop) - // gets closed after this second release event. The code then resumes from - // here. So make sure that the mouse-button is still down before doing a - // capture. + // + // It is possible that capture has changed as a result of a mouse-press. + // In these cases do not update internal state. + // + // A mouse-press may trigger a nested message-loop, and absorb the paired + // release. If so the code returns here. So make sure that that + // mouse-button is still down before attempting to do a capture. if (root_view && root_view->OnMousePressed(*event) && widget_deletion_observer.IsWidgetAlive() && IsVisible() && - internal::NativeWidgetPrivate::IsMouseButtonDown()) { + internal::NativeWidgetPrivate::IsMouseButtonDown() && + current_capture == internal::NativeWidgetPrivate::GetGlobalCapture( + native_widget_->GetNativeView())) { is_mouse_button_pressed_ = true; if (!native_widget_->HasCapture()) native_widget_->SetCapture(); diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h index 0ceaf825ffb..e52c7fff2ed 100644 --- a/chromium/ui/views/widget/widget.h +++ b/chromium/ui/views/widget/widget.h @@ -5,12 +5,14 @@ #ifndef UI_VIEWS_WIDGET_WIDGET_H_ #define UI_VIEWS_WIDGET_WIDGET_H_ +#include <map> +#include <memory> #include <set> #include <stack> +#include <string> #include <vector> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/scoped_observer.h" #include "build/build_config.h" @@ -47,6 +49,10 @@ class Point; class Rect; } +namespace mus { +class Window; +} + namespace ui { class Accelerator; class Compositor; @@ -97,8 +103,8 @@ class RootView; // The Widget instance owns its NativeWidget. This state implies someone // else wants to control the lifetime of this object. When they destroy // the Widget it is responsible for destroying the NativeWidget (from its -// destructor). This is often used to place a Widget in a scoped_ptr<> or -// on the stack in a test. +// destructor). This is often used to place a Widget in a std::unique_ptr<> +// or on the stack in a test. class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, public ui::EventSource, public FocusTraversable, @@ -209,6 +215,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // If null, a default implementation will be constructed. The default // implementation deletes itself when the Widget closes. WidgetDelegate* delegate; + // Internal name. Propagated to the NativeWidget. Useful for debugging. + std::string name; bool child; // If TRANSLUCENT_WINDOW, the widget may be fully or partially transparent. // If OPAQUE_WINDOW, we can perform optimizations based on the widget being @@ -236,11 +244,16 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Whether the widget should be maximized or minimized. ui::WindowShowState show_state; gfx::NativeView parent; + // Used only by mus and is necessitated by mus not being a NativeView. + mus::Window* parent_mus = nullptr; // Specifies the initial bounds of the Widget. Default is empty, which means // the NativeWidget may specify a default size. If the parent is specified, // |bounds| is in the parent's coordinate system. If the parent is not // specified, it's in screen's global coordinate system. gfx::Rect bounds; + // The initial workspace of the Widget. Default is "", which means the + // current workspace. + std::string workspace; // When set, this value is used as the Widget's NativeWidget implementation. // The Widget will not construct a default one. Default is NULL. NativeWidget* native_widget; @@ -277,6 +290,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Used if widget is not activatable to do determine if mouse events should // be sent to the widget. bool wants_mouse_events_when_inactive = false; + + // A map of properties applied to windows when running in mus. + std::map<std::string, std::vector<uint8_t>> mus_properties; }; Widget(); @@ -416,6 +432,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // Retrieves the restored bounds for the window. gfx::Rect GetRestoredBounds() const; + // Retrieves the current workspace for the window. + std::string GetWorkspace() const; + // Sizes and/or places the widget to the specified bounds, size or position. void SetBounds(const gfx::Rect& bounds); void SetSize(const gfx::Size& size); @@ -758,6 +777,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // closes. virtual void OnOwnerClosing(); + // Returns the internal name for this Widget and NativeWidget. + std::string GetName() const; + // Overridden from NativeWidgetDelegate: bool IsModal() const override; bool IsDialogBox() const override; @@ -776,6 +798,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, gfx::Size GetMaximumSize() const override; void OnNativeWidgetMove() override; void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override; + void OnNativeWidgetWorkspaceChanged() override; void OnNativeWidgetWindowShowStateChanged() override; void OnNativeWidgetBeginUserBoundsChange() override; void OnNativeWidgetEndUserBoundsChange() override; @@ -861,7 +884,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // The root of the View hierarchy attached to this window. // WARNING: see warning in tooltip_manager_ for ordering dependencies with // this and tooltip_manager_. - scoped_ptr<internal::RootView> root_view_; + std::unique_ptr<internal::RootView> root_view_; // The View that provides the non-client area of the window (title bar, // window controls, sizing borders etc). To use an implementation other than @@ -873,10 +896,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // children. NULL for non top-level widgets. // WARNING: RootView's destructor calls into the FocusManager. As such, this // must be destroyed AFTER root_view_. This is enforced in DestroyRootView(). - scoped_ptr<FocusManager> focus_manager_; + std::unique_ptr<FocusManager> focus_manager_; // A theme provider to use when no other theme provider is specified. - scoped_ptr<ui::DefaultThemeProvider> default_theme_provider_; + std::unique_ptr<ui::DefaultThemeProvider> default_theme_provider_; // Valid for the lifetime of RunShellDrag(), indicates the view the drag // started from. diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc index ced90b6f392..c5f9d97490c 100644 --- a/chromium/ui/views/widget/widget_delegate.cc +++ b/chromium/ui/views/widget/widget_delegate.cc @@ -6,7 +6,6 @@ #include "base/strings/utf_string_conversions.h" #include "ui/gfx/image/image_skia.h" -#include "ui/views/bubble/bubble_delegate.h" #include "ui/views/view.h" #include "ui/views/views_delegate.h" #include "ui/views/widget/widget.h" @@ -35,10 +34,6 @@ View* WidgetDelegate::GetInitiallyFocusedView() { return nullptr; } -BubbleDelegateView* WidgetDelegate::AsBubbleDelegate() { - return nullptr; -} - BubbleDialogDelegateView* WidgetDelegate::AsBubbleDialogDelegate() { return nullptr; } diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h index 0ec021505b6..8a344c55623 100644 --- a/chromium/ui/views/widget/widget_delegate.h +++ b/chromium/ui/views/widget/widget_delegate.h @@ -20,7 +20,6 @@ class Rect; namespace views { class BubbleDialogDelegateView; -class BubbleDelegateView; class ClientView; class DialogDelegate; class NonClientFrameView; @@ -51,7 +50,6 @@ class VIEWS_EXPORT WidgetDelegate { // NULL no view is focused. virtual View* GetInitiallyFocusedView(); - virtual BubbleDelegateView* AsBubbleDelegate(); virtual BubbleDialogDelegateView* AsBubbleDialogDelegate(); virtual DialogDelegate* AsDialogDelegate(); diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc index ca561b6d6dc..b843416dac5 100644 --- a/chromium/ui/views/widget/widget_hwnd_utils.cc +++ b/chromium/ui/views/widget/widget_hwnd_utils.cc @@ -7,7 +7,6 @@ #include <dwmapi.h> #include "base/command_line.h" -#include "base/win/windows_version.h" #include "build/build_config.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/base/ui_base_switches.h" @@ -66,14 +65,12 @@ void CalculateWindowStylesFromInitParams( // We also set the WS_EX_COMPOSITED style for software composited translucent // windows, which ensures that they are updated via the layered window code // path in the software compositor. - if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) { - if (ui::win::IsAeroGlassEnabled() || params.force_software_compositing) + if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW && + (ui::win::IsAeroGlassEnabled() || params.force_software_compositing)) *ex_style |= WS_EX_COMPOSITED; - } - if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP) { - *class_style |= (base::win::GetVersion() < base::win::VERSION_XP) ? - 0 : CS_DROPSHADOW; - } + + if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP) + *class_style |= CS_DROPSHADOW; // Set type-dependent style attributes. switch (params.type) { diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc index e9f9397c01b..a64a3faba98 100644 --- a/chromium/ui/views/widget/widget_interactive_uitest.cc +++ b/chromium/ui/views/widget/widget_interactive_uitest.cc @@ -278,11 +278,15 @@ class WidgetTestInteractive : public WidgetTest { ~WidgetTestInteractive() override {} void SetUp() override { - gfx::GLSurfaceTestSupport::InitializeOneOff(); - ui::RegisterPathProvider(); - base::FilePath ui_test_pak_path; - ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); - ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); + // On mus these tests run as part of views::ViewsTestSuite which already + // does this initialization. + if (!IsMus()) { + gfx::GLSurfaceTestSupport::InitializeOneOff(); + ui::RegisterPathProvider(); + base::FilePath ui_test_pak_path; + ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); + ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); + } WidgetTest::SetUp(); } @@ -318,7 +322,7 @@ class WidgetTestInteractive : public WidgetTest { TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) { // Create widget 1 and expect the active window to be its window. View* focusable_view1 = new View; - focusable_view1->SetFocusable(true); + focusable_view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); Widget* widget1 = CreateWidget(); widget1->GetContentsView()->AddChildView(focusable_view1); widget1->Show(); @@ -602,14 +606,14 @@ TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) { TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) { Widget* widget1 = CreateTopLevelPlatformWidget(); View* view1 = new View; - view1->SetFocusable(true); + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget1->GetContentsView()->AddChildView(view1); Widget* widget2 = CreateTopLevelPlatformWidget(); View* view2a = new View; View* view2b = new View; - view2a->SetFocusable(true); - view2b->SetFocusable(true); + view2a->SetFocusBehavior(View::FocusBehavior::ALWAYS); + view2b->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget2->GetContentsView()->AddChildView(view2a); widget2->GetContentsView()->AddChildView(view2b); @@ -649,9 +653,10 @@ TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) { TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) { Widget* widget = CreateTopLevelFramelessPlatformWidget(); widget->SetContentsView(new View); - for (size_t i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) { widget->GetContentsView()->AddChildView(new View); - widget->GetContentsView()->child_at(i)->SetFocusable(true); + widget->GetContentsView()->child_at(i)->SetFocusBehavior( + View::FocusBehavior::ALWAYS); } widget->Show(); @@ -805,6 +810,56 @@ TEST_F(WidgetTestInteractive, FullscreenBoundsReducedOnActivationLoss) { widget1.CloseNow(); widget2.CloseNow(); } + +// Ensure the window rect and client rects are correct with a window that was +// maximized. +TEST_F(WidgetTestInteractive, FullscreenMaximizedWindowBounds) { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.native_widget = new DesktopNativeWidgetAura(&widget); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM); + widget.Init(params); + widget.SetBounds(gfx::Rect(0, 0, 200, 200)); + widget.Show(); + + widget.Maximize(); + EXPECT_TRUE(widget.IsMaximized()); + + widget.SetFullscreen(true); + EXPECT_TRUE(widget.IsFullscreen()); + EXPECT_FALSE(widget.IsMaximized()); + // Ensure that the StopIgnoringPosChanges task in HWNDMessageHandler runs. + // This task is queued when a widget becomes fullscreen. + RunPendingMessages(); + + aura::WindowTreeHost* host = widget.GetNativeWindow()->GetHost(); + HWND hwnd = host->GetAcceleratedWidget(); + + HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + ASSERT_TRUE(!!monitor); + MONITORINFO monitor_info; + monitor_info.cbSize = sizeof(monitor_info); + ASSERT_TRUE(::GetMonitorInfo(monitor, &monitor_info)); + + gfx::Rect monitor_bounds(monitor_info.rcMonitor); + gfx::Rect window_bounds = widget.GetWindowBoundsInScreen(); + gfx::Rect client_area_bounds = host->GetBounds(); + + EXPECT_EQ(window_bounds, monitor_bounds); + EXPECT_EQ(monitor_bounds, client_area_bounds); + + // Setting not fullscreen should return it to maximized. + widget.SetFullscreen(false); + EXPECT_FALSE(widget.IsFullscreen()); + EXPECT_TRUE(widget.IsMaximized()); + + client_area_bounds = host->GetBounds(); + EXPECT_TRUE(monitor_bounds.Contains(client_area_bounds)); + EXPECT_NE(monitor_bounds, client_area_bounds); + + widget.CloseNow(); +} #endif // defined(OS_WIN) #if !defined(OS_CHROMEOS) @@ -826,6 +881,10 @@ class ModalDialogDelegate : public DialogDelegateView { // Tests whether the focused window is set correctly when a modal window is // created and destroyed. When it is destroyed it should focus the owner window. TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) { + // Fails on mus due to focus issues. http://crbug.com/611601 + if (IsMus()) + return; + TestWidgetFocusChangeListener focus_listener; WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener); const std::vector<gfx::NativeView>& focus_changes = @@ -863,7 +922,7 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) { modal_dialog_widget->Show(); gfx::NativeView modal_native_view = modal_dialog_widget->GetNativeView(); - EXPECT_EQ(3u, focus_changes.size()); + ASSERT_EQ(3u, focus_changes.size()); EXPECT_EQ(nullptr, focus_changes[1]); EXPECT_EQ(modal_native_view, focus_changes[2]); @@ -877,7 +936,7 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) { modal_dialog_widget->CloseNow(); #endif - EXPECT_EQ(5u, focus_changes.size()); + ASSERT_EQ(5u, focus_changes.size()); EXPECT_EQ(nullptr, focus_changes[3]); EXPECT_EQ(top_level_native_view, focus_changes[4]); @@ -897,6 +956,10 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) { // Test that when opening a system-modal window, capture is released. TEST_F(WidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) { + // Crashes on mus due to capture issue. http://crbug.com/611764 + if (IsMus()) + return; + TestWidgetFocusChangeListener focus_listener; WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener); @@ -988,6 +1051,10 @@ TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) { #endif // defined(USE_AURA) TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) { + // Times out on mus. See http://crbug.com/612193 + if (IsMus()) + return; + #if defined(OS_WIN) views_delegate()->set_use_desktop_native_widgets(true); #endif // !defined(OS_WIN) @@ -1000,7 +1067,7 @@ TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) { widget1.Init(params1); View* view1 = new View(); - view1->SetFocusable(true); + view1->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget1.GetRootView()->AddChildView(view1); ActivateSync(&widget1); @@ -1018,7 +1085,7 @@ TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) { widget2.Init(params2); View* view2 = new View(); - view2->SetFocusable(true); + view2->SetFocusBehavior(View::FocusBehavior::ALWAYS); widget2.GetRootView()->AddChildView(view2); ActivateSync(&widget2); @@ -1179,7 +1246,7 @@ TEST_F(WidgetTestInteractive, InitialFocus) { // focusable subview). Widget* toplevel(CreateTopLevelPlatformWidget()); View* view = new View; - view->SetFocusable(true); + view->SetFocusBehavior(View::FocusBehavior::ALWAYS); toplevel->GetContentsView()->AddChildView(view); ShowSync(toplevel); @@ -1234,11 +1301,15 @@ class WidgetCaptureTest : public ViewsTestBase { ~WidgetCaptureTest() override {} void SetUp() override { - gfx::GLSurfaceTestSupport::InitializeOneOff(); - ui::RegisterPathProvider(); - base::FilePath ui_test_pak_path; - ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); - ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); + // On mus these tests run as part of views::ViewsTestSuite which already + // does this initialization. + if (!IsMus()) { + gfx::GLSurfaceTestSupport::InitializeOneOff(); + ui::RegisterPathProvider(); + base::FilePath ui_test_pak_path; + ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); + ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); + } ViewsTestBase::SetUp(); } @@ -1305,12 +1376,20 @@ TEST_F(WidgetCaptureTest, Capture) { #if !defined(OS_CHROMEOS) // See description in TestCapture(). Creates DesktopNativeWidget. TEST_F(WidgetCaptureTest, CaptureDesktopNativeWidget) { + // Fails on mus. http://crbug.com/611764 + if (IsMus()) + return; + TestCapture(true); } #endif // Test that no state is set if capture fails. TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) { + // Fails on mus. http://crbug.com/611764 + if (IsMus()) + return; + Widget widget; Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -1353,6 +1432,10 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) { // Test that a synthetic mouse exit is sent to the widget which was handling // mouse events when a different widget grabs capture. TEST_F(WidgetCaptureTest, MAYBE_MouseExitOnCaptureGrab) { + // Fails on mus. http://crbug.com/611764 + if (IsMus()) + return; + Widget widget1; Widget::InitParams params1 = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -1608,6 +1691,10 @@ TEST_F(WidgetInputMethodInteractiveTest, OneWindow) { // Test input method focus changes affected by focus changes cross 2 windows // which shares the same top window. TEST_F(WidgetInputMethodInteractiveTest, TwoWindows) { + // Fails on mus. http://crbug.com/611766 + if (IsMus()) + return; + Widget* parent = CreateWidget(); parent->SetBounds(gfx::Rect(100, 100, 100, 100)); diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc index 12dec089cc9..3dfd3572eb1 100644 --- a/chromium/ui/views/widget/widget_unittest.cc +++ b/chromium/ui/views/widget/widget_unittest.cc @@ -3,11 +3,11 @@ // found in the LICENSE file. #include <algorithm> +#include <memory> #include <set> #include "base/bind.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" @@ -21,7 +21,7 @@ #include "ui/events/test/event_generator.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/native_widget_types.h" -#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/native_widget_factory.h" #include "ui/views/test/test_views.h" @@ -61,13 +61,28 @@ gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) { return tmp; } -// This class can be used as a deleter for scoped_ptr<Widget> +// This class can be used as a deleter for std::unique_ptr<Widget> // to call function Widget::CloseNow automatically. struct WidgetCloser { inline void operator()(Widget* widget) const { widget->CloseNow(); } }; -using WidgetAutoclosePtr = scoped_ptr<Widget, WidgetCloser>; +class TestBubbleDialogDelegateView : public BubbleDialogDelegateView { + public: + TestBubbleDialogDelegateView(View* anchor) + : BubbleDialogDelegateView(anchor, BubbleBorder::NONE), + reset_controls_called_(false) {} + ~TestBubbleDialogDelegateView() override {} + + bool ShouldShowCloseButton() const override { + reset_controls_called_ = true; + return true; + } + + mutable bool reset_controls_called_; +}; + +using WidgetAutoclosePtr = std::unique_ptr<Widget, WidgetCloser>; } // namespace @@ -154,6 +169,19 @@ TEST_F(WidgetTest, WidgetInitParams) { EXPECT_EQ(Widget::InitParams::INFER_OPACITY, init1.opacity); } +// Tests that the internal name is propagated through widget initialization to +// the native widget and back. +TEST_F(WidgetTest, GetName) { + Widget widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.name = "MyWidget"; + widget.Init(params); + + EXPECT_EQ("MyWidget", widget.native_widget_private()->GetName()); + EXPECT_EQ("MyWidget", widget.GetName()); +} + TEST_F(WidgetTest, NativeWindowProperty) { const char* key = "foo"; int value = 3; @@ -379,7 +407,7 @@ class OwnershipTestWidget : public Widget { TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { OwnershipTestState state; - scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); + std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); @@ -400,7 +428,7 @@ TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsPlatformNativeWidget) { TEST_F(WidgetOwnershipTest, Ownership_WidgetOwnsViewsNativeWidget) { OwnershipTestState state; - scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); + std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); @@ -425,7 +453,7 @@ TEST_F(WidgetOwnershipTest, Widget* toplevel = CreateTopLevelPlatformWidget(); - scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); + std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.parent = toplevel->GetNativeView(); params.native_widget = CreatePlatformNativeWidgetImpl( @@ -571,7 +599,7 @@ TEST_F(WidgetOwnershipTest, WidgetDelegateView* delegate_view = new WidgetDelegateView; - scoped_ptr<Widget> widget(new OwnershipTestWidget(&state)); + std::unique_ptr<Widget> widget(new OwnershipTestWidget(&state)); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.native_widget = CreatePlatformNativeWidgetImpl( params, widget.get(), kStubCapture, &state.native_widget_deleted); @@ -822,11 +850,11 @@ TEST_F(WidgetObserverTest, DestroyBubble) { WidgetAutoclosePtr anchor(CreateTopLevelPlatformWidget()); anchor->Show(); - BubbleDelegateView* bubble_delegate = - new BubbleDelegateView(anchor->client_view(), BubbleBorder::NONE); + BubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor->client_view()); { WidgetAutoclosePtr bubble_widget( - BubbleDelegateView::CreateBubble(bubble_delegate)); + BubbleDialogDelegateView::CreateBubble(bubble_delegate)); bubble_widget->Show(); } @@ -1189,7 +1217,7 @@ TEST_F(WidgetTest, KeyboardInputEvent) { TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) { // Create a widget, show and activate it and focus the contents view. View* contents_view = new View; - contents_view->SetFocusable(true); + contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -1207,10 +1235,10 @@ TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) { EXPECT_TRUE(contents_view->HasFocus()); // Show a bubble. - BubbleDelegateView* bubble_delegate_view = - new BubbleDelegateView(contents_view, BubbleBorder::TOP_LEFT); - bubble_delegate_view->SetFocusable(true); - BubbleDelegateView::CreateBubble(bubble_delegate_view)->Show(); + BubbleDialogDelegateView* bubble_delegate_view = + new TestBubbleDialogDelegateView(contents_view); + bubble_delegate_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); + BubbleDialogDelegateView::CreateBubble(bubble_delegate_view)->Show(); bubble_delegate_view->RequestFocus(); // |contents_view_| should no longer have focus. @@ -1223,30 +1251,15 @@ TEST_F(WidgetTest, DISABLED_FocusChangesOnBubble) { EXPECT_TRUE(contents_view->HasFocus()); } -class TestBubbleDelegateView : public BubbleDelegateView { - public: - TestBubbleDelegateView(View* anchor) - : BubbleDelegateView(anchor, BubbleBorder::NONE), - reset_controls_called_(false) {} - ~TestBubbleDelegateView() override {} - - bool ShouldShowCloseButton() const override { - reset_controls_called_ = true; - return true; - } - - mutable bool reset_controls_called_; -}; - TEST_F(WidgetTest, BubbleControlsResetOnInit) { WidgetAutoclosePtr anchor(CreateTopLevelPlatformWidget()); anchor->Show(); { - TestBubbleDelegateView* bubble_delegate = - new TestBubbleDelegateView(anchor->client_view()); + TestBubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor->client_view()); WidgetAutoclosePtr bubble_widget( - BubbleDelegateView::CreateBubble(bubble_delegate)); + BubbleDialogDelegateView::CreateBubble(bubble_delegate)); EXPECT_TRUE(bubble_delegate->reset_controls_called_); bubble_widget->Show(); } @@ -1351,7 +1364,7 @@ void DesktopAuraTestValidPaintWidget::InitForTest(InitParams init_params) { Init(init_params); View* contents_view = new View; - contents_view->SetFocusable(true); + contents_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); SetContentsView(contents_view); Show(); @@ -1534,7 +1547,7 @@ TEST_F(WidgetTest, EventHandlersOnRootView) { WidgetAutoclosePtr widget(CreateTopLevelNativeWidget()); View* root_view = widget->GetRootView(); - scoped_ptr<EventCountView> view(new EventCountView()); + std::unique_ptr<EventCountView> view(new EventCountView()); view->set_owned_by_client(); view->SetBounds(0, 0, 20, 20); root_view->AddChildView(view.get()); @@ -1688,9 +1701,6 @@ TEST_F(WidgetTest, SynthesizeMouseMoveEvent) { EXPECT_EQ(1, v2->GetEventCount(ui::ET_MOUSE_MOVED)); } -// No touch on desktop Mac. Tracked in http://crbug.com/445520. -#if !defined(OS_MACOSX) || defined(USE_AURA) - namespace { // ui::EventHandler which handles all mouse press events. @@ -1710,6 +1720,9 @@ class MousePressEventConsumer : public ui::EventHandler { } // namespace +// No touch on desktop Mac. Tracked in http://crbug.com/445520. +#if !defined(OS_MACOSX) || defined(USE_AURA) + // Test that mouse presses and mouse releases are dispatched normally when a // touch is down. TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) { @@ -1724,9 +1737,10 @@ TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) { MousePressEventConsumer consumer; event_count_view->AddPostTargetHandler(&consumer); - scoped_ptr<ui::test::EventGenerator> generator(new ui::test::EventGenerator( - IsMus() ? widget->GetNativeWindow() : GetContext(), - widget->GetNativeWindow())); + std::unique_ptr<ui::test::EventGenerator> generator( + new ui::test::EventGenerator( + IsMus() ? widget->GetNativeWindow() : GetContext(), + widget->GetNativeWindow())); generator->PressTouch(); generator->ClickLeftButton(); @@ -1739,6 +1753,107 @@ TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) { #endif // !defined(OS_MACOSX) || defined(USE_AURA) +// Tests that when there is no active capture, that a mouse press causes capture +// to be set. +TEST_F(WidgetTest, MousePressCausesCapture) { + Widget* widget = CreateTopLevelNativeWidget(); + widget->Show(); + widget->SetSize(gfx::Size(300, 300)); + + EventCountView* event_count_view = new EventCountView(); + event_count_view->SetBounds(0, 0, 300, 300); + widget->GetRootView()->AddChildView(event_count_view); + + // No capture has been set. + EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture( + widget->GetNativeView())); + + MousePressEventConsumer consumer; + event_count_view->AddPostTargetHandler(&consumer); + std::unique_ptr<ui::test::EventGenerator> generator( + new ui::test::EventGenerator( + IsMus() ? widget->GetNativeWindow() : GetContext(), + widget->GetNativeWindow())); + generator->PressLeftButton(); + + EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_EQ( + widget->GetNativeView(), + internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView())); + + // For mus it's important we destroy the widget before the EventGenerator. + widget->CloseNow(); +} + +namespace { + +// An EventHandler which shows a Wiget upon receiving a mouse event. The Widget +// proceeds to take capture. +class CaptureEventConsumer : public ui::EventHandler { + public: + CaptureEventConsumer(Widget* widget) + : event_count_view_(new EventCountView()), widget_(widget) {} + ~CaptureEventConsumer() override { widget_->CloseNow(); } + + private: + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + if (event->type() == ui::ET_MOUSE_PRESSED) { + event->SetHandled(); + widget_->Show(); + widget_->SetSize(gfx::Size(200, 200)); + + event_count_view_->SetBounds(0, 0, 200, 200); + widget_->GetRootView()->AddChildView(event_count_view_); + widget_->SetCapture(event_count_view_); + } + } + + EventCountView* event_count_view_; + Widget* widget_; + DISALLOW_COPY_AND_ASSIGN(CaptureEventConsumer); +}; + +} // namespace + +// Tests that if explicit capture occurs during a mouse press, that implicit +// capture is not applied. +TEST_F(WidgetTest, CaptureDuringMousePressNotOverridden) { + Widget* widget = CreateTopLevelNativeWidget(); + widget->Show(); + widget->SetSize(gfx::Size(300, 300)); + + EventCountView* event_count_view = new EventCountView(); + event_count_view->SetBounds(0, 0, 300, 300); + widget->GetRootView()->AddChildView(event_count_view); + + EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture( + widget->GetNativeView())); + + Widget* widget2 = CreateTopLevelNativeWidget(); + // Gives explicit capture to |widget2| + CaptureEventConsumer consumer(widget2); + event_count_view->AddPostTargetHandler(&consumer); + std::unique_ptr<ui::test::EventGenerator> generator( + new ui::test::EventGenerator( + IsMus() ? widget->GetNativeWindow() : GetContext(), + widget->GetNativeWindow())); + // This event should implicitly give capture to |widget|, except that + // |consumer| will explicitly set capture on |widget2|. + generator->PressLeftButton(); + + EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSE_PRESSED)); + EXPECT_NE( + widget->GetNativeView(), + internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView())); + EXPECT_EQ( + widget2->GetNativeView(), + internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView())); + + // For mus it's important we destroy the widget before the EventGenerator. + widget->CloseNow(); +} + // Verifies WindowClosing() is invoked correctly on the delegate when a Widget // is closed. TEST_F(WidgetTest, SingleWindowClosing) { @@ -1837,8 +1952,9 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) { #if !defined(OS_MACOSX) || defined(USE_AURA) TEST_F(WidgetTest, WidgetDeleted_InDispatchGestureEvent) { - // This test doesn't make sense for mus. Force NativeWidgetAura to be used. - DisableNativeWidgetMus(); + // This test doesn't make sense for mus. + if (IsMus()) + return; Widget* widget = new Widget; Widget::InitParams params = @@ -1996,7 +2112,7 @@ TEST_F(WidgetTest, CloseDestroys) { // Tests that killing a widget while animating it does not crash. TEST_F(WidgetTest, CloseWidgetWhileAnimating) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(50, 50, 250, 250); @@ -2058,7 +2174,7 @@ TEST_F(WidgetTest, ValidDuringOnNativeWidgetDestroyingFromClose) { // Tests that we do not crash when a Widget is destroyed by going out of // scope (as opposed to being explicitly deleted by its NativeWidget). TEST_F(WidgetTest, NoCrashOnWidgetDelete) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; widget->Init(params); @@ -2067,7 +2183,7 @@ TEST_F(WidgetTest, NoCrashOnWidgetDelete) { // Tests that we do not crash when a Widget is destroyed before it finishes // processing of pending input events in the message loop. TEST_F(WidgetTest, NoCrashOnWidgetDeleteWithPendingEvents) { - scoped_ptr<Widget> widget(new Widget); + std::unique_ptr<Widget> widget(new Widget); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; diff --git a/chromium/ui/views/widget/window_reorderer.h b/chromium/ui/views/widget/window_reorderer.h index 7b9db7ccad4..1d8d253e80f 100644 --- a/chromium/ui/views/widget/window_reorderer.h +++ b/chromium/ui/views/widget/window_reorderer.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_WIDGET_WINDOW_REORDERER_H_ #define UI_VIEWS_WIDGET_WINDOW_REORDERER_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/aura/window_observer.h" namespace aura { @@ -50,7 +51,7 @@ class WindowReorderer : public aura::WindowObserver { // Reorders windows as a result of the kHostViewKey being set on a child of // |parent_window_|. class AssociationObserver; - scoped_ptr<AssociationObserver> association_observer_; + std::unique_ptr<AssociationObserver> association_observer_; DISALLOW_COPY_AND_ASSIGN(WindowReorderer); }; diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc index 67cf246e73a..08be48b904f 100644 --- a/chromium/ui/views/widget/window_reorderer_unittest.cc +++ b/chromium/ui/views/widget/window_reorderer_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> + #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" @@ -52,8 +54,8 @@ typedef aura::test::AuraTestBase WindowReordererTest; // Test that views with layers and views with associated windows are reordered // according to the view hierarchy. TEST_F(WindowReordererTest, Basic) { - scoped_ptr<Widget> parent(CreateControlWidget(root_window(), - gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent( + CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -68,12 +70,12 @@ TEST_F(WindowReordererTest, Basic) { v->layer()->set_name("v"); contents_view->AddChildView(v); - scoped_ptr<Widget> w1(CreateControlWidget(parent_window, - gfx::Rect(0, 1, 100, 101))); + std::unique_ptr<Widget> w1( + CreateControlWidget(parent_window, gfx::Rect(0, 1, 100, 101))); SetWindowAndLayerName(w1->GetNativeView(), "w1"); w1->Show(); - scoped_ptr<Widget> w2(CreateControlWidget(parent_window, - gfx::Rect(0, 2, 100, 102))); + std::unique_ptr<Widget> w2( + CreateControlWidget(parent_window, gfx::Rect(0, 2, 100, 102))); SetWindowAndLayerName(w2->GetNativeView(), "w2"); w2->Show(); @@ -130,8 +132,8 @@ TEST_F(WindowReordererTest, Basic) { // - associating the "host" view and window // all correctly reorder the child windows and layers. TEST_F(WindowReordererTest, Association) { - scoped_ptr<Widget> parent(CreateControlWidget(root_window(), - gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent( + CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -191,8 +193,8 @@ TEST_F(WindowReordererTest, Association) { // view and the parent layer of the associated window are different. Test that // the layers and windows are properly reordered in this case. TEST_F(WindowReordererTest, HostViewParentHasLayer) { - scoped_ptr<Widget> parent(CreateControlWidget(root_window(), - gfx::Rect(0, 0, 100, 100))); + std::unique_ptr<Widget> parent( + CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100))); parent->Show(); aura::Window* parent_window = parent->GetNativeWindow(); @@ -217,8 +219,8 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { v11->layer()->set_name("v11"); v1->AddChildView(v11); - scoped_ptr<Widget> w(CreateControlWidget(parent_window, - gfx::Rect(0, 1, 100, 101))); + std::unique_ptr<Widget> w( + CreateControlWidget(parent_window, gfx::Rect(0, 1, 100, 101))); SetWindowAndLayerName(w->GetNativeView(), "w"); w->Show(); diff --git a/chromium/ui/views/win/fullscreen_handler.cc b/chromium/ui/views/win/fullscreen_handler.cc index 0529f6e37d8..89581d79d06 100644 --- a/chromium/ui/views/win/fullscreen_handler.cc +++ b/chromium/ui/views/win/fullscreen_handler.cc @@ -4,8 +4,9 @@ #include "ui/views/win/fullscreen_handler.h" +#include <memory> + #include "base/logging.h" -#include "base/memory/scoped_ptr.h" #include "base/win/win_util.h" #include "ui/base/win/shell.h" #include "ui/gfx/geometry/rect.h" @@ -36,7 +37,7 @@ gfx::Rect FullscreenHandler::GetRestoreBounds() const { // FullscreenHandler, private: void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { - scoped_ptr<ScopedFullscreenVisibility> visibility; + std::unique_ptr<ScopedFullscreenVisibility> visibility; // With Aero enabled disabling the visibility causes the window to disappear // for several frames, which looks worse than doing other updates @@ -46,12 +47,6 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { // Save current window state if not already fullscreen. if (!fullscreen_) { - // Save current window information. We force the window into restored mode - // before going fullscreen because Windows doesn't seem to hide the - // taskbar if the window is in the maximized state. - saved_window_info_.maximized = !!::IsZoomed(hwnd_); - if (saved_window_info_.maximized) - ::SendMessage(hwnd_, WM_SYSCOMMAND, SC_RESTORE, 0); saved_window_info_.style = GetWindowLong(hwnd_, GWL_STYLE); saved_window_info_.ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE); GetWindowRect(hwnd_, &saved_window_info_.window_rect); @@ -89,8 +84,6 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { SetWindowPos(hwnd_, NULL, new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height(), SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); - if (saved_window_info_.maximized) - ::SendMessage(hwnd_, WM_SYSCOMMAND, SC_MAXIMIZE, 0); } } diff --git a/chromium/ui/views/win/fullscreen_handler.h b/chromium/ui/views/win/fullscreen_handler.h index b23b1421374..9714057ed86 100644 --- a/chromium/ui/views/win/fullscreen_handler.h +++ b/chromium/ui/views/win/fullscreen_handler.h @@ -34,7 +34,6 @@ class FullscreenHandler { // Information saved before going into fullscreen mode, used to restore the // window afterwards. struct SavedWindowInfo { - bool maximized; LONG style; LONG ex_style; RECT window_rect; diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc index 7555abd0f26..3d77ea47a79 100644 --- a/chromium/ui/views/win/hwnd_message_handler.cc +++ b/chromium/ui/views/win/hwnd_message_handler.cc @@ -34,9 +34,7 @@ #include "ui/gfx/icon_util.h" #include "ui/gfx/path.h" #include "ui/gfx/path_win.h" -#include "ui/gfx/screen.h" #include "ui/gfx/win/direct_manipulation.h" -#include "ui/gfx/win/dpi.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/rendering_window_manager.h" #include "ui/native_theme/native_theme_win.h" @@ -302,6 +300,10 @@ class HWNDMessageHandler::ScopedRedrawLock { DISALLOW_COPY_AND_ASSIGN(ScopedRedrawLock); }; +// static HWNDMessageHandler member initialization. +base::LazyInstance<HWNDMessageHandler::FullscreenWindowMonitorMap> + HWNDMessageHandler::fullscreen_monitor_map_ = LAZY_INSTANCE_INITIALIZER; + //////////////////////////////////////////////////////////////////////////////// // HWNDMessageHandler, public: @@ -683,7 +685,7 @@ bool HWNDMessageHandler::IsMinimized() const { } bool HWNDMessageHandler::IsMaximized() const { - return !!::IsZoomed(hwnd()); + return !!::IsZoomed(hwnd()) && !IsFullscreen(); } bool HWNDMessageHandler::IsFullscreen() const { @@ -815,6 +817,18 @@ void HWNDMessageHandler::SetFullscreen(bool fullscreen) { // window, then go ahead and do it now. if (!fullscreen && dwm_transition_desired_) PerformDwmTransition(); + + // Add the fullscreen window to the fullscreen window map which is used to + // handle window activations. + HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY); + if (fullscreen) { + (fullscreen_monitor_map_.Get())[monitor] = this; + } else { + FullscreenWindowMonitorMap::iterator iter = + fullscreen_monitor_map_.Get().find(monitor); + if (iter != fullscreen_monitor_map_.Get().end()) + fullscreen_monitor_map_.Get().erase(iter); + } } void HWNDMessageHandler::SizeConstraintsChanged() { @@ -1025,18 +1039,18 @@ void HWNDMessageHandler::PostProcessActivateMessage( // By reducing the size of the fullscreen window by 1px, we ensure that the // taskbar no longer treats the window and in turn the thread as a fullscreen // thread. This in turn ensures that maximized windows on the same thread - /// don't obscure the taskbar, etc. + // don't obscure the taskbar, etc. + // Please note that this taskbar behavior only occurs if the window becoming + // active is on the same monitor as the fullscreen window. if (!active) { if (IsFullscreen() && ::IsWindow(window_gaining_or_losing_activation)) { - // Reduce the bounds of the window by 1px to ensure that Windows does - // not treat this like a fullscreen window. - MONITORINFO monitor_info = {sizeof(monitor_info)}; - GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY), - &monitor_info); - gfx::Rect shrunk_rect(monitor_info.rcMonitor); - shrunk_rect.set_height(shrunk_rect.height() - 1); - background_fullscreen_hack_ = true; - SetBoundsInternal(shrunk_rect, false); + HMONITOR active_window_monitor = MonitorFromWindow( + window_gaining_or_losing_activation, MONITOR_DEFAULTTOPRIMARY); + HMONITOR fullscreen_window_monitor = + MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY); + + if (active_window_monitor == fullscreen_window_monitor) + OnBackgroundFullscreen(); } } else if (background_fullscreen_hack_) { // Restore the bounds of the window to fullscreen. @@ -1046,6 +1060,13 @@ void HWNDMessageHandler::PostProcessActivateMessage( &monitor_info); SetBoundsInternal(gfx::Rect(monitor_info.rcMonitor), false); background_fullscreen_hack_ = false; + } else { + // If the window becoming active has a fullscreen window on the same + // monitor then we need to reduce the size of the fullscreen window by + // 1 px. Please refer to the comments above for the reasoning behind + // this. + CheckAndHandleBackgroundFullscreenOnMonitor( + window_gaining_or_losing_activation); } } @@ -1093,7 +1114,7 @@ void HWNDMessageHandler::TrackMouseEvents(DWORD mouse_tracking_flags) { void HWNDMessageHandler::ClientAreaSizeChanged() { // Ignore size changes due to fullscreen windows losing activation. - if (background_fullscreen_hack_) + if (background_fullscreen_hack_ && !sent_window_size_changing_) return; gfx::Size s = GetClientAreaBounds().size(); delegate_->HandleClientSizeChanged(s); @@ -1341,6 +1362,16 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) { void HWNDMessageHandler::OnDestroy() { windows_session_change_observer_.reset(nullptr); delegate_->HandleDestroying(); + // If the window going away is a fullscreen window then remove its references + // from the full screen window map. + for (auto iter = fullscreen_monitor_map_.Get().begin(); + iter != fullscreen_monitor_map_.Get().end(); + iter++) { + if (iter->second == this) { + fullscreen_monitor_map_.Get().erase(iter); + break; + } + } } void HWNDMessageHandler::OnDisplayChange(UINT bits_per_pixel, @@ -1401,14 +1432,17 @@ void HWNDMessageHandler::OnExitSizeMove() { // trackpoint drivers. if (in_size_loop_ && needs_scroll_styles_) AddScrollStylesToWindow(hwnd()); + // If the window was moved to a monitor which has a fullscreen window active, + // we need to reduce the size of the fullscreen window by 1px. + CheckAndHandleBackgroundFullscreenOnMonitor(hwnd()); } void HWNDMessageHandler::OnGetMinMaxInfo(MINMAXINFO* minmax_info) { gfx::Size min_window_size; gfx::Size max_window_size; delegate_->GetMinMaxSize(&min_window_size, &max_window_size); - min_window_size = gfx::win::DIPToScreenSize(min_window_size); - max_window_size = gfx::win::DIPToScreenSize(max_window_size); + min_window_size = delegate_->DIPToScreenSize(min_window_size); + max_window_size = delegate_->DIPToScreenSize(max_window_size); // Add the native frame border size to the minimum and maximum size if the @@ -1562,6 +1596,29 @@ LRESULT HWNDMessageHandler::OnMouseRange(UINT message, return HandleMouseEventInternal(message, w_param, l_param, true); } +// On some systems with a high-resolution track pad and running Windows 10, +// using the scrolling gesture (two-finger scroll) on the track pad +// causes it to also generate a WM_POINTERDOWN message if the window +// isn't focused. This leads to a WM_POINTERACTIVATE message and the window +// gaining focus and coming to the front. This code detects a +// WM_POINTERACTIVATE coming from the track pad and kills the activation +// of the window. NOTE: most other trackpad messages come in as mouse +// messages, including WM_MOUSEWHEEL instead of WM_POINTERWHEEL. +LRESULT HWNDMessageHandler::OnPointerActivate(UINT message, + WPARAM w_param, + LPARAM l_param) { + using GetPointerTypeFn = BOOL(WINAPI*)(UINT32, POINTER_INPUT_TYPE*); + UINT32 pointer_id = GET_POINTERID_WPARAM(w_param); + POINTER_INPUT_TYPE pointer_type; + static GetPointerTypeFn get_pointer_type = reinterpret_cast<GetPointerTypeFn>( + GetProcAddress(GetModuleHandleA("user32.dll"), "GetPointerType")); + if (get_pointer_type && get_pointer_type(pointer_id, &pointer_type) && + pointer_type == PT_TOUCHPAD) + return PA_NOACTIVATE; + SetMsgHandled(FALSE); + return -1; +} + void HWNDMessageHandler::OnMove(const gfx::Point& point) { delegate_->HandleMove(); SetMsgHandled(FALSE); @@ -1725,6 +1782,21 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const gfx::Point& point) { return 0; } + // Some views may overlap the non client area of the window. + // This means that we should look for these views before handing the + // hittest message off to DWM or DefWindowProc. + // If the hittest returned from the search for a view returns HTCLIENT + // then it means that we have a view overlapping the non client area. + // In all other cases we can fallback to the system default handling. + + // Allow the NonClientView to handle the hittest to see if we have a view + // overlapping the non client area of the window. + POINT temp = { point.x(), point.y() }; + MapWindowPoints(HWND_DESKTOP, hwnd(), &temp, 1); + int component = delegate_->GetNonClientComponent(gfx::Point(temp)); + if (component == HTCLIENT) + return component; + // If the DWM is rendering the window controls, we need to give the DWM's // default window procedure first chance to handle hit testing. if (HasSystemFrame()) { @@ -1735,11 +1807,7 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const gfx::Point& point) { } } - // First, give the NonClientView a chance to test the point to see if it - // provides any of the non-client area. - POINT temp = { point.x(), point.y() }; - MapWindowPoints(HWND_DESKTOP, hwnd(), &temp, 1); - int component = delegate_->GetNonClientComponent(gfx::Point(temp)); + // If the point is specified as custom or system nonclient item, return it. if (component != HTNOWHERE) return component; @@ -2123,7 +2191,7 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, LPARAM l_param) { // Handle touch events only on Aura for now. int num_points = LOWORD(w_param); - scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]); + std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]); if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), num_points, input.get(), sizeof(TOUCHINPUT))) { @@ -2653,5 +2721,29 @@ void HWNDMessageHandler::SetBoundsInternal(const gfx::Rect& bounds_in_pixels, direct_manipulation_helper_->SetBounds(bounds_in_pixels); } +void HWNDMessageHandler::CheckAndHandleBackgroundFullscreenOnMonitor( + HWND window) { + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); + + FullscreenWindowMonitorMap::iterator iter = + fullscreen_monitor_map_.Get().find(monitor); + if (iter != fullscreen_monitor_map_.Get().end()) { + DCHECK(iter->second); + if (window != iter->second->hwnd()) + iter->second->OnBackgroundFullscreen(); + } +} + +void HWNDMessageHandler::OnBackgroundFullscreen() { + // Reduce the bounds of the window by 1px to ensure that Windows does + // not treat this like a fullscreen window. + MONITORINFO monitor_info = {sizeof(monitor_info)}; + GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY), + &monitor_info); + gfx::Rect shrunk_rect(monitor_info.rcMonitor); + shrunk_rect.set_height(shrunk_rect.height() - 1); + background_fullscreen_hack_ = true; + SetBoundsInternal(shrunk_rect, false); +} } // namespace views diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h index 143b1c61fec..f011864177c 100644 --- a/chromium/ui/views/win/hwnd_message_handler.h +++ b/chromium/ui/views/win/hwnd_message_handler.h @@ -6,14 +6,16 @@ #define UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_ #include <windows.h> -#include <stddef.h> +#include <stddef.h> +#include <map> +#include <memory> #include <set> #include <vector> #include "base/compiler_specific.h" +#include "base/lazy_instance.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/win/scoped_gdi_object.h" @@ -337,6 +339,9 @@ class VIEWS_EXPORT HWNDMessageHandler : CR_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseRange) CR_MESSAGE_HANDLER_EX(WM_SETCURSOR, OnSetCursor); + // Pointer events. + CR_MESSAGE_HANDLER_EX(WM_POINTERACTIVATE, OnPointerActivate) + // Key events. CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent) CR_MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent) @@ -432,6 +437,7 @@ class VIEWS_EXPORT HWNDMessageHandler : void OnKillFocus(HWND focused_window); LRESULT OnMouseActivate(UINT message, WPARAM w_param, LPARAM l_param); LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param); + LRESULT OnPointerActivate(UINT message, WPARAM w_param, LPARAM l_param); void OnMove(const gfx::Point& point); void OnMoving(UINT param, const RECT* new_bounds); LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param); @@ -513,9 +519,19 @@ class VIEWS_EXPORT HWNDMessageHandler : void SetBoundsInternal(const gfx::Rect& bounds_in_pixels, bool force_size_changed); + // Checks if there is a full screen window on the same monitor as the + // |window| which is becoming active. If yes then we reduce the size of the + // fullscreen window by 1 px to ensure that maximized windows on the same + // monitor don't draw over the taskbar. + void CheckAndHandleBackgroundFullscreenOnMonitor(HWND window); + + // Provides functionality to reduce the bounds of the fullscreen window by 1 + // px on activation loss to a window on the same monitor. + void OnBackgroundFullscreen(); + HWNDMessageHandlerDelegate* delegate_; - scoped_ptr<FullscreenHandler> fullscreen_handler_; + std::unique_ptr<FullscreenHandler> fullscreen_handler_; // Set to true in Close() and false is CloseNow(). bool waiting_for_close_now_; @@ -591,7 +607,7 @@ class VIEWS_EXPORT HWNDMessageHandler : // Stores a pointer to the WindowEventTarget interface implemented by this // class. Allows callers to retrieve the interface pointer. - scoped_ptr<ui::ViewProp> prop_window_target_; + std::unique_ptr<ui::ViewProp> prop_window_target_; // Number of active touch down contexts. This is incremented on touch down // events and decremented later using a delayed task. @@ -623,12 +639,14 @@ class VIEWS_EXPORT HWNDMessageHandler : bool sent_window_size_changing_; // Manages observation of Windows Session Change messages. - scoped_ptr<WindowsSessionChangeObserver> windows_session_change_observer_; + std::unique_ptr<WindowsSessionChangeObserver> + windows_session_change_observer_; // This class provides functionality to register the legacy window as a // Direct Manipulation consumer. This allows us to support smooth scroll // in Chrome on Windows 10. - scoped_ptr<gfx::win::DirectManipulationHelper> direct_manipulation_helper_; + std::unique_ptr<gfx::win::DirectManipulationHelper> + direct_manipulation_helper_; // The location where the user clicked on the caption. We cache this when we // receive the WM_NCLBUTTONDOWN message. We use this in the subsequent @@ -645,6 +663,12 @@ class VIEWS_EXPORT HWNDMessageHandler : // fullscreen window which lost activation. Defaults to false. bool background_fullscreen_hack_; + // This is a map of the HMONITOR to full screeen window instance. It is safe + // to keep a raw pointer to the HWNDMessageHandler instance as we track the + // window destruction and ensure that the map is cleaned up. + using FullscreenWindowMonitorMap = std::map<HMONITOR, HWNDMessageHandler*>; + static base::LazyInstance<FullscreenWindowMonitorMap> fullscreen_monitor_map_; + // The WeakPtrFactories below must occur last in the class definition so they // get destroyed last. diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h index 007157aefe8..631f3592b8c 100644 --- a/chromium/ui/views/win/hwnd_message_handler_delegate.h +++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h @@ -89,6 +89,8 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { // Returns the current size of the RootView. virtual gfx::Size GetRootViewSize() const = 0; + virtual gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const = 0; + virtual void ResetWindowControls() = 0; virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0; diff --git a/chromium/ui/views/win/windows_session_change_observer.cc b/chromium/ui/views/win/windows_session_change_observer.cc index 6d230d6edd0..ddbb3191ae3 100644 --- a/chromium/ui/views/win/windows_session_change_observer.cc +++ b/chromium/ui/views/win/windows_session_change_observer.cc @@ -6,13 +6,14 @@ #include <wtsapi32.h> +#include <memory> + #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" #include "base/location.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" #include "base/observer_list.h" #include "base/task_runner.h" @@ -101,7 +102,7 @@ class WindowsSessionChangeObserver::WtsRegistrationNotificationManager { } base::ObserverList<WindowsSessionChangeObserver, true> observer_list_; - scoped_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_; + std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_; DISALLOW_COPY_AND_ASSIGN(WtsRegistrationNotificationManager); }; diff --git a/chromium/ui/views/window/custom_frame_view.h b/chromium/ui/views/window/custom_frame_view.h index db77648a273..8869bef4aa3 100644 --- a/chromium/ui/views/window/custom_frame_view.h +++ b/chromium/ui/views/window/custom_frame_view.h @@ -5,9 +5,10 @@ #ifndef UI_VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_ #define UI_VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/memory/scoped_ptr.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/button.h" #include "ui/views/window/frame_buttons.h" @@ -144,7 +145,7 @@ class VIEWS_EXPORT CustomFrameView : public NonClientFrameView, ImageButton* close_button_; // Background painter for the window frame. - scoped_ptr<FrameBackground> frame_background_; + std::unique_ptr<FrameBackground> frame_background_; // The horizontal boundaries for the title bar to layout within. Restricted // by the space used by the leading and trailing buttons. diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc index 1d5c1f25205..55bf0047508 100644 --- a/chromium/ui/views/window/dialog_client_view.cc +++ b/chromium/ui/views/window/dialog_client_view.cc @@ -7,10 +7,12 @@ #include <algorithm> #include "build/build_config.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/views/background.h" #include "ui/views/controls/button/blue_button.h" #include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/md_text_button.h" #include "ui/views/layout/layout_constants.h" #include "ui/views/widget/widget.h" #include "ui/views/window/dialog_delegate.h" @@ -58,9 +60,9 @@ DialogClientView::DialogClientView(Widget* owner, View* contents_view) kButtonHEdgeMarginNew, kButtonVEdgeMarginNew, kButtonHEdgeMarginNew), - ok_button_(NULL), - cancel_button_(NULL), - extra_view_(NULL), + ok_button_(nullptr), + cancel_button_(nullptr), + extra_view_(nullptr), delegate_allowed_close_(false) { // Doing this now ensures this accelerator will have lower priority than // one set by the contents view. @@ -98,7 +100,7 @@ void DialogClientView::UpdateDialogButtons() { GetDialogDelegate()->UpdateButton(ok_button_, ui::DIALOG_BUTTON_OK); } else if (ok_button_) { delete ok_button_; - ok_button_ = NULL; + ok_button_ = nullptr; } if (buttons & ui::DIALOG_BUTTON_CANCEL) { @@ -110,7 +112,7 @@ void DialogClientView::UpdateDialogButtons() { GetDialogDelegate()->UpdateButton(cancel_button_, ui::DIALOG_BUTTON_CANCEL); } else if (cancel_button_) { delete cancel_button_; - cancel_button_ = NULL; + cancel_button_ = nullptr; } SetupFocusChain(); @@ -238,7 +240,7 @@ void DialogClientView::OnNativeThemeChanged(const ui::NativeTheme* theme) { // dialog style simply inherits the bubble's frame view color. const DialogDelegate* dialog = GetDialogDelegate(); - if (dialog && !dialog->UseNewStyleForThisDialog()) { + if (dialog && !dialog->ShouldUseCustomFrame()) { set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> GetSystemColor(ui::NativeTheme::kColorId_DialogBackground))); } @@ -264,10 +266,10 @@ void DialogClientView::ButtonPressed(Button* sender, const ui::Event& event) { // DialogClientView, protected: DialogClientView::DialogClientView(View* contents_view) - : ClientView(NULL, contents_view), - ok_button_(NULL), - cancel_button_(NULL), - extra_view_(NULL), + : ClientView(nullptr, contents_view), + ok_button_(nullptr), + cancel_button_(nullptr), + extra_view_(nullptr), delegate_allowed_close_(false) {} DialogDelegate* DialogClientView::GetDialogDelegate() const { @@ -300,16 +302,13 @@ void DialogClientView::ChildVisibilityChanged(View* child) { LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) { const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type); - LabelButton* button = NULL; - if (GetDialogDelegate()->UseNewStyleForThisDialog() && - GetDialogDelegate()->GetDefaultDialogButton() == type && + LabelButton* button = nullptr; + if (GetDialogDelegate()->GetDefaultDialogButton() == type && GetDialogDelegate()->ShouldDefaultButtonBeBlue()) { - button = new BlueButton(this, title); + return MdTextButton::CreateSecondaryUiBlueButton(this, title); } else { - button = new LabelButton(this, title); - button->SetStyle(Button::STYLE_BUTTON); + button = MdTextButton::CreateSecondaryUiButton(this, title); } - button->SetFocusable(true); const int kDialogMinButtonWidth = 75; button->SetMinSize(gfx::Size(kDialogMinButtonWidth, 0)); diff --git a/chromium/ui/views/window/dialog_client_view_unittest.cc b/chromium/ui/views/window/dialog_client_view_unittest.cc index 9078aba9f17..c483d254af3 100644 --- a/chromium/ui/views/window/dialog_client_view_unittest.cc +++ b/chromium/ui/views/window/dialog_client_view_unittest.cc @@ -110,11 +110,11 @@ class DialogClientViewTest : public ViewsTestBase, private: // The DialogClientView that's being tested. - scoped_ptr<TestDialogClientView> client_view_; + std::unique_ptr<TestDialogClientView> client_view_; // The bitmask of buttons to show in the dialog. int dialog_buttons_; View* extra_view_; // weak - scoped_ptr<int> extra_view_padding_; // Null by default. + std::unique_ptr<int> extra_view_padding_; // Null by default. DISALLOW_COPY_AND_ASSIGN(DialogClientViewTest); }; diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc index 84ed6b9fc2e..d2271142430 100644 --- a/chromium/ui/views/window/dialog_delegate.cc +++ b/chromium/ui/views/window/dialog_delegate.cc @@ -29,7 +29,7 @@ namespace views { //////////////////////////////////////////////////////////////////////////////// // DialogDelegate: -DialogDelegate::DialogDelegate() : supports_new_style_(true) {} +DialogDelegate::DialogDelegate() : supports_custom_frame_(true) {} DialogDelegate::~DialogDelegate() {} @@ -54,14 +54,14 @@ Widget* DialogDelegate::CreateDialogWidgetWithBounds(WidgetDelegate* delegate, #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // The new style doesn't support unparented dialogs on Linux desktop. if (dialog) - dialog->supports_new_style_ &= parent != NULL; + dialog->supports_custom_frame_ &= parent != NULL; #elif defined(OS_WIN) // The new style doesn't support unparented dialogs on Windows Classic themes. if (dialog && !ui::win::IsAeroGlassEnabled()) - dialog->supports_new_style_ &= parent != NULL; + dialog->supports_custom_frame_ &= parent != NULL; #endif - if (!dialog || dialog->UseNewStyleForThisDialog()) { + if (!dialog || dialog->ShouldUseCustomFrame()) { params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; params.remove_standard_frame = true; #if !defined(OS_MACOSX) @@ -181,7 +181,7 @@ ClientView* DialogDelegate::CreateClientView(Widget* widget) { } NonClientFrameView* DialogDelegate::CreateNonClientFrameView(Widget* widget) { - if (UseNewStyleForThisDialog()) + if (ShouldUseCustomFrame()) return CreateDialogFrameView(widget); return WidgetDelegate::CreateNonClientFrameView(widget); } @@ -193,7 +193,7 @@ NonClientFrameView* DialogDelegate::CreateDialogFrameView(Widget* widget) { 0, kButtonHEdgeMarginNew), gfx::Insets()); const BubbleBorder::Shadow kShadow = BubbleBorder::SMALL_SHADOW; - scoped_ptr<BubbleBorder> border( + std::unique_ptr<BubbleBorder> border( new BubbleBorder(BubbleBorder::FLOAT, kShadow, gfx::kPlaceholderColor)); border->set_use_theme_background_color(true); frame->SetBubbleBorder(std::move(border)); @@ -203,8 +203,8 @@ NonClientFrameView* DialogDelegate::CreateDialogFrameView(Widget* widget) { return frame; } -bool DialogDelegate::UseNewStyleForThisDialog() const { - return supports_new_style_; +bool DialogDelegate::ShouldUseCustomFrame() const { + return supports_custom_frame_; } const DialogClientView* DialogDelegate::GetDialogClientView() const { diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h index 06c9bbe6b93..b6532dc44bc 100644 --- a/chromium/ui/views/window/dialog_delegate.h +++ b/chromium/ui/views/window/dialog_delegate.h @@ -102,8 +102,10 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel, // Create a frame view using the new dialog style. static NonClientFrameView* CreateDialogFrameView(Widget* widget); - // Returns whether this particular dialog should use the new dialog style. - virtual bool UseNewStyleForThisDialog() const; + // Returns true if this particular dialog should use a Chrome-styled frame + // like the one used for bubbles. The alternative is a more platform-native + // frame. + virtual bool ShouldUseCustomFrame() const; // A helper for accessing the DialogClientView object contained by this // delegate's Window. @@ -115,8 +117,9 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel, ui::AXRole GetAccessibleWindowRole() const override; private: - // A flag indicating whether this dialog supports the new style. - bool supports_new_style_; + // A flag indicating whether this dialog is able to use the custom frame + // style for dialogs. + bool supports_custom_frame_; }; // A DialogDelegate implementation that is-a View. Used to override GetWidget() diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc index 8dd6e231cf0..648175d8d23 100644 --- a/chromium/ui/views/window/dialog_delegate_unittest.cc +++ b/chromium/ui/views/window/dialog_delegate_unittest.cc @@ -70,7 +70,7 @@ class TestDialog : public DialogDelegateView, public ButtonListener { } base::string16 GetWindowTitle() const override { return title_; } View* GetInitiallyFocusedView() override { return input_; } - bool UseNewStyleForThisDialog() const override { return true; } + bool ShouldUseCustomFrame() const override { return true; } // ButtonListener override: void ButtonPressed(Button* sender, const ui::Event& event) override { diff --git a/chromium/ui/views/window/non_client_view.cc b/chromium/ui/views/window/non_client_view.cc index a6d38a24f4c..1cb6bc374c0 100644 --- a/chromium/ui/views/window/non_client_view.cc +++ b/chromium/ui/views/window/non_client_view.cc @@ -43,9 +43,10 @@ bool NonClientFrameView::GetClientMask(const gfx::Size& size, NonClientView::NonClientView() : client_view_(nullptr), + mirror_client_in_rtl_(true), overlay_view_(nullptr) { SetEventTargeter( - scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); + std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); } NonClientView::~NonClientView() { @@ -165,7 +166,14 @@ void NonClientView::Layout() { LayoutFrameView(); // Then layout the ClientView, using those bounds. - client_view_->SetBoundsRect(frame_view_->GetBoundsForClientView()); + gfx::Rect client_bounds = frame_view_->GetBoundsForClientView(); + + // RTL code will mirror the ClientView in the frame by default. If this isn't + // desired, do a second mirror here to get the standard LTR position. + if (base::i18n::IsRTL() && !mirror_client_in_rtl_) + client_bounds.set_x(GetMirroredXForRect(client_bounds)); + + client_view_->SetBoundsRect(client_bounds); gfx::Path client_clip; if (frame_view_->GetClientMask(client_view_->size(), &client_clip)) @@ -324,7 +332,7 @@ const char* NonClientFrameView::GetClassName() const { NonClientFrameView::NonClientFrameView() : active_state_override_(nullptr) { SetEventTargeter( - scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); + std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); } // ViewTargeterDelegate: diff --git a/chromium/ui/views/window/non_client_view.h b/chromium/ui/views/window/non_client_view.h index 40000243b30..74209869f26 100644 --- a/chromium/ui/views/window/non_client_view.h +++ b/chromium/ui/views/window/non_client_view.h @@ -220,6 +220,8 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate { client_view_ = client_view; } + void set_mirror_client_in_rtl(bool mirror) { mirror_client_in_rtl_ = mirror; } + // Layout just the frame view. This is necessary on Windows when non-client // metrics such as the position of the window controls changes independently // of a window resize message. @@ -252,10 +254,13 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate { // implementation. ClientView* client_view_; + // Set to false if client_view_ position shouldn't be mirrored in RTL. + bool mirror_client_in_rtl_; + // The NonClientFrameView that renders the non-client portions of the window. // This object is not owned by the view hierarchy because it can be replaced // dynamically as the system settings change. - scoped_ptr<NonClientFrameView> frame_view_; + std::unique_ptr<NonClientFrameView> frame_view_; // The overlay view, when non-NULL and visible, takes up the entire widget and // is placed on top of the ClientView and NonClientFrameView. |