| 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 |