 Chromium Code Reviews
 Chromium Code Reviews Issue 1298513003:
  Implemented prototype for new ink drop specs.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1298513003:
  Implemented prototype for new ink drop specs.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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 |