| 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 #include "ui/views/view.h" | 28 #include "ui/views/view.h" |
| 28 #include "ui/views/widget/widget.h" | 29 #include "ui/views/widget/widget.h" |
| 29 | 30 |
| 30 DECLARE_WINDOW_PROPERTY_TYPE(int) | 31 DECLARE_WINDOW_PROPERTY_TYPE(int) |
| 31 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) | 32 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) |
| 32 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) | 33 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) |
| 33 DECLARE_WINDOW_PROPERTY_TYPE(float) | 34 DECLARE_WINDOW_PROPERTY_TYPE(float) |
| 34 | 35 |
| 36 using aura::Window; |
| 35 using base::TimeDelta; | 37 using base::TimeDelta; |
| 38 using ui::Layer; |
| 36 | 39 |
| 37 namespace ash { | 40 namespace ash { |
| 38 namespace internal { | 41 namespace internal { |
| 39 namespace { | 42 namespace { |
| 40 const float kWindowAnimation_Vertical_TranslateY = 15.f; | 43 const float kWindowAnimation_Vertical_TranslateY = 15.f; |
| 41 } | 44 } |
| 42 | 45 |
| 43 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, | 46 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, |
| 44 kWindowVisibilityAnimationTypeKey, | 47 kWindowVisibilityAnimationTypeKey, |
| 45 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); | 48 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); |
| 46 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); | 49 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); |
| 47 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, | 50 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, |
| 48 kWindowVisibilityAnimationTransitionKey, | 51 kWindowVisibilityAnimationTransitionKey, |
| 49 ANIMATE_BOTH); | 52 ANIMATE_BOTH); |
| 50 DEFINE_WINDOW_PROPERTY_KEY(float, | 53 DEFINE_WINDOW_PROPERTY_KEY(float, |
| 51 kWindowVisibilityAnimationVerticalPositionKey, | 54 kWindowVisibilityAnimationVerticalPositionKey, |
| 52 kWindowAnimation_Vertical_TranslateY); | 55 kWindowAnimation_Vertical_TranslateY); |
| 53 | 56 |
| 54 namespace { | 57 namespace { |
| 55 | 58 |
| 56 const int kDefaultAnimationDurationForMenuMS = 150; | 59 const int kDefaultAnimationDurationForMenuMS = 150; |
| 57 | 60 |
| 61 // TODO(jamescook): Shorten the duration if the window doesn't move much. |
| 62 const int kCrossFadeAnimationDurationMs = 400; |
| 63 |
| 58 const float kWindowAnimation_HideOpacity = 0.f; | 64 const float kWindowAnimation_HideOpacity = 0.f; |
| 59 const float kWindowAnimation_ShowOpacity = 1.f; | 65 const float kWindowAnimation_ShowOpacity = 1.f; |
| 60 const float kWindowAnimation_TranslateFactor = -0.025f; | 66 const float kWindowAnimation_TranslateFactor = -0.025f; |
| 61 const float kWindowAnimation_ScaleFactor = 1.05f; | 67 const float kWindowAnimation_ScaleFactor = 1.05f; |
| 62 const float kWindowAnimation_MinimizeRotate = -5.f; | 68 const float kWindowAnimation_MinimizeRotate = -5.f; |
| 63 | 69 |
| 64 // Amount windows are scaled during workspace animations. | 70 // Amount windows are scaled during workspace animations. |
| 65 const float kWorkspaceScale = .95f; | 71 const float kWorkspaceScale = .95f; |
| 66 | 72 |
| 67 base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) { | 73 base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) { |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 return true; | 496 return true; |
| 491 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: | 497 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: |
| 492 AnimateHideWindow_Minimize(window); | 498 AnimateHideWindow_Minimize(window); |
| 493 return true; | 499 return true; |
| 494 default: | 500 default: |
| 495 NOTREACHED(); | 501 NOTREACHED(); |
| 496 return false; | 502 return false; |
| 497 } | 503 } |
| 498 } | 504 } |
| 499 | 505 |
| 506 // Recreates a fresh layer for |window| and all its child windows. Does not |
| 507 // recreate shadows or other non-window layers. Returns the old layer and its |
| 508 // children, maintaining the hierarchy. |
| 509 Layer* RecreateWindowLayers(Window* window) { |
| 510 Layer* old_layer = window->RecreateLayer(); |
| 511 for (Window::Windows::const_iterator it = window->children().begin(); |
| 512 it != window->children().end(); |
| 513 ++it) { |
| 514 aura::Window* child = *it; |
| 515 Layer* old_child_layer = RecreateWindowLayers(child); |
| 516 // Maintain the hierarchy of the detached layers. |
| 517 old_layer->Add(old_child_layer); |
| 518 } |
| 519 return old_layer; |
| 520 } |
| 521 |
| 522 // Deletes |layer| and all its child layers. |
| 523 void DeepDelete(Layer* layer) { |
| 524 std::vector<Layer*> children = layer->children(); |
| 525 for (std::vector<Layer*>::const_iterator it = children.begin(); |
| 526 it != children.end(); |
| 527 ++it) { |
| 528 Layer* child = *it; |
| 529 DeepDelete(child); |
| 530 } |
| 531 delete layer; |
| 532 } |
| 533 |
| 534 // Observer for a window cross-fade animation. If either the window closes or |
| 535 // the layer's animation completes or compositing is aborted due to GPU crash, |
| 536 // it deletes the layer and removes itself as an observer. |
| 537 class CrossFadeObserver : public ui::CompositorObserver, |
| 538 public aura::WindowObserver, |
| 539 public ui::ImplicitAnimationObserver { |
| 540 public: |
| 541 // Observes |window| for destruction, but does not take ownership. |
| 542 // Takes ownership of |layer| and its child layers. |
| 543 CrossFadeObserver(Window* window, Layer* layer) |
| 544 : window_(window), |
| 545 layer_(layer) { |
| 546 window_->AddObserver(this); |
| 547 layer_->GetCompositor()->AddObserver(this); |
| 548 } |
| 549 virtual ~CrossFadeObserver() { |
| 550 Cleanup(); |
| 551 } |
| 552 |
| 553 // ui::CompositorObserver overrides: |
| 554 virtual void OnCompositingStarted(ui::Compositor* compositor) OVERRIDE { |
| 555 } |
| 556 virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE { |
| 557 } |
| 558 virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE { |
| 559 // Something went wrong with compositing and our layers are now invalid. |
| 560 if (layer_) |
| 561 layer_->GetAnimator()->StopAnimating(); |
| 562 // Delete is scheduled in OnImplicitAnimationsCompleted(). |
| 563 Cleanup(); |
| 564 } |
| 565 |
| 566 // aura::WindowObserver overrides: |
| 567 virtual void OnWindowDestroying(Window* window) OVERRIDE { |
| 568 if (layer_) |
| 569 layer_->GetAnimator()->StopAnimating(); |
| 570 // Delete is scheduled in OnImplicitAnimationsCompleted(). |
| 571 Cleanup(); |
| 572 } |
| 573 |
| 574 // ui::ImplicitAnimationObserver overrides: |
| 575 virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| 576 // ImplicitAnimationObserver's base class uses the object after calling |
| 577 // this function, so we cannot delete |this|. |
| 578 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 579 } |
| 580 |
| 581 private: |
| 582 // Can be called multiple times if the window is closed or the compositor |
| 583 // fails in the middle of the animation. |
| 584 void Cleanup() { |
| 585 if (window_) { |
| 586 window_->RemoveObserver(this); |
| 587 window_ = NULL; |
| 588 } |
| 589 if (layer_) { |
| 590 layer_->GetCompositor()->RemoveObserver(this); |
| 591 DeepDelete(layer_); |
| 592 layer_ = NULL; |
| 593 } |
| 594 } |
| 595 |
| 596 Window* window_; // not owned |
| 597 Layer* layer_; // owned |
| 598 |
| 599 DISALLOW_COPY_AND_ASSIGN(CrossFadeObserver); |
| 600 }; |
| 601 |
| 500 } // namespace | 602 } // namespace |
| 501 } // namespace internal | 603 } // namespace internal |
| 502 | 604 |
| 503 //////////////////////////////////////////////////////////////////////////////// | 605 //////////////////////////////////////////////////////////////////////////////// |
| 504 // External interface | 606 // External interface |
| 505 | 607 |
| 506 void SetWindowVisibilityAnimationType(aura::Window* window, | 608 void SetWindowVisibilityAnimationType(aura::Window* window, |
| 507 WindowVisibilityAnimationType type) { | 609 WindowVisibilityAnimationType type) { |
| 508 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); | 610 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); |
| 509 } | 611 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 532 position); | 634 position); |
| 533 } | 635 } |
| 534 | 636 |
| 535 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( | 637 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( |
| 536 aura::Window* window) { | 638 aura::Window* window) { |
| 537 return new internal::HidingWindowAnimationObserver(window); | 639 return new internal::HidingWindowAnimationObserver(window); |
| 538 } | 640 } |
| 539 | 641 |
| 540 namespace internal { | 642 namespace internal { |
| 541 | 643 |
| 644 void CrossFadeToBounds(aura::Window* window, const gfx::Rect& new_bounds) { |
| 645 DCHECK(window->TargetVisibility()); |
| 646 gfx::Rect old_bounds = window->bounds(); |
| 647 |
| 648 // Create fresh layers for the window and all its children to paint into. |
| 649 // Takes ownership of the old layer and all its children, which will be |
| 650 // cleaned up after the animation completes. |
| 651 ui::Layer* old_layer = RecreateWindowLayers(window); |
| 652 ui::Layer* new_layer = window->layer(); |
| 653 |
| 654 // Ensure the higher-resolution layer is on top. |
| 655 bool old_on_top = (old_bounds.width() > new_bounds.width()); |
| 656 if (old_on_top) |
| 657 old_layer->parent()->StackBelow(new_layer, old_layer); |
| 658 else |
| 659 old_layer->parent()->StackAbove(new_layer, old_layer); |
| 660 |
| 661 // Tween types for transform animations must match to keep the window edges |
| 662 // aligned during the animation. |
| 663 const ui::Tween::Type kTransformTween = ui::Tween::EASE_OUT; |
| 664 { |
| 665 // Scale up the old layer while translating to new position. |
| 666 ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator()); |
| 667 // Animation observer owns the old layer and deletes itself. |
| 668 settings.AddObserver(new CrossFadeObserver(window, old_layer)); |
| 669 settings.SetTransitionDuration( |
| 670 TimeDelta::FromMilliseconds(kCrossFadeAnimationDurationMs)); |
| 671 settings.SetTweenType(kTransformTween); |
| 672 ui::Transform out_transform; |
| 673 float scale_x = static_cast<float>(new_bounds.width()) / |
| 674 static_cast<float>(old_bounds.width()); |
| 675 float scale_y = static_cast<float>(new_bounds.height()) / |
| 676 static_cast<float>(old_bounds.height()); |
| 677 out_transform.ConcatScale(scale_x, scale_y); |
| 678 out_transform.ConcatTranslate(new_bounds.x() - old_bounds.x(), |
| 679 new_bounds.y() - old_bounds.y()); |
| 680 old_layer->SetTransform(out_transform); |
| 681 if (old_on_top) { |
| 682 // The old layer is on top, and should fade out. The new layer below will |
| 683 // stay opaque to block the desktop. |
| 684 old_layer->SetOpacity(0.f); |
| 685 } |
| 686 // In tests |old_layer| is deleted here, as animations have zero duration. |
| 687 } |
| 688 |
| 689 // Resize the window to the new size, which will force a layout and paint. |
| 690 window->SetBounds(new_bounds); |
| 691 |
| 692 // Set the new layer's current transform, such that the user sees a scaled |
| 693 // version of the window with the original bounds at the original position. |
| 694 ui::Transform in_transform; |
| 695 float scale_x = static_cast<float>(old_bounds.width()) / |
| 696 static_cast<float>(new_bounds.width()); |
| 697 float scale_y = static_cast<float>(old_bounds.height()) / |
| 698 static_cast<float>(new_bounds.height()); |
| 699 in_transform.ConcatScale(scale_x, scale_y); |
| 700 in_transform.ConcatTranslate(old_bounds.x() - new_bounds.x(), |
| 701 old_bounds.y() - new_bounds.y()); |
| 702 new_layer->SetTransform(in_transform); |
| 703 if (!old_on_top) { |
| 704 // The new layer is on top and should fade in. The old layer below will |
| 705 // stay opaque and block the desktop. |
| 706 new_layer->SetOpacity(0.f); |
| 707 } |
| 708 { |
| 709 // Animate the new layer to the identity transform, so the window goes to |
| 710 // its newly set bounds. |
| 711 ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator()); |
| 712 settings.SetTransitionDuration( |
| 713 TimeDelta::FromMilliseconds(kCrossFadeAnimationDurationMs)); |
| 714 settings.SetTweenType(kTransformTween); |
| 715 new_layer->SetTransform(ui::Transform()); |
| 716 if (!old_on_top) { |
| 717 // New layer is on top, fade it in. |
| 718 new_layer->SetOpacity(1.f); |
| 719 } |
| 720 } |
| 721 } |
| 722 |
| 542 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { | 723 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |
| 543 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || | 724 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || |
| 544 CommandLine::ForCurrentProcess()->HasSwitch( | 725 CommandLine::ForCurrentProcess()->HasSwitch( |
| 545 switches::kAshWindowAnimationsDisabled)) { | 726 switches::kAshWindowAnimationsDisabled)) { |
| 546 return false; | 727 return false; |
| 547 } | 728 } |
| 548 if (visible) { | 729 if (visible) { |
| 549 return AnimateShowWindow(window); | 730 return AnimateShowWindow(window); |
| 550 } else { | 731 } else { |
| 551 // Don't start hiding the window again if it's already being hidden. | 732 // Don't start hiding the window again if it's already being hidden. |
| 552 return window->layer()->GetTargetOpacity() != 0.0f && | 733 return window->layer()->GetTargetOpacity() != 0.0f && |
| 553 AnimateHideWindow(window); | 734 AnimateHideWindow(window); |
| 554 } | 735 } |
| 555 } | 736 } |
| 556 | 737 |
| 557 } // namespace internal | 738 } // namespace internal |
| 558 } // namespace ash | 739 } // namespace ash |
| OLD | NEW |