Chromium Code Reviews| 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::CreateScrollbarAnimationControllerLinearFade( | |
| 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::CreateScrollbarAnimationControllerThinning( | |
| 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 : ScrollbarAnimationController(scroll_layer_id, | |
| 67 client, | |
| 68 delay_before_starting, | |
| 69 resize_delay_before_starting, | |
| 70 fade_duration) { | |
| 71 need_thinning_animation_ = true; | |
| 72 vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create( | |
| 73 scroll_layer_id, ScrollbarOrientation::VERTICAL, client, | |
| 74 thinning_duration); | |
| 75 horizontal_controller_ = SingleScrollbarAnimationControllerThinning::Create( | |
| 76 scroll_layer_id, ScrollbarOrientation::HORIZONTAL, client, | |
| 77 thinning_duration); | |
| 27 } | 78 } |
| 28 | 79 |
| 29 ScrollbarAnimationController::~ScrollbarAnimationController() {} | 80 ScrollbarAnimationController::~ScrollbarAnimationController() {} |
| 30 | 81 |
| 82 ScrollbarSet ScrollbarAnimationController::Scrollbars() const { | |
| 83 return client_->ScrollbarsFor(scroll_layer_id_); | |
| 84 } | |
| 85 | |
| 31 SingleScrollbarAnimationControllerThinning& | 86 SingleScrollbarAnimationControllerThinning& |
| 32 ScrollbarAnimationController::GetScrollbarAnimationController( | 87 ScrollbarAnimationController::GetScrollbarAnimationController( |
| 33 ScrollbarOrientation orientation) const { | 88 ScrollbarOrientation orientation) const { |
| 34 DCHECK(NeedThinningAnimation()); | 89 DCHECK(need_thinning_animation_); |
| 35 if (orientation == ScrollbarOrientation::VERTICAL) | 90 if (orientation == ScrollbarOrientation::VERTICAL) |
| 36 return *(vertical_controller_.get()); | 91 return *(vertical_controller_.get()); |
| 37 else | 92 else |
| 38 return *(horizontal_controller_.get()); | 93 return *(horizontal_controller_.get()); |
| 39 } | 94 } |
| 40 | 95 |
| 96 void ScrollbarAnimationController::StartAnimation() { | |
| 97 delayed_scrollbar_fade_.Cancel(); | |
| 98 is_animating_ = true; | |
| 99 last_awaken_time_ = base::TimeTicks(); | |
| 100 client_->SetNeedsAnimateForScrollbarAnimation(); | |
| 101 } | |
| 102 | |
| 103 void ScrollbarAnimationController::StopAnimation() { | |
| 104 delayed_scrollbar_fade_.Cancel(); | |
| 105 is_animating_ = false; | |
| 106 } | |
| 107 | |
| 108 void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) { | |
| 109 base::TimeDelta delay = | |
| 110 on_resize ? resize_delay_before_starting_ : delay_before_starting_; | |
| 111 delayed_scrollbar_fade_.Reset( | |
| 112 base::Bind(&ScrollbarAnimationController::StartAnimation, | |
| 113 weak_factory_.GetWeakPtr())); | |
| 114 client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(), | |
| 115 delay); | |
| 116 } | |
| 117 | |
| 41 bool ScrollbarAnimationController::Animate(base::TimeTicks now) { | 118 bool ScrollbarAnimationController::Animate(base::TimeTicks now) { |
| 42 bool animated = false; | 119 bool animated = false; |
| 43 | 120 |
| 44 if (is_animating_) { | 121 if (is_animating_) { |
| 45 if (last_awaken_time_.is_null()) | 122 if (last_awaken_time_.is_null()) |
| 46 last_awaken_time_ = now; | 123 last_awaken_time_ = now; |
| 47 | 124 |
| 48 float progress = AnimationProgressAtTime(now); | 125 float progress = AnimationProgressAtTime(now); |
| 49 RunAnimationFrame(progress); | 126 RunAnimationFrame(progress); |
| 50 | 127 |
| 51 if (is_animating_) | 128 if (is_animating_) |
| 52 client_->SetNeedsAnimateForScrollbarAnimation(); | 129 client_->SetNeedsAnimateForScrollbarAnimation(); |
| 53 animated = true; | 130 animated = true; |
| 54 } | 131 } |
| 55 | 132 |
| 56 if (NeedThinningAnimation()) { | 133 if (need_thinning_animation_) { |
| 57 animated |= vertical_controller_->Animate(now); | 134 animated |= vertical_controller_->Animate(now); |
| 58 animated |= horizontal_controller_->Animate(now); | 135 animated |= horizontal_controller_->Animate(now); |
| 59 } | 136 } |
| 60 | 137 |
| 61 return animated; | 138 return animated; |
| 62 } | 139 } |
| 63 | 140 |
| 64 bool ScrollbarAnimationController::ScrollbarsHidden() const { | |
| 65 return false; | |
| 66 } | |
| 67 | |
| 68 bool ScrollbarAnimationController::NeedThinningAnimation() const { | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 float ScrollbarAnimationController::AnimationProgressAtTime( | 141 float ScrollbarAnimationController::AnimationProgressAtTime( |
| 73 base::TimeTicks now) { | 142 base::TimeTicks now) { |
| 74 base::TimeDelta delta = now - last_awaken_time_; | 143 base::TimeDelta delta = now - last_awaken_time_; |
| 75 float progress = delta.InSecondsF() / Duration().InSecondsF(); | 144 float progress = delta.InSecondsF() / fade_duration_.InSecondsF(); |
| 76 return std::max(std::min(progress, 1.f), 0.f); | 145 return std::max(std::min(progress, 1.f), 0.f); |
| 77 } | 146 } |
| 78 | 147 |
| 79 void ScrollbarAnimationController::DidScrollBegin() { | 148 void ScrollbarAnimationController::DidScrollBegin() { |
| 80 currently_scrolling_ = true; | 149 currently_scrolling_ = true; |
| 81 } | 150 } |
| 82 | 151 |
| 152 void ScrollbarAnimationController::RunAnimationFrame(float progress) { | |
| 153 ApplyOpacityToScrollbars(1.f - progress); | |
| 154 client_->SetNeedsRedrawForScrollbarAnimation(); | |
| 155 if (progress == 1.f) | |
| 156 StopAnimation(); | |
| 157 } | |
| 158 | |
| 83 void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) { | 159 void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) { |
| 160 if (need_thinning_animation_ && Captured()) | |
| 161 return; | |
| 162 | |
| 84 StopAnimation(); | 163 StopAnimation(); |
| 85 | 164 |
| 86 // As an optimization, we avoid spamming fade delay tasks during active fast | 165 // 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. | 166 // scrolls. But if we're not within one, we need to post every scroll update. |
| 88 if (!currently_scrolling_) | 167 if (!currently_scrolling_) { |
| 89 PostDelayedAnimationTask(on_resize); | 168 // We don't fade out scrollbar if they need thinning animation and mouse is |
| 90 else | 169 // near. |
| 170 if (!need_thinning_animation_ || !mouse_is_near_any_scrollbar()) | |
| 171 PostDelayedAnimationTask(on_resize); | |
| 172 } else { | |
| 91 scroll_gesture_has_scrolled_ = true; | 173 scroll_gesture_has_scrolled_ = true; |
| 174 } | |
| 175 | |
| 176 ApplyOpacityToScrollbars(1); | |
| 177 | |
| 178 if (need_thinning_animation_) { | |
| 179 vertical_controller_->UpdateThumbThicknessScale(); | |
| 180 horizontal_controller_->UpdateThumbThicknessScale(); | |
| 181 } | |
| 92 } | 182 } |
| 93 | 183 |
| 94 void ScrollbarAnimationController::DidScrollEnd() { | 184 void ScrollbarAnimationController::DidScrollEnd() { |
| 95 if (scroll_gesture_has_scrolled_) { | 185 bool has_scrolled = scroll_gesture_has_scrolled_; |
| 96 PostDelayedAnimationTask(false); | 186 scroll_gesture_has_scrolled_ = false; |
| 97 scroll_gesture_has_scrolled_ = false; | |
| 98 } | |
| 99 | 187 |
| 100 currently_scrolling_ = false; | 188 currently_scrolling_ = false; |
| 189 | |
| 190 // We don't fade out scrollbar if they need thinning animation and mouse is | |
| 191 // near. | |
| 192 if (need_thinning_animation_ && mouse_is_near_any_scrollbar()) | |
| 193 return; | |
| 194 | |
| 195 if (has_scrolled) | |
| 196 PostDelayedAnimationTask(false); | |
| 101 } | 197 } |
| 102 | 198 |
| 103 void ScrollbarAnimationController::DidMouseDown() { | 199 void ScrollbarAnimationController::DidMouseDown() { |
| 104 if (!NeedThinningAnimation() || ScrollbarsHidden()) | 200 if (!need_thinning_animation_ || ScrollbarsHidden()) |
| 105 return; | 201 return; |
| 106 | 202 |
| 107 vertical_controller_->DidMouseDown(); | 203 vertical_controller_->DidMouseDown(); |
| 108 horizontal_controller_->DidMouseDown(); | 204 horizontal_controller_->DidMouseDown(); |
| 109 } | 205 } |
| 110 | 206 |
| 111 void ScrollbarAnimationController::DidMouseUp() { | 207 void ScrollbarAnimationController::DidMouseUp() { |
| 112 if (!NeedThinningAnimation()) | 208 if (!need_thinning_animation_) |
| 113 return; | 209 return; |
| 114 | 210 |
| 115 vertical_controller_->DidMouseUp(); | 211 vertical_controller_->DidMouseUp(); |
| 116 horizontal_controller_->DidMouseUp(); | 212 horizontal_controller_->DidMouseUp(); |
| 117 | 213 |
| 118 if (!mouse_is_near_any_scrollbar()) | 214 if (!mouse_is_near_any_scrollbar()) |
| 119 PostDelayedAnimationTask(false); | 215 PostDelayedAnimationTask(false); |
| 120 } | 216 } |
| 121 | 217 |
| 122 void ScrollbarAnimationController::DidMouseLeave() { | 218 void ScrollbarAnimationController::DidMouseLeave() { |
| 123 if (!NeedThinningAnimation()) | 219 if (!need_thinning_animation_) |
| 124 return; | 220 return; |
| 125 | 221 |
| 126 vertical_controller_->DidMouseLeave(); | 222 vertical_controller_->DidMouseLeave(); |
| 127 horizontal_controller_->DidMouseLeave(); | 223 horizontal_controller_->DidMouseLeave(); |
| 128 | 224 |
| 129 if (ScrollbarsHidden() || Captured()) | 225 if (ScrollbarsHidden() || Captured()) |
| 130 return; | 226 return; |
| 131 | 227 |
| 132 PostDelayedAnimationTask(false); | 228 PostDelayedAnimationTask(false); |
| 133 } | 229 } |
| 134 | 230 |
| 135 void ScrollbarAnimationController::DidMouseMoveNear( | 231 void ScrollbarAnimationController::DidMouseMoveNear( |
| 136 ScrollbarOrientation orientation, | 232 ScrollbarOrientation orientation, |
| 137 float distance) { | 233 float distance) { |
| 138 if (!NeedThinningAnimation()) | 234 if (!need_thinning_animation_) |
| 139 return; | 235 return; |
| 140 | 236 |
| 141 GetScrollbarAnimationController(orientation).DidMouseMoveNear(distance); | 237 GetScrollbarAnimationController(orientation).DidMouseMoveNear(distance); |
| 142 | 238 |
| 143 if (ScrollbarsHidden() || Captured()) | 239 if (ScrollbarsHidden() || Captured()) |
| 144 return; | 240 return; |
| 145 | 241 |
| 146 if (mouse_is_near_any_scrollbar()) { | 242 if (mouse_is_near_any_scrollbar()) { |
| 147 ApplyOpacityToScrollbars(1); | 243 ApplyOpacityToScrollbars(1); |
| 148 StopAnimation(); | 244 StopAnimation(); |
| 149 } else if (!animating_fade()) { | 245 } else if (!is_animating_) { |
| 150 PostDelayedAnimationTask(false); | 246 PostDelayedAnimationTask(false); |
| 151 } | 247 } |
| 152 } | 248 } |
| 153 | 249 |
| 154 bool ScrollbarAnimationController::mouse_is_over_scrollbar( | 250 bool ScrollbarAnimationController::mouse_is_over_scrollbar( |
| 155 ScrollbarOrientation orientation) const { | 251 ScrollbarOrientation orientation) const { |
| 156 DCHECK(NeedThinningAnimation()); | 252 DCHECK(need_thinning_animation_); |
| 157 return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar(); | 253 return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar(); |
| 158 } | 254 } |
| 159 | 255 |
| 160 bool ScrollbarAnimationController::mouse_is_near_scrollbar( | 256 bool ScrollbarAnimationController::mouse_is_near_scrollbar( |
| 161 ScrollbarOrientation orientation) const { | 257 ScrollbarOrientation orientation) const { |
| 162 DCHECK(NeedThinningAnimation()); | 258 DCHECK(need_thinning_animation_); |
| 163 return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar(); | 259 return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar(); |
| 164 } | 260 } |
| 165 | 261 |
| 166 bool ScrollbarAnimationController::mouse_is_near_any_scrollbar() const { | 262 bool ScrollbarAnimationController::mouse_is_near_any_scrollbar() const { |
| 167 DCHECK(NeedThinningAnimation()); | 263 DCHECK(need_thinning_animation_); |
| 168 return vertical_controller_->mouse_is_near_scrollbar() || | 264 return vertical_controller_->mouse_is_near_scrollbar() || |
| 169 horizontal_controller_->mouse_is_near_scrollbar(); | 265 horizontal_controller_->mouse_is_near_scrollbar(); |
| 170 } | 266 } |
| 171 | 267 |
| 172 bool ScrollbarAnimationController::Captured() const { | 268 bool ScrollbarAnimationController::ScrollbarsHidden() const { |
| 173 DCHECK(NeedThinningAnimation()); | 269 return opacity_ == 0.0f; |
| 174 return vertical_controller_->captured() || horizontal_controller_->captured(); | |
| 175 } | 270 } |
| 176 | 271 |
| 177 void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) { | 272 bool ScrollbarAnimationController::Captured() const { |
| 178 base::TimeDelta delay = | 273 DCHECK(need_thinning_animation_); |
| 179 on_resize ? resize_delay_before_starting_ : delay_before_starting_; | 274 return vertical_controller_->captured() || horizontal_controller_->captured(); |
| 180 delayed_scrollbar_fade_.Reset( | |
| 181 base::Bind(&ScrollbarAnimationController::StartAnimation, | |
| 182 weak_factory_.GetWeakPtr())); | |
| 183 client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(), | |
| 184 delay); | |
| 185 } | |
| 186 | |
| 187 void ScrollbarAnimationController::StartAnimation() { | |
| 188 delayed_scrollbar_fade_.Cancel(); | |
| 189 is_animating_ = true; | |
| 190 last_awaken_time_ = base::TimeTicks(); | |
| 191 client_->SetNeedsAnimateForScrollbarAnimation(); | |
| 192 } | |
| 193 | |
| 194 void ScrollbarAnimationController::StopAnimation() { | |
| 195 delayed_scrollbar_fade_.Cancel(); | |
| 196 is_animating_ = false; | |
| 197 } | |
| 198 | |
| 199 ScrollbarSet ScrollbarAnimationController::Scrollbars() const { | |
| 200 return client_->ScrollbarsFor(scroll_layer_id_); | |
| 201 } | 275 } |
| 202 | 276 |
| 203 void ScrollbarAnimationController::set_mouse_move_distance_for_test( | 277 void ScrollbarAnimationController::set_mouse_move_distance_for_test( |
|
weiliangc
2017/02/15 19:41:15
Since set_moust_move_distance_for_test is availabl
chaopeng
2017/02/15 19:59:50
This is the entry for layer_tree_host_impl_unittes
weiliangc
2017/02/15 20:06:08
I see three use cases there, none of which seems l
| |
| 204 float distance) { | 278 float distance) { |
| 205 vertical_controller_->set_mouse_move_distance_for_test(distance); | 279 vertical_controller_->set_mouse_move_distance_for_test(distance); |
| 206 horizontal_controller_->set_mouse_move_distance_for_test(distance); | 280 horizontal_controller_->set_mouse_move_distance_for_test(distance); |
| 207 } | 281 } |
| 208 | 282 |
| 283 void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) { | |
| 284 for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) { | |
| 285 if (!scrollbar->is_overlay_scrollbar()) | |
| 286 continue; | |
| 287 float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0; | |
| 288 PropertyTrees* property_trees = | |
| 289 scrollbar->layer_tree_impl()->property_trees(); | |
| 290 // If this method is called during LayerImpl::PushPropertiesTo, we may not | |
| 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 } | |
| 303 | |
| 304 bool previouslyVisible = opacity_ > 0.0f; | |
| 305 bool currentlyVisible = opacity > 0.0f; | |
| 306 | |
| 307 opacity_ = opacity; | |
| 308 | |
| 309 if (previouslyVisible != currentlyVisible) | |
| 310 client_->DidChangeScrollbarVisibility(); | |
| 311 } | |
| 312 | |
| 209 } // namespace cc | 313 } // namespace cc |
| OLD | NEW |