| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/wm/window_animations.h" | 5 #include "ash/wm/window_animations.h" |
| 6 | 6 |
| 7 #include "ash/ash_switches.h" | 7 #include "ash/ash_switches.h" |
| 8 #include "ash/launcher/launcher.h" | 8 #include "ash/launcher/launcher.h" |
| 9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 15 #include "base/time.h" | 15 #include "base/time.h" |
| 16 #include "ui/aura/client/aura_constants.h" | 16 #include "ui/aura/client/aura_constants.h" |
| 17 #include "ui/aura/window.h" | 17 #include "ui/aura/window.h" |
| 18 #include "ui/aura/window_observer.h" | 18 #include "ui/aura/window_observer.h" |
| 19 #include "ui/aura/window_property.h" | 19 #include "ui/aura/window_property.h" |
| 20 #include "ui/compositor/compositor_observer.h" |
| 20 #include "ui/compositor/layer.h" | 21 #include "ui/compositor/layer.h" |
| 21 #include "ui/compositor/layer_animation_observer.h" | 22 #include "ui/compositor/layer_animation_observer.h" |
| 22 #include "ui/compositor/layer_animation_sequence.h" | 23 #include "ui/compositor/layer_animation_sequence.h" |
| 23 #include "ui/compositor/layer_animator.h" | 24 #include "ui/compositor/layer_animator.h" |
| 24 #include "ui/compositor/scoped_layer_animation_settings.h" | 25 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 25 #include "ui/gfx/interpolated_transform.h" | 26 #include "ui/gfx/interpolated_transform.h" |
| 26 #include "ui/gfx/screen.h" | 27 #include "ui/gfx/screen.h" |
| 27 | 28 |
| 28 DECLARE_WINDOW_PROPERTY_TYPE(int) | 29 DECLARE_WINDOW_PROPERTY_TYPE(int) |
| 29 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) | 30 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) |
| 30 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) | 31 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) |
| 31 | 32 |
| 33 using aura::Window; |
| 32 using base::TimeDelta; | 34 using base::TimeDelta; |
| 35 using ui::Layer; |
| 33 | 36 |
| 34 namespace ash { | 37 namespace ash { |
| 35 namespace internal { | 38 namespace internal { |
| 36 | 39 |
| 37 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, | 40 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, |
| 38 kWindowVisibilityAnimationTypeKey, | 41 kWindowVisibilityAnimationTypeKey, |
| 39 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); | 42 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); |
| 40 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); | 43 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); |
| 41 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, | 44 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, |
| 42 kWindowVisibilityAnimationTransitionKey, | 45 kWindowVisibilityAnimationTransitionKey, |
| 43 ANIMATE_BOTH); | 46 ANIMATE_BOTH); |
| 44 | 47 |
| 45 namespace { | 48 namespace { |
| 46 | 49 |
| 47 const int kDefaultAnimationDurationForMenuMS = 150; | 50 const int kDefaultAnimationDurationForMenuMS = 150; |
| 48 | 51 |
| 52 const int kCrossFadeAnimationDurationMs = 400; |
| 53 |
| 49 const float kWindowAnimation_HideOpacity = 0.f; | 54 const float kWindowAnimation_HideOpacity = 0.f; |
| 50 const float kWindowAnimation_ShowOpacity = 1.f; | 55 const float kWindowAnimation_ShowOpacity = 1.f; |
| 51 const float kWindowAnimation_TranslateFactor = -0.025f; | 56 const float kWindowAnimation_TranslateFactor = -0.025f; |
| 52 const float kWindowAnimation_ScaleFactor = 1.05f; | 57 const float kWindowAnimation_ScaleFactor = 1.05f; |
| 53 const float kWindowAnimation_MinimizeRotate = -5.f; | 58 const float kWindowAnimation_MinimizeRotate = -5.f; |
| 54 | 59 |
| 55 const float kWindowAnimation_Vertical_TranslateY = 15.f; | 60 const float kWindowAnimation_Vertical_TranslateY = 15.f; |
| 56 | 61 |
| 57 // Amount windows are scaled during workspace animations. | 62 // Amount windows are scaled during workspace animations. |
| 58 const float kWorkspaceScale = .95f; | 63 const float kWorkspaceScale = .95f; |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 return true; | 470 return true; |
| 466 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: | 471 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: |
| 467 AnimateHideWindow_Minimize(window); | 472 AnimateHideWindow_Minimize(window); |
| 468 return true; | 473 return true; |
| 469 default: | 474 default: |
| 470 NOTREACHED(); | 475 NOTREACHED(); |
| 471 return false; | 476 return false; |
| 472 } | 477 } |
| 473 } | 478 } |
| 474 | 479 |
| 480 // Recreates a fresh layer for |window| and all its child windows. Does not |
| 481 // recreate shadows or other non-window layers. Returns the old layer and its |
| 482 // children, maintaining the hierarchy. |
| 483 Layer* RecreateWindowLayers(Window* window) { |
| 484 Layer* old_layer = window->RecreateLayer(); |
| 485 for (Window::Windows::const_iterator it = window->children().begin(); |
| 486 it != window->children().end(); |
| 487 ++it) { |
| 488 aura::Window* child = *it; |
| 489 Layer* old_child_layer = RecreateWindowLayers(child); |
| 490 // Maintain the hierarchy of the detached layers. |
| 491 old_layer->Add(old_child_layer); |
| 492 } |
| 493 return old_layer; |
| 494 } |
| 495 |
| 496 // Deletes |layer| and all its child layers. |
| 497 void DeepDelete(Layer* layer) { |
| 498 std::vector<Layer*> children = layer->children(); |
| 499 for (std::vector<Layer*>::const_iterator it = children.begin(); |
| 500 it != children.end(); |
| 501 ++it) { |
| 502 Layer* child = *it; |
| 503 DeepDelete(child); |
| 504 } |
| 505 delete layer; |
| 506 } |
| 507 |
| 508 // Observer for a window cross-fade animation. If either the window closes or |
| 509 // the layer's animation completes or compositing is aborted due to GPU crash, |
| 510 // it deletes the layer and removes itself as an observer. |
| 511 class CrossFadeObserver : public ui::CompositorObserver, |
| 512 public aura::WindowObserver, |
| 513 public ui::ImplicitAnimationObserver { |
| 514 public: |
| 515 // Observes |window| for destruction, but does not take ownership. |
| 516 // Takes ownership of |layer| and its child layers. |
| 517 CrossFadeObserver(Window* window, Layer* layer) |
| 518 : window_(window), |
| 519 layer_(layer) { |
| 520 window_->AddObserver(this); |
| 521 layer_->GetCompositor()->AddObserver(this); |
| 522 } |
| 523 virtual ~CrossFadeObserver() { |
| 524 Cleanup(); |
| 525 } |
| 526 |
| 527 // ui::CompositorObserver overrides: |
| 528 virtual void OnCompositingStarted(ui::Compositor* compositor) OVERRIDE { |
| 529 } |
| 530 virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE { |
| 531 } |
| 532 virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE { |
| 533 // Something went wrong with compositing and our layers are now invalid. |
| 534 if (layer_) |
| 535 layer_->GetAnimator()->StopAnimating(); |
| 536 // Delete is scheduled in OnImplicitAnimationsCompleted(). |
| 537 Cleanup(); |
| 538 } |
| 539 |
| 540 // aura::WindowObserver overrides: |
| 541 virtual void OnWindowDestroying(Window* window) OVERRIDE { |
| 542 if (layer_) |
| 543 layer_->GetAnimator()->StopAnimating(); |
| 544 // Delete is scheduled in OnImplicitAnimationsCompleted(). |
| 545 Cleanup(); |
| 546 } |
| 547 |
| 548 // ui::ImplicitAnimationObserver overrides: |
| 549 virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| 550 // ImplicitAnimationObserver's base class uses the object after calling |
| 551 // this function, so we cannot delete |this|. |
| 552 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 553 } |
| 554 |
| 555 private: |
| 556 // Can be called multiple times if the window is closed or the compositor |
| 557 // fails in the middle of the animation. |
| 558 void Cleanup() { |
| 559 if (window_) { |
| 560 window_->RemoveObserver(this); |
| 561 window_ = NULL; |
| 562 } |
| 563 if (layer_) { |
| 564 layer_->GetCompositor()->RemoveObserver(this); |
| 565 DeepDelete(layer_); |
| 566 layer_ = NULL; |
| 567 } |
| 568 } |
| 569 |
| 570 Window* window_; // not owned |
| 571 Layer* layer_; // owned |
| 572 |
| 573 DISALLOW_COPY_AND_ASSIGN(CrossFadeObserver); |
| 574 }; |
| 575 |
| 475 } // namespace | 576 } // namespace |
| 476 } // namespace internal | 577 } // namespace internal |
| 477 | 578 |
| 478 //////////////////////////////////////////////////////////////////////////////// | 579 //////////////////////////////////////////////////////////////////////////////// |
| 479 // External interface | 580 // External interface |
| 480 | 581 |
| 481 void SetWindowVisibilityAnimationType(aura::Window* window, | 582 void SetWindowVisibilityAnimationType(aura::Window* window, |
| 482 WindowVisibilityAnimationType type) { | 583 WindowVisibilityAnimationType type) { |
| 483 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); | 584 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); |
| 484 } | 585 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 501 static_cast<int>(duration.ToInternalValue())); | 602 static_cast<int>(duration.ToInternalValue())); |
| 502 } | 603 } |
| 503 | 604 |
| 504 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( | 605 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( |
| 505 aura::Window* window) { | 606 aura::Window* window) { |
| 506 return new internal::HidingWindowAnimationObserver(window); | 607 return new internal::HidingWindowAnimationObserver(window); |
| 507 } | 608 } |
| 508 | 609 |
| 509 namespace internal { | 610 namespace internal { |
| 510 | 611 |
| 612 void CrossFadeToBounds(aura::Window* window, const gfx::Rect& new_bounds) { |
| 613 DCHECK(window->TargetVisibility()); |
| 614 gfx::Rect old_bounds = window->bounds(); |
| 615 |
| 616 // Create fresh layers for the window and all its children to paint into. |
| 617 // Takes ownership of the old layer and all its children, which will be |
| 618 // cleaned up after the animation completes. |
| 619 ui::Layer* old_layer = RecreateWindowLayers(window); |
| 620 ui::Layer* new_layer = window->layer(); |
| 621 |
| 622 // Ensure the higher-resolution layer is on top. |
| 623 bool old_on_top = (old_bounds.width() > new_bounds.width()); |
| 624 if (old_on_top) |
| 625 old_layer->parent()->StackBelow(new_layer, old_layer); |
| 626 else |
| 627 old_layer->parent()->StackAbove(new_layer, old_layer); |
| 628 |
| 629 // Tween types for transform animations must match to keep the window edges |
| 630 // aligned during the animation. |
| 631 const ui::Tween::Type kTransformTween = ui::Tween::EASE_OUT; |
| 632 { |
| 633 // Scale up the old layer while translating to new position. |
| 634 ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator()); |
| 635 // Animation observer owns the old layer and deletes itself. |
| 636 settings.AddObserver(new CrossFadeObserver(window, old_layer)); |
| 637 settings.SetTransitionDuration( |
| 638 TimeDelta::FromMilliseconds(kCrossFadeAnimationDurationMs)); |
| 639 settings.SetTweenType(kTransformTween); |
| 640 ui::Transform out_transform; |
| 641 float scale_x = static_cast<float>(new_bounds.width()) / |
| 642 static_cast<float>(old_bounds.width()); |
| 643 float scale_y = static_cast<float>(new_bounds.height()) / |
| 644 static_cast<float>(old_bounds.height()); |
| 645 out_transform.ConcatScale(scale_x, scale_y); |
| 646 out_transform.ConcatTranslate(new_bounds.x() - old_bounds.x(), |
| 647 new_bounds.y() - old_bounds.y()); |
| 648 old_layer->SetTransform(out_transform); |
| 649 if (old_on_top) { |
| 650 // The old layer is on top, and should fade out. The new layer below will |
| 651 // stay opaque to block the desktop. |
| 652 old_layer->SetOpacity(0.f); |
| 653 } |
| 654 // In tests |old_layer| is deleted here, as animations have zero duration. |
| 655 } |
| 656 |
| 657 // Resize the window to the new size, which will force a layout and paint. |
| 658 window->SetBounds(new_bounds); |
| 659 |
| 660 // Set the new layer's current transform, such that the user sees a scaled |
| 661 // version of the window with the original bounds at the original position. |
| 662 ui::Transform in_transform; |
| 663 float scale_x = static_cast<float>(old_bounds.width()) / |
| 664 static_cast<float>(new_bounds.width()); |
| 665 float scale_y = static_cast<float>(old_bounds.height()) / |
| 666 static_cast<float>(new_bounds.height()); |
| 667 in_transform.ConcatScale(scale_x, scale_y); |
| 668 in_transform.ConcatTranslate(old_bounds.x() - new_bounds.x(), |
| 669 old_bounds.y() - new_bounds.y()); |
| 670 new_layer->SetTransform(in_transform); |
| 671 if (!old_on_top) { |
| 672 // The new layer is on top and should fade in. The old layer below will |
| 673 // stay opaque and block the desktop. |
| 674 new_layer->SetOpacity(0.f); |
| 675 } |
| 676 { |
| 677 // Animate the new layer to the identity transform, so the window goes to |
| 678 // its newly set bounds. |
| 679 ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator()); |
| 680 settings.SetTransitionDuration( |
| 681 TimeDelta::FromMilliseconds(kCrossFadeAnimationDurationMs)); |
| 682 settings.SetTweenType(kTransformTween); |
| 683 new_layer->SetTransform(ui::Transform()); |
| 684 if (!old_on_top) { |
| 685 // New layer is on top, fade it in. |
| 686 new_layer->SetOpacity(1.f); |
| 687 } |
| 688 } |
| 689 } |
| 690 |
| 511 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { | 691 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |
| 512 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || | 692 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || |
| 513 CommandLine::ForCurrentProcess()->HasSwitch( | 693 CommandLine::ForCurrentProcess()->HasSwitch( |
| 514 switches::kAuraWindowAnimationsDisabled)) { | 694 switches::kAuraWindowAnimationsDisabled)) { |
| 515 return false; | 695 return false; |
| 516 } | 696 } |
| 517 if (visible) { | 697 if (visible) { |
| 518 return AnimateShowWindow(window); | 698 return AnimateShowWindow(window); |
| 519 } else { | 699 } else { |
| 520 // Don't start hiding the window again if it's already being hidden. | 700 // Don't start hiding the window again if it's already being hidden. |
| 521 return window->layer()->GetTargetOpacity() != 0.0f && | 701 return window->layer()->GetTargetOpacity() != 0.0f && |
| 522 AnimateHideWindow(window); | 702 AnimateHideWindow(window); |
| 523 } | 703 } |
| 524 } | 704 } |
| 525 | 705 |
| 526 } // namespace internal | 706 } // namespace internal |
| 527 } // namespace ash | 707 } // namespace ash |
| OLD | NEW |