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 "base/time/time.h"
8#include "cc/layers/layer_impl.h"
9#include "cc/layers/scrollbar_layer_impl_base.h"
10
11namespace {
12const float kIdleThicknessScale = 0.4f;
13const float kIdleOpacity = 0.7f;
14const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
15}
16
17namespace cc {
18
19scoped_ptr<ScrollbarAnimationControllerThinning>
20ScrollbarAnimationControllerThinning::Create(
21    LayerImpl* scroll_layer,
22    ScrollbarAnimationControllerClient* client,
23    base::TimeDelta delay_before_starting,
24    base::TimeDelta duration) {
25  return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
26      scroll_layer, client, delay_before_starting, duration));
27}
28
29ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
30    LayerImpl* scroll_layer,
31    ScrollbarAnimationControllerClient* client,
32    base::TimeDelta delay_before_starting,
33    base::TimeDelta duration)
34    : ScrollbarAnimationController(client, delay_before_starting, duration),
35      scroll_layer_(scroll_layer),
36      mouse_is_over_scrollbar_(false),
37      mouse_is_near_scrollbar_(false),
38      thickness_change_(NONE),
39      opacity_change_(NONE),
40      mouse_move_distance_to_trigger_animation_(
41          kDefaultMouseMoveDistanceToTriggerAnimation) {
42  ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
43}
44
45ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
46}
47
48void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
49  float opacity = OpacityAtAnimationProgress(progress);
50  float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
51      progress);
52  ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
53  if (progress == 1.f) {
54    opacity_change_ = NONE;
55    thickness_change_ = NONE;
56    StopAnimation();
57  }
58}
59
60void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar() {
61  mouse_is_over_scrollbar_ = false;
62  mouse_is_near_scrollbar_ = false;
63  opacity_change_ = DECREASE;
64  thickness_change_ = DECREASE;
65  StartAnimation();
66}
67
68void ScrollbarAnimationControllerThinning::DidScrollUpdate() {
69  ScrollbarAnimationController::DidScrollUpdate();
70  ApplyOpacityAndThumbThicknessScale(
71    1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
72
73  if (!mouse_is_over_scrollbar_)
74    opacity_change_ = DECREASE;
75}
76
77void ScrollbarAnimationControllerThinning::DidMouseMoveNear(float distance) {
78  bool mouse_is_over_scrollbar = distance == 0.0;
79  bool mouse_is_near_scrollbar =
80      distance < mouse_move_distance_to_trigger_animation_;
81
82  if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
83      mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
84    return;
85
86  if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) {
87    mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
88    opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE;
89  }
90
91  if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) {
92    mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
93    thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
94  }
95
96  StartAnimation();
97}
98
99float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
100    float progress) {
101  if (opacity_change_ == NONE)
102    return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity;
103  float factor = opacity_change_ == INCREASE ? progress : (1.f - progress);
104  float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity;
105  return ret;
106}
107
108float
109ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress(
110    float progress) {
111  if (thickness_change_ == NONE)
112    return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
113  float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
114  return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale;
115}
116
117float ScrollbarAnimationControllerThinning::AdjustScale(
118    float new_value,
119    float current_value,
120    AnimationChange animation_change) {
121  if (animation_change == INCREASE && current_value > new_value)
122    return current_value;
123  if (animation_change == DECREASE && current_value < new_value)
124    return current_value;
125  return new_value;
126}
127
128void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
129    float opacity, float thumb_thickness_scale) {
130  if (!scroll_layer_->scrollbars())
131    return;
132
133  LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
134  for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
135       it != scrollbars->end();
136       ++it) {
137    ScrollbarLayerImplBase* scrollbar = *it;
138    if (scrollbar->is_overlay_scrollbar()) {
139      scrollbar->SetOpacity(
140          AdjustScale(opacity, scrollbar->opacity(), opacity_change_));
141      scrollbar->SetThumbThicknessScaleFactor(
142          AdjustScale(thumb_thickness_scale,
143                      scrollbar->thumb_thickness_scale_factor(),
144                      thickness_change_));
145    }
146  }
147}
148
149}  // namespace cc
150