| 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..232ef6a92f85fef02b4b3e7714802a943a7bdcbd 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,416 @@ 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 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BasePaintedLayerDelegate);
|
| +};
|
|
|
| - bool RequiresNotificationWhenAnimatorDestroyed() const override;
|
| +BasePaintedLayerDelegate::BasePaintedLayerDelegate(SkColor color)
|
| + : color_(color) {}
|
|
|
| - // The ui::Layer being observed, which hide animations will be set on.
|
| - ui::Layer* layer_;
|
| +BasePaintedLayerDelegate::~BasePaintedLayerDelegate() {}
|
|
|
| - // Optional ui::Layer which will be hidden upon the completion of animating
|
| - // |layer_|
|
| - ui::Layer* background_layer_;
|
| +void BasePaintedLayerDelegate::OnDelegatedFrameDamage(
|
| + const gfx::Rect& damage_rect_in_dip) {}
|
|
|
| - // If true the hide animation will immediately be scheduled upon completion of
|
| - // the observed animation.
|
| - bool hide_;
|
| +void BasePaintedLayerDelegate::OnDeviceScaleFactorChanged(
|
| + float device_scale_factor) {}
|
| +
|
| +base::Closure BasePaintedLayerDelegate::PrepareForLayerBoundsChange() {
|
| + return base::Closure();
|
| +}
|
| +
|
| +// A BasePaintedLayerDelegate that paints a circle of a specified color and
|
| +// radius.
|
| +class CircleLayerDelegate : public BasePaintedLayerDelegate {
|
| + public:
|
| + CircleLayerDelegate(SkColor color, int radius);
|
| + ~CircleLayerDelegate() override;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver);
|
| + int radius() const { return radius_; }
|
| +
|
| + // ui::LayerDelegate:
|
| + void OnPaintLayer(const ui::PaintContext& context) override;
|
| +
|
| + private:
|
| + // The radius of the circle.
|
| + int radius_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CircleLayerDelegate);
|
| };
|
|
|
| -AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide)
|
| - : layer_(layer), background_layer_(nullptr), hide_(hide) {}
|
| +CircleLayerDelegate::CircleLayerDelegate(SkColor color, int radius)
|
| + : BasePaintedLayerDelegate(color), radius_(radius) {}
|
|
|
| -AppearAnimationObserver::~AppearAnimationObserver() {
|
| - StopObserving();
|
| -}
|
| +CircleLayerDelegate::~CircleLayerDelegate() {}
|
|
|
| -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();
|
| -}
|
| +void CircleLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {
|
| + SkPaint paint;
|
| + paint.setColor(color());
|
| + paint.setFlags(SkPaint::kAntiAlias_Flag);
|
| + paint.setStyle(SkPaint::kFill_Style);
|
|
|
| -void AppearAnimationObserver::StartHideAnimation() {
|
| - if (background_layer_)
|
| - background_layer_->SetVisible(false);
|
| - if (!layer_->GetTargetVisibility())
|
| - return;
|
| + ui::PaintRecorder recorder(context, gfx::Size(radius_, radius_));
|
| + gfx::Canvas* canvas = recorder.canvas();
|
|
|
| - 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);
|
| + gfx::Point center_point = gfx::Point(radius_, radius_);
|
| + canvas->DrawCircle(center_point, radius_, paint);
|
| }
|
|
|
| -void AppearAnimationObserver::HideNowIfDoneOrOnceCompleted() {
|
| - hide_ = true;
|
| - if (attached_sequences().empty())
|
| - StartHideAnimation();
|
| -}
|
| +// 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;
|
|
|
| -void AppearAnimationObserver::SetBackgroundToHide(ui::Layer* background_layer) {
|
| - background_layer_ = background_layer;
|
| -}
|
| + const gfx::Size& size() const { return size_; }
|
|
|
| -void AppearAnimationObserver::OnLayerAnimationEnded(
|
| - ui::LayerAnimationSequence* sequence) {
|
| - if (hide_)
|
| - StartHideAnimation();
|
| -}
|
| + // ui::LayerDelegate:
|
| + void OnPaintLayer(const ui::PaintContext& context) override;
|
|
|
| -void AppearAnimationObserver::OnLayerAnimationAborted(
|
| - ui::LayerAnimationSequence* sequence) {
|
| - if (hide_)
|
| - StartHideAnimation();
|
| -}
|
| + 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() {}
|
|
|
| -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;
|
| +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(size_), paint);
|
| }
|
|
|
| -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(
|
| + const 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);
|
| + 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(const InkDropTransforms transforms) {
|
| + for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
|
| + painted_layers_[i]->SetTransform(transforms[i]);
|
| }
|
|
|
| -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_out) const {
|
| + CalculateRectTransforms(size, std::min(size.width(), size.height()) / 2.0f,
|
| + transforms_out);
|
| }
|
|
|
| -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_out) const {
|
| + DCHECK_GE(size.width() / 2.0f, corner_radius)
|
| + << "The circle's diameter should not be greater than the total width.";
|
| + DCHECK_GE(size.height() / 2.0f, corner_radius)
|
| + << "The circle's diameter should not be greater than the total height.";
|
| +
|
| + // 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_out)[TOP_LEFT_CIRCLE] = CalculateCircleTransform(
|
| + painted_layers_[TOP_LEFT_CIRCLE]->bounds().CenterPoint(), circle_scale,
|
| + -circle_target_x_offset, -circle_target_y_offset);
|
| +
|
| + (*transforms_out)[TOP_RIGHT_CIRCLE] = CalculateCircleTransform(
|
| + painted_layers_[TOP_RIGHT_CIRCLE]->bounds().CenterPoint(), circle_scale,
|
| + circle_target_x_offset, -circle_target_y_offset);
|
| +
|
| + (*transforms_out)[BOTTOM_RIGHT_CIRCLE] = CalculateCircleTransform(
|
| + painted_layers_[BOTTOM_RIGHT_CIRCLE]->bounds().CenterPoint(),
|
| + circle_scale, circle_target_x_offset, circle_target_y_offset);
|
| +
|
| + (*transforms_out)[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_out)[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_out)[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_out) const {
|
| + for (int i = 0; i < PAINTED_SHAPE_COUNT; ++i)
|
| + (*transforms_out)[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);
|
| }
|
|
|
| } // namespace views
|
|
|