OLD | NEW |
| (Empty) |
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 "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" | |
18 | |
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; | |
24 } | |
25 | |
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)); | |
34 } | |
35 | |
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_); | |
48 } | |
49 | |
50 TopControlsManager::~TopControlsManager() { | |
51 } | |
52 | |
53 float TopControlsManager::ControlsTopOffset() const { | |
54 return ContentTopOffset() - TopControlsHeight(); | |
55 } | |
56 | |
57 float TopControlsManager::ContentTopOffset() const { | |
58 return TopControlsShownRatio() * TopControlsHeight(); | |
59 } | |
60 | |
61 float TopControlsManager::TopControlsShownRatio() const { | |
62 return client_->CurrentTopControlsShownRatio(); | |
63 } | |
64 | |
65 float TopControlsManager::TopControlsHeight() const { | |
66 return client_->TopControlsHeight(); | |
67 } | |
68 | |
69 void TopControlsManager::UpdateTopControlsState(TopControlsState constraints, | |
70 TopControlsState current, | |
71 bool animate) { | |
72 DCHECK(!(constraints == SHOWN && current == HIDDEN)); | |
73 DCHECK(!(constraints == HIDDEN && current == SHOWN)); | |
74 | |
75 permitted_state_ = constraints; | |
76 | |
77 // Don't do anything if it doesn't matter which state the controls are in. | |
78 if (constraints == BOTH && current == BOTH) | |
79 return; | |
80 | |
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; | |
87 | |
88 if (animate) { | |
89 SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS); | |
90 } else { | |
91 ResetAnimations(); | |
92 client_->SetCurrentTopControlsShownRatio(final_shown_ratio); | |
93 } | |
94 } | |
95 | |
96 void TopControlsManager::ScrollBegin() { | |
97 DCHECK(!pinch_gesture_active_); | |
98 ResetAnimations(); | |
99 ResetBaseline(); | |
100 } | |
101 | |
102 gfx::Vector2dF TopControlsManager::ScrollBy( | |
103 const gfx::Vector2dF& pending_delta) { | |
104 if (!TopControlsHeight()) | |
105 return pending_delta; | |
106 | |
107 if (pinch_gesture_active_) | |
108 return pending_delta; | |
109 | |
110 if (!TopControlsHeight()) | |
111 return pending_delta; | |
112 | |
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; | |
117 | |
118 accumulated_scroll_delta_ += pending_delta.y(); | |
119 | |
120 float old_offset = ContentTopOffset(); | |
121 client_->SetCurrentTopControlsShownRatio( | |
122 (baseline_content_offset_ - accumulated_scroll_delta_) / | |
123 TopControlsHeight()); | |
124 | |
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(); | |
129 | |
130 ResetAnimations(); | |
131 | |
132 gfx::Vector2dF applied_delta(0.f, old_offset - ContentTopOffset()); | |
133 return pending_delta - applied_delta; | |
134 } | |
135 | |
136 void TopControlsManager::ScrollEnd() { | |
137 DCHECK(!pinch_gesture_active_); | |
138 StartAnimationIfNecessary(); | |
139 } | |
140 | |
141 void TopControlsManager::PinchBegin() { | |
142 DCHECK(!pinch_gesture_active_); | |
143 pinch_gesture_active_ = true; | |
144 StartAnimationIfNecessary(); | |
145 } | |
146 | |
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(); | |
153 } | |
154 | |
155 void TopControlsManager::MainThreadHasStoppedFlinging() { | |
156 StartAnimationIfNecessary(); | |
157 } | |
158 | |
159 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) { | |
160 if (!top_controls_animation_ || !client_->HaveRootScrollLayer()) | |
161 return gfx::Vector2dF(); | |
162 | |
163 base::TimeDelta time = monotonic_time - base::TimeTicks(); | |
164 | |
165 float old_offset = ContentTopOffset(); | |
166 client_->SetCurrentTopControlsShownRatio( | |
167 top_controls_animation_->GetValue(time)); | |
168 | |
169 if (IsAnimationCompleteAtTime(monotonic_time)) | |
170 ResetAnimations(); | |
171 | |
172 gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset); | |
173 return scroll_delta; | |
174 } | |
175 | |
176 void TopControlsManager::ResetAnimations() { | |
177 top_controls_animation_ = nullptr; | |
178 animation_direction_ = NO_ANIMATION; | |
179 } | |
180 | |
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); | |
185 | |
186 if (top_controls_animation_ && animation_direction_ == direction) | |
187 return; | |
188 | |
189 if (!TopControlsHeight()) { | |
190 client_->SetCurrentTopControlsShownRatio( | |
191 direction == HIDING_CONTROLS ? 0.f : 1.f); | |
192 return; | |
193 } | |
194 | |
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(); | |
206 } | |
207 | |
208 void TopControlsManager::StartAnimationIfNecessary() { | |
209 if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f) | |
210 return; | |
211 | |
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); | |
224 } | |
225 } | |
226 | |
227 bool TopControlsManager::IsAnimationCompleteAtTime(base::TimeTicks time) { | |
228 if (!top_controls_animation_) | |
229 return true; | |
230 | |
231 base::TimeDelta animation_time = time - base::TimeTicks(); | |
232 float new_ratio = top_controls_animation_->GetValue(animation_time); | |
233 | |
234 if ((animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) || | |
235 (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f)) { | |
236 return true; | |
237 } | |
238 return false; | |
239 } | |
240 | |
241 void TopControlsManager::ResetBaseline() { | |
242 accumulated_scroll_delta_ = 0.f; | |
243 baseline_content_offset_ = ContentTopOffset(); | |
244 } | |
245 | |
246 } // namespace cc | |
OLD | NEW |