Home | History | Annotate | Download | only in animation
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/animation/scrollbar_animation_controller_thinning.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/time/time.h"
     10 #include "cc/layers/layer_impl.h"
     11 #include "cc/layers/scrollbar_layer_impl_base.h"
     12 
     13 namespace {
     14 const float kIdleThicknessScale = 0.4f;
     15 const float kIdleOpacity = 0.7f;
     16 const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
     17 const int kDefaultAnimationDelay = 500;
     18 const int kDefaultAnimationDuration = 300;
     19 }
     20 
     21 namespace cc {
     22 
     23 scoped_ptr<ScrollbarAnimationControllerThinning>
     24 ScrollbarAnimationControllerThinning::Create(LayerImpl* scroll_layer) {
     25   return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
     26       scroll_layer,
     27       base::TimeDelta::FromMilliseconds(kDefaultAnimationDelay),
     28       base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)));
     29 }
     30 
     31 scoped_ptr<ScrollbarAnimationControllerThinning>
     32 ScrollbarAnimationControllerThinning::CreateForTest(LayerImpl* scroll_layer,
     33     base::TimeDelta animation_delay, base::TimeDelta animation_duration) {
     34   return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
     35       scroll_layer, animation_delay, animation_duration));
     36 }
     37 
     38 ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
     39     LayerImpl* scroll_layer,
     40     base::TimeDelta animation_delay,
     41     base::TimeDelta animation_duration)
     42     : ScrollbarAnimationController(),
     43       scroll_layer_(scroll_layer),
     44       mouse_is_over_scrollbar_(false),
     45       mouse_is_near_scrollbar_(false),
     46       thickness_change_(NONE),
     47       opacity_change_(NONE),
     48       should_delay_animation_(false),
     49       animation_delay_(animation_delay),
     50       animation_duration_(animation_duration),
     51       mouse_move_distance_to_trigger_animation_(
     52           kDefaultMouseMoveDistanceToTriggerAnimation) {
     53   ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
     54 }
     55 
     56 ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
     57 }
     58 
     59 bool ScrollbarAnimationControllerThinning::IsAnimating() const {
     60   return !last_awaken_time_.is_null();
     61 }
     62 
     63 base::TimeDelta ScrollbarAnimationControllerThinning::DelayBeforeStart(
     64     base::TimeTicks now) const {
     65   if (!should_delay_animation_)
     66     return base::TimeDelta();
     67   if (now > last_awaken_time_ + animation_delay_)
     68     return base::TimeDelta();
     69   return animation_delay_ - (now - last_awaken_time_);
     70 }
     71 
     72 bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) {
     73   float progress = AnimationProgressAtTime(now);
     74   float opacity = OpacityAtAnimationProgress(progress);
     75   float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
     76       progress);
     77   ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
     78   if (progress == 1.f) {
     79     opacity_change_ = NONE;
     80     thickness_change_ = NONE;
     81     last_awaken_time_ = base::TimeTicks();
     82   }
     83   return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta();
     84 }
     85 
     86 void ScrollbarAnimationControllerThinning::DidScrollGestureBegin() {
     87 }
     88 
     89 void ScrollbarAnimationControllerThinning::DidScrollGestureEnd(
     90     base::TimeTicks now) {
     91 }
     92 
     93 void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar(
     94     base::TimeTicks now) {
     95   mouse_is_over_scrollbar_ = false;
     96   mouse_is_near_scrollbar_ = false;
     97   last_awaken_time_ = now;
     98   should_delay_animation_ = false;
     99   opacity_change_ = DECREASE;
    100   thickness_change_ = DECREASE;
    101 }
    102 
    103 bool ScrollbarAnimationControllerThinning::DidScrollUpdate(
    104     base::TimeTicks now) {
    105   ApplyOpacityAndThumbThicknessScale(
    106     1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
    107 
    108   last_awaken_time_ = now;
    109   should_delay_animation_ = true;
    110   if (!mouse_is_over_scrollbar_)
    111     opacity_change_ = DECREASE;
    112   return true;
    113 }
    114 
    115 bool ScrollbarAnimationControllerThinning::DidMouseMoveNear(
    116     base::TimeTicks now, float distance) {
    117   bool mouse_is_over_scrollbar = distance == 0.0;
    118   bool mouse_is_near_scrollbar =
    119       distance < mouse_move_distance_to_trigger_animation_;
    120 
    121   if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
    122       mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
    123     return false;
    124 
    125   if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) {
    126     mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
    127     opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE;
    128   }
    129 
    130   if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) {
    131     mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
    132     thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
    133   }
    134 
    135   last_awaken_time_ = now;
    136   should_delay_animation_ = false;
    137   return true;
    138 }
    139 
    140 float ScrollbarAnimationControllerThinning::AnimationProgressAtTime(
    141     base::TimeTicks now) {
    142   if (last_awaken_time_.is_null())
    143     return 1;
    144 
    145   base::TimeDelta delta = now - last_awaken_time_;
    146   if (should_delay_animation_)
    147     delta -= animation_delay_;
    148   float progress = delta.InSecondsF() / animation_duration_.InSecondsF();
    149   return std::max(std::min(progress, 1.f), 0.f);
    150 }
    151 
    152 float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
    153     float progress) {
    154   if (opacity_change_ == NONE)
    155     return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity;
    156   float factor = opacity_change_ == INCREASE ? progress : (1.f - progress);
    157   float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity;
    158   return ret;
    159 }
    160 
    161 float
    162 ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress(
    163     float progress) {
    164   if (thickness_change_ == NONE)
    165     return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
    166   float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
    167   return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale;
    168 }
    169 
    170 float ScrollbarAnimationControllerThinning::AdjustScale(
    171     float new_value,
    172     float current_value,
    173     AnimationChange animation_change) {
    174   if (animation_change == INCREASE && current_value > new_value)
    175     return current_value;
    176   if (animation_change == DECREASE && current_value < new_value)
    177     return current_value;
    178   return new_value;
    179 }
    180 
    181 void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
    182     float opacity, float thumb_thickness_scale) {
    183   ScrollbarLayerImplBase* horizontal_scrollbar =
    184       scroll_layer_->horizontal_scrollbar_layer();
    185   if (horizontal_scrollbar) {
    186     horizontal_scrollbar->SetOpacity(
    187         AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_));
    188     horizontal_scrollbar->SetThumbThicknessScaleFactor(
    189         AdjustScale(
    190           thumb_thickness_scale,
    191           horizontal_scrollbar->thumb_thickness_scale_factor(),
    192           thickness_change_));
    193   }
    194 
    195   ScrollbarLayerImplBase* vertical_scrollbar =
    196       scroll_layer_->vertical_scrollbar_layer();
    197   if (vertical_scrollbar) {
    198     vertical_scrollbar->SetOpacity(
    199         AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_));
    200     vertical_scrollbar->SetThumbThicknessScaleFactor(
    201         AdjustScale(
    202           thumb_thickness_scale,
    203           vertical_scrollbar->thumb_thickness_scale_factor(),
    204           thickness_change_));
    205   }
    206 }
    207 
    208 }  // namespace cc
    209