| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/animation/ink_drop_animation_controller.h" | 5 #include "ui/views/animation/ink_drop_animation_controller_impl.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "ui/base/ui_base_switches.h" | 8 #include "ui/base/ui_base_switches.h" |
| 9 #include "ui/compositor/layer.h" | 9 #include "ui/compositor/layer.h" |
| 10 #include "ui/compositor/layer_animation_observer.h" | 10 #include "ui/compositor/layer_animation_observer.h" |
| 11 #include "ui/compositor/layer_animation_sequence.h" | 11 #include "ui/compositor/layer_animation_sequence.h" |
| 12 #include "ui/compositor/paint_recorder.h" | 12 #include "ui/compositor/paint_recorder.h" |
| 13 #include "ui/compositor/scoped_layer_animation_settings.h" | 13 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 14 #include "ui/events/event.h" | 14 #include "ui/events/event.h" |
| 15 #include "ui/gfx/canvas.h" | 15 #include "ui/gfx/canvas.h" |
| 16 #include "ui/gfx/geometry/size.h" |
| 17 #include "ui/views/animation/ink_drop_delegate.h" |
| 18 #include "ui/views/animation/ink_drop_host.h" |
| 16 #include "ui/views/view.h" | 19 #include "ui/views/view.h" |
| 17 | 20 |
| 18 namespace { | 21 namespace { |
| 19 | 22 |
| 20 // Animation constants | 23 // Animation constants |
| 21 const float kMinimumScale = 0.1f; | 24 const float kMinimumScale = 0.1f; |
| 22 const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f; | 25 const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f; |
| 23 | 26 |
| 24 const int kHideAnimationDurationFastMs = 100; | 27 const int kHideAnimationDurationFastMs = 100; |
| 25 const int kHideAnimationDurationSlowMs = 1000; | 28 const int kHideAnimationDurationSlowMs = 1000; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 ui::Layer* background_layer_; | 109 ui::Layer* background_layer_; |
| 107 | 110 |
| 108 // If true the hide animation will immediately be scheduled upon completion of | 111 // If true the hide animation will immediately be scheduled upon completion of |
| 109 // the observed animation. | 112 // the observed animation. |
| 110 bool hide_; | 113 bool hide_; |
| 111 | 114 |
| 112 DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver); | 115 DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver); |
| 113 }; | 116 }; |
| 114 | 117 |
| 115 AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide) | 118 AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide) |
| 116 : layer_(layer), background_layer_(nullptr), hide_(hide) { | 119 : layer_(layer), background_layer_(nullptr), hide_(hide) {} |
| 117 } | |
| 118 | 120 |
| 119 AppearAnimationObserver::~AppearAnimationObserver() { | 121 AppearAnimationObserver::~AppearAnimationObserver() { |
| 120 StopObserving(); | 122 StopObserving(); |
| 121 } | 123 } |
| 122 | 124 |
| 123 bool AppearAnimationObserver::IsAnimationActive() { | 125 bool AppearAnimationObserver::IsAnimationActive() { |
| 124 // Initial animation ongoing | 126 // Initial animation ongoing |
| 125 if (!attached_sequences().empty()) | 127 if (!attached_sequences().empty()) |
| 126 return true; | 128 return true; |
| 127 // Maintain the animation until told to hide. | 129 // Maintain the animation until told to hide. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 StartHideAnimation(); | 177 StartHideAnimation(); |
| 176 } | 178 } |
| 177 | 179 |
| 178 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() | 180 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() |
| 179 const { | 181 const { |
| 180 // Ensures that OnImplicitAnimationsCompleted is called even if the observed | 182 // Ensures that OnImplicitAnimationsCompleted is called even if the observed |
| 181 // animation is deleted. Allows for setting the proper state on |layer_|. | 183 // animation is deleted. Allows for setting the proper state on |layer_|. |
| 182 return true; | 184 return true; |
| 183 } | 185 } |
| 184 | 186 |
| 185 // Renders the visual feedback. Will render a circle if |circle_| is true, | 187 InkDropAnimationControllerImpl::InkDropAnimationControllerImpl( |
| 186 // otherwise renders a rounded rectangle. | 188 InkDropHost* ink_drop_host) |
| 187 class InkDropDelegate : public ui::LayerDelegate { | 189 : ink_drop_host_(ink_drop_host), |
| 188 public: | 190 root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), |
| 189 InkDropDelegate(ui::Layer* layer, SkColor color); | 191 ink_drop_layer_(new ui::Layer()), |
| 190 ~InkDropDelegate() override; | 192 appear_animation_observer_(nullptr), |
| 193 long_press_layer_(new ui::Layer()), |
| 194 long_press_animation_observer_(nullptr), |
| 195 ink_drop_bounds_(0, 0, 0, 0) { |
| 196 ink_drop_delegate_.reset(new InkDropDelegate(ink_drop_layer_.get(), |
| 197 kInkDropColor, kCircleRadius, |
| 198 kRoundedRectCorners)); |
| 199 long_press_delegate_.reset(new InkDropDelegate(long_press_layer_.get(), |
| 200 kLongPressColor, kCircleRadius, |
| 201 kRoundedRectCorners)); |
| 191 | 202 |
| 192 // Sets the visual style of the feedback. | 203 SetupAnimationLayer(long_press_layer_.get(), long_press_delegate_.get()); |
| 193 void set_should_render_circle(bool should_render_circle) { | 204 SetupAnimationLayer(ink_drop_layer_.get(), ink_drop_delegate_.get()); |
| 194 should_render_circle_ = should_render_circle; | |
| 195 } | |
| 196 | 205 |
| 197 // ui::LayerDelegate: | 206 root_layer_->Add(ink_drop_layer_.get()); |
| 198 void OnPaintLayer(const ui::PaintContext& context) override; | 207 root_layer_->Add(long_press_layer_.get()); |
| 199 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override; | |
| 200 void OnDeviceScaleFactorChanged(float device_scale_factor) override; | |
| 201 base::Closure PrepareForLayerBoundsChange() override; | |
| 202 | 208 |
| 203 private: | 209 // TODO(bruthig): Change this to only be called before the ink drop becomes |
| 204 // The ui::Layer being rendered to. | 210 // active. See www.crbug.com/522175. |
| 205 ui::Layer* layer_; | 211 ink_drop_host_->AddInkDropLayer(root_layer_.get()); |
| 206 | |
| 207 // The color to paint. | |
| 208 SkColor color_; | |
| 209 | |
| 210 // When true renders a circle, otherwise renders a rounded rectangle. | |
| 211 bool should_render_circle_; | |
| 212 | |
| 213 DISALLOW_COPY_AND_ASSIGN(InkDropDelegate); | |
| 214 }; | |
| 215 | |
| 216 InkDropDelegate::InkDropDelegate(ui::Layer* layer, SkColor color) | |
| 217 : layer_(layer), color_(color), should_render_circle_(true) { | |
| 218 } | 212 } |
| 219 | 213 |
| 220 InkDropDelegate::~InkDropDelegate() { | 214 InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() { |
| 215 // TODO(bruthig): Change this to be called when the ink drop becomes hidden. |
| 216 // See www.crbug.com/522175. |
| 217 ink_drop_host_->RemoveInkDropLayer(root_layer_.get()); |
| 221 } | 218 } |
| 222 | 219 |
| 223 void InkDropDelegate::OnPaintLayer(const ui::PaintContext& context) { | 220 void InkDropAnimationControllerImpl::AnimateToState(InkDropState state) { |
| 224 SkPaint paint; | 221 // TODO(bruthig): Do not transition if we are already in |state| and restrict |
| 225 paint.setColor(color_); | 222 // any state transition that don't make sense or wouldn't look visually |
| 226 paint.setFlags(SkPaint::kAntiAlias_Flag); | 223 // appealing. |
| 227 paint.setStyle(SkPaint::kFill_Style); | 224 switch (state) { |
| 228 | 225 case InkDropState::HIDDEN: |
| 229 gfx::Rect bounds = layer_->bounds(); | 226 AnimateHide(); |
| 230 | 227 break; |
| 231 ui::PaintRecorder recorder(context, layer_->size()); | 228 case InkDropState::ACTION_PENDING: |
| 232 gfx::Canvas* canvas = recorder.canvas(); | 229 AnimateTapDown(); |
| 233 if (should_render_circle_) { | 230 break; |
| 234 gfx::Point midpoint(bounds.width() * 0.5f, bounds.height() * 0.5f); | 231 case InkDropState::QUICK_ACTION: |
| 235 canvas->DrawCircle(midpoint, kCircleRadius, paint); | 232 AnimateTapDown(); |
| 236 } else { | 233 AnimateHide(); |
| 237 canvas->DrawRoundRect(bounds, kRoundedRectCorners, paint); | 234 break; |
| 235 case InkDropState::SLOW_ACTION: |
| 236 AnimateLongPress(); |
| 237 break; |
| 238 case InkDropState::ACTIVATED: |
| 239 AnimateLongPress(); |
| 240 break; |
| 238 } | 241 } |
| 239 } | 242 } |
| 240 | 243 |
| 241 void InkDropDelegate::OnDelegatedFrameDamage( | 244 void InkDropAnimationControllerImpl::SetInkDropSize(const gfx::Size& size) { |
| 242 const gfx::Rect& damage_rect_in_dip) { | 245 SetInkDropBounds(gfx::Rect(ink_drop_bounds_.origin(), size)); |
| 243 } | 246 } |
| 244 | 247 |
| 245 void InkDropDelegate::OnDeviceScaleFactorChanged(float device_scale_factor) { | 248 gfx::Rect InkDropAnimationControllerImpl::GetInkDropBounds() const { |
| 249 return ink_drop_bounds_; |
| 246 } | 250 } |
| 247 | 251 |
| 248 base::Closure InkDropDelegate::PrepareForLayerBoundsChange() { | 252 void InkDropAnimationControllerImpl::SetInkDropBounds(const gfx::Rect& bounds) { |
| 249 return base::Closure(); | 253 ink_drop_bounds_ = bounds; |
| 254 SetLayerBounds(ink_drop_layer_.get()); |
| 255 SetLayerBounds(long_press_layer_.get()); |
| 250 } | 256 } |
| 251 | 257 |
| 252 InkDropAnimationController::InkDropAnimationController(views::View* view) | 258 void InkDropAnimationControllerImpl::AnimateTapDown() { |
| 253 : ink_drop_layer_(new ui::Layer()), | |
| 254 ink_drop_delegate_( | |
| 255 new InkDropDelegate(ink_drop_layer_.get(), kInkDropColor)), | |
| 256 appear_animation_observer_(nullptr), | |
| 257 long_press_layer_(new ui::Layer()), | |
| 258 long_press_delegate_( | |
| 259 new InkDropDelegate(long_press_layer_.get(), kLongPressColor)), | |
| 260 long_press_animation_observer_(nullptr), | |
| 261 view_(view) { | |
| 262 view_->SetPaintToLayer(true); | |
| 263 view_->AddPreTargetHandler(this); | |
| 264 ui::Layer* layer = view_->layer(); | |
| 265 layer->SetMasksToBounds(!UseCircularFeedback()); | |
| 266 SetupAnimationLayer(layer, long_press_layer_.get(), | |
| 267 long_press_delegate_.get()); | |
| 268 SetupAnimationLayer(layer, ink_drop_layer_.get(), ink_drop_delegate_.get()); | |
| 269 ink_drop_delegate_->set_should_render_circle(UseCircularFeedback()); | |
| 270 } | |
| 271 | |
| 272 InkDropAnimationController::~InkDropAnimationController() { | |
| 273 view_->RemovePreTargetHandler(this); | |
| 274 } | |
| 275 | |
| 276 void InkDropAnimationController::AnimateTapDown() { | |
| 277 if ((appear_animation_observer_ && | 259 if ((appear_animation_observer_ && |
| 278 appear_animation_observer_->IsAnimationActive()) || | 260 appear_animation_observer_->IsAnimationActive()) || |
| 279 (long_press_animation_observer_ && | 261 (long_press_animation_observer_ && |
| 280 long_press_animation_observer_->IsAnimationActive())) { | 262 long_press_animation_observer_->IsAnimationActive())) { |
| 281 // Only one animation at a time. Subsequent tap downs are ignored until the | 263 // Only one animation at a time. Subsequent tap downs are ignored until the |
| 282 // current animation completes. | 264 // current animation completes. |
| 283 return; | 265 return; |
| 284 } | 266 } |
| 285 appear_animation_observer_.reset( | 267 appear_animation_observer_.reset( |
| 286 new AppearAnimationObserver(ink_drop_layer_.get(), false)); | 268 new AppearAnimationObserver(ink_drop_layer_.get(), false)); |
| 287 AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(), | 269 AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(), |
| 288 UseCircularFeedback(), | |
| 289 base::TimeDelta::FromMilliseconds( | 270 base::TimeDelta::FromMilliseconds( |
| 290 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs | 271 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs |
| 291 : kShowInkDropAnimationDurationSlowMs))); | 272 : kShowInkDropAnimationDurationSlowMs))); |
| 292 } | 273 } |
| 293 | 274 |
| 294 void InkDropAnimationController::AnimateHide() { | 275 void InkDropAnimationControllerImpl::AnimateHide() { |
| 295 if (appear_animation_observer_) | 276 if (appear_animation_observer_ && |
| 277 appear_animation_observer_->IsAnimationActive()) { |
| 296 appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); | 278 appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); |
| 279 } else if (long_press_animation_observer_) { |
| 280 long_press_animation_observer_->HideNowIfDoneOrOnceCompleted(); |
| 281 } |
| 297 } | 282 } |
| 298 | 283 |
| 299 void InkDropAnimationController::AnimateLongPress() { | 284 void InkDropAnimationControllerImpl::AnimateLongPress() { |
| 300 // Only one animation at a time. Subsequent long presses are ignored until the | 285 // Only one animation at a time. Subsequent long presses are ignored until the |
| 301 // current animation completes. | 286 // current animation completes. |
| 302 if (long_press_animation_observer_ && | 287 if (long_press_animation_observer_ && |
| 303 long_press_animation_observer_->IsAnimationActive()) { | 288 long_press_animation_observer_->IsAnimationActive()) { |
| 304 return; | 289 return; |
| 305 } | 290 } |
| 306 appear_animation_observer_.reset(); | 291 appear_animation_observer_.reset(); |
| 307 long_press_animation_observer_.reset( | 292 long_press_animation_observer_.reset( |
| 308 new AppearAnimationObserver(long_press_layer_.get(), true)); | 293 new AppearAnimationObserver(long_press_layer_.get(), false)); |
| 309 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get()); | 294 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get()); |
| 310 AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(), | 295 AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(), |
| 311 true, | |
| 312 base::TimeDelta::FromMilliseconds( | 296 base::TimeDelta::FromMilliseconds( |
| 313 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs | 297 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs |
| 314 : kShowLongPressAnimationDurationSlowMs)); | 298 : kShowLongPressAnimationDurationSlowMs)); |
| 315 } | 299 } |
| 316 | 300 |
| 317 void InkDropAnimationController::AnimateShow(ui::Layer* layer, | 301 void InkDropAnimationControllerImpl::AnimateShow( |
| 318 AppearAnimationObserver* observer, | 302 ui::Layer* layer, |
| 319 bool circle, | 303 AppearAnimationObserver* observer, |
| 320 base::TimeDelta duration) { | 304 base::TimeDelta duration) { |
| 321 SetLayerBounds(layer, circle, view_->width(), view_->height()); | |
| 322 layer->SetVisible(true); | 305 layer->SetVisible(true); |
| 323 layer->SetOpacity(1.0f); | 306 layer->SetOpacity(1.0f); |
| 324 | 307 |
| 325 float start_x = layer->bounds().width() * kMinimumScaleCenteringOffset; | 308 float start_x = ink_drop_bounds_.x() + |
| 326 float start_y = layer->bounds().height() * kMinimumScaleCenteringOffset; | 309 layer->bounds().width() * kMinimumScaleCenteringOffset; |
| 310 float start_y = ink_drop_bounds_.y() + |
| 311 layer->bounds().height() * kMinimumScaleCenteringOffset; |
| 327 | 312 |
| 328 gfx::Transform initial_transform; | 313 gfx::Transform initial_transform; |
| 329 initial_transform.Translate(start_x, start_y); | 314 initial_transform.Translate(start_x, start_y); |
| 330 initial_transform.Scale(kMinimumScale, kMinimumScale); | 315 initial_transform.Scale(kMinimumScale, kMinimumScale); |
| 331 layer->SetTransform(initial_transform); | 316 layer->SetTransform(initial_transform); |
| 332 | 317 |
| 333 ui::LayerAnimator* animator = layer->GetAnimator(); | 318 ui::LayerAnimator* animator = layer->GetAnimator(); |
| 334 ui::ScopedLayerAnimationSettings animation(animator); | 319 ui::ScopedLayerAnimationSettings animation(animator); |
| 335 animation.SetPreemptionStrategy( | 320 animation.SetPreemptionStrategy( |
| 336 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 321 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 337 | 322 |
| 338 gfx::Transform identity_transform; | 323 gfx::Transform target_transform; |
| 324 target_transform.Translate(ink_drop_bounds_.x(), ink_drop_bounds_.y()); |
| 339 ui::LayerAnimationElement* element = | 325 ui::LayerAnimationElement* element = |
| 340 ui::LayerAnimationElement::CreateTransformElement(identity_transform, | 326 ui::LayerAnimationElement::CreateTransformElement(target_transform, |
| 341 duration); | 327 duration); |
| 342 ui::LayerAnimationSequence* sequence = | 328 ui::LayerAnimationSequence* sequence = |
| 343 new ui::LayerAnimationSequence(element); | 329 new ui::LayerAnimationSequence(element); |
| 344 sequence->AddObserver(observer); | 330 sequence->AddObserver(observer); |
| 345 animator->StartAnimation(sequence); | 331 animator->StartAnimation(sequence); |
| 346 } | 332 } |
| 347 | 333 |
| 348 void InkDropAnimationController::SetLayerBounds(ui::Layer* layer, | 334 void InkDropAnimationControllerImpl::SetLayerBounds(ui::Layer* layer) { |
| 349 bool circle, | 335 bool circle = UseCircularFeedback(); |
| 350 int width, | 336 gfx::Size size = ink_drop_bounds_.size(); |
| 351 int height) { | 337 float circle_width = circle ? 2.0f * kCircleRadius : size.width(); |
| 352 float circle_width = circle ? 2.0f * kCircleRadius : width; | 338 float circle_height = circle ? 2.0f * kCircleRadius : size.height(); |
| 353 float circle_height = circle ? 2.0f * kCircleRadius : height; | 339 float circle_x = circle ? (size.width() - circle_width) * 0.5f : 0; |
| 354 float circle_x = circle ? (width - circle_width) * 0.5f : 0; | 340 float circle_y = circle ? (size.height() - circle_height) * 0.5f : 0; |
| 355 float circle_y = circle ? (height - circle_height) * 0.5f : 0; | |
| 356 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height)); | 341 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height)); |
| 357 } | 342 } |
| 358 | 343 |
| 359 void InkDropAnimationController::SetupAnimationLayer( | 344 void InkDropAnimationControllerImpl::SetupAnimationLayer( |
| 360 ui::Layer* parent, | |
| 361 ui::Layer* layer, | 345 ui::Layer* layer, |
| 362 InkDropDelegate* delegate) { | 346 InkDropDelegate* delegate) { |
| 363 layer->SetFillsBoundsOpaquely(false); | 347 layer->SetFillsBoundsOpaquely(false); |
| 364 layer->set_delegate(delegate); | 348 layer->set_delegate(delegate); |
| 365 layer->SetVisible(false); | 349 layer->SetVisible(false); |
| 366 layer->SetBounds(gfx::Rect()); | 350 layer->SetBounds(gfx::Rect()); |
| 367 parent->Add(layer); | 351 delegate->set_should_render_circle(UseCircularFeedback()); |
| 368 parent->StackAtBottom(layer); | |
| 369 } | |
| 370 | |
| 371 void InkDropAnimationController::OnGestureEvent(ui::GestureEvent* event) { | |
| 372 if (event->target() != view_) | |
| 373 return; | |
| 374 | |
| 375 switch (event->type()) { | |
| 376 case ui::ET_GESTURE_TAP_DOWN: | |
| 377 AnimateTapDown(); | |
| 378 break; | |
| 379 case ui::ET_GESTURE_LONG_PRESS: | |
| 380 AnimateLongPress(); | |
| 381 break; | |
| 382 case ui::ET_GESTURE_END: | |
| 383 case ui::ET_GESTURE_TAP_CANCEL: | |
| 384 case ui::ET_GESTURE_TAP: | |
| 385 AnimateHide(); | |
| 386 break; | |
| 387 default: | |
| 388 break; | |
| 389 } | |
| 390 } | 352 } |
| 391 | 353 |
| 392 } // namespace views | 354 } // namespace views |
| OLD | NEW |