top_controls_manager.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/input/top_controls_manager.h" 6 7#include <algorithm> 8 9#include "base/logging.h" 10#include "base/time.h" 11#include "cc/animation/keyframed_animation_curve.h" 12#include "cc/animation/timing_function.h" 13#include "cc/input/top_controls_manager_client.h" 14#include "cc/trees/layer_tree_impl.h" 15#include "ui/gfx/transform.h" 16#include "ui/gfx/vector2d_f.h" 17 18namespace cc { 19namespace { 20// These constants were chosen empirically for their visually pleasant behavior. 21// Contact tedchoc@chromium.org for questions about changing these values. 22const int64 kShowHideMaxDurationMs = 200; 23} 24 25// static 26scoped_ptr<TopControlsManager> TopControlsManager::Create( 27 TopControlsManagerClient* client, 28 float top_controls_height, 29 float top_controls_show_threshold, 30 float top_controls_hide_threshold) { 31 return make_scoped_ptr(new TopControlsManager(client, 32 top_controls_height, 33 top_controls_show_threshold, 34 top_controls_hide_threshold)); 35} 36 37TopControlsManager::TopControlsManager(TopControlsManagerClient* client, 38 float top_controls_height, 39 float top_controls_show_threshold, 40 float top_controls_hide_threshold) 41 : client_(client), 42 animation_direction_(NO_ANIMATION), 43 visibility_restriction_(NONE), 44 controls_top_offset_(0.f), 45 top_controls_height_(top_controls_height), 46 current_scroll_delta_(0.f), 47 controls_scroll_begin_offset_(0.f), 48 top_controls_show_height_( 49 top_controls_height * top_controls_hide_threshold), 50 top_controls_hide_height_( 51 top_controls_height * (1.f - top_controls_show_threshold)) { 52 CHECK(client_); 53} 54 55TopControlsManager::~TopControlsManager() { 56} 57 58void TopControlsManager::UpdateTopControlsState(bool enable_hiding, 59 bool enable_showing, 60 bool animate) { 61 float final_controls_position = 0.f; 62 63 if (enable_hiding && enable_showing) { 64 visibility_restriction_ = NONE; 65 } else if (enable_showing || !enable_hiding) { 66 visibility_restriction_ = ALWAYS_SHOWN; 67 } else { 68 visibility_restriction_ = ALWAYS_HIDDEN; 69 final_controls_position = -top_controls_height_; 70 } 71 72 if (visibility_restriction_ != NONE && 73 final_controls_position != controls_top_offset_) { 74 ResetAnimations(); 75 if (animate) { 76 SetupAnimation(visibility_restriction_ == ALWAYS_SHOWN ? 77 SHOWING_CONTROLS : HIDING_CONTROLS); 78 } else { 79 controls_top_offset_ = final_controls_position; 80 } 81 client_->DidChangeTopControlsPosition(); 82 } 83} 84 85void TopControlsManager::ScrollBegin() { 86 ResetAnimations(); 87 current_scroll_delta_ = 0.f; 88 controls_scroll_begin_offset_ = controls_top_offset_; 89} 90 91gfx::Vector2dF TopControlsManager::ScrollBy( 92 const gfx::Vector2dF pending_delta) { 93 if (visibility_restriction_ == ALWAYS_SHOWN && pending_delta.y() > 0) 94 return pending_delta; 95 else if (visibility_restriction_ == ALWAYS_HIDDEN && pending_delta.y() < 0) 96 return pending_delta; 97 98 current_scroll_delta_ += pending_delta.y(); 99 100 float old_offset = controls_top_offset_; 101 SetControlsTopOffset(controls_scroll_begin_offset_ - current_scroll_delta_); 102 103 // If the controls are fully visible, treat the current position as the 104 // new baseline even if the gesture didn't end. 105 if (controls_top_offset_ == 0.f) { 106 current_scroll_delta_ = 0.f; 107 controls_scroll_begin_offset_ = 0.f; 108 } 109 110 ResetAnimations(); 111 112 gfx::Vector2dF applied_delta(0.f, old_offset - controls_top_offset_); 113 return pending_delta - applied_delta; 114} 115 116void TopControlsManager::ScrollEnd() { 117 StartAnimationIfNecessary(); 118} 119 120void TopControlsManager::SetControlsTopOffset(float controls_top_offset) { 121 controls_top_offset = std::max(controls_top_offset, -top_controls_height_); 122 controls_top_offset = std::min(controls_top_offset, 0.f); 123 124 if (controls_top_offset_ == controls_top_offset) 125 return; 126 127 controls_top_offset_ = controls_top_offset; 128 129 client_->DidChangeTopControlsPosition(); 130} 131 132gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) { 133 if (!top_controls_animation_ || !client_->HaveRootScrollLayer()) 134 return gfx::Vector2dF(); 135 136 double time = (monotonic_time - base::TimeTicks()).InMillisecondsF(); 137 138 float old_offset = controls_top_offset_; 139 SetControlsTopOffset(top_controls_animation_->GetValue(time)); 140 141 if (IsAnimationCompleteAtTime(monotonic_time)) 142 ResetAnimations(); 143 144 gfx::Vector2dF scroll_delta(0.f, controls_top_offset_ - old_offset); 145 return scroll_delta; 146} 147 148void TopControlsManager::ResetAnimations() { 149 if (top_controls_animation_) 150 top_controls_animation_.reset(); 151 152 animation_direction_ = NO_ANIMATION; 153} 154 155void TopControlsManager::SetupAnimation(AnimationDirection direction) { 156 top_controls_animation_ = KeyframedFloatAnimationCurve::Create(); 157 double start_time = 158 (base::TimeTicks::Now() - base::TimeTicks()).InMillisecondsF(); 159 top_controls_animation_->AddKeyframe( 160 FloatKeyframe::Create(start_time, controls_top_offset_, 161 scoped_ptr<TimingFunction>())); 162 float max_ending_offset = 163 (direction == SHOWING_CONTROLS ? 1 : -1) * top_controls_height_; 164 top_controls_animation_->AddKeyframe( 165 FloatKeyframe::Create(start_time + kShowHideMaxDurationMs, 166 controls_top_offset_ + max_ending_offset, 167 EaseTimingFunction::Create())); 168 animation_direction_ = direction; 169} 170 171void TopControlsManager::StartAnimationIfNecessary() { 172 if (controls_top_offset_ != 0 173 && controls_top_offset_ != -top_controls_height_) { 174 AnimationDirection show_controls = NO_ANIMATION; 175 176 if (controls_top_offset_ >= -top_controls_show_height_) { 177 // If we're showing so much that the hide threshold won't trigger, show. 178 show_controls = SHOWING_CONTROLS; 179 } else if (controls_top_offset_ <= -top_controls_hide_height_) { 180 // If we're showing so little that the show threshold won't trigger, hide. 181 show_controls = HIDING_CONTROLS; 182 } else { 183 // If we could be either showing or hiding, we determine which one to 184 // do based on whether or not the total scroll delta was moving up or 185 // down. 186 show_controls = current_scroll_delta_ <= 0.f ? 187 SHOWING_CONTROLS : HIDING_CONTROLS; 188 } 189 190 if (show_controls != NO_ANIMATION && 191 (!top_controls_animation_ || animation_direction_ != show_controls)) { 192 SetupAnimation(show_controls); 193 client_->DidChangeTopControlsPosition(); 194 } 195 } 196} 197 198bool TopControlsManager::IsAnimationCompleteAtTime(base::TimeTicks time) { 199 if (!top_controls_animation_) 200 return true; 201 202 double time_ms = (time - base::TimeTicks()).InMillisecondsF(); 203 float new_offset = top_controls_animation_->GetValue(time_ms); 204 205 if ((animation_direction_ == SHOWING_CONTROLS && new_offset >= 0) || 206 (animation_direction_ == HIDING_CONTROLS 207 && new_offset <= -top_controls_height_)) { 208 return true; 209 } 210 return false; 211} 212 213} // namespace cc 214