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 <stdint.h> | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "base/logging.h" | |
12 #include "base/memory/ptr_util.h" | |
13 #include "cc/input/top_controls_manager_client.h" | |
14 #include "cc/output/begin_frame_args.h" | |
15 #include "cc/trees/layer_tree_impl.h" | |
16 #include "ui/gfx/animation/tween.h" | |
17 #include "ui/gfx/geometry/vector2d_f.h" | |
18 #include "ui/gfx/transform.h" | |
19 | |
20 namespace cc { | |
21 namespace { | |
22 // These constants were chosen empirically for their visually pleasant behavior. | |
23 // Contact tedchoc@chromium.org for questions about changing these values. | |
24 const int64_t kShowHideMaxDurationMs = 200; | |
25 } | |
26 | |
27 // static | |
28 std::unique_ptr<TopControlsManager> TopControlsManager::Create( | |
29 TopControlsManagerClient* client, | |
30 float top_controls_show_threshold, | |
31 float top_controls_hide_threshold) { | |
32 return base::WrapUnique(new TopControlsManager( | |
33 client, top_controls_show_threshold, 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_start_value_(0.f), | |
41 animation_stop_value_(0.f), | |
42 animation_direction_(NO_ANIMATION), | |
43 permitted_state_(BOTH), | |
44 accumulated_scroll_delta_(0.f), | |
45 baseline_content_offset_(0.f), | |
46 top_controls_show_threshold_(top_controls_hide_threshold), | |
47 top_controls_hide_threshold_(top_controls_show_threshold), | |
48 pinch_gesture_active_(false) { | |
49 CHECK(client_); | |
50 } | |
51 | |
52 TopControlsManager::~TopControlsManager() { | |
53 } | |
54 | |
55 float TopControlsManager::ControlsTopOffset() const { | |
56 return ContentTopOffset() - TopControlsHeight(); | |
57 } | |
58 | |
59 float TopControlsManager::ContentTopOffset() const { | |
60 return TopControlsShownRatio() * TopControlsHeight(); | |
61 } | |
62 | |
63 float TopControlsManager::ContentOffsetInternal() const { | |
64 if (!TopControlsHeight()) | |
65 return BottomControlsShownRatio() * BottomControlsHeight(); | |
66 return ContentTopOffset(); | |
67 } | |
68 | |
69 float TopControlsManager::TopControlsShownRatio() const { | |
70 return client_->CurrentTopControlsShownRatio(); | |
71 } | |
72 | |
73 float TopControlsManager::TopControlsHeight() const { | |
74 return client_->TopControlsHeight(); | |
75 } | |
76 | |
77 float TopControlsManager::BottomControlsHeight() const { | |
78 return client_->BottomControlsHeight(); | |
79 } | |
80 | |
81 float TopControlsManager::ContentBottomOffset() const { | |
82 return BottomControlsShownRatio() * BottomControlsHeight(); | |
83 } | |
84 | |
85 float TopControlsManager::BottomControlsShownRatio() const { | |
86 return TopControlsShownRatio(); | |
87 } | |
88 | |
89 void TopControlsManager::UpdateTopControlsState(TopControlsState constraints, | |
90 TopControlsState current, | |
91 bool animate) { | |
92 DCHECK(!(constraints == SHOWN && current == HIDDEN)); | |
93 DCHECK(!(constraints == HIDDEN && current == SHOWN)); | |
94 | |
95 permitted_state_ = constraints; | |
96 | |
97 // Don't do anything if it doesn't matter which state the controls are in. | |
98 if (constraints == BOTH && current == BOTH) | |
99 return; | |
100 | |
101 // Don't do anything if there is no change in offset. | |
102 float final_shown_ratio = 1.f; | |
103 if (constraints == HIDDEN || current == HIDDEN) | |
104 final_shown_ratio = 0.f; | |
105 if (final_shown_ratio == TopControlsShownRatio()) { | |
106 ResetAnimations(); | |
107 return; | |
108 } | |
109 | |
110 if (animate) { | |
111 SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS); | |
112 } else { | |
113 ResetAnimations(); | |
114 client_->SetCurrentTopControlsShownRatio(final_shown_ratio); | |
115 } | |
116 } | |
117 | |
118 void TopControlsManager::ScrollBegin() { | |
119 if (pinch_gesture_active_) | |
120 return; | |
121 | |
122 ResetAnimations(); | |
123 ResetBaseline(); | |
124 } | |
125 | |
126 gfx::Vector2dF TopControlsManager::ScrollBy( | |
127 const gfx::Vector2dF& pending_delta) { | |
128 // If one or both of the top/bottom controls are showing, the shown ratio | |
129 // needs to be computed. | |
130 float controls_height = | |
131 TopControlsHeight() ? TopControlsHeight() : BottomControlsHeight(); | |
132 | |
133 if (!controls_height) | |
134 return pending_delta; | |
135 | |
136 if (pinch_gesture_active_) | |
137 return pending_delta; | |
138 | |
139 if (permitted_state_ == SHOWN && pending_delta.y() > 0) | |
140 return pending_delta; | |
141 else if (permitted_state_ == HIDDEN && pending_delta.y() < 0) | |
142 return pending_delta; | |
143 | |
144 accumulated_scroll_delta_ += pending_delta.y(); | |
145 | |
146 float old_offset = ContentOffsetInternal(); | |
147 client_->SetCurrentTopControlsShownRatio( | |
148 (baseline_content_offset_ - accumulated_scroll_delta_) / controls_height); | |
149 | |
150 // If the controls are fully visible, treat the current position as the | |
151 // new baseline even if the gesture didn't end. | |
152 if (TopControlsShownRatio() == 1.f) | |
153 ResetBaseline(); | |
154 | |
155 ResetAnimations(); | |
156 | |
157 gfx::Vector2dF applied_delta(0.f, old_offset - ContentOffsetInternal()); | |
158 return pending_delta - applied_delta; | |
159 } | |
160 | |
161 void TopControlsManager::ScrollEnd() { | |
162 if (pinch_gesture_active_) | |
163 return; | |
164 | |
165 StartAnimationIfNecessary(); | |
166 } | |
167 | |
168 void TopControlsManager::PinchBegin() { | |
169 DCHECK(!pinch_gesture_active_); | |
170 pinch_gesture_active_ = true; | |
171 StartAnimationIfNecessary(); | |
172 } | |
173 | |
174 void TopControlsManager::PinchEnd() { | |
175 DCHECK(pinch_gesture_active_); | |
176 // Pinch{Begin,End} will always occur within the scope of Scroll{Begin,End}, | |
177 // so return to a state expected by the remaining scroll sequence. | |
178 pinch_gesture_active_ = false; | |
179 ScrollBegin(); | |
180 } | |
181 | |
182 void TopControlsManager::MainThreadHasStoppedFlinging() { | |
183 StartAnimationIfNecessary(); | |
184 } | |
185 | |
186 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) { | |
187 if (!has_animation() || !client_->HaveRootScrollLayer()) | |
188 return gfx::Vector2dF(); | |
189 | |
190 float old_offset = ContentOffsetInternal(); | |
191 float new_ratio = gfx::Tween::ClampedFloatValueBetween( | |
192 monotonic_time, animation_start_time_, animation_start_value_, | |
193 animation_stop_time_, animation_stop_value_); | |
194 client_->SetCurrentTopControlsShownRatio(new_ratio); | |
195 | |
196 if (IsAnimationComplete(new_ratio)) | |
197 ResetAnimations(); | |
198 | |
199 gfx::Vector2dF scroll_delta(0.f, ContentOffsetInternal() - old_offset); | |
200 return scroll_delta; | |
201 } | |
202 | |
203 void TopControlsManager::ResetAnimations() { | |
204 animation_start_time_ = base::TimeTicks(); | |
205 animation_start_value_ = 0.f; | |
206 animation_stop_time_ = base::TimeTicks(); | |
207 animation_stop_value_ = 0.f; | |
208 | |
209 animation_direction_ = NO_ANIMATION; | |
210 } | |
211 | |
212 void TopControlsManager::SetupAnimation(AnimationDirection direction) { | |
213 DCHECK_NE(NO_ANIMATION, direction); | |
214 DCHECK(direction != HIDING_CONTROLS || TopControlsShownRatio() > 0.f); | |
215 DCHECK(direction != SHOWING_CONTROLS || TopControlsShownRatio() < 1.f); | |
216 | |
217 if (has_animation() && animation_direction_ == direction) | |
218 return; | |
219 | |
220 if (!TopControlsHeight() && !BottomControlsHeight()) { | |
221 client_->SetCurrentTopControlsShownRatio( | |
222 direction == HIDING_CONTROLS ? 0.f : 1.f); | |
223 return; | |
224 } | |
225 | |
226 animation_start_time_ = base::TimeTicks::Now(); | |
227 animation_start_value_ = TopControlsShownRatio(); | |
228 | |
229 const float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1); | |
230 animation_stop_time_ = | |
231 animation_start_time_ + | |
232 base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); | |
233 animation_stop_value_ = animation_start_value_ + max_ending_ratio; | |
234 | |
235 animation_direction_ = direction; | |
236 client_->DidChangeTopControlsPosition(); | |
237 } | |
238 | |
239 void TopControlsManager::StartAnimationIfNecessary() { | |
240 if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f) | |
241 return; | |
242 | |
243 if (TopControlsShownRatio() >= 1.f - top_controls_hide_threshold_) { | |
244 // If we're showing so much that the hide threshold won't trigger, show. | |
245 SetupAnimation(SHOWING_CONTROLS); | |
246 } else if (TopControlsShownRatio() <= top_controls_show_threshold_) { | |
247 // If we're showing so little that the show threshold won't trigger, hide. | |
248 SetupAnimation(HIDING_CONTROLS); | |
249 } else { | |
250 // If we could be either showing or hiding, we determine which one to | |
251 // do based on whether or not the total scroll delta was moving up or | |
252 // down. | |
253 SetupAnimation(accumulated_scroll_delta_ <= 0.f ? SHOWING_CONTROLS | |
254 : HIDING_CONTROLS); | |
255 } | |
256 } | |
257 | |
258 bool TopControlsManager::IsAnimationComplete(float new_ratio) { | |
259 return (animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) || | |
260 (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f); | |
261 } | |
262 | |
263 void TopControlsManager::ResetBaseline() { | |
264 accumulated_scroll_delta_ = 0.f; | |
265 baseline_content_offset_ = ContentOffsetInternal(); | |
266 } | |
267 | |
268 } // namespace cc | |
OLD | NEW |