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::TopControlsShownRatio() const { | |
64 return client_->CurrentTopControlsShownRatio(); | |
65 } | |
66 | |
67 float TopControlsManager::TopControlsHeight() const { | |
68 return client_->TopControlsHeight(); | |
69 } | |
70 | |
71 float TopControlsManager::BottomControlsHeight() const { | |
72 return client_->BottomControlsHeight(); | |
73 } | |
74 | |
75 float TopControlsManager::ContentBottomOffset() const { | |
76 return TopControlsShownRatio() * BottomControlsHeight(); | |
77 } | |
78 | |
79 float TopControlsManager::BottomControlsShownRatio() const { | |
80 return TopControlsShownRatio(); | |
81 } | |
82 | |
83 void TopControlsManager::UpdateTopControlsState(TopControlsState constraints, | |
84 TopControlsState current, | |
85 bool animate) { | |
86 DCHECK(!(constraints == SHOWN && current == HIDDEN)); | |
87 DCHECK(!(constraints == HIDDEN && current == SHOWN)); | |
88 | |
89 permitted_state_ = constraints; | |
90 | |
91 // Don't do anything if it doesn't matter which state the controls are in. | |
92 if (constraints == BOTH && current == BOTH) | |
93 return; | |
94 | |
95 // Don't do anything if there is no change in offset. | |
96 float final_shown_ratio = 1.f; | |
97 if (constraints == HIDDEN || current == HIDDEN) | |
98 final_shown_ratio = 0.f; | |
99 if (final_shown_ratio == TopControlsShownRatio()) { | |
100 ResetAnimations(); | |
101 return; | |
102 } | |
103 | |
104 if (animate) { | |
105 SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS); | |
106 } else { | |
107 ResetAnimations(); | |
108 client_->SetCurrentTopControlsShownRatio(final_shown_ratio); | |
109 } | |
110 } | |
111 | |
112 void TopControlsManager::ScrollBegin() { | |
113 if (pinch_gesture_active_) | |
114 return; | |
115 | |
116 ResetAnimations(); | |
117 ResetBaseline(); | |
118 } | |
119 | |
120 gfx::Vector2dF TopControlsManager::ScrollBy( | |
121 const gfx::Vector2dF& pending_delta) { | |
122 if (!TopControlsHeight()) | |
123 return pending_delta; | |
124 | |
125 if (pinch_gesture_active_) | |
126 return pending_delta; | |
127 | |
128 if (permitted_state_ == SHOWN && pending_delta.y() > 0) | |
129 return pending_delta; | |
130 else if (permitted_state_ == HIDDEN && pending_delta.y() < 0) | |
131 return pending_delta; | |
132 | |
133 accumulated_scroll_delta_ += pending_delta.y(); | |
134 | |
135 float old_offset = ContentTopOffset(); | |
136 client_->SetCurrentTopControlsShownRatio( | |
137 (baseline_content_offset_ - accumulated_scroll_delta_) / | |
138 TopControlsHeight()); | |
139 | |
140 // If the controls are fully visible, treat the current position as the | |
141 // new baseline even if the gesture didn't end. | |
142 if (TopControlsShownRatio() == 1.f) | |
143 ResetBaseline(); | |
144 | |
145 ResetAnimations(); | |
146 | |
147 gfx::Vector2dF applied_delta(0.f, old_offset - ContentTopOffset()); | |
148 return pending_delta - applied_delta; | |
149 } | |
150 | |
151 void TopControlsManager::ScrollEnd() { | |
152 if (pinch_gesture_active_) | |
153 return; | |
154 | |
155 StartAnimationIfNecessary(); | |
156 } | |
157 | |
158 void TopControlsManager::PinchBegin() { | |
159 DCHECK(!pinch_gesture_active_); | |
160 pinch_gesture_active_ = true; | |
161 StartAnimationIfNecessary(); | |
162 } | |
163 | |
164 void TopControlsManager::PinchEnd() { | |
165 DCHECK(pinch_gesture_active_); | |
166 // Pinch{Begin,End} will always occur within the scope of Scroll{Begin,End}, | |
167 // so return to a state expected by the remaining scroll sequence. | |
168 pinch_gesture_active_ = false; | |
169 ScrollBegin(); | |
170 } | |
171 | |
172 void TopControlsManager::MainThreadHasStoppedFlinging() { | |
173 StartAnimationIfNecessary(); | |
174 } | |
175 | |
176 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) { | |
177 if (!has_animation() || !client_->HaveRootScrollLayer()) | |
178 return gfx::Vector2dF(); | |
179 | |
180 float old_offset = ContentTopOffset(); | |
181 float new_ratio = gfx::Tween::ClampedFloatValueBetween( | |
182 monotonic_time, animation_start_time_, animation_start_value_, | |
183 animation_stop_time_, animation_stop_value_); | |
184 client_->SetCurrentTopControlsShownRatio(new_ratio); | |
185 | |
186 if (IsAnimationComplete(new_ratio)) | |
187 ResetAnimations(); | |
188 | |
189 gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset); | |
190 return scroll_delta; | |
191 } | |
192 | |
193 void TopControlsManager::ResetAnimations() { | |
194 animation_start_time_ = base::TimeTicks(); | |
195 animation_start_value_ = 0.f; | |
196 animation_stop_time_ = base::TimeTicks(); | |
197 animation_stop_value_ = 0.f; | |
198 | |
199 animation_direction_ = NO_ANIMATION; | |
200 } | |
201 | |
202 void TopControlsManager::SetupAnimation(AnimationDirection direction) { | |
203 DCHECK_NE(NO_ANIMATION, direction); | |
204 DCHECK(direction != HIDING_CONTROLS || TopControlsShownRatio() > 0.f); | |
205 DCHECK(direction != SHOWING_CONTROLS || TopControlsShownRatio() < 1.f); | |
206 | |
207 if (has_animation() && animation_direction_ == direction) | |
208 return; | |
209 | |
210 if (!TopControlsHeight()) { | |
211 client_->SetCurrentTopControlsShownRatio( | |
212 direction == HIDING_CONTROLS ? 0.f : 1.f); | |
213 return; | |
214 } | |
215 | |
216 animation_start_time_ = base::TimeTicks::Now(); | |
217 animation_start_value_ = TopControlsShownRatio(); | |
218 | |
219 const float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1); | |
220 animation_stop_time_ = | |
221 animation_start_time_ + | |
222 base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs); | |
223 animation_stop_value_ = animation_start_value_ + max_ending_ratio; | |
224 | |
225 animation_direction_ = direction; | |
226 client_->DidChangeTopControlsPosition(); | |
227 } | |
228 | |
229 void TopControlsManager::StartAnimationIfNecessary() { | |
230 if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f) | |
231 return; | |
232 | |
233 if (TopControlsShownRatio() >= 1.f - top_controls_hide_threshold_) { | |
234 // If we're showing so much that the hide threshold won't trigger, show. | |
235 SetupAnimation(SHOWING_CONTROLS); | |
236 } else if (TopControlsShownRatio() <= top_controls_show_threshold_) { | |
237 // If we're showing so little that the show threshold won't trigger, hide. | |
238 SetupAnimation(HIDING_CONTROLS); | |
239 } else { | |
240 // If we could be either showing or hiding, we determine which one to | |
241 // do based on whether or not the total scroll delta was moving up or | |
242 // down. | |
243 SetupAnimation(accumulated_scroll_delta_ <= 0.f ? SHOWING_CONTROLS | |
244 : HIDING_CONTROLS); | |
245 } | |
246 } | |
247 | |
248 bool TopControlsManager::IsAnimationComplete(float new_ratio) { | |
249 return (animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) || | |
250 (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f); | |
251 } | |
252 | |
253 void TopControlsManager::ResetBaseline() { | |
254 accumulated_scroll_delta_ = 0.f; | |
255 baseline_content_offset_ = ContentTopOffset(); | |
256 } | |
257 | |
258 } // namespace cc | |
OLD | NEW |