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