| 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 | 
|  |