Chromium Code Reviews| 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 b02fcd6cbf65fa13709c441b3127cae1c19c0f2c..0c7682467feafc8cf6b66c51b089c27856fd809a 100644 |
| --- a/ui/views/animation/ink_drop_animation.cc |
| +++ b/ui/views/animation/ink_drop_animation.cc |
| @@ -4,7 +4,12 @@ |
| #include "ui/views/animation/ink_drop_animation.h" |
| +#include <algorithm> |
| + |
| #include "base/command_line.h" |
| +#include "base/logging.h" |
| +#include "third_party/skia/include/core/SkColor.h" |
| +#include "third_party/skia/include/core/SkPaint.h" |
| #include "ui/base/ui_base_switches.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/layer_animation_observer.h" |
| @@ -12,40 +17,39 @@ |
| #include "ui/compositor/paint_recorder.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/gfx/canvas.h" |
| -#include "ui/gfx/geometry/size.h" |
| -#include "ui/views/animation/ink_drop_delegate.h" |
| +#include "ui/gfx/transform_util.h" |
| #include "ui/views/view.h" |
| namespace { |
| -// Animation constants |
| -const float kMinimumScale = 0.1f; |
| -const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f; |
| +// The minimum scale factor to use when scaling rectangle layers. Smaller values |
| +// were causing visual anomalies. |
| +const float kMinimumRectScale = 0.0001f; |
| -const int kHideAnimationDurationFastMs = 100; |
| -const int kHideAnimationDurationSlowMs = 1000; |
| +// The minimum scale factor to use when scaling circle layers. Smaller values |
| +// were causing visual anomalies. |
| +const float kMinimumCircleScale = 0.001f; |
| -const int kShowInkDropAnimationDurationFastMs = 250; |
| -const int kShowInkDropAnimationDurationSlowMs = 750; |
| +// The ink drop color. |
| +const SkColor kInkDropColor = SK_ColorBLACK; |
| -const int kShowLongPressAnimationDurationFastMs = 250; |
| -const int kShowLongPressAnimationDurationSlowMs = 2500; |
| +// The opacity of the ink drop when it is visible. |
| +const float kVisibleOpacity = 0.12f; |
| -const int kRoundedRectCorners = 5; |
| -const int kCircleRadius = 30; |
| +// The opacity of the ink drop when it is not visible. |
| +const float kHiddenOpacity = 0.0f; |
| -const SkColor kInkDropColor = SK_ColorLTGRAY; |
| -const SkColor kLongPressColor = SkColorSetRGB(182, 182, 182); |
| +// 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 = 250; |
| +const int kDeactivatedStateAnimationDurationMs = 250; |
| -// Checks CommandLine switches to determine if the visual feedback should be |
| -// circular. |
| -bool UseCircularFeedback() { |
| - static bool circular = |
| - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| - (::switches::kMaterialDesignInkDrop)) != |
| - ::switches::kMaterialDesignInkDropSquare; |
| - return circular; |
| -} |
| +// A multiplicative factor used to slow down InkDropState animations. |
| +const int kSlowAnimationDurationFactor = 3; |
| // Checks CommandLine switches to determine if the visual feedback should have |
| // a fast animations speed. |
| @@ -57,284 +61,418 @@ bool UseFastAnimations() { |
| return fast; |
| } |
| +// Returns the InkDropState animation duration for the given |state|. |
| +base::TimeDelta GetAnimationDuration(views::InkDropState state) { |
| + int duration = 0; |
| + switch (state) { |
| + case views::InkDropState::HIDDEN: |
| + duration = kHiddenStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::ACTION_PENDING: |
| + duration = kActionPendingStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::QUICK_ACTION: |
| + duration = kQuickActionStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::SLOW_ACTION_PENDING: |
| + duration = kSlowActionPendingStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::SLOW_ACTION: |
| + duration = kSlowActionStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::ACTIVATED: |
| + duration = kActivatedStateAnimationDurationMs; |
| + break; |
| + case views::InkDropState::DEACTIVATED: |
| + duration = kDeactivatedStateAnimationDurationMs; |
| + break; |
| + } |
| + |
| + return base::TimeDelta::FromMilliseconds( |
| + (UseFastAnimations() ? 1 : kSlowAnimationDurationFactor) * duration); |
| +} |
| + |
| +// Calculates a Transform for a circle layer. The transform will be set up to |
| +// translate the |drawn_center_point| to the origin, scale, and then translate |
| +// to the target point defined by |target_center_x| and |target_center_y|. |
| +gfx::Transform CalculateCircleTransform(const gfx::Point& drawn_center_point, |
| + float scale, |
| + float target_center_x, |
| + float target_center_y) { |
| + gfx::Transform transform; |
| + transform.Translate(target_center_x, target_center_y); |
| + transform.Scale(scale, scale); |
| + transform.Translate(-drawn_center_point.x(), -drawn_center_point.y()); |
| + return transform; |
| +} |
| + |
| +// Calculates a Transform for a rectangle layer. The transform will be set up to |
| +// translate the |drawn_center_point| to the origin and then scale by the |
| +// |x_scale| and |y_scale| factors. |
| +gfx::Transform CalculateRectTransform(const gfx::Point& drawn_center_point, |
| + float x_scale, |
| + float y_scale) { |
| + gfx::Transform transform; |
| + transform.Scale(x_scale, y_scale); |
| + transform.Translate(-drawn_center_point.x(), -drawn_center_point.y()); |
| + return transform; |
| +} |
| + |
| } // namespace |
| namespace views { |
| -// An animation observer that should be set on animations of the provided |
| -// ui::Layer. Can be used to either start a hide animation, or to trigger one |
| -// upon completion of the current animation. |
| -// |
| -// Sequential animations with PreemptionStrategy::ENQUEUE_NEW_ANIMATION cannot |
| -// be used as the observed animation can complete before user input is received |
| -// which determines if the hide animation should run. |
| -class AppearAnimationObserver : public ui::LayerAnimationObserver { |
| +// Base ui::LayerDelegate stub that can be extended to paint shapes of a |
| +// specific color. |
| +class BasePaintedLayerDelegate : public ui::LayerDelegate { |
| public: |
| - // Will automatically start a hide animation of |layer| if |hide| is true. |
| - // Otherwise StartHideAnimation() or HideNowIfDoneOrOnceCompleted() must be |
| - // called. |
| - AppearAnimationObserver(ui::Layer* layer, bool hide); |
| - ~AppearAnimationObserver() override; |
| - |
| - // Returns true during both the appearing animation, and the hiding animation. |
| - bool IsAnimationActive(); |
| + ~BasePaintedLayerDelegate() override; |
| - // Starts a hide animation, preempting any current animations on |layer_|. |
| - void StartHideAnimation(); |
| + SkColor color() const { return color_; } |
| - // Starts a hide animation if |layer_| is no longer animating. Otherwise the |
| - // hide animation will be started once the current animation is completed. |
| - void HideNowIfDoneOrOnceCompleted(); |
| + // ui::LayerDelegate: |
| + void OnPaintLayer(const ui::PaintContext& context) override; |
|
sadrul
2015/09/14 20:05:40
Should this be left as pure virtual?
bruthig
2015/09/15 19:47:09
Done.
|
| + void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override; |
| + void OnDeviceScaleFactorChanged(float device_scale_factor) override; |
| + base::Closure PrepareForLayerBoundsChange() override; |
| - // Hides |background_layer| (without animation) after the current animation |
| - // completes. |
| - void SetBackgroundToHide(ui::Layer* background_layer); |
| + protected: |
| + explicit BasePaintedLayerDelegate(SkColor color); |
| private: |
| - // ui::ImplicitAnimationObserver: |
| - void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override; |
| - void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override; |
| - void OnLayerAnimationScheduled( |
| - ui::LayerAnimationSequence* sequence) override {} |
| + // The color to paint. |
| + SkColor color_; |
| - bool RequiresNotificationWhenAnimatorDestroyed() const override; |
| + DISALLOW_COPY_AND_ASSIGN(BasePaintedLayerDelegate); |
| +}; |
| - // The ui::Layer being observed, which hide animations will be set on. |
| - ui::Layer* layer_; |
| +BasePaintedLayerDelegate::BasePaintedLayerDelegate(SkColor color) |
| + : color_(color) {} |
| - // Optional ui::Layer which will be hidden upon the completion of animating |
| - // |layer_| |
| - ui::Layer* background_layer_; |
| +BasePaintedLayerDelegate::~BasePaintedLayerDelegate() {} |
| - // If true the hide animation will immediately be scheduled upon completion of |
| - // the observed animation. |
| - bool hide_; |
| +void BasePaintedLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {} |
| - DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver); |
| -}; |
| +void BasePaintedLayerDelegate::OnDelegatedFrameDamage( |
| + const gfx::Rect& damage_rect_in_dip) {} |
| -AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide) |
| - : layer_(layer), background_layer_(nullptr), hide_(hide) {} |
| +void BasePaintedLayerDelegate::OnDeviceScaleFactorChanged( |
| + float device_scale_factor) {} |
| -AppearAnimationObserver::~AppearAnimationObserver() { |
| - StopObserving(); |
| +base::Closure BasePaintedLayerDelegate::PrepareForLayerBoundsChange() { |
| + return base::Closure(); |
| } |
| -bool AppearAnimationObserver::IsAnimationActive() { |
| - // Initial animation ongoing |
| - if (!attached_sequences().empty()) |
| - return true; |
| - // Maintain the animation until told to hide. |
| - if (!hide_) |
| - return true; |
| - |
| - // Check the state of the triggered hide animation |
| - return layer_->GetAnimator()->IsAnimatingProperty( |
| - ui::LayerAnimationElement::OPACITY) && |
| - layer_->GetTargetOpacity() == 0.0f && |
| - layer_->GetAnimator()->IsAnimatingProperty( |
| - ui::LayerAnimationElement::VISIBILITY) && |
| - !layer_->GetTargetVisibility(); |
| -} |
| +// A BasePaintedLayerDelegate that paints a circle of a specified color and |
| +// radius. |
| +class CircleLayerDelegate : public BasePaintedLayerDelegate { |
| + public: |
| + CircleLayerDelegate(SkColor color, int radius); |
| + ~CircleLayerDelegate() override; |
| -void AppearAnimationObserver::StartHideAnimation() { |
| - if (background_layer_) |
| - background_layer_->SetVisible(false); |
| - if (!layer_->GetTargetVisibility()) |
| - return; |
| + int radius() const { return radius_; } |
| - ui::ScopedLayerAnimationSettings animation(layer_->GetAnimator()); |
| - animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds( |
| - UseFastAnimations() ? kHideAnimationDurationFastMs |
| - : kHideAnimationDurationSlowMs)); |
| - animation.SetPreemptionStrategy( |
| - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| - layer_->SetOpacity(0.0f); |
| - layer_->SetVisible(false); |
| -} |
| + // ui::LayerDelegate: |
| + void OnPaintLayer(const ui::PaintContext& context) override; |
| -void AppearAnimationObserver::HideNowIfDoneOrOnceCompleted() { |
| - hide_ = true; |
| - if (attached_sequences().empty()) |
| - StartHideAnimation(); |
| -} |
| + private: |
| + // The radius of the circle. |
| + int radius_; |
| -void AppearAnimationObserver::SetBackgroundToHide(ui::Layer* background_layer) { |
| - background_layer_ = background_layer; |
| -} |
| + DISALLOW_COPY_AND_ASSIGN(CircleLayerDelegate); |
| +}; |
| -void AppearAnimationObserver::OnLayerAnimationEnded( |
| - ui::LayerAnimationSequence* sequence) { |
| - if (hide_) |
| - StartHideAnimation(); |
| -} |
| +CircleLayerDelegate::CircleLayerDelegate(SkColor color, int radius) |
| + : BasePaintedLayerDelegate(color), radius_(radius) {} |
| -void AppearAnimationObserver::OnLayerAnimationAborted( |
| - ui::LayerAnimationSequence* sequence) { |
| - if (hide_) |
| - StartHideAnimation(); |
| +CircleLayerDelegate::~CircleLayerDelegate() {} |
| + |
| +void CircleLayerDelegate::OnPaintLayer(const ui::PaintContext& context) { |
| + SkPaint paint; |
| + paint.setColor(color()); |
| + paint.setFlags(SkPaint::kAntiAlias_Flag); |
| + paint.setStyle(SkPaint::kFill_Style); |
| + |
| + ui::PaintRecorder recorder(context, gfx::Size(radius_, radius_)); |
| + gfx::Canvas* canvas = recorder.canvas(); |
| + |
| + gfx::Point center_point = gfx::Point(radius_, radius_); |
| + canvas->DrawCircle(center_point, radius_, paint); |
| } |
| -bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() |
| - const { |
| - // Ensures that OnImplicitAnimationsCompleted is called even if the observed |
| - // animation is deleted. Allows for setting the proper state on |layer_|. |
| - return true; |
| +// A BasePaintedLayerDelegate that paints a rectangle of a specified color and |
| +// size. |
| +class RectangleLayerDelegate : public BasePaintedLayerDelegate { |
| + public: |
| + RectangleLayerDelegate(SkColor color, gfx::Size size); |
| + ~RectangleLayerDelegate() override; |
| + |
| + gfx::Size size() const { return size_; } |
|
sadrul
2015/09/14 20:05:40
const gfx::Size& size()
bruthig
2015/09/15 19:47:09
Done.
|
| + |
| + // ui::LayerDelegate: |
| + void OnPaintLayer(const ui::PaintContext& context) override; |
| + |
| + private: |
| + // The size of the rectangle. |
| + gfx::Size size_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(RectangleLayerDelegate); |
| +}; |
| + |
| +RectangleLayerDelegate::RectangleLayerDelegate(SkColor color, gfx::Size size) |
| + : BasePaintedLayerDelegate(color), size_(size) {} |
| + |
| +RectangleLayerDelegate::~RectangleLayerDelegate() {} |
| + |
| +void RectangleLayerDelegate::OnPaintLayer(const ui::PaintContext& context) { |
| + SkPaint paint; |
| + paint.setColor(color()); |
| + paint.setFlags(SkPaint::kAntiAlias_Flag); |
| + paint.setStyle(SkPaint::kFill_Style); |
| + |
| + ui::PaintRecorder recorder(context, size_); |
| + gfx::Canvas* canvas = recorder.canvas(); |
| + canvas->DrawRect(gfx::Rect(0, 0, size_.width(), size_.height()), paint); |
|
sadrul
2015/09/14 20:05:40
gfx::Rect(size_)
bruthig
2015/09/15 19:47:09
Done.
|
| } |
| -InkDropAnimation::InkDropAnimation() |
| - : root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), |
| - ink_drop_layer_(new ui::Layer()), |
| - appear_animation_observer_(nullptr), |
| - long_press_layer_(new ui::Layer()), |
| - long_press_animation_observer_(nullptr), |
| - ink_drop_bounds_(0, 0, 0, 0) { |
| - ink_drop_delegate_.reset(new InkDropDelegate(ink_drop_layer_.get(), |
| - kInkDropColor, kCircleRadius, |
| - kRoundedRectCorners)); |
| - long_press_delegate_.reset(new InkDropDelegate(long_press_layer_.get(), |
| - kLongPressColor, kCircleRadius, |
| - kRoundedRectCorners)); |
| - |
| - SetupAnimationLayer(long_press_layer_.get(), long_press_delegate_.get()); |
| - SetupAnimationLayer(ink_drop_layer_.get(), ink_drop_delegate_.get()); |
| - |
| - root_layer_->Add(ink_drop_layer_.get()); |
| - root_layer_->Add(long_press_layer_.get()); |
| +InkDropAnimation::InkDropAnimation(const gfx::Size& large_size, |
| + int large_corner_radius, |
| + const gfx::Size& small_size, |
| + int small_corner_radius) |
| + : large_size_(large_size), |
| + large_corner_radius_(large_corner_radius), |
| + small_size_(small_size), |
| + small_corner_radius_(small_corner_radius), |
| + circle_layer_delegate_(new CircleLayerDelegate( |
| + kInkDropColor, |
| + std::min(large_size_.width(), large_size_.height()) / 2)), |
| + rect_layer_delegate_( |
| + new RectangleLayerDelegate(kInkDropColor, large_size_)), |
| + root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), |
| + ink_drop_state_(InkDropState::HIDDEN) { |
| + for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) |
| + AddPaintLayer(static_cast<PaintedShape>(i)); |
| + |
| + root_layer_->SetMasksToBounds(false); |
| + root_layer_->SetBounds(gfx::Rect(large_size_)); |
| + |
| + ResetTransformsToMinSize(); |
| + |
| + SetOpacity(kHiddenOpacity); |
| } |
| InkDropAnimation::~InkDropAnimation() {} |
| -void InkDropAnimation::AnimateToState(InkDropState state) { |
| - // TODO(bruthig): Do not transition if we are already in |state| and restrict |
| - // any state transition that don't make sense or wouldn't look visually |
| - // appealing. |
| - switch (state) { |
| +void InkDropAnimation::AnimateToState(InkDropState ink_drop_state) { |
| + if (ink_drop_state_ == ink_drop_state) |
| + return; |
| + |
| + if (ink_drop_state_ == InkDropState::HIDDEN) { |
| + ResetTransformsToMinSize(); |
| + SetOpacity(kVisibleOpacity); |
| + } |
| + |
| + InkDropTransforms transforms; |
| + |
| + // Must set the |ink_drop_state_| before handling the state change because |
| + // some state changes make recursive calls to AnimateToState() and the last |
| + // call should 'win'. |
| + ink_drop_state_ = ink_drop_state; |
| + |
| + switch (ink_drop_state_) { |
| case InkDropState::HIDDEN: |
| - AnimateHide(); |
| + GetCurrentTansforms(transforms); |
| + AnimateToTransforms(transforms, kHiddenOpacity, |
| + GetAnimationDuration(InkDropState::HIDDEN), |
| + ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); |
| break; |
| case InkDropState::ACTION_PENDING: |
| - AnimateTapDown(); |
| + CalculateCircleTransforms(large_size_, transforms); |
| + AnimateToTransforms(transforms, kVisibleOpacity, |
| + GetAnimationDuration(InkDropState::ACTION_PENDING), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| break; |
| case InkDropState::QUICK_ACTION: |
| - AnimateTapDown(); |
| - AnimateHide(); |
| + CalculateCircleTransforms(large_size_, transforms); |
| + AnimateToTransforms(transforms, kHiddenOpacity, |
| + GetAnimationDuration(InkDropState::QUICK_ACTION), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + AnimateToState(InkDropState::HIDDEN); |
| + break; |
| + case InkDropState::SLOW_ACTION_PENDING: |
| + CalculateRectTransforms(small_size_, small_corner_radius_, transforms); |
| + AnimateToTransforms( |
| + transforms, kVisibleOpacity, |
| + GetAnimationDuration(InkDropState::SLOW_ACTION_PENDING), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| break; |
| case InkDropState::SLOW_ACTION: |
| - AnimateLongPress(); |
| + CalculateRectTransforms(large_size_, large_corner_radius_, transforms); |
| + AnimateToTransforms(transforms, kHiddenOpacity, |
| + GetAnimationDuration(InkDropState::SLOW_ACTION), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + AnimateToState(InkDropState::HIDDEN); |
| break; |
| case InkDropState::ACTIVATED: |
| - AnimateLongPress(); |
| + CalculateRectTransforms(small_size_, small_corner_radius_, transforms); |
| + AnimateToTransforms(transforms, kVisibleOpacity, |
| + GetAnimationDuration(InkDropState::ACTIVATED), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + break; |
| + case InkDropState::DEACTIVATED: |
| + CalculateRectTransforms(large_size_, large_corner_radius_, transforms); |
| + AnimateToTransforms(transforms, kHiddenOpacity, |
| + GetAnimationDuration(InkDropState::DEACTIVATED), |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + AnimateToState(InkDropState::HIDDEN); |
| break; |
| } |
| } |
| -void InkDropAnimation::SetInkDropSize(const gfx::Size& size) { |
| - SetInkDropBounds(gfx::Rect(ink_drop_bounds_.origin(), size)); |
| +void InkDropAnimation::AnimateToTransforms( |
| + InkDropTransforms transforms, |
| + float opacity, |
| + base::TimeDelta duration, |
| + ui::LayerAnimator::PreemptionStrategy preemption_strategy) { |
| + 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); |
| + 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); |
| + ui::LayerAnimationElement* element = |
| + ui::LayerAnimationElement::CreateTransformElement(transforms[i], |
| + duration); |
| + ui::LayerAnimationSequence* sequence = |
| + new ui::LayerAnimationSequence(element); |
| + animator->StartAnimation(sequence); |
| + } |
| } |
| -gfx::Rect InkDropAnimation::GetInkDropBounds() const { |
| - return ink_drop_bounds_; |
| +void InkDropAnimation::ResetTransformsToMinSize() { |
| + InkDropTransforms transforms; |
| + // Using a size of 0x0 creates visual anomalies. |
| + CalculateCircleTransforms(gfx::Size(1, 1), transforms); |
|
sadrul
2015/09/14 20:05:40
Explain why size(1,1) is used here (instead of, sa
bruthig
2015/09/15 19:47:09
Discussed offline. This should make more sense on
|
| + SetTransforms(transforms); |
| } |
| -void InkDropAnimation::SetInkDropBounds(const gfx::Rect& bounds) { |
| - ink_drop_bounds_ = bounds; |
| - SetLayerBounds(ink_drop_layer_.get()); |
| - SetLayerBounds(long_press_layer_.get()); |
| +void InkDropAnimation::SetTransforms(InkDropTransforms transforms) { |
| + for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) |
| + painted_layers_[i]->SetTransform(transforms[i]); |
|
sadrul
2015/09/14 20:05:40
Can you clarify why you need to set transforms on
bruthig
2015/09/15 19:47:09
(I'm assuming this is not a request for added docu
|
| } |
| -void InkDropAnimation::AnimateTapDown() { |
| - if ((appear_animation_observer_ && |
| - appear_animation_observer_->IsAnimationActive()) || |
| - (long_press_animation_observer_ && |
| - long_press_animation_observer_->IsAnimationActive())) { |
| - // Only one animation at a time. Subsequent tap downs are ignored until the |
| - // current animation completes. |
| - return; |
| - } |
| - appear_animation_observer_.reset( |
| - new AppearAnimationObserver(ink_drop_layer_.get(), false)); |
| - AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(), |
| - base::TimeDelta::FromMilliseconds( |
| - (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs |
| - : kShowInkDropAnimationDurationSlowMs))); |
| +void InkDropAnimation::SetOpacity(float opacity) { |
| + root_layer_->SetOpacity(opacity); |
| } |
| -void InkDropAnimation::AnimateHide() { |
| - if (appear_animation_observer_ && |
| - appear_animation_observer_->IsAnimationActive()) { |
| - appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); |
| - } else if (long_press_animation_observer_) { |
| - long_press_animation_observer_->HideNowIfDoneOrOnceCompleted(); |
| - } |
| +void InkDropAnimation::CalculateCircleTransforms( |
| + const gfx::SizeF size, |
| + InkDropTransforms transforms) const { |
| + CalculateRectTransforms(size, std::min(size.width(), size.height()) / 2.0f, |
| + transforms); |
| } |
| -void InkDropAnimation::AnimateLongPress() { |
| - // Only one animation at a time. Subsequent long presses are ignored until the |
| - // current animation completes. |
| - if (long_press_animation_observer_ && |
| - long_press_animation_observer_->IsAnimationActive()) { |
| - return; |
| - } |
| - appear_animation_observer_.reset(); |
| - long_press_animation_observer_.reset( |
| - new AppearAnimationObserver(long_press_layer_.get(), false)); |
| - long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get()); |
| - AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(), |
| - base::TimeDelta::FromMilliseconds( |
| - UseFastAnimations() ? kShowLongPressAnimationDurationFastMs |
| - : kShowLongPressAnimationDurationSlowMs)); |
| +void InkDropAnimation::CalculateRectTransforms( |
| + const gfx::SizeF size, |
| + float corner_radius, |
| + InkDropTransforms transforms) const { |
| + CHECK_GE(size.width() / 2.0f, corner_radius) |
| + << "The circle's diameter should not be greater than the total width."; |
| + CHECK_GE(size.height() / 2.0f, corner_radius) |
| + << "The circle's diameter should not be greater than the total height."; |
|
sadrul
2015/09/14 20:05:40
DCHECK*
bruthig
2015/09/15 19:47:09
Done.
|
| + |
| + // The shapes are drawn such that their center points are not at the origin. |
| + // Thus we use the CalculateCircleTransform() and CalculateRectTransform() |
| + // methods to calculate the complex Transforms. |
| + |
| + const float circle_scale = std::max( |
| + kMinimumCircleScale, |
| + corner_radius / static_cast<float>(circle_layer_delegate_->radius())); |
| + |
| + const float circle_target_x_offset = size.width() / 2.0f - corner_radius; |
| + const float circle_target_y_offset = size.height() / 2.0f - corner_radius; |
| + |
| + transforms[TOP_LEFT_CIRCLE] = CalculateCircleTransform( |
| + painted_layers_[TOP_LEFT_CIRCLE]->bounds().CenterPoint(), circle_scale, |
| + -circle_target_x_offset, -circle_target_y_offset); |
| + |
| + transforms[TOP_RIGHT_CIRCLE] = CalculateCircleTransform( |
| + painted_layers_[TOP_RIGHT_CIRCLE]->bounds().CenterPoint(), circle_scale, |
| + circle_target_x_offset, -circle_target_y_offset); |
| + |
| + transforms[BOTTOM_RIGHT_CIRCLE] = CalculateCircleTransform( |
| + painted_layers_[BOTTOM_RIGHT_CIRCLE]->bounds().CenterPoint(), |
| + circle_scale, circle_target_x_offset, circle_target_y_offset); |
| + |
| + transforms[BOTTOM_LEFT_CIRCLE] = CalculateCircleTransform( |
| + painted_layers_[BOTTOM_LEFT_CIRCLE]->bounds().CenterPoint(), circle_scale, |
| + -circle_target_x_offset, circle_target_y_offset); |
| + |
| + const float rect_delegate_width = |
| + static_cast<float>(rect_layer_delegate_->size().width()); |
| + const float rect_delegate_height = |
| + static_cast<float>(rect_layer_delegate_->size().height()); |
| + |
| + transforms[HORIZONTAL_RECT] = CalculateRectTransform( |
| + painted_layers_[HORIZONTAL_RECT]->bounds().CenterPoint(), |
| + std::max(kMinimumRectScale, size.width() / rect_delegate_width), |
| + std::max(kMinimumRectScale, |
| + (size.height() - 2.0f * corner_radius) / rect_delegate_height)); |
| + |
| + transforms[VERTICAL_RECT] = CalculateRectTransform( |
| + painted_layers_[VERTICAL_RECT]->bounds().CenterPoint(), |
| + std::max(kMinimumRectScale, |
| + (size.width() - 2.0f * corner_radius) / rect_delegate_width), |
| + std::max(kMinimumRectScale, size.height() / rect_delegate_height)); |
| } |
| -void InkDropAnimation::AnimateShow(ui::Layer* layer, |
| - AppearAnimationObserver* observer, |
| - base::TimeDelta duration) { |
| - layer->SetVisible(true); |
| - layer->SetOpacity(1.0f); |
| - |
| - float start_x = ink_drop_bounds_.x() + |
| - layer->bounds().width() * kMinimumScaleCenteringOffset; |
| - float start_y = ink_drop_bounds_.y() + |
| - layer->bounds().height() * kMinimumScaleCenteringOffset; |
| - |
| - gfx::Transform initial_transform; |
| - initial_transform.Translate(start_x, start_y); |
| - initial_transform.Scale(kMinimumScale, kMinimumScale); |
| - layer->SetTransform(initial_transform); |
| - |
| - ui::LayerAnimator* animator = layer->GetAnimator(); |
| - ui::ScopedLayerAnimationSettings animation(animator); |
| - animation.SetPreemptionStrategy( |
| - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| - |
| - gfx::Transform target_transform; |
| - target_transform.Translate(ink_drop_bounds_.x(), ink_drop_bounds_.y()); |
| - ui::LayerAnimationElement* element = |
| - ui::LayerAnimationElement::CreateTransformElement(target_transform, |
| - duration); |
| - ui::LayerAnimationSequence* sequence = |
| - new ui::LayerAnimationSequence(element); |
| - sequence->AddObserver(observer); |
| - animator->StartAnimation(sequence); |
| +void InkDropAnimation::GetCurrentTansforms(InkDropTransforms transforms) const { |
| + for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i) |
| + transforms[i] = painted_layers_[i]->GetTargetTransform(); |
| } |
| -void InkDropAnimation::SetLayerBounds(ui::Layer* layer) { |
| - bool circle = UseCircularFeedback(); |
| - gfx::Size size = ink_drop_bounds_.size(); |
| - float circle_width = circle ? 2.0f * kCircleRadius : size.width(); |
| - float circle_height = circle ? 2.0f * kCircleRadius : size.height(); |
| - float circle_x = circle ? (size.width() - circle_width) * 0.5f : 0; |
| - float circle_y = circle ? (size.height() - circle_height) * 0.5f : 0; |
| - layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height)); |
| +void InkDropAnimation::SetCenterPoint(const gfx::Point& center_point) { |
| + gfx::Transform transform; |
| + transform.Translate(center_point.x(), center_point.y()); |
| + root_layer_->SetTransform(transform); |
| } |
| -void InkDropAnimation::SetupAnimationLayer(ui::Layer* layer, |
| - InkDropDelegate* delegate) { |
| +void InkDropAnimation::AddPaintLayer(PaintedShape painted_shape) { |
| + ui::LayerDelegate* delegate = nullptr; |
| + switch (painted_shape) { |
| + case TOP_LEFT_CIRCLE: |
| + case TOP_RIGHT_CIRCLE: |
| + case BOTTOM_RIGHT_CIRCLE: |
| + case BOTTOM_LEFT_CIRCLE: |
| + delegate = circle_layer_delegate_.get(); |
| + break; |
| + case HORIZONTAL_RECT: |
| + case VERTICAL_RECT: |
| + delegate = rect_layer_delegate_.get(); |
| + break; |
| + case PAINTED_SHAPE_COUNT: |
| + NOTREACHED() << "PAINTED_SHAPE_COUNT is not an actual shape type."; |
| + break; |
| + } |
| + |
| + ui::Layer* layer = new ui::Layer(); |
| + root_layer_->Add(layer); |
| + |
| + layer->SetBounds(gfx::Rect(large_size_)); |
| layer->SetFillsBoundsOpaquely(false); |
| layer->set_delegate(delegate); |
| - layer->SetVisible(false); |
| - layer->SetBounds(gfx::Rect()); |
| - delegate->set_should_render_circle(UseCircularFeedback()); |
| + layer->SetVisible(true); |
| + layer->SetOpacity(1.0); |
| + layer->SetMasksToBounds(false); |
| + |
| + painted_layers_[painted_shape].reset(layer); |
|
sadrul
2015/09/14 20:05:40
Looks like you are creating 6 layers at startup. C
sadrul
2015/09/14 20:06:25
We discussed this offline. Please make sure there
|
| } |
| } // namespace views |