Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / cc / input / top_controls_manager.cc
blob56c9d8f43ff8d14419cb93986ebce052f278fda2
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.
5 #include "cc/input/top_controls_manager.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "cc/animation/keyframed_animation_curve.h"
11 #include "cc/animation/timing_function.h"
12 #include "cc/input/top_controls_manager_client.h"
13 #include "cc/output/begin_frame_args.h"
14 #include "cc/trees/layer_tree_impl.h"
15 #include "ui/gfx/frame_time.h"
16 #include "ui/gfx/geometry/vector2d_f.h"
17 #include "ui/gfx/transform.h"
19 namespace cc {
20 namespace {
21 // These constants were chosen empirically for their visually pleasant behavior.
22 // Contact tedchoc@chromium.org for questions about changing these values.
23 const int64 kShowHideMaxDurationMs = 200;
26 // static
27 scoped_ptr<TopControlsManager> TopControlsManager::Create(
28 TopControlsManagerClient* client,
29 float top_controls_show_threshold,
30 float top_controls_hide_threshold) {
31 return make_scoped_ptr(new TopControlsManager(client,
32 top_controls_show_threshold,
33 top_controls_hide_threshold));
36 TopControlsManager::TopControlsManager(TopControlsManagerClient* client,
37 float top_controls_show_threshold,
38 float top_controls_hide_threshold)
39 : client_(client),
40 animation_direction_(NO_ANIMATION),
41 permitted_state_(BOTH),
42 accumulated_scroll_delta_(0.f),
43 baseline_content_offset_(0.f),
44 top_controls_show_threshold_(top_controls_hide_threshold),
45 top_controls_hide_threshold_(top_controls_show_threshold),
46 pinch_gesture_active_(false) {
47 CHECK(client_);
50 TopControlsManager::~TopControlsManager() {
53 float TopControlsManager::ControlsTopOffset() const {
54 return ContentTopOffset() - TopControlsHeight();
57 float TopControlsManager::ContentTopOffset() const {
58 return TopControlsShownRatio() * TopControlsHeight();
61 float TopControlsManager::TopControlsShownRatio() const {
62 return client_->CurrentTopControlsShownRatio();
65 float TopControlsManager::TopControlsHeight() const {
66 return client_->TopControlsHeight();
69 void TopControlsManager::UpdateTopControlsState(TopControlsState constraints,
70 TopControlsState current,
71 bool animate) {
72 DCHECK(!(constraints == SHOWN && current == HIDDEN));
73 DCHECK(!(constraints == HIDDEN && current == SHOWN));
75 permitted_state_ = constraints;
77 // Don't do anything if it doesn't matter which state the controls are in.
78 if (constraints == BOTH && current == BOTH)
79 return;
81 // Don't do anything if there is no change in offset.
82 float final_shown_ratio = 1.f;
83 if (constraints == HIDDEN || current == HIDDEN)
84 final_shown_ratio = 0.f;
85 if (final_shown_ratio == TopControlsShownRatio())
86 return;
88 if (animate) {
89 SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS);
90 } else {
91 ResetAnimations();
92 client_->SetCurrentTopControlsShownRatio(final_shown_ratio);
96 void TopControlsManager::ScrollBegin() {
97 DCHECK(!pinch_gesture_active_);
98 ResetAnimations();
99 ResetBaseline();
102 gfx::Vector2dF TopControlsManager::ScrollBy(
103 const gfx::Vector2dF& pending_delta) {
104 if (!TopControlsHeight())
105 return pending_delta;
107 if (pinch_gesture_active_)
108 return pending_delta;
110 if (!TopControlsHeight())
111 return pending_delta;
113 if (permitted_state_ == SHOWN && pending_delta.y() > 0)
114 return pending_delta;
115 else if (permitted_state_ == HIDDEN && pending_delta.y() < 0)
116 return pending_delta;
118 accumulated_scroll_delta_ += pending_delta.y();
120 float old_offset = ContentTopOffset();
121 client_->SetCurrentTopControlsShownRatio(
122 (baseline_content_offset_ - accumulated_scroll_delta_) /
123 TopControlsHeight());
125 // If the controls are fully visible, treat the current position as the
126 // new baseline even if the gesture didn't end.
127 if (TopControlsShownRatio() == 1.f)
128 ResetBaseline();
130 ResetAnimations();
132 gfx::Vector2dF applied_delta(0.f, old_offset - ContentTopOffset());
133 return pending_delta - applied_delta;
136 void TopControlsManager::ScrollEnd() {
137 DCHECK(!pinch_gesture_active_);
138 StartAnimationIfNecessary();
141 void TopControlsManager::PinchBegin() {
142 DCHECK(!pinch_gesture_active_);
143 pinch_gesture_active_ = true;
144 StartAnimationIfNecessary();
147 void TopControlsManager::PinchEnd() {
148 DCHECK(pinch_gesture_active_);
149 // Pinch{Begin,End} will always occur within the scope of Scroll{Begin,End},
150 // so return to a state expected by the remaining scroll sequence.
151 pinch_gesture_active_ = false;
152 ScrollBegin();
155 void TopControlsManager::MainThreadHasStoppedFlinging() {
156 StartAnimationIfNecessary();
159 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) {
160 if (!top_controls_animation_ || !client_->HaveRootScrollLayer())
161 return gfx::Vector2dF();
163 base::TimeDelta time = monotonic_time - base::TimeTicks();
165 float old_offset = ContentTopOffset();
166 client_->SetCurrentTopControlsShownRatio(
167 top_controls_animation_->GetValue(time));
169 if (IsAnimationCompleteAtTime(monotonic_time))
170 ResetAnimations();
172 gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset);
173 return scroll_delta;
176 void TopControlsManager::ResetAnimations() {
177 top_controls_animation_ = nullptr;
178 animation_direction_ = NO_ANIMATION;
181 void TopControlsManager::SetupAnimation(AnimationDirection direction) {
182 DCHECK_NE(NO_ANIMATION, direction);
183 DCHECK_IMPLIES(direction == HIDING_CONTROLS, TopControlsShownRatio() > 0.f);
184 DCHECK_IMPLIES(direction == SHOWING_CONTROLS, TopControlsShownRatio() < 1.f);
186 if (top_controls_animation_ && animation_direction_ == direction)
187 return;
189 if (!TopControlsHeight()) {
190 client_->SetCurrentTopControlsShownRatio(
191 direction == HIDING_CONTROLS ? 0.f : 1.f);
192 return;
195 top_controls_animation_ = KeyframedFloatAnimationCurve::Create();
196 base::TimeDelta start_time = gfx::FrameTime::Now() - base::TimeTicks();
197 top_controls_animation_->AddKeyframe(
198 FloatKeyframe::Create(start_time, TopControlsShownRatio(), nullptr));
199 float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1);
200 top_controls_animation_->AddKeyframe(FloatKeyframe::Create(
201 start_time + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs),
202 TopControlsShownRatio() + max_ending_ratio,
203 EaseTimingFunction::Create()));
204 animation_direction_ = direction;
205 client_->DidChangeTopControlsPosition();
208 void TopControlsManager::StartAnimationIfNecessary() {
209 if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f)
210 return;
212 if (TopControlsShownRatio() >= 1.f - top_controls_hide_threshold_) {
213 // If we're showing so much that the hide threshold won't trigger, show.
214 SetupAnimation(SHOWING_CONTROLS);
215 } else if (TopControlsShownRatio() <= top_controls_show_threshold_) {
216 // If we're showing so little that the show threshold won't trigger, hide.
217 SetupAnimation(HIDING_CONTROLS);
218 } else {
219 // If we could be either showing or hiding, we determine which one to
220 // do based on whether or not the total scroll delta was moving up or
221 // down.
222 SetupAnimation(accumulated_scroll_delta_ <= 0.f ? SHOWING_CONTROLS
223 : HIDING_CONTROLS);
227 bool TopControlsManager::IsAnimationCompleteAtTime(base::TimeTicks time) {
228 if (!top_controls_animation_)
229 return true;
231 base::TimeDelta animation_time = time - base::TimeTicks();
232 float new_ratio = top_controls_animation_->GetValue(animation_time);
234 if ((animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) ||
235 (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f)) {
236 return true;
238 return false;
241 void TopControlsManager::ResetBaseline() {
242 accumulated_scroll_delta_ = 0.f;
243 baseline_content_offset_ = ContentTopOffset();
246 } // namespace cc