Index: ui/views/animation/ink_drop_animation.cc |
diff --git a/ui/views/animation/ink_drop_animation.cc b/ui/views/animation/ink_drop_animation.cc |
index 6fbc648d352d1a034e5c396514c37be28c248422..a17f4179b611709a69f1117e5d525d41efc287e1 100644 |
--- a/ui/views/animation/ink_drop_animation.cc |
+++ b/ui/views/animation/ink_drop_animation.cc |
@@ -14,7 +14,10 @@ |
#include "ui/compositor/layer.h" |
#include "ui/compositor/layer_animation_sequence.h" |
#include "ui/compositor/scoped_layer_animation_settings.h" |
+#include "ui/gfx/geometry/point3_f.h" |
#include "ui/gfx/geometry/point_conversions.h" |
+#include "ui/gfx/geometry/point_f.h" |
+#include "ui/gfx/geometry/vector3d_f.h" |
#include "ui/gfx/transform_util.h" |
#include "ui/views/animation/ink_drop_animation_observer.h" |
#include "ui/views/animation/ink_drop_painted_layer_delegates.h" |
@@ -34,19 +37,100 @@ const float kMinimumCircleScale = 0.001f; |
const SkColor kInkDropColor = SK_ColorBLACK; |
// The opacity of the ink drop when it is visible. |
-const float kVisibleOpacity = 0.14f; |
+const float kVisibleOpacity = 0.09f; |
// The opacity of the ink drop when it is not visible. |
const float kHiddenOpacity = 0.0f; |
-// Durations for the different InkDropState animations in milliseconds. |
-const int kHiddenStateAnimationDurationMs = 1; |
-const int kActionPendingStateAnimationDurationMs = 500; |
-const int kQuickActionStateAnimationDurationMs = 250; |
-const int kSlowActionPendingStateAnimationDurationMs = 500; |
-const int kSlowActionStateAnimationDurationMs = 250; |
-const int kActivatedStateAnimationDurationMs = 125; |
-const int kDeactivatedStateAnimationDurationMs = 250; |
+// All the sub animations that are used to animate each of the InkDropStates. |
+// These are used to get time durations with |
+// GetAnimationDuration(InkDropSubAnimations). Note that in general a sub |
+// animation defines the duration for either a transformation animation or an |
+// opacity animation but there are some exceptions where an entire InkDropState |
+// animation consists of only 1 sub animation and it defines the duration for |
+// both the transformation and opacity animations. |
+enum InkDropSubAnimations { |
+ // Multi-purpose sub animation that is used for all InkDropState animations |
+ // that fade out. It defines the portion of the animation where the ripple |
+ // shape should be in it's final form and should pause at full opacity before |
+ // fading out. |
+ OPACITY_PAUSE_BEFORE_FADE_OUT, |
+ |
+ // HIDDEN sub animations. |
+ |
+ // The HIDDEN animation consists of a single sub animation that is fading out |
+ // to a hidden opacity. |
+ HIDDEN_FADE_OUT, |
+ |
+ // ACTION_PENDING sub animations. |
+ |
+ // The ACTION_PENDING sub animation that fades in to the visible opacity. |
+ ACTION_PENDING_FADE_IN, |
+ |
+ // The ACTION_PENDING sub animation that transforms the shape to a |
+ // |large_size_| circle. |
+ ACTION_PENDING_TRANSFORM, |
+ |
+ // QUICK_ACTION sub animations. |
+ |
+ // The QUICK_ACTION sub animation that is fading in to a visible opacity. |
+ QUICK_ACTION_FADE_IN, |
+ |
+ // The QUICK_ACTION sub animation that is fading out to a hidden opacity. |
+ QUICK_ACTION_FADE_OUT, |
+ |
+ // The QUICK_ACTION sub animation that transforms the shape to a |large_size_| |
+ // circle. |
+ QUICK_ACTION_TRANSFORM, |
+ |
+ // The SLOW_ACTION_PENDING animation has only one sub animation which animates |
+ // to a |small_size_| rounded rectangle at visible opacity. |
+ SLOW_ACTION_PENDING, |
+ |
+ // SLOW_ACTION sub animations. |
+ |
+ // The SLOW_ACTION sub animation that is fading out to a hidden opacity. |
+ SLOW_ACTION_FADE_OUT, |
+ |
+ // The SLOW_ACTION sub animation that transforms the shape to a |large_size_| |
+ // rounded rectangle. |
+ SLOW_ACTION_TRANSFORM, |
+ |
+ // ACTIVATED sub animations. |
+ |
+ // The ACTIVATED sub animation that is fading in to a visible opacity. |
+ ACTIVATED_FADE_IN, |
+ |
+ // The ACTIVATED sub animation that transforms the shape to a |small_size_| |
+ // rounded rectangle. |
+ ACTIVATED_TRANSFORM, |
+ |
+ // DEACTIVATED sub animations. |
+ |
+ // The DEACTIVATED sub animation that is fading out to a hidden opacity. |
+ DEACTIVATED_FADE_OUT, |
+ |
+ // The DEACTIVATED sub animation that transforms the shape to a |large_size_| |
+ // rounded rectangle. |
+ DEACTIVATED_TRANSFORM, |
+}; |
+ |
+// Duration constants for InkDropStateSubAnimations. See the |
+// InkDropStateSubAnimations enum documentation for more info. |
+const int kOpacityPauseBeforeFadeDurationMs = 100; |
+const int kHiddenFadeOutDurationMs = 100; |
+const int kActionPendingFadeInDurationMs = 100; |
+const int kActionPendingTransformDurationMs = 300; |
+const int kQuickActionFadeInDurationMs = 100; |
+const int kQuickActionFadeOutDurationMs = 100; |
+const int kQuickActionTransformDurationMs = 300; |
+const int kSlowActionPendingDurationMs = 100; |
+const int kSlowActionFadeOutDurationMs = 100; |
+const int kSlowActionTransformDurationMs = 250; |
+const int kActivatedFadeInDurationMs = 75; |
+const int kActivatedTransformDurationMs = 150; |
+const int kDeactivatedFadeOutDurationMs = 100; |
+const int kDeactivatedTransformDurationMs = 100; |
// A multiplicative factor used to slow down InkDropState animations. |
const int kSlowAnimationDurationFactor = 3; |
@@ -61,33 +145,53 @@ bool UseFastAnimations() { |
return fast; |
} |
-// Returns the InkDropState animation duration for the given |state|. |
-base::TimeDelta GetAnimationDuration(views::InkDropState state) { |
+// Returns the InkDropState sub animation duration for the given |state|. |
+base::TimeDelta GetAnimationDuration(InkDropSubAnimations state) { |
int duration = 0; |
switch (state) { |
- case views::InkDropState::HIDDEN: |
- duration = kHiddenStateAnimationDurationMs; |
+ case OPACITY_PAUSE_BEFORE_FADE_OUT: |
+ duration = kOpacityPauseBeforeFadeDurationMs; |
+ break; |
+ case HIDDEN_FADE_OUT: |
+ duration = kHiddenFadeOutDurationMs; |
break; |
- case views::InkDropState::ACTION_PENDING: |
- duration = kActionPendingStateAnimationDurationMs; |
+ case ACTION_PENDING_FADE_IN: |
+ duration = kActionPendingFadeInDurationMs; |
break; |
- case views::InkDropState::QUICK_ACTION: |
- duration = kQuickActionStateAnimationDurationMs; |
+ case ACTION_PENDING_TRANSFORM: |
+ duration = kActionPendingTransformDurationMs; |
break; |
- case views::InkDropState::SLOW_ACTION_PENDING: |
- duration = kSlowActionPendingStateAnimationDurationMs; |
+ case QUICK_ACTION_FADE_IN: |
+ duration = kQuickActionFadeInDurationMs; |
break; |
- case views::InkDropState::SLOW_ACTION: |
- duration = kSlowActionStateAnimationDurationMs; |
+ case QUICK_ACTION_FADE_OUT: |
+ duration = kQuickActionFadeOutDurationMs; |
break; |
- case views::InkDropState::ACTIVATED: |
- duration = kActivatedStateAnimationDurationMs; |
+ case QUICK_ACTION_TRANSFORM: |
+ duration = kQuickActionTransformDurationMs; |
break; |
- case views::InkDropState::DEACTIVATED: |
- duration = kDeactivatedStateAnimationDurationMs; |
+ case SLOW_ACTION_PENDING: |
+ duration = kSlowActionPendingDurationMs; |
+ break; |
+ case SLOW_ACTION_TRANSFORM: |
+ duration = kSlowActionTransformDurationMs; |
+ break; |
+ case SLOW_ACTION_FADE_OUT: |
+ duration = kSlowActionFadeOutDurationMs; |
+ break; |
+ case ACTIVATED_FADE_IN: |
+ duration = kActivatedFadeInDurationMs; |
+ break; |
+ case ACTIVATED_TRANSFORM: |
+ duration = kActivatedTransformDurationMs; |
+ break; |
+ case DEACTIVATED_FADE_OUT: |
+ duration = kDeactivatedFadeOutDurationMs; |
+ break; |
+ case DEACTIVATED_TRANSFORM: |
+ duration = kDeactivatedTransformDurationMs; |
break; |
} |
- |
return base::TimeDelta::FromMilliseconds( |
(UseFastAnimations() ? 1 : kSlowAnimationDurationFactor) * duration); |
} |
@@ -182,96 +286,143 @@ void InkDropAnimation::SetCenterPoint(const gfx::Point& center_point) { |
void InkDropAnimation::AnimateToStateInternal( |
InkDropState ink_drop_state, |
ui::LayerAnimationObserver* animation_observer) { |
- ink_drop_state_ = ink_drop_state; |
- |
if (ink_drop_state_ == InkDropState::HIDDEN) { |
- // Animating to the HIDDEN state doesn't actually use any |
- // LayerAnimationSequences so we need to explicitly abort any running ones |
- // so that observers receive an InkDropAnimationEnded() event for the |
- // running animation prior to receiving an InkDropAnimationStarted() event |
- // for the HIDDEN 'animation'. |
+ // The HIDDEN state animations might still be in progress and we don't want |
+ // to start the new ink drop sequence from that shape so snap the state to |
+ // hidden. |
AbortAllAnimations(); |
- root_layer_->SetVisible(false); |
SetStateToHidden(); |
- return; |
} |
+ ink_drop_state_ = ink_drop_state; |
+ |
InkDropTransforms transforms; |
root_layer_->SetVisible(true); |
switch (ink_drop_state_) { |
case InkDropState::HIDDEN: |
- // This case is handled above in a short circuit return. |
+ // Only the opacity is animated so we have to explicitly abort the other |
+ // running animations so that the LayerAnimationObservers are notified in |
+ // the proper order. |
+ AbortAllAnimations(); |
+ if (GetCurrentOpacity() != kHiddenOpacity) { |
+ AnimateToOpacity(kHiddenOpacity, GetAnimationDuration(HIDDEN_FADE_OUT), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
+ } |
break; |
case InkDropState::ACTION_PENDING: |
+ AnimateToOpacity(kVisibleOpacity, |
+ GetAnimationDuration(ACTION_PENDING_FADE_IN), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
CalculateCircleTransforms(large_size_, &transforms); |
- AnimateToTransforms(transforms, kVisibleOpacity, |
- GetAnimationDuration(InkDropState::ACTION_PENDING), |
+ AnimateToTransforms(transforms, |
+ GetAnimationDuration(ACTION_PENDING_TRANSFORM), |
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ gfx::Tween::EASE_OUT, animation_observer); |
break; |
- case InkDropState::QUICK_ACTION: |
+ case InkDropState::QUICK_ACTION: { |
+ const float fade_in_ratio = 1.0f - GetCurrentOpacity() / kVisibleOpacity; |
+ const base::TimeDelta fade_in_duration = |
+ GetAnimationDuration(QUICK_ACTION_FADE_IN) * fade_in_ratio; |
+ |
+ const base::TimeDelta fade_out_duration = |
+ GetAnimationDuration(QUICK_ACTION_FADE_OUT); |
+ |
+ GetCurrentTransforms(&transforms); |
+ const float transformation_ratio = |
+ 1.0f - CalculateDistanceEstimateToQuickAction(transforms); |
+ const base::TimeDelta transformation_duration = |
+ GetAnimationDuration(QUICK_ACTION_TRANSFORM) * transformation_ratio; |
+ |
+ const base::TimeDelta visible_duration = |
+ transformation_duration - fade_in_duration + |
+ GetAnimationDuration(OPACITY_PAUSE_BEFORE_FADE_OUT); |
+ |
+ if (fade_in_duration.InMilliseconds() > 0) { |
+ AnimateToOpacity(kVisibleOpacity, fade_in_duration, |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
+ } |
+ |
+ AnimateToOpacity(kVisibleOpacity, visible_duration, |
+ ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, |
+ gfx::Tween::LINEAR, animation_observer); |
+ AnimateToOpacity(kHiddenOpacity, fade_out_duration, |
+ ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, |
+ gfx::Tween::EASE_OUT, animation_observer); |
CalculateCircleTransforms(large_size_, &transforms); |
- AnimateToTransforms(transforms, kHiddenOpacity, |
- GetAnimationDuration(InkDropState::QUICK_ACTION), |
+ AnimateToTransforms(transforms, transformation_duration, |
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ gfx::Tween::EASE_OUT, animation_observer); |
break; |
+ } |
case InkDropState::SLOW_ACTION_PENDING: |
+ AnimateToOpacity(kVisibleOpacity, |
+ GetAnimationDuration(SLOW_ACTION_PENDING), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
CalculateRectTransforms(small_size_, small_corner_radius_, &transforms); |
- AnimateToTransforms( |
- transforms, kVisibleOpacity, |
- GetAnimationDuration(InkDropState::SLOW_ACTION_PENDING), |
- ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ AnimateToTransforms(transforms, GetAnimationDuration(SLOW_ACTION_PENDING), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
break; |
case InkDropState::SLOW_ACTION: |
+ AnimateToOpacity(kVisibleOpacity, |
+ GetAnimationDuration(SLOW_ACTION_TRANSFORM) + |
+ GetAnimationDuration(OPACITY_PAUSE_BEFORE_FADE_OUT), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
+ AnimateToOpacity(kHiddenOpacity, |
+ GetAnimationDuration(SLOW_ACTION_FADE_OUT), |
+ ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
CalculateRectTransforms(large_size_, large_corner_radius_, &transforms); |
- AnimateToTransforms(transforms, kHiddenOpacity, |
- GetAnimationDuration(InkDropState::SLOW_ACTION), |
+ AnimateToTransforms(transforms, |
+ GetAnimationDuration(SLOW_ACTION_TRANSFORM), |
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
break; |
case InkDropState::ACTIVATED: |
+ AnimateToOpacity(kVisibleOpacity, GetAnimationDuration(ACTIVATED_FADE_IN), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
CalculateRectTransforms(small_size_, small_corner_radius_, &transforms); |
- AnimateToTransforms(transforms, kVisibleOpacity, |
- GetAnimationDuration(InkDropState::ACTIVATED), |
+ AnimateToTransforms(transforms, GetAnimationDuration(ACTIVATED_TRANSFORM), |
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ gfx::Tween::EASE_OUT, animation_observer); |
break; |
case InkDropState::DEACTIVATED: |
+ AnimateToOpacity(kVisibleOpacity, |
+ GetAnimationDuration(DEACTIVATED_TRANSFORM) + |
+ GetAnimationDuration(OPACITY_PAUSE_BEFORE_FADE_OUT), |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
+ gfx::Tween::EASE_IN, animation_observer); |
+ AnimateToOpacity(kHiddenOpacity, |
+ GetAnimationDuration(DEACTIVATED_FADE_OUT), |
+ ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
CalculateRectTransforms(large_size_, large_corner_radius_, &transforms); |
- AnimateToTransforms(transforms, kHiddenOpacity, |
- GetAnimationDuration(InkDropState::DEACTIVATED), |
+ AnimateToTransforms(transforms, |
+ GetAnimationDuration(DEACTIVATED_TRANSFORM), |
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, |
- animation_observer); |
+ gfx::Tween::EASE_IN_OUT, animation_observer); |
break; |
} |
} |
void InkDropAnimation::AnimateToTransforms( |
const InkDropTransforms transforms, |
- float opacity, |
base::TimeDelta duration, |
ui::LayerAnimator::PreemptionStrategy preemption_strategy, |
+ gfx::Tween::Type tween, |
ui::LayerAnimationObserver* animation_observer) { |
- ui::LayerAnimator* root_animator = root_layer_->GetAnimator(); |
- ui::ScopedLayerAnimationSettings root_animation(root_animator); |
- root_animation.SetPreemptionStrategy(preemption_strategy); |
- ui::LayerAnimationElement* root_element = |
- ui::LayerAnimationElement::CreateOpacityElement(opacity, duration); |
- ui::LayerAnimationSequence* root_sequence = |
- new ui::LayerAnimationSequence(root_element); |
- |
- if (animation_observer) |
- root_sequence->AddObserver(animation_observer); |
- |
- root_animator->StartAnimation(root_sequence); |
- |
for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) { |
ui::LayerAnimator* animator = painted_layers_[i]->GetAnimator(); |
ui::ScopedLayerAnimationSettings animation(animator); |
animation.SetPreemptionStrategy(preemption_strategy); |
+ animation.SetTweenType(tween); |
ui::LayerAnimationElement* element = |
ui::LayerAnimationElement::CreateTransformElement(transforms[i], |
duration); |
@@ -291,6 +442,7 @@ void InkDropAnimation::SetStateToHidden() { |
CalculateCircleTransforms(gfx::Size(1, 1), &transforms); |
SetTransforms(transforms); |
SetOpacity(kHiddenOpacity); |
+ root_layer_->SetVisible(false); |
} |
void InkDropAnimation::SetTransforms(const InkDropTransforms transforms) { |
@@ -298,10 +450,35 @@ void InkDropAnimation::SetTransforms(const InkDropTransforms transforms) { |
painted_layers_[i]->SetTransform(transforms[i]); |
} |
+float InkDropAnimation::GetCurrentOpacity() const { |
+ return root_layer_->opacity(); |
+} |
+ |
void InkDropAnimation::SetOpacity(float opacity) { |
root_layer_->SetOpacity(opacity); |
} |
+void InkDropAnimation::AnimateToOpacity( |
+ float opacity, |
+ base::TimeDelta duration, |
+ ui::LayerAnimator::PreemptionStrategy preemption_strategy, |
+ gfx::Tween::Type tween, |
+ ui::LayerAnimationObserver* animation_observer) { |
+ ui::LayerAnimator* animator = root_layer_->GetAnimator(); |
+ ui::ScopedLayerAnimationSettings animation_settings(animator); |
+ animation_settings.SetPreemptionStrategy(preemption_strategy); |
+ animation_settings.SetTweenType(tween); |
+ ui::LayerAnimationElement* animation_element = |
+ ui::LayerAnimationElement::CreateOpacityElement(opacity, duration); |
+ ui::LayerAnimationSequence* animation_sequence = |
+ new ui::LayerAnimationSequence(animation_element); |
+ |
+ if (animation_observer) |
+ animation_sequence->AddObserver(animation_observer); |
+ |
+ animator->StartAnimation(animation_sequence); |
+} |
+ |
void InkDropAnimation::CalculateCircleTransforms( |
const gfx::Size& size, |
InkDropTransforms* transforms_out) const { |
@@ -363,10 +540,10 @@ void InkDropAnimation::CalculateRectTransforms( |
std::max(kMinimumRectScale, size.height() / rect_delegate_height)); |
} |
-void InkDropAnimation::GetCurrentTansforms( |
+void InkDropAnimation::GetCurrentTransforms( |
InkDropTransforms* transforms_out) const { |
for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) |
- (*transforms_out)[i] = painted_layers_[i]->GetTargetTransform(); |
+ (*transforms_out)[i] = painted_layers_[i]->transform(); |
} |
void InkDropAnimation::AddPaintLayer(PaintedShape painted_shape) { |
@@ -406,6 +583,36 @@ void InkDropAnimation::AbortAllAnimations() { |
painted_layers_[i]->GetAnimator()->AbortAllAnimations(); |
} |
+float InkDropAnimation::CalculateDistanceEstimateToQuickAction( |
+ const InkDropTransforms& transforms) const { |
+ gfx::Point3F circle_center_point = |
+ gfx::Point3F(circle_layer_delegate_->GetCenterPoint()); |
+ |
+ gfx::Point3F circle_top_point( |
+ circle_center_point.x(), |
+ circle_center_point.y() - circle_layer_delegate_->radius(), 0); |
+ |
+ transforms[TOP_LEFT_CIRCLE].TransformPoint(&circle_center_point); |
+ transforms[TOP_LEFT_CIRCLE].TransformPoint(&circle_top_point); |
+ |
+ // Calculate the ratio of how far the transformed circle's center point is |
+ // from the destination compared to how far it can be. |
+ const float center_point_distance_estimate = |
+ 1.0f - |
+ gfx::Vector3dF(circle_center_point.x(), circle_center_point.y(), 0) |
+ .Length() / |
+ (gfx::Vector3dF(large_size_.width(), large_size_.height(), 0) |
+ .Length() / |
+ 2.0f); |
+ |
+ // Calculate the ratio of how far the transformed circle's topmost point is |
+ // from the destination compared to how far it can be. |
+ const float top_point_distance_estimate = |
+ -circle_top_point.y() / (large_size_.height() / 2.0f); |
+ |
+ return std::min(center_point_distance_estimate, top_point_distance_estimate); |
+} |
+ |
void InkDropAnimation::AnimationStartedCallback( |
InkDropState ink_drop_state, |
const ui::CallbackLayerAnimationObserver& observer) { |
@@ -416,6 +623,9 @@ void InkDropAnimation::AnimationStartedCallback( |
bool InkDropAnimation::AnimationEndedCallback( |
InkDropState ink_drop_state, |
const ui::CallbackLayerAnimationObserver& observer) { |
+ if (ink_drop_state == InkDropState::HIDDEN) |
+ SetStateToHidden(); |
+ |
FOR_EACH_OBSERVER( |
InkDropAnimationObserver, observers_, |
InkDropAnimationEnded(ink_drop_state, |