| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/input/scrollbar_animation_controller.h" | 5 #include "cc/input/scrollbar_animation_controller.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/time/time.h" | 9 #include "base/time/time.h" |
| 10 #include "cc/trees/layer_tree_impl.h" | 10 #include "cc/trees/layer_tree_impl.h" |
| 11 | 11 |
| 12 namespace cc { | 12 namespace cc { |
| 13 | 13 |
| 14 std::unique_ptr<ScrollbarAnimationController> |
| 15 ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid( |
| 16 int scroll_layer_id, |
| 17 ScrollbarAnimationControllerClient* client, |
| 18 base::TimeDelta delay_before_starting, |
| 19 base::TimeDelta resize_delay_before_starting, |
| 20 base::TimeDelta fade_duration) { |
| 21 return base::WrapUnique(new ScrollbarAnimationController( |
| 22 scroll_layer_id, client, delay_before_starting, |
| 23 resize_delay_before_starting, fade_duration)); |
| 24 } |
| 25 |
| 26 std::unique_ptr<ScrollbarAnimationController> |
| 27 ScrollbarAnimationController::CreateScrollbarAnimationControllerAuraOverlay( |
| 28 int scroll_layer_id, |
| 29 ScrollbarAnimationControllerClient* client, |
| 30 base::TimeDelta delay_before_starting, |
| 31 base::TimeDelta resize_delay_before_starting, |
| 32 base::TimeDelta fade_duration, |
| 33 base::TimeDelta thinning_duration) { |
| 34 return base::WrapUnique(new ScrollbarAnimationController( |
| 35 scroll_layer_id, client, delay_before_starting, |
| 36 resize_delay_before_starting, fade_duration, thinning_duration)); |
| 37 } |
| 38 |
| 14 ScrollbarAnimationController::ScrollbarAnimationController( | 39 ScrollbarAnimationController::ScrollbarAnimationController( |
| 15 int scroll_layer_id, | 40 int scroll_layer_id, |
| 16 ScrollbarAnimationControllerClient* client, | 41 ScrollbarAnimationControllerClient* client, |
| 17 base::TimeDelta delay_before_starting, | 42 base::TimeDelta delay_before_starting, |
| 18 base::TimeDelta resize_delay_before_starting) | 43 base::TimeDelta resize_delay_before_starting, |
| 44 base::TimeDelta fade_duration) |
| 19 : client_(client), | 45 : client_(client), |
| 20 delay_before_starting_(delay_before_starting), | 46 delay_before_starting_(delay_before_starting), |
| 21 resize_delay_before_starting_(resize_delay_before_starting), | 47 resize_delay_before_starting_(resize_delay_before_starting), |
| 22 is_animating_(false), | 48 is_animating_(false), |
| 23 scroll_layer_id_(scroll_layer_id), | 49 scroll_layer_id_(scroll_layer_id), |
| 24 currently_scrolling_(false), | 50 currently_scrolling_(false), |
| 25 scroll_gesture_has_scrolled_(false), | 51 scroll_gesture_has_scrolled_(false), |
| 52 opacity_(0.0f), |
| 53 fade_duration_(fade_duration), |
| 54 need_thinning_animation_(false), |
| 26 weak_factory_(this) { | 55 weak_factory_(this) { |
| 56 ApplyOpacityToScrollbars(0.0f); |
| 57 } |
| 58 |
| 59 ScrollbarAnimationController::ScrollbarAnimationController( |
| 60 int scroll_layer_id, |
| 61 ScrollbarAnimationControllerClient* client, |
| 62 base::TimeDelta delay_before_starting, |
| 63 base::TimeDelta resize_delay_before_starting, |
| 64 base::TimeDelta fade_duration, |
| 65 base::TimeDelta thinning_duration) |
| 66 : client_(client), |
| 67 delay_before_starting_(delay_before_starting), |
| 68 resize_delay_before_starting_(resize_delay_before_starting), |
| 69 is_animating_(false), |
| 70 scroll_layer_id_(scroll_layer_id), |
| 71 currently_scrolling_(false), |
| 72 scroll_gesture_has_scrolled_(false), |
| 73 opacity_(0.0f), |
| 74 fade_duration_(fade_duration), |
| 75 need_thinning_animation_(true), |
| 76 weak_factory_(this) { |
| 77 vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create( |
| 78 scroll_layer_id, ScrollbarOrientation::VERTICAL, client, |
| 79 thinning_duration); |
| 80 horizontal_controller_ = SingleScrollbarAnimationControllerThinning::Create( |
| 81 scroll_layer_id, ScrollbarOrientation::HORIZONTAL, client, |
| 82 thinning_duration); |
| 83 ApplyOpacityToScrollbars(0.0f); |
| 27 } | 84 } |
| 28 | 85 |
| 29 ScrollbarAnimationController::~ScrollbarAnimationController() {} | 86 ScrollbarAnimationController::~ScrollbarAnimationController() {} |
| 30 | 87 |
| 88 ScrollbarSet ScrollbarAnimationController::Scrollbars() const { |
| 89 return client_->ScrollbarsFor(scroll_layer_id_); |
| 90 } |
| 91 |
| 31 SingleScrollbarAnimationControllerThinning& | 92 SingleScrollbarAnimationControllerThinning& |
| 32 ScrollbarAnimationController::GetScrollbarAnimationController( | 93 ScrollbarAnimationController::GetScrollbarAnimationController( |
| 33 ScrollbarOrientation orientation) const { | 94 ScrollbarOrientation orientation) const { |
| 34 DCHECK(NeedThinningAnimation()); | 95 DCHECK(need_thinning_animation_); |
| 35 if (orientation == ScrollbarOrientation::VERTICAL) | 96 if (orientation == ScrollbarOrientation::VERTICAL) |
| 36 return *(vertical_controller_.get()); | 97 return *(vertical_controller_.get()); |
| 37 else | 98 else |
| 38 return *(horizontal_controller_.get()); | 99 return *(horizontal_controller_.get()); |
| 39 } | 100 } |
| 40 | 101 |
| 102 void ScrollbarAnimationController::StartAnimation() { |
| 103 delayed_scrollbar_fade_.Cancel(); |
| 104 is_animating_ = true; |
| 105 last_awaken_time_ = base::TimeTicks(); |
| 106 client_->SetNeedsAnimateForScrollbarAnimation(); |
| 107 } |
| 108 |
| 109 void ScrollbarAnimationController::StopAnimation() { |
| 110 delayed_scrollbar_fade_.Cancel(); |
| 111 is_animating_ = false; |
| 112 } |
| 113 |
| 114 void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) { |
| 115 base::TimeDelta delay = |
| 116 on_resize ? resize_delay_before_starting_ : delay_before_starting_; |
| 117 delayed_scrollbar_fade_.Reset( |
| 118 base::Bind(&ScrollbarAnimationController::StartAnimation, |
| 119 weak_factory_.GetWeakPtr())); |
| 120 client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(), |
| 121 delay); |
| 122 } |
| 123 |
| 41 bool ScrollbarAnimationController::Animate(base::TimeTicks now) { | 124 bool ScrollbarAnimationController::Animate(base::TimeTicks now) { |
| 42 bool animated = false; | 125 bool animated = false; |
| 43 | 126 |
| 44 if (is_animating_) { | 127 if (is_animating_) { |
| 45 if (last_awaken_time_.is_null()) | 128 if (last_awaken_time_.is_null()) |
| 46 last_awaken_time_ = now; | 129 last_awaken_time_ = now; |
| 47 | 130 |
| 48 float progress = AnimationProgressAtTime(now); | 131 float progress = AnimationProgressAtTime(now); |
| 49 RunAnimationFrame(progress); | 132 RunAnimationFrame(progress); |
| 50 | 133 |
| 51 if (is_animating_) | 134 if (is_animating_) |
| 52 client_->SetNeedsAnimateForScrollbarAnimation(); | 135 client_->SetNeedsAnimateForScrollbarAnimation(); |
| 53 animated = true; | 136 animated = true; |
| 54 } | 137 } |
| 55 | 138 |
| 56 if (NeedThinningAnimation()) { | 139 if (need_thinning_animation_) { |
| 57 animated |= vertical_controller_->Animate(now); | 140 animated |= vertical_controller_->Animate(now); |
| 58 animated |= horizontal_controller_->Animate(now); | 141 animated |= horizontal_controller_->Animate(now); |
| 59 } | 142 } |
| 60 | 143 |
| 61 return animated; | 144 return animated; |
| 62 } | 145 } |
| 63 | 146 |
| 64 bool ScrollbarAnimationController::ScrollbarsHidden() const { | |
| 65 return false; | |
| 66 } | |
| 67 | |
| 68 bool ScrollbarAnimationController::NeedThinningAnimation() const { | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 float ScrollbarAnimationController::AnimationProgressAtTime( | 147 float ScrollbarAnimationController::AnimationProgressAtTime( |
| 73 base::TimeTicks now) { | 148 base::TimeTicks now) { |
| 74 base::TimeDelta delta = now - last_awaken_time_; | 149 base::TimeDelta delta = now - last_awaken_time_; |
| 75 float progress = delta.InSecondsF() / Duration().InSecondsF(); | 150 float progress = delta.InSecondsF() / fade_duration_.InSecondsF(); |
| 76 return std::max(std::min(progress, 1.f), 0.f); | 151 return std::max(std::min(progress, 1.f), 0.f); |
| 77 } | 152 } |
| 78 | 153 |
| 79 void ScrollbarAnimationController::DidScrollBegin() { | 154 void ScrollbarAnimationController::DidScrollBegin() { |
| 80 currently_scrolling_ = true; | 155 currently_scrolling_ = true; |
| 81 } | 156 } |
| 82 | 157 |
| 158 void ScrollbarAnimationController::RunAnimationFrame(float progress) { |
| 159 ApplyOpacityToScrollbars(1.f - progress); |
| 160 client_->SetNeedsRedrawForScrollbarAnimation(); |
| 161 if (progress == 1.f) |
| 162 StopAnimation(); |
| 163 } |
| 164 |
| 83 void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) { | 165 void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) { |
| 166 if (need_thinning_animation_ && Captured()) |
| 167 return; |
| 168 |
| 84 StopAnimation(); | 169 StopAnimation(); |
| 85 | 170 |
| 86 // As an optimization, we avoid spamming fade delay tasks during active fast | 171 // As an optimization, we avoid spamming fade delay tasks during active fast |
| 87 // scrolls. But if we're not within one, we need to post every scroll update. | 172 // scrolls. But if we're not within one, we need to post every scroll update. |
| 88 if (!currently_scrolling_) | 173 if (!currently_scrolling_) { |
| 89 PostDelayedAnimationTask(on_resize); | 174 // We don't fade out scrollbar if they need thinning animation and mouse is |
| 90 else | 175 // near. |
| 176 if (!need_thinning_animation_ || !mouse_is_near_any_scrollbar()) |
| 177 PostDelayedAnimationTask(on_resize); |
| 178 } else { |
| 91 scroll_gesture_has_scrolled_ = true; | 179 scroll_gesture_has_scrolled_ = true; |
| 180 } |
| 181 |
| 182 ApplyOpacityToScrollbars(1); |
| 183 |
| 184 if (need_thinning_animation_) { |
| 185 vertical_controller_->UpdateThumbThicknessScale(); |
| 186 horizontal_controller_->UpdateThumbThicknessScale(); |
| 187 } |
| 92 } | 188 } |
| 93 | 189 |
| 94 void ScrollbarAnimationController::DidScrollEnd() { | 190 void ScrollbarAnimationController::DidScrollEnd() { |
| 95 if (scroll_gesture_has_scrolled_) { | 191 bool has_scrolled = scroll_gesture_has_scrolled_; |
| 96 PostDelayedAnimationTask(false); | 192 scroll_gesture_has_scrolled_ = false; |
| 97 scroll_gesture_has_scrolled_ = false; | |
| 98 } | |
| 99 | 193 |
| 100 currently_scrolling_ = false; | 194 currently_scrolling_ = false; |
| 195 |
| 196 // We don't fade out scrollbar if they need thinning animation and mouse is |
| 197 // near. |
| 198 if (need_thinning_animation_ && mouse_is_near_any_scrollbar()) |
| 199 return; |
| 200 |
| 201 if (has_scrolled) |
| 202 PostDelayedAnimationTask(false); |
| 101 } | 203 } |
| 102 | 204 |
| 103 void ScrollbarAnimationController::DidMouseDown() { | 205 void ScrollbarAnimationController::DidMouseDown() { |
| 104 if (!NeedThinningAnimation() || ScrollbarsHidden()) | 206 if (!need_thinning_animation_ || ScrollbarsHidden()) |
| 105 return; | 207 return; |
| 106 | 208 |
| 107 vertical_controller_->DidMouseDown(); | 209 vertical_controller_->DidMouseDown(); |
| 108 horizontal_controller_->DidMouseDown(); | 210 horizontal_controller_->DidMouseDown(); |
| 109 } | 211 } |
| 110 | 212 |
| 111 void ScrollbarAnimationController::DidMouseUp() { | 213 void ScrollbarAnimationController::DidMouseUp() { |
| 112 if (!NeedThinningAnimation()) | 214 if (!need_thinning_animation_) |
| 113 return; | 215 return; |
| 114 | 216 |
| 115 vertical_controller_->DidMouseUp(); | 217 vertical_controller_->DidMouseUp(); |
| 116 horizontal_controller_->DidMouseUp(); | 218 horizontal_controller_->DidMouseUp(); |
| 117 | 219 |
| 118 if (!mouse_is_near_any_scrollbar()) | 220 if (!mouse_is_near_any_scrollbar()) |
| 119 PostDelayedAnimationTask(false); | 221 PostDelayedAnimationTask(false); |
| 120 } | 222 } |
| 121 | 223 |
| 122 void ScrollbarAnimationController::DidMouseLeave() { | 224 void ScrollbarAnimationController::DidMouseLeave() { |
| 123 if (!NeedThinningAnimation()) | 225 if (!need_thinning_animation_) |
| 124 return; | 226 return; |
| 125 | 227 |
| 126 vertical_controller_->DidMouseLeave(); | 228 vertical_controller_->DidMouseLeave(); |
| 127 horizontal_controller_->DidMouseLeave(); | 229 horizontal_controller_->DidMouseLeave(); |
| 128 | 230 |
| 129 if (ScrollbarsHidden() || Captured()) | 231 if (ScrollbarsHidden() || Captured()) |
| 130 return; | 232 return; |
| 131 | 233 |
| 132 PostDelayedAnimationTask(false); | 234 PostDelayedAnimationTask(false); |
| 133 } | 235 } |
| 134 | 236 |
| 135 void ScrollbarAnimationController::DidMouseMoveNear( | 237 void ScrollbarAnimationController::DidMouseMoveNear( |
| 136 ScrollbarOrientation orientation, | 238 ScrollbarOrientation orientation, |
| 137 float distance) { | 239 float distance) { |
| 138 if (!NeedThinningAnimation()) | 240 if (!need_thinning_animation_) |
| 139 return; | 241 return; |
| 140 | 242 |
| 141 GetScrollbarAnimationController(orientation).DidMouseMoveNear(distance); | 243 GetScrollbarAnimationController(orientation).DidMouseMoveNear(distance); |
| 142 | 244 |
| 143 if (ScrollbarsHidden() || Captured()) | 245 if (ScrollbarsHidden() || Captured()) |
| 144 return; | 246 return; |
| 145 | 247 |
| 146 if (mouse_is_near_any_scrollbar()) { | 248 if (mouse_is_near_any_scrollbar()) { |
| 147 ApplyOpacityToScrollbars(1); | 249 ApplyOpacityToScrollbars(1); |
| 148 StopAnimation(); | 250 StopAnimation(); |
| 149 } else if (!animating_fade()) { | 251 } else if (!is_animating_) { |
| 150 PostDelayedAnimationTask(false); | 252 PostDelayedAnimationTask(false); |
| 151 } | 253 } |
| 152 } | 254 } |
| 153 | 255 |
| 154 bool ScrollbarAnimationController::mouse_is_over_scrollbar( | 256 bool ScrollbarAnimationController::mouse_is_over_scrollbar( |
| 155 ScrollbarOrientation orientation) const { | 257 ScrollbarOrientation orientation) const { |
| 156 DCHECK(NeedThinningAnimation()); | 258 DCHECK(need_thinning_animation_); |
| 157 return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar(); | 259 return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar(); |
| 158 } | 260 } |
| 159 | 261 |
| 160 bool ScrollbarAnimationController::mouse_is_near_scrollbar( | 262 bool ScrollbarAnimationController::mouse_is_near_scrollbar( |
| 161 ScrollbarOrientation orientation) const { | 263 ScrollbarOrientation orientation) const { |
| 162 DCHECK(NeedThinningAnimation()); | 264 DCHECK(need_thinning_animation_); |
| 163 return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar(); | 265 return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar(); |
| 164 } | 266 } |
| 165 | 267 |
| 166 bool ScrollbarAnimationController::mouse_is_near_any_scrollbar() const { | 268 bool ScrollbarAnimationController::mouse_is_near_any_scrollbar() const { |
| 167 DCHECK(NeedThinningAnimation()); | 269 DCHECK(need_thinning_animation_); |
| 168 return vertical_controller_->mouse_is_near_scrollbar() || | 270 return vertical_controller_->mouse_is_near_scrollbar() || |
| 169 horizontal_controller_->mouse_is_near_scrollbar(); | 271 horizontal_controller_->mouse_is_near_scrollbar(); |
| 170 } | 272 } |
| 171 | 273 |
| 274 bool ScrollbarAnimationController::ScrollbarsHidden() const { |
| 275 return opacity_ == 0.0f; |
| 276 } |
| 277 |
| 172 bool ScrollbarAnimationController::Captured() const { | 278 bool ScrollbarAnimationController::Captured() const { |
| 173 DCHECK(NeedThinningAnimation()); | 279 DCHECK(need_thinning_animation_); |
| 174 return vertical_controller_->captured() || horizontal_controller_->captured(); | 280 return vertical_controller_->captured() || horizontal_controller_->captured(); |
| 175 } | 281 } |
| 176 | 282 |
| 177 void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) { | 283 void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) { |
| 178 base::TimeDelta delay = | 284 for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) { |
| 179 on_resize ? resize_delay_before_starting_ : delay_before_starting_; | 285 if (!scrollbar->is_overlay_scrollbar()) |
| 180 delayed_scrollbar_fade_.Reset( | 286 continue; |
| 181 base::Bind(&ScrollbarAnimationController::StartAnimation, | 287 float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0; |
| 182 weak_factory_.GetWeakPtr())); | 288 PropertyTrees* property_trees = |
| 183 client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(), | 289 scrollbar->layer_tree_impl()->property_trees(); |
| 184 delay); | 290 // If this method is called during LayerImpl::PushPropertiesTo, we may not |
| 185 } | 291 // yet have valid layer_id_to_effect_node_index entries as property trees |
| 292 // are pushed after layers during activation. We can skip updating opacity |
| 293 // in that case as we are only registering a scrollbar and because opacity |
| 294 // will be overwritten anyway when property trees are pushed. |
| 295 if (property_trees->IsInIdToIndexMap(PropertyTrees::TreeType::EFFECT, |
| 296 scrollbar->id())) { |
| 297 property_trees->effect_tree.OnOpacityAnimated( |
| 298 effective_opacity, |
| 299 property_trees->layer_id_to_effect_node_index[scrollbar->id()], |
| 300 scrollbar->layer_tree_impl()); |
| 301 } |
| 302 } |
| 186 | 303 |
| 187 void ScrollbarAnimationController::StartAnimation() { | 304 bool previouslyVisible = opacity_ > 0.0f; |
| 188 delayed_scrollbar_fade_.Cancel(); | 305 bool currentlyVisible = opacity > 0.0f; |
| 189 is_animating_ = true; | |
| 190 last_awaken_time_ = base::TimeTicks(); | |
| 191 client_->SetNeedsAnimateForScrollbarAnimation(); | |
| 192 } | |
| 193 | 306 |
| 194 void ScrollbarAnimationController::StopAnimation() { | 307 opacity_ = opacity; |
| 195 delayed_scrollbar_fade_.Cancel(); | |
| 196 is_animating_ = false; | |
| 197 } | |
| 198 | 308 |
| 199 ScrollbarSet ScrollbarAnimationController::Scrollbars() const { | 309 if (previouslyVisible != currentlyVisible) |
| 200 return client_->ScrollbarsFor(scroll_layer_id_); | 310 client_->DidChangeScrollbarVisibility(); |
| 201 } | |
| 202 | |
| 203 void ScrollbarAnimationController::set_mouse_move_distance_for_test( | |
| 204 float distance) { | |
| 205 vertical_controller_->set_mouse_move_distance_for_test(distance); | |
| 206 horizontal_controller_->set_mouse_move_distance_for_test(distance); | |
| 207 } | 311 } |
| 208 | 312 |
| 209 } // namespace cc | 313 } // namespace cc |
| OLD | NEW |