| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "ui/views/animation/flood_fill_ink_drop_animation.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "third_party/skia/include/core/SkColor.h" | |
| 11 #include "ui/compositor/layer.h" | |
| 12 #include "ui/compositor/layer_animation_sequence.h" | |
| 13 #include "ui/compositor/scoped_layer_animation_settings.h" | |
| 14 #include "ui/gfx/geometry/point_conversions.h" | |
| 15 #include "ui/gfx/geometry/vector2d_f.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // The minimum radius to use when scaling the painted layers. Smaller values | |
| 20 // were causing visual anomalies. | |
| 21 const float kMinRadius = 1.f; | |
| 22 | |
| 23 // All the sub animations that are used to animate each of the InkDropStates. | |
| 24 // These are used to get time durations with | |
| 25 // GetAnimationDuration(InkDropSubAnimations). Note that in general a sub | |
| 26 // animation defines the duration for either a transformation animation or an | |
| 27 // opacity animation but there are some exceptions where an entire InkDropState | |
| 28 // animation consists of only 1 sub animation and it defines the duration for | |
| 29 // both the transformation and opacity animations. | |
| 30 enum InkDropSubAnimations { | |
| 31 // HIDDEN sub animations. | |
| 32 | |
| 33 // The HIDDEN sub animation that is fading out to a hidden opacity. | |
| 34 HIDDEN_FADE_OUT, | |
| 35 | |
| 36 // The HIDDEN sub animation that transform the circle to a small one. | |
| 37 HIDDEN_TRANSFORM, | |
| 38 | |
| 39 // ACTION_PENDING sub animations. | |
| 40 | |
| 41 // The ACTION_PENDING sub animation that fades in to the visible opacity. | |
| 42 ACTION_PENDING_FADE_IN, | |
| 43 | |
| 44 // The ACTION_PENDING sub animation that transforms the circle to fill the | |
| 45 // bounds. | |
| 46 ACTION_PENDING_TRANSFORM, | |
| 47 | |
| 48 // ACTION_TRIGGERED sub animations. | |
| 49 | |
| 50 // The ACTION_TRIGGERED sub animation that is fading out to a hidden opacity. | |
| 51 ACTION_TRIGGERED_FADE_OUT, | |
| 52 | |
| 53 // ALTERNATE_ACTION_PENDING sub animations. | |
| 54 | |
| 55 // The ALTERNATE_ACTION_PENDING animation has only one sub animation which | |
| 56 // animates | |
| 57 // the circleto fill the bounds at visible opacity. | |
| 58 ALTERNATE_ACTION_PENDING, | |
| 59 | |
| 60 // ALTERNATE_ACTION_TRIGGERED sub animations. | |
| 61 | |
| 62 // The ALTERNATE_ACTION_TRIGGERED sub animation that is fading out to a hidden | |
| 63 // opacity. | |
| 64 ALTERNATE_ACTION_TRIGGERED_FADE_OUT, | |
| 65 | |
| 66 // ACTIVATED sub animations. | |
| 67 | |
| 68 // The ACTIVATED sub animation that is fading in to the visible opacity. | |
| 69 ACTIVATED_FADE_IN, | |
| 70 | |
| 71 // The ACTIVATED sub animation that transforms the circle to fill the entire | |
| 72 // bounds. | |
| 73 ACTIVATED_TRANSFORM, | |
| 74 | |
| 75 // DEACTIVATED sub animations. | |
| 76 | |
| 77 // The DEACTIVATED sub animation that is fading out to a hidden opacity. | |
| 78 DEACTIVATED_FADE_OUT, | |
| 79 }; | |
| 80 | |
| 81 // Duration constants for InkDropStateSubAnimations. See the | |
| 82 // InkDropStateSubAnimations enum documentation for more info. | |
| 83 int kAnimationDurationInMs[] = { | |
| 84 200, // HIDDEN_FADE_OUT | |
| 85 300, // HIDDEN_TRANSFORM | |
| 86 0, // ACTION_PENDING_FADE_IN | |
| 87 240, // ACTION_PENDING_TRANSFORM | |
| 88 300, // ACTION_TRIGGERED_FADE_OUT | |
| 89 200, // ALTERNATE_ACTION_PENDING | |
| 90 300, // ALTERNATE_ACTION_TRIGGERED_FADE_OUT | |
| 91 150, // ACTIVATED_FADE_IN | |
| 92 200, // ACTIVATED_TRANSFORM | |
| 93 300, // DEACTIVATED_FADE_OUT | |
| 94 }; | |
| 95 | |
| 96 // Returns the InkDropState sub animation duration for the given |state|. | |
| 97 base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) { | |
| 98 return base::TimeDelta::FromMilliseconds( | |
| 99 (views::InkDropAnimation::UseFastAnimations() | |
| 100 ? 1 | |
| 101 : views::InkDropAnimation::kSlowAnimationDurationFactor) * | |
| 102 kAnimationDurationInMs[state]); | |
| 103 } | |
| 104 | |
| 105 } // namespace | |
| 106 | |
| 107 namespace views { | |
| 108 | |
| 109 FloodFillInkDropAnimation::FloodFillInkDropAnimation( | |
| 110 const gfx::Rect& clip_bounds, | |
| 111 const gfx::Point& center_point, | |
| 112 SkColor color) | |
| 113 : clip_bounds_(clip_bounds), | |
| 114 center_point_(center_point), | |
| 115 root_layer_(ui::LAYER_NOT_DRAWN), | |
| 116 circle_layer_delegate_( | |
| 117 color, | |
| 118 std::max(clip_bounds_.width(), clip_bounds_.height()) / 2.f), | |
| 119 ink_drop_state_(InkDropState::HIDDEN) { | |
| 120 root_layer_.set_name("FloodFillInkDropAnimation:ROOT_LAYER"); | |
| 121 root_layer_.SetMasksToBounds(true); | |
| 122 root_layer_.SetBounds(clip_bounds); | |
| 123 | |
| 124 const int painted_size_length = | |
| 125 2 * std::max(clip_bounds_.width(), clip_bounds_.height()); | |
| 126 | |
| 127 painted_layer_.SetBounds(gfx::Rect(painted_size_length, painted_size_length)); | |
| 128 painted_layer_.SetFillsBoundsOpaquely(false); | |
| 129 painted_layer_.set_delegate(&circle_layer_delegate_); | |
| 130 painted_layer_.SetVisible(true); | |
| 131 painted_layer_.SetOpacity(1.0); | |
| 132 painted_layer_.SetMasksToBounds(false); | |
| 133 painted_layer_.set_name("FloodFillInkDropAnimation:PAINTED_LAYER"); | |
| 134 | |
| 135 root_layer_.Add(&painted_layer_); | |
| 136 | |
| 137 SetStateToHidden(); | |
| 138 } | |
| 139 | |
| 140 FloodFillInkDropAnimation::~FloodFillInkDropAnimation() { | |
| 141 // Explicitly aborting all the animations ensures all callbacks are invoked | |
| 142 // while this instance still exists. | |
| 143 AbortAllAnimations(); | |
| 144 } | |
| 145 | |
| 146 void FloodFillInkDropAnimation::SnapToActivated() { | |
| 147 InkDropAnimation::SnapToActivated(); | |
| 148 SetOpacity(kVisibleOpacity); | |
| 149 painted_layer_.SetTransform(GetMaxSizeTargetTransform()); | |
| 150 } | |
| 151 | |
| 152 ui::Layer* FloodFillInkDropAnimation::GetRootLayer() { | |
| 153 return &root_layer_; | |
| 154 } | |
| 155 | |
| 156 bool FloodFillInkDropAnimation::IsVisible() const { | |
| 157 return root_layer_.visible(); | |
| 158 } | |
| 159 | |
| 160 void FloodFillInkDropAnimation::AnimateStateChange( | |
| 161 InkDropState old_ink_drop_state, | |
| 162 InkDropState new_ink_drop_state, | |
| 163 ui::LayerAnimationObserver* animation_observer) { | |
| 164 switch (new_ink_drop_state) { | |
| 165 case InkDropState::HIDDEN: | |
| 166 if (!IsVisible()) { | |
| 167 SetStateToHidden(); | |
| 168 } else { | |
| 169 AnimateToOpacity(kHiddenOpacity, GetAnimationDuration(HIDDEN_FADE_OUT), | |
| 170 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 171 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 172 const gfx::Transform transform = CalculateTransform(kMinRadius); | |
| 173 AnimateToTransform(transform, GetAnimationDuration(HIDDEN_TRANSFORM), | |
| 174 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 175 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 176 } | |
| 177 break; | |
| 178 case InkDropState::ACTION_PENDING: { | |
| 179 DCHECK(old_ink_drop_state == InkDropState::HIDDEN); | |
| 180 | |
| 181 AnimateToOpacity(kVisibleOpacity, | |
| 182 GetAnimationDuration(ACTION_PENDING_FADE_IN), | |
| 183 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 184 gfx::Tween::EASE_IN, animation_observer); | |
| 185 AnimateToOpacity(kVisibleOpacity, | |
| 186 GetAnimationDuration(ACTION_PENDING_TRANSFORM) - | |
| 187 GetAnimationDuration(ACTION_PENDING_FADE_IN), | |
| 188 ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, | |
| 189 gfx::Tween::EASE_IN, animation_observer); | |
| 190 | |
| 191 AnimateToTransform(GetMaxSizeTargetTransform(), | |
| 192 GetAnimationDuration(ACTION_PENDING_TRANSFORM), | |
| 193 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 194 gfx::Tween::FAST_OUT_SLOW_IN, animation_observer); | |
| 195 break; | |
| 196 } | |
| 197 case InkDropState::ACTION_TRIGGERED: { | |
| 198 DCHECK(old_ink_drop_state == InkDropState::HIDDEN || | |
| 199 old_ink_drop_state == InkDropState::ACTION_PENDING); | |
| 200 if (old_ink_drop_state == InkDropState::HIDDEN) { | |
| 201 AnimateStateChange(old_ink_drop_state, InkDropState::ACTION_PENDING, | |
| 202 animation_observer); | |
| 203 } | |
| 204 AnimateToOpacity(kHiddenOpacity, | |
| 205 GetAnimationDuration(ACTION_TRIGGERED_FADE_OUT), | |
| 206 ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, | |
| 207 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 208 break; | |
| 209 } | |
| 210 case InkDropState::ALTERNATE_ACTION_PENDING: { | |
| 211 DCHECK(old_ink_drop_state == InkDropState::ACTION_PENDING); | |
| 212 AnimateToOpacity(kVisibleOpacity, | |
| 213 GetAnimationDuration(ALTERNATE_ACTION_PENDING), | |
| 214 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 215 gfx::Tween::EASE_IN, animation_observer); | |
| 216 AnimateToTransform(GetMaxSizeTargetTransform(), | |
| 217 GetAnimationDuration(ALTERNATE_ACTION_PENDING), | |
| 218 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 219 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 220 break; | |
| 221 } | |
| 222 case InkDropState::ALTERNATE_ACTION_TRIGGERED: | |
| 223 DCHECK(old_ink_drop_state == InkDropState::ALTERNATE_ACTION_PENDING); | |
| 224 AnimateToOpacity(kHiddenOpacity, GetAnimationDuration( | |
| 225 ALTERNATE_ACTION_TRIGGERED_FADE_OUT), | |
| 226 ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, | |
| 227 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 228 break; | |
| 229 case InkDropState::ACTIVATED: { | |
| 230 AnimateToOpacity(kVisibleOpacity, GetAnimationDuration(ACTIVATED_FADE_IN), | |
| 231 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 232 gfx::Tween::EASE_IN, animation_observer); | |
| 233 AnimateToTransform(GetMaxSizeTargetTransform(), | |
| 234 GetAnimationDuration(ACTIVATED_TRANSFORM), | |
| 235 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 236 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 237 break; | |
| 238 } | |
| 239 case InkDropState::DEACTIVATED: | |
| 240 AnimateToOpacity(kHiddenOpacity, | |
| 241 GetAnimationDuration(DEACTIVATED_FADE_OUT), | |
| 242 ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, | |
| 243 gfx::Tween::EASE_IN_OUT, animation_observer); | |
| 244 break; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 void FloodFillInkDropAnimation::SetStateToHidden() { | |
| 249 painted_layer_.SetTransform(CalculateTransform(kMinRadius)); | |
| 250 root_layer_.SetOpacity(InkDropAnimation::kHiddenOpacity); | |
| 251 root_layer_.SetVisible(false); | |
| 252 } | |
| 253 | |
| 254 void FloodFillInkDropAnimation::AbortAllAnimations() { | |
| 255 root_layer_.GetAnimator()->AbortAllAnimations(); | |
| 256 painted_layer_.GetAnimator()->AbortAllAnimations(); | |
| 257 } | |
| 258 | |
| 259 void FloodFillInkDropAnimation::AnimateToTransform( | |
| 260 const gfx::Transform& transform, | |
| 261 base::TimeDelta duration, | |
| 262 ui::LayerAnimator::PreemptionStrategy preemption_strategy, | |
| 263 gfx::Tween::Type tween, | |
| 264 ui::LayerAnimationObserver* animation_observer) { | |
| 265 ui::LayerAnimator* animator = painted_layer_.GetAnimator(); | |
| 266 ui::ScopedLayerAnimationSettings animation(animator); | |
| 267 animation.SetPreemptionStrategy(preemption_strategy); | |
| 268 animation.SetTweenType(tween); | |
| 269 ui::LayerAnimationElement* element = | |
| 270 ui::LayerAnimationElement::CreateTransformElement(transform, duration); | |
| 271 ui::LayerAnimationSequence* sequence = | |
| 272 new ui::LayerAnimationSequence(element); | |
| 273 | |
| 274 if (animation_observer) | |
| 275 sequence->AddObserver(animation_observer); | |
| 276 | |
| 277 animator->StartAnimation(sequence); | |
| 278 } | |
| 279 | |
| 280 void FloodFillInkDropAnimation::SetOpacity(float opacity) { | |
| 281 root_layer_.SetOpacity(opacity); | |
| 282 } | |
| 283 | |
| 284 void FloodFillInkDropAnimation::AnimateToOpacity( | |
| 285 float opacity, | |
| 286 base::TimeDelta duration, | |
| 287 ui::LayerAnimator::PreemptionStrategy preemption_strategy, | |
| 288 gfx::Tween::Type tween, | |
| 289 ui::LayerAnimationObserver* animation_observer) { | |
| 290 ui::LayerAnimator* animator = root_layer_.GetAnimator(); | |
| 291 ui::ScopedLayerAnimationSettings animation_settings(animator); | |
| 292 animation_settings.SetPreemptionStrategy(preemption_strategy); | |
| 293 animation_settings.SetTweenType(tween); | |
| 294 ui::LayerAnimationElement* animation_element = | |
| 295 ui::LayerAnimationElement::CreateOpacityElement(opacity, duration); | |
| 296 ui::LayerAnimationSequence* animation_sequence = | |
| 297 new ui::LayerAnimationSequence(animation_element); | |
| 298 | |
| 299 if (animation_observer) | |
| 300 animation_sequence->AddObserver(animation_observer); | |
| 301 | |
| 302 animator->StartAnimation(animation_sequence); | |
| 303 } | |
| 304 | |
| 305 gfx::Transform FloodFillInkDropAnimation::CalculateTransform( | |
| 306 float target_radius) const { | |
| 307 const float target_scale = target_radius / circle_layer_delegate_.radius(); | |
| 308 const gfx::Point drawn_center_point = | |
| 309 ToRoundedPoint(circle_layer_delegate_.GetCenterPoint()); | |
| 310 | |
| 311 gfx::Transform transform = gfx::Transform(); | |
| 312 transform.Translate(center_point_.x(), center_point_.y()); | |
| 313 transform.Scale(target_scale, target_scale); | |
| 314 transform.Translate(-drawn_center_point.x() - root_layer_.bounds().x(), | |
| 315 -drawn_center_point.y() - root_layer_.bounds().y()); | |
| 316 | |
| 317 return transform; | |
| 318 } | |
| 319 | |
| 320 gfx::Transform FloodFillInkDropAnimation::GetMaxSizeTargetTransform() const { | |
| 321 // TODO(estade): get rid of this 2, but make the fade out start before the | |
| 322 // active/action transform is done. | |
| 323 return CalculateTransform( | |
| 324 gfx::Vector2dF(clip_bounds_.width(), clip_bounds_.height()).Length() / 2); | |
| 325 } | |
| 326 | |
| 327 } // namespace views | |
| OLD | NEW |