Chromium Code Reviews| 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.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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 StartHideAnimation(); | 178 StartHideAnimation(); |
| 176 } | 179 } |
| 177 | 180 |
| 178 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() | 181 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed() |
| 179 const { | 182 const { |
| 180 // Ensures that OnImplicitAnimationsCompleted is called even if the observed | 183 // Ensures that OnImplicitAnimationsCompleted is called even if the observed |
| 181 // animation is deleted. Allows for setting the proper state on |layer_|. | 184 // animation is deleted. Allows for setting the proper state on |layer_|. |
| 182 return true; | 185 return true; |
| 183 } | 186 } |
| 184 | 187 |
| 185 // Renders the visual feedback. Will render a circle if |circle_| is true, | 188 InkDropAnimationController::InkDropAnimationController( |
| 186 // otherwise renders a rounded rectangle. | 189 InkDropHost* ink_drop_host) |
| 187 class InkDropDelegate : public ui::LayerDelegate { | 190 : ink_drop_host_(ink_drop_host), |
| 188 public: | 191 layer_tree_(new ui::Layer()), |
| 189 InkDropDelegate(ui::Layer* layer, SkColor color); | 192 ink_drop_layer_(new ui::Layer()), |
| 190 ~InkDropDelegate() override; | 193 ink_drop_delegate_(new InkDropDelegate(ink_drop_layer_, |
| 194 kInkDropColor, | |
| 195 kCircleRadius, | |
| 196 kRoundedRectCorners)), | |
| 197 appear_animation_observer_(nullptr), | |
| 198 long_press_layer_(new ui::Layer()), | |
| 199 long_press_delegate_(new InkDropDelegate(long_press_layer_, | |
| 200 kLongPressColor, | |
| 201 kCircleRadius, | |
| 202 kRoundedRectCorners)), | |
| 203 long_press_animation_observer_(nullptr), | |
| 204 bounds_(0, 0, 0, 0) { | |
| 205 SetupAnimationLayer(long_press_layer_, long_press_delegate_.get()); | |
| 206 SetupAnimationLayer(ink_drop_layer_, ink_drop_delegate_.get()); | |
| 191 | 207 |
| 192 // Sets the visual style of the feedback. | 208 layer_tree_.root()->Add(ink_drop_layer_); |
| 193 void set_should_render_circle(bool should_render_circle) { | 209 layer_tree_.root()->Add(long_press_layer_); |
| 194 should_render_circle_ = should_render_circle; | |
| 195 } | |
| 196 | 210 |
| 197 // ui::LayerDelegate: | 211 ink_drop_host_->AddInkDropLayer(layer_tree_.root()); |
| 198 void OnPaintLayer(const ui::PaintContext& context) override; | |
| 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 | |
| 203 private: | |
| 204 // The ui::Layer being rendered to. | |
| 205 ui::Layer* layer_; | |
| 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 InkDropAnimationController::~InkDropAnimationController() { |
| 215 // TODO(bruthig): Currently this virtual function is going to be called during | |
| 216 // ToolbarButton's destructor, is that ok?? This should hopefully change and | |
| 217 // be called when the Ink Drop becomes hidden. | |
| 218 ink_drop_host_->RemoveInkDropLayer(layer_tree_.root()); | |
| 221 } | 219 } |
| 222 | 220 |
| 223 void InkDropDelegate::OnPaintLayer(const ui::PaintContext& context) { | 221 void InkDropAnimationController::AnimateToState(InkDropState state) { |
| 224 SkPaint paint; | 222 switch (state) { |
|
jonross
2015/08/07 17:14:31
Do we need to restrict state transitions?
I think
bruthig
2015/08/07 22:00:45
All the work for state transitions and the visuals
jonross
2015/08/10 20:32:02
A good plan. Do we have this noted in the bug? Or
bruthig
2015/08/10 21:57:15
Hmmm I'm not sure either of those two places are a
tdanderson
2015/08/11 12:57:36
If you're fairly sure of what you're going to be d
bruthig
2015/08/11 14:31:10
Done.
| |
| 225 paint.setColor(color_); | 223 case InkDropState::HIDDEN: |
| 226 paint.setFlags(SkPaint::kAntiAlias_Flag); | 224 AnimateHide(); |
| 227 paint.setStyle(SkPaint::kFill_Style); | 225 break; |
| 228 | 226 case InkDropState::ACTION_PENDING: |
| 229 gfx::Rect bounds = layer_->bounds(); | 227 AnimateTapDown(); |
| 230 | 228 break; |
| 231 ui::PaintRecorder recorder(context, layer_->size()); | 229 case InkDropState::QUICK_ACTION: |
| 232 gfx::Canvas* canvas = recorder.canvas(); | 230 AnimateTapDown(); |
| 233 if (should_render_circle_) { | 231 AnimateHide(); |
| 234 gfx::Point midpoint(bounds.width() * 0.5f, bounds.height() * 0.5f); | 232 break; |
| 235 canvas->DrawCircle(midpoint, kCircleRadius, paint); | 233 case InkDropState::SLOW_ACTION: |
| 236 } else { | 234 AnimateLongPress(); |
| 237 canvas->DrawRoundRect(bounds, kRoundedRectCorners, paint); | 235 break; |
| 236 case InkDropState::ACTIVATED: | |
| 237 AnimateLongPress(); | |
| 238 break; | |
| 238 } | 239 } |
| 239 } | 240 } |
| 240 | 241 |
| 241 void InkDropDelegate::OnDelegatedFrameDamage( | 242 void InkDropAnimationController::SetSize(const gfx::Size& size) { |
| 242 const gfx::Rect& damage_rect_in_dip) { | 243 SetBounds(gfx::Rect(bounds().x(), bounds().y(), size.width(), size.height())); |
| 243 } | 244 } |
| 244 | 245 |
| 245 void InkDropDelegate::OnDeviceScaleFactorChanged(float device_scale_factor) { | 246 void InkDropAnimationController::SetBounds(const gfx::Rect& bounds) { |
| 246 } | 247 bounds_ = bounds; |
| 247 | 248 SetLayerBounds(ink_drop_layer_); |
| 248 base::Closure InkDropDelegate::PrepareForLayerBoundsChange() { | 249 SetLayerBounds(long_press_layer_); |
| 249 return base::Closure(); | |
| 250 } | |
| 251 | |
| 252 InkDropAnimationController::InkDropAnimationController(views::View* view) | |
| 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 } | 250 } |
| 275 | 251 |
| 276 void InkDropAnimationController::AnimateTapDown() { | 252 void InkDropAnimationController::AnimateTapDown() { |
| 277 if ((appear_animation_observer_ && | 253 if ((appear_animation_observer_ && |
| 278 appear_animation_observer_->IsAnimationActive()) || | 254 appear_animation_observer_->IsAnimationActive()) || |
| 279 (long_press_animation_observer_ && | 255 (long_press_animation_observer_ && |
| 280 long_press_animation_observer_->IsAnimationActive())) { | 256 long_press_animation_observer_->IsAnimationActive())) { |
| 281 // Only one animation at a time. Subsequent tap downs are ignored until the | 257 // Only one animation at a time. Subsequent tap downs are ignored until the |
| 282 // current animation completes. | 258 // current animation completes. |
| 283 return; | 259 return; |
| 284 } | 260 } |
| 285 appear_animation_observer_.reset( | 261 appear_animation_observer_.reset( |
| 286 new AppearAnimationObserver(ink_drop_layer_.get(), false)); | 262 new AppearAnimationObserver(ink_drop_layer_, false)); |
| 287 AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(), | 263 AnimateShow(ink_drop_layer_, appear_animation_observer_.get(), |
| 288 UseCircularFeedback(), | |
| 289 base::TimeDelta::FromMilliseconds( | 264 base::TimeDelta::FromMilliseconds( |
| 290 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs | 265 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs |
| 291 : kShowInkDropAnimationDurationSlowMs))); | 266 : kShowInkDropAnimationDurationSlowMs))); |
| 292 } | 267 } |
| 293 | 268 |
| 294 void InkDropAnimationController::AnimateHide() { | 269 void InkDropAnimationController::AnimateHide() { |
| 295 if (appear_animation_observer_) | 270 if (appear_animation_observer_ && |
| 271 appear_animation_observer_->IsAnimationActive()) { | |
| 296 appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); | 272 appear_animation_observer_->HideNowIfDoneOrOnceCompleted(); |
| 273 } else if (long_press_animation_observer_) { | |
| 274 long_press_animation_observer_->HideNowIfDoneOrOnceCompleted(); | |
| 275 } | |
| 297 } | 276 } |
| 298 | 277 |
| 299 void InkDropAnimationController::AnimateLongPress() { | 278 void InkDropAnimationController::AnimateLongPress() { |
| 300 // Only one animation at a time. Subsequent long presses are ignored until the | 279 // Only one animation at a time. Subsequent long presses are ignored until the |
| 301 // current animation completes. | 280 // current animation completes. |
| 302 if (long_press_animation_observer_ && | 281 if (long_press_animation_observer_ && |
| 303 long_press_animation_observer_->IsAnimationActive()) { | 282 long_press_animation_observer_->IsAnimationActive()) { |
| 304 return; | 283 return; |
| 305 } | 284 } |
| 306 appear_animation_observer_.reset(); | 285 appear_animation_observer_.reset(); |
| 307 long_press_animation_observer_.reset( | 286 long_press_animation_observer_.reset( |
| 308 new AppearAnimationObserver(long_press_layer_.get(), true)); | 287 new AppearAnimationObserver(long_press_layer_, false)); |
| 309 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get()); | 288 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_); |
| 310 AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(), | 289 AnimateShow(long_press_layer_, long_press_animation_observer_.get(), |
| 311 true, | |
| 312 base::TimeDelta::FromMilliseconds( | 290 base::TimeDelta::FromMilliseconds( |
| 313 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs | 291 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs |
| 314 : kShowLongPressAnimationDurationSlowMs)); | 292 : kShowLongPressAnimationDurationSlowMs)); |
| 315 } | 293 } |
| 316 | 294 |
| 317 void InkDropAnimationController::AnimateShow(ui::Layer* layer, | 295 void InkDropAnimationController::AnimateShow(ui::Layer* layer, |
| 318 AppearAnimationObserver* observer, | 296 AppearAnimationObserver* observer, |
| 319 bool circle, | |
| 320 base::TimeDelta duration) { | 297 base::TimeDelta duration) { |
| 321 SetLayerBounds(layer, circle, view_->width(), view_->height()); | |
| 322 layer->SetVisible(true); | 298 layer->SetVisible(true); |
| 323 layer->SetOpacity(1.0f); | 299 layer->SetOpacity(1.0f); |
| 324 | 300 |
| 325 float start_x = layer->bounds().width() * kMinimumScaleCenteringOffset; | 301 float start_x = |
| 326 float start_y = layer->bounds().height() * kMinimumScaleCenteringOffset; | 302 bounds_.x() + layer->bounds().width() * kMinimumScaleCenteringOffset; |
| 303 float start_y = | |
| 304 bounds_.y() + layer->bounds().height() * kMinimumScaleCenteringOffset; | |
| 327 | 305 |
| 328 gfx::Transform initial_transform; | 306 gfx::Transform initial_transform; |
| 329 initial_transform.Translate(start_x, start_y); | 307 initial_transform.Translate(start_x, start_y); |
| 330 initial_transform.Scale(kMinimumScale, kMinimumScale); | 308 initial_transform.Scale(kMinimumScale, kMinimumScale); |
| 331 layer->SetTransform(initial_transform); | 309 layer->SetTransform(initial_transform); |
| 332 | 310 |
| 333 ui::LayerAnimator* animator = layer->GetAnimator(); | 311 ui::LayerAnimator* animator = layer->GetAnimator(); |
| 334 ui::ScopedLayerAnimationSettings animation(animator); | 312 ui::ScopedLayerAnimationSettings animation(animator); |
| 335 animation.SetPreemptionStrategy( | 313 animation.SetPreemptionStrategy( |
| 336 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 314 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 337 | 315 |
| 338 gfx::Transform identity_transform; | 316 gfx::Transform target_transform; |
| 317 target_transform.Translate(bounds_.x(), bounds_.y()); | |
| 339 ui::LayerAnimationElement* element = | 318 ui::LayerAnimationElement* element = |
| 340 ui::LayerAnimationElement::CreateTransformElement(identity_transform, | 319 ui::LayerAnimationElement::CreateTransformElement(target_transform, |
| 341 duration); | 320 duration); |
| 342 ui::LayerAnimationSequence* sequence = | 321 ui::LayerAnimationSequence* sequence = |
| 343 new ui::LayerAnimationSequence(element); | 322 new ui::LayerAnimationSequence(element); |
| 344 sequence->AddObserver(observer); | 323 sequence->AddObserver(observer); |
| 345 animator->StartAnimation(sequence); | 324 animator->StartAnimation(sequence); |
| 346 } | 325 } |
| 347 | 326 |
| 348 void InkDropAnimationController::SetLayerBounds(ui::Layer* layer, | 327 void InkDropAnimationController::SetLayerBounds(ui::Layer* layer) { |
| 349 bool circle, | 328 bool circle = UseCircularFeedback(); |
| 350 int width, | 329 gfx::Size size = bounds_.size(); |
| 351 int height) { | 330 float circle_width = circle ? 2.0f * kCircleRadius : size.width(); |
| 352 float circle_width = circle ? 2.0f * kCircleRadius : width; | 331 float circle_height = circle ? 2.0f * kCircleRadius : size.height(); |
| 353 float circle_height = circle ? 2.0f * kCircleRadius : height; | 332 float circle_x = circle ? (size.width() - circle_width) * 0.5f : 0; |
| 354 float circle_x = circle ? (width - circle_width) * 0.5f : 0; | 333 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)); | 334 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height)); |
| 357 } | 335 } |
| 358 | 336 |
| 359 void InkDropAnimationController::SetupAnimationLayer( | 337 void InkDropAnimationController::SetupAnimationLayer( |
| 360 ui::Layer* parent, | |
| 361 ui::Layer* layer, | 338 ui::Layer* layer, |
| 362 InkDropDelegate* delegate) { | 339 InkDropDelegate* delegate) { |
| 363 layer->SetFillsBoundsOpaquely(false); | 340 layer->SetFillsBoundsOpaquely(false); |
| 364 layer->set_delegate(delegate); | 341 layer->set_delegate(delegate); |
| 365 layer->SetVisible(false); | 342 layer->SetVisible(false); |
| 366 layer->SetBounds(gfx::Rect()); | 343 layer->SetBounds(gfx::Rect()); |
| 367 parent->Add(layer); | 344 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 } | 345 } |
| 391 | 346 |
| 392 } // namespace views | 347 } // namespace views |
| OLD | NEW |