| 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" | |
| 21 #include "ui/compositor/layer.h" | 20 #include "ui/compositor/layer.h" |
| 22 #include "ui/compositor/layer_animation_observer.h" | 21 #include "ui/compositor/layer_animation_observer.h" |
| 23 #include "ui/compositor/layer_animation_sequence.h" | 22 #include "ui/compositor/layer_animation_sequence.h" |
| 24 #include "ui/compositor/layer_animator.h" | 23 #include "ui/compositor/layer_animator.h" |
| 25 #include "ui/compositor/scoped_layer_animation_settings.h" | 24 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 26 #include "ui/gfx/interpolated_transform.h" | 25 #include "ui/gfx/interpolated_transform.h" |
| 27 #include "ui/gfx/screen.h" | 26 #include "ui/gfx/screen.h" |
| 28 #include "ui/views/view.h" | 27 #include "ui/views/view.h" |
| 29 #include "ui/views/widget/widget.h" | 28 #include "ui/views/widget/widget.h" |
| 30 | 29 |
| 31 DECLARE_WINDOW_PROPERTY_TYPE(int) | 30 DECLARE_WINDOW_PROPERTY_TYPE(int) |
| 32 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) | 31 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) |
| 33 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) | 32 DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) |
| 34 DECLARE_WINDOW_PROPERTY_TYPE(float) | 33 DECLARE_WINDOW_PROPERTY_TYPE(float) |
| 35 | 34 |
| 36 using aura::Window; | |
| 37 using base::TimeDelta; | 35 using base::TimeDelta; |
| 38 using ui::Layer; | |
| 39 | 36 |
| 40 namespace ash { | 37 namespace ash { |
| 41 namespace internal { | 38 namespace internal { |
| 42 namespace { | 39 namespace { |
| 43 const float kWindowAnimation_Vertical_TranslateY = 15.f; | 40 const float kWindowAnimation_Vertical_TranslateY = 15.f; |
| 44 } | 41 } |
| 45 | 42 |
| 46 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, | 43 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationType, |
| 47 kWindowVisibilityAnimationTypeKey, | 44 kWindowVisibilityAnimationTypeKey, |
| 48 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); | 45 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); |
| 49 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); | 46 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); |
| 50 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, | 47 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, |
| 51 kWindowVisibilityAnimationTransitionKey, | 48 kWindowVisibilityAnimationTransitionKey, |
| 52 ANIMATE_BOTH); | 49 ANIMATE_BOTH); |
| 53 DEFINE_WINDOW_PROPERTY_KEY(float, | 50 DEFINE_WINDOW_PROPERTY_KEY(float, |
| 54 kWindowVisibilityAnimationVerticalPositionKey, | 51 kWindowVisibilityAnimationVerticalPositionKey, |
| 55 kWindowAnimation_Vertical_TranslateY); | 52 kWindowAnimation_Vertical_TranslateY); |
| 56 | 53 |
| 57 namespace { | 54 namespace { |
| 58 | 55 |
| 59 const int kDefaultAnimationDurationForMenuMS = 150; | 56 const int kDefaultAnimationDurationForMenuMS = 150; |
| 60 | 57 |
| 61 // TODO(jamescook): Shorten the duration if the window doesn't move much. | |
| 62 const int kCrossFadeAnimationDurationMs = 400; | |
| 63 | |
| 64 const float kWindowAnimation_HideOpacity = 0.f; | 58 const float kWindowAnimation_HideOpacity = 0.f; |
| 65 const float kWindowAnimation_ShowOpacity = 1.f; | 59 const float kWindowAnimation_ShowOpacity = 1.f; |
| 66 const float kWindowAnimation_TranslateFactor = -0.025f; | 60 const float kWindowAnimation_TranslateFactor = -0.025f; |
| 67 const float kWindowAnimation_ScaleFactor = 1.05f; | 61 const float kWindowAnimation_ScaleFactor = 1.05f; |
| 68 const float kWindowAnimation_MinimizeRotate = -5.f; | 62 const float kWindowAnimation_MinimizeRotate = -5.f; |
| 69 | 63 |
| 70 // Amount windows are scaled during workspace animations. | 64 // Amount windows are scaled during workspace animations. |
| 71 const float kWorkspaceScale = .95f; | 65 const float kWorkspaceScale = .95f; |
| 72 | 66 |
| 73 base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) { | 67 base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) { |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 return true; | 490 return true; |
| 497 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: | 491 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE: |
| 498 AnimateHideWindow_Minimize(window); | 492 AnimateHideWindow_Minimize(window); |
| 499 return true; | 493 return true; |
| 500 default: | 494 default: |
| 501 NOTREACHED(); | 495 NOTREACHED(); |
| 502 return false; | 496 return false; |
| 503 } | 497 } |
| 504 } | 498 } |
| 505 | 499 |
| 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 | |
| 602 } // namespace | 500 } // namespace |
| 603 } // namespace internal | 501 } // namespace internal |
| 604 | 502 |
| 605 //////////////////////////////////////////////////////////////////////////////// | 503 //////////////////////////////////////////////////////////////////////////////// |
| 606 // External interface | 504 // External interface |
| 607 | 505 |
| 608 void SetWindowVisibilityAnimationType(aura::Window* window, | 506 void SetWindowVisibilityAnimationType(aura::Window* window, |
| 609 WindowVisibilityAnimationType type) { | 507 WindowVisibilityAnimationType type) { |
| 610 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); | 508 window->SetProperty(internal::kWindowVisibilityAnimationTypeKey, type); |
| 611 } | 509 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 634 position); | 532 position); |
| 635 } | 533 } |
| 636 | 534 |
| 637 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( | 535 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( |
| 638 aura::Window* window) { | 536 aura::Window* window) { |
| 639 return new internal::HidingWindowAnimationObserver(window); | 537 return new internal::HidingWindowAnimationObserver(window); |
| 640 } | 538 } |
| 641 | 539 |
| 642 namespace internal { | 540 namespace internal { |
| 643 | 541 |
| 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 | |
| 723 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { | 542 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |
| 724 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || | 543 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || |
| 725 CommandLine::ForCurrentProcess()->HasSwitch( | 544 CommandLine::ForCurrentProcess()->HasSwitch( |
| 726 switches::kAshWindowAnimationsDisabled)) { | 545 switches::kAshWindowAnimationsDisabled)) { |
| 727 return false; | 546 return false; |
| 728 } | 547 } |
| 729 if (visible) { | 548 if (visible) { |
| 730 return AnimateShowWindow(window); | 549 return AnimateShowWindow(window); |
| 731 } else { | 550 } else { |
| 732 // Don't start hiding the window again if it's already being hidden. | 551 // Don't start hiding the window again if it's already being hidden. |
| 733 return window->layer()->GetTargetOpacity() != 0.0f && | 552 return window->layer()->GetTargetOpacity() != 0.0f && |
| 734 AnimateHideWindow(window); | 553 AnimateHideWindow(window); |
| 735 } | 554 } |
| 736 } | 555 } |
| 737 | 556 |
| 738 } // namespace internal | 557 } // namespace internal |
| 739 } // namespace ash | 558 } // namespace ash |
| OLD | NEW |