diff options
author | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-25 21:19:20 +0000 |
---|---|---|
committer | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-25 21:19:20 +0000 |
commit | 534236bc91432c5d4c18e0c07477399d0e6aa928 (patch) | |
tree | 893800b3abc4f838f33630a7443f42a8d8053ac6 | |
parent | e3e6f91a6234c552eaa915a2c6e1cab9f28d4dd7 (diff) | |
download | chromium_src-534236bc91432c5d4c18e0c07477399d0e6aa928.zip chromium_src-534236bc91432c5d4c18e0c07477399d0e6aa928.tar.gz chromium_src-534236bc91432c5d4c18e0c07477399d0e6aa928.tar.bz2 |
Implement new overlay scrollbar specs
Make overlay scrollbars thicken only on mouse movement (not scrolling).
Keep the bars thick as long as the mouse is near them.
Thicken and darken the bars through an animation.
Make the distance to thicken the bars 25 dips (instead of 100).
BUG=299046,274010
R=enne@chromium.org, enne, tony
Review URL: https://codereview.chromium.org/40603006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231118 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/animation/scrollbar_animation_controller_thinning.cc | 123 | ||||
-rw-r--r-- | cc/animation/scrollbar_animation_controller_thinning.h | 24 | ||||
-rw-r--r-- | cc/animation/scrollbar_animation_controller_thinning_unittest.cc | 212 | ||||
-rw-r--r-- | cc/layers/scrollbar_layer_impl_base.cc | 7 | ||||
-rw-r--r-- | cc/layers/scrollbar_layer_impl_base.h | 4 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl.cc | 11 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl_unittest.cc | 11 |
7 files changed, 286 insertions, 106 deletions
diff --git a/cc/animation/scrollbar_animation_controller_thinning.cc b/cc/animation/scrollbar_animation_controller_thinning.cc index ce196fb..3de7598 100644 --- a/cc/animation/scrollbar_animation_controller_thinning.cc +++ b/cc/animation/scrollbar_animation_controller_thinning.cc @@ -10,14 +10,22 @@ #include "cc/layers/layer_impl.h" #include "cc/layers/scrollbar_layer_impl_base.h" +namespace { +const float kIdleThicknessScale = 0.4f; +const float kIdleOpacity = 0.7f; +const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f; +const int kDefaultAnimationDelay = 500; +const int kDefaultAnimationDuration = 300; +} + namespace cc { scoped_ptr<ScrollbarAnimationControllerThinning> ScrollbarAnimationControllerThinning::Create(LayerImpl* scroll_layer) { return make_scoped_ptr(new ScrollbarAnimationControllerThinning( scroll_layer, - base::TimeDelta::FromMilliseconds(500), - base::TimeDelta::FromMilliseconds(300))); + base::TimeDelta::FromMilliseconds(kDefaultAnimationDelay), + base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration))); } scoped_ptr<ScrollbarAnimationControllerThinning> @@ -33,11 +41,17 @@ ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning( base::TimeDelta animation_duration) : ScrollbarAnimationController(), scroll_layer_(scroll_layer), - scroll_gesture_in_progress_(false), mouse_is_over_scrollbar_(false), + mouse_is_near_scrollbar_(false), + thickness_change_(NONE), + opacity_change_(NONE), + should_delay_animation_(false), animation_delay_(animation_delay), animation_duration_(animation_duration), - mouse_move_distance_to_trigger_animation_(100.f) {} + mouse_move_distance_to_trigger_animation_( + kDefaultMouseMoveDistanceToTriggerAnimation) { + ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale); +} ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() { } @@ -48,92 +62,120 @@ bool ScrollbarAnimationControllerThinning::IsAnimating() const { base::TimeDelta ScrollbarAnimationControllerThinning::DelayBeforeStart( base::TimeTicks now) const { + if (!should_delay_animation_) + return base::TimeDelta(); if (now > last_awaken_time_ + animation_delay_) return base::TimeDelta(); return animation_delay_ - (now - last_awaken_time_); } bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) { - if (mouse_is_over_scrollbar_) { - ApplyOpacityAndThumbThicknessScale(1, 1); - return false; - } float progress = AnimationProgressAtTime(now); float opacity = OpacityAtAnimationProgress(progress); float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress( progress); ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale); - if (progress == 1.f) + if (progress == 1.f) { + opacity_change_ = NONE; + thickness_change_ = NONE; last_awaken_time_ = base::TimeTicks(); + } return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta(); } void ScrollbarAnimationControllerThinning::DidScrollGestureBegin() { - ApplyOpacityAndThumbThicknessScale(1, 1); - last_awaken_time_ = base::TimeTicks(); - scroll_gesture_in_progress_ = true; } void ScrollbarAnimationControllerThinning::DidScrollGestureEnd( base::TimeTicks now) { - last_awaken_time_ = now; - scroll_gesture_in_progress_ = false; } void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar( base::TimeTicks now) { mouse_is_over_scrollbar_ = false; - DidScrollUpdate(now); + mouse_is_near_scrollbar_ = false; + last_awaken_time_ = now; + should_delay_animation_ = false; + opacity_change_ = DECREASE; + thickness_change_ = DECREASE; } bool ScrollbarAnimationControllerThinning::DidScrollUpdate( base::TimeTicks now) { - ApplyOpacityAndThumbThicknessScale(1, 1); + ApplyOpacityAndThumbThicknessScale( + 1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale); last_awaken_time_ = now; + should_delay_animation_ = true; + if (!mouse_is_over_scrollbar_) + opacity_change_ = DECREASE; return true; } bool ScrollbarAnimationControllerThinning::DidMouseMoveNear( base::TimeTicks now, float distance) { - if (distance == 0.0) { - mouse_is_over_scrollbar_ = true; + bool mouse_is_over_scrollbar = distance == 0.0; + bool mouse_is_near_scrollbar = + distance < mouse_move_distance_to_trigger_animation_; + + if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ && + mouse_is_near_scrollbar == mouse_is_near_scrollbar_) return false; + + if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) { + mouse_is_over_scrollbar_ = mouse_is_over_scrollbar; + opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE; } - if (distance < mouse_move_distance_to_trigger_animation_) - return DidScrollUpdate(now); + if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) { + mouse_is_near_scrollbar_ = mouse_is_near_scrollbar; + thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE; + } - return false; + last_awaken_time_ = now; + should_delay_animation_ = false; + return true; } float ScrollbarAnimationControllerThinning::AnimationProgressAtTime( base::TimeTicks now) { - if (scroll_gesture_in_progress_) - return 0; - if (last_awaken_time_.is_null()) return 1; base::TimeDelta delta = now - last_awaken_time_; - float progress = (delta - animation_delay_).InSecondsF() / - animation_duration_.InSecondsF(); + if (should_delay_animation_) + delta -= animation_delay_; + float progress = delta.InSecondsF() / animation_duration_.InSecondsF(); return std::max(std::min(progress, 1.f), 0.f); } float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress( float progress) { - const float kIdleOpacity = 0.7f; - - return ((1.f - kIdleOpacity) * (1.f - progress)) + kIdleOpacity; + if (opacity_change_ == NONE) + return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity; + float factor = opacity_change_ == INCREASE ? progress : (1.f - progress); + float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity; + return ret; } float ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress( float progress) { - const float kIdleThicknessScale = 0.4f; + if (thickness_change_ == NONE) + return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale; + float factor = thickness_change_ == INCREASE ? progress : (1.f - progress); + return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale; +} - return ((1.f - kIdleThicknessScale) * (1.f - progress)) + kIdleThicknessScale; +float ScrollbarAnimationControllerThinning::AdjustScale( + float new_value, + float current_value, + AnimationChange animation_change) { + if (animation_change == INCREASE && current_value > new_value) + return current_value; + if (animation_change == DECREASE && current_value < new_value) + return current_value; + return new_value; } void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( @@ -141,16 +183,25 @@ void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( ScrollbarLayerImplBase* horizontal_scrollbar = scroll_layer_->horizontal_scrollbar_layer(); if (horizontal_scrollbar) { - horizontal_scrollbar->SetOpacity(opacity); - horizontal_scrollbar->set_thumb_thickness_scale_factor( - thumb_thickness_scale); + horizontal_scrollbar->SetOpacity( + AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_)); + horizontal_scrollbar->SetThumbThicknessScaleFactor( + AdjustScale( + thumb_thickness_scale, + horizontal_scrollbar->thumb_thickness_scale_factor(), + thickness_change_)); } ScrollbarLayerImplBase* vertical_scrollbar = scroll_layer_->vertical_scrollbar_layer(); if (vertical_scrollbar) { - vertical_scrollbar->SetOpacity(opacity); - vertical_scrollbar->set_thumb_thickness_scale_factor(thumb_thickness_scale); + vertical_scrollbar->SetOpacity( + AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_)); + vertical_scrollbar->SetThumbThicknessScaleFactor( + AdjustScale( + thumb_thickness_scale, + vertical_scrollbar->thumb_thickness_scale_factor(), + thickness_change_)); } } diff --git a/cc/animation/scrollbar_animation_controller_thinning.h b/cc/animation/scrollbar_animation_controller_thinning.h index 8038745..07b4515 100644 --- a/cc/animation/scrollbar_animation_controller_thinning.h +++ b/cc/animation/scrollbar_animation_controller_thinning.h @@ -29,6 +29,8 @@ class CC_EXPORT ScrollbarAnimationControllerThinning void set_mouse_move_distance_for_test(float distance) { mouse_move_distance_to_trigger_animation_ = distance; } + bool mouse_is_over_scrollbar() const { return mouse_is_over_scrollbar_; } + bool mouse_is_near_scrollbar() const { return mouse_is_near_scrollbar_; } // ScrollbarAnimationController overrides. virtual bool IsAnimating() const OVERRIDE; @@ -47,22 +49,40 @@ class CC_EXPORT ScrollbarAnimationControllerThinning base::TimeDelta animation_duration); private: + // Describes whether the current animation should INCREASE (darken / thicken) + // a bar or DECREASE it (lighten / thin). + enum AnimationChange { + NONE, + INCREASE, + DECREASE + }; // Returns how far through the animation we are as a progress value from // 0 to 1. float AnimationProgressAtTime(base::TimeTicks now); float OpacityAtAnimationProgress(float progress); float ThumbThicknessScaleAtAnimationProgress(float progress); + float AdjustScale(float new_value, + float current_value, + AnimationChange animation_change); void ApplyOpacityAndThumbThicknessScale(float opacity, float thumb_thickness_scale); LayerImpl* scroll_layer_; base::TimeTicks last_awaken_time_; - bool scroll_gesture_in_progress_; bool mouse_is_over_scrollbar_; - + bool mouse_is_near_scrollbar_; + // Are we narrowing or thickening the bars. + AnimationChange thickness_change_; + // Are we darkening or lightening the bars. + AnimationChange opacity_change_; + // Should the animation be delayed or start immediately. + bool should_delay_animation_; + // If |should_delay_animation_| is true, delay the animation by this amount. base::TimeDelta animation_delay_; + // The time for the animation to run. base::TimeDelta animation_duration_; + // How close should the mouse be to the scrollbar before we thicken it. float mouse_move_distance_to_trigger_animation_; DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerThinning); diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc index 7bb5076..c915632 100644 --- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc +++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc @@ -43,128 +43,194 @@ class ScrollbarAnimationControllerThinningTest : public testing::Test { scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_; }; +// Check initialization of scrollbar. TEST_F(ScrollbarAnimationControllerThinningTest, Idle) { scrollbar_controller_->Animate(base::TimeTicks()); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); } -TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByScrollGesture) { +// Scroll content. Confirm the scrollbar gets dark and then becomes light +// after stopping. +TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->DidScrollGestureBegin(); - EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + // Scrollbar doesn't change size if triggered by scroll. + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - time += base::TimeDelta::FromSeconds(100); + time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - scrollbar_controller_->DidScrollGestureEnd(time); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + // Subsequent scroll restarts animation. + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); - scrollbar_controller_->DidScrollGestureBegin(); - scrollbar_controller_->DidScrollGestureEnd(time); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); +} +// Initiate a scroll when the pointer is already near the scrollbar. It should +// remain thick. +TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) { + base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); + + scrollbar_controller_->DidMouseMoveNear(time, 1); + time += base::TimeDelta::FromSeconds(3); scrollbar_controller_->Animate(time); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + + EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + // Scrollbar should still be thick. EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - time += base::TimeDelta::FromSeconds(1); + time += base::TimeDelta::FromSeconds(5); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); +} +// Move the pointer near the scrollbar. Confirm it gets thick and narrow when +// moved away. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) { + base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + scrollbar_controller_->DidMouseMoveNear(time, 1); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + // Should animate to thickened but not darken. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); -} + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); -TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { - base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); - EXPECT_TRUE(scrollbar_controller_->IsAnimating()); - EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + // Subsequent moves should not change anything. + scrollbar_controller_->DidMouseMoveNear(time, 1); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // Now move away from bar. time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + scrollbar_controller_->DidMouseMoveNear(time, 26); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + // Animate to narrow. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); +} +// Move the pointer over the scrollbar. Make sure it gets thick and dark +// and that it gets thin and light when moved away. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) { + base::TimeTicks time; + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->DidMouseMoveNear(time, 0); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Should animate to thickened and darkened. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + scrollbar_controller_->Animate(time); + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + + // Subsequent moves should not change anything. + scrollbar_controller_->DidMouseMoveNear(time, 0); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + // Now move away from bar. time += base::TimeDelta::FromSeconds(1); - scrollbar_controller_->Animate(time); + scrollbar_controller_->DidMouseMoveNear(time, 26); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + // Animate to narrow. time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); @@ -179,47 +245,87 @@ TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) { scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); } -TEST_F(ScrollbarAnimationControllerThinningTest, MouseOverAndOut) { +// First move the pointer near the scrollbar, then over it, then back near +// then far away. Confirm that first the bar gets thick, then dark, then light, +// then narrow. +TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) { base::TimeTicks time; time += base::TimeDelta::FromSeconds(1); - EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time)); + scrollbar_controller_->DidMouseMoveNear(time, 1); EXPECT_TRUE(scrollbar_controller_->IsAnimating()); - EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + + // Should animate to thickened but not darken. + time += base::TimeDelta::FromSeconds(3); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); - time += base::TimeDelta::FromSeconds(4); + // Now move over. + scrollbar_controller_->DidMouseMoveNear(time, 0); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds()); + + // Should animate to darkened. + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - scrollbar_controller_->DidMouseMoveNear(time, 0); + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); - time += base::TimeDelta::FromSeconds(4); + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FALSE(scrollbar_controller_->IsAnimating()); + // This is tricky. The DidMouseMoveOffScrollbar() is sent before the + // subsequent DidMouseMoveNear(), if the mouse moves in that direction. + // This results in the thumb thinning. We want to make sure that when the + // thumb starts expanding it doesn't first narrow to the idle thinness. + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->DidMouseMoveOffScrollbar(time); + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); - time += base::TimeDelta::FromSeconds(4); + scrollbar_controller_->DidMouseMoveNear(time, 1); + // A new animation is kicked off. + EXPECT_TRUE(scrollbar_controller_->IsAnimating()); + + time += base::TimeDelta::FromSeconds(1); + scrollbar_controller_->Animate(time); + // We will initiate the narrowing again, but it won't get decremented until + // the new animation catches up to it. + EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity()); + // Now the thickness should be increasing, but it shouldn't happen until the + // animation catches up. + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); + + time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor()); + // The thickness now gets big again. + EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor()); time += base::TimeDelta::FromSeconds(1); scrollbar_controller_->Animate(time); EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity()); - EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor()); + // The thickness now gets big again. + EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor()); } } // namespace diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc index c1e7126..362465b 100644 --- a/cc/layers/scrollbar_layer_impl_base.cc +++ b/cc/layers/scrollbar_layer_impl_base.cc @@ -72,6 +72,13 @@ void ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) { NoteLayerPropertyChanged(); } +void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) { + if (thumb_thickness_scale_factor_ == factor) + return; + thumb_thickness_scale_factor_ = factor; + NoteLayerPropertyChanged(); +} + gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const { // Thumb extent is the length of the thumb in the scrolling direction, thumb // thickness is in the perpendicular direction. Here's an example of a diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h index 55ade6a..360ef97 100644 --- a/cc/layers/scrollbar_layer_impl_base.h +++ b/cc/layers/scrollbar_layer_impl_base.h @@ -44,9 +44,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { float thumb_thickness_scale_factor() { return thumb_thickness_scale_factor_; } - void set_thumb_thickness_scale_factor(float thumb_thickness_scale_factor) { - thumb_thickness_scale_factor_ = thumb_thickness_scale_factor; - } + void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor); protected: ScrollbarLayerImplBase(LayerTreeImpl* tree_impl, diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index aa03b20..56e2042 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -2341,10 +2341,8 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) { bool should_animate = animation_controller->DidMouseMoveNear( CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_); - if (should_animate) { - client_->SetNeedsRedrawOnImplThread(); + if (should_animate) StartScrollbarAnimation(); - } } bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl, @@ -2354,8 +2352,11 @@ bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl, layer_impl = active_tree_->LayerById(scroll_layer_id); if (layer_impl && layer_impl->scrollbar_animation_controller()) { scroll_layer_id_when_mouse_over_scrollbar_ = scroll_layer_id; - layer_impl->scrollbar_animation_controller()->DidMouseMoveNear( - CurrentPhysicalTimeTicks(), 0); + bool should_animate = + layer_impl->scrollbar_animation_controller()->DidMouseMoveNear( + CurrentPhysicalTimeTicks(), 0); + if (should_animate) + StartScrollbarAnimation(); } else { scroll_layer_id_when_mouse_over_scrollbar_ = 0; } diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index a35191a..e885d90 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -1329,20 +1329,17 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( scrollbar_animation_controller->set_mouse_move_distance_for_test(100.f); host_impl_->MouseMoveAt(gfx::Point(1, 1)); - EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar()); - did_request_redraw_ = false; host_impl_->MouseMoveAt(gfx::Point(200, 50)); - EXPECT_TRUE(did_request_redraw_); + EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar()); - did_request_redraw_ = false; host_impl_->MouseMoveAt(gfx::Point(184, 100)); - EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(scrollbar_animation_controller->mouse_is_near_scrollbar()); scrollbar_animation_controller->set_mouse_move_distance_for_test(102.f); - did_request_redraw_ = false; host_impl_->MouseMoveAt(gfx::Point(184, 100)); - EXPECT_TRUE(did_request_redraw_); + EXPECT_TRUE(scrollbar_animation_controller->mouse_is_near_scrollbar()); did_request_redraw_ = false; EXPECT_EQ(0, host_impl_->scroll_layer_id_when_mouse_over_scrollbar()); |