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 3 // found in the LICENSE file. 4 5 #include "ui/wm/core/window_animations.h" 6 7 #include <math.h> 8 9 #include <algorithm> 10 #include <vector> 11 12 #include "base/command_line.h" 13 #include "base/compiler_specific.h" 14 #include "base/logging.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/stl_util.h" 17 #include "base/time/time.h" 18 #include "ui/aura/client/aura_constants.h" 19 #include "ui/aura/window.h" 20 #include "ui/aura/window_delegate.h" 21 #include "ui/aura/window_observer.h" 22 #include "ui/aura/window_property.h" 23 #include "ui/compositor/compositor_observer.h" 24 #include "ui/compositor/layer.h" 25 #include "ui/compositor/layer_animation_observer.h" 26 #include "ui/compositor/layer_animation_sequence.h" 27 #include "ui/compositor/layer_animator.h" 28 #include "ui/compositor/layer_tree_owner.h" 29 #include "ui/compositor/scoped_layer_animation_settings.h" 30 #include "ui/gfx/animation/animation.h" 31 #include "ui/gfx/interpolated_transform.h" 32 #include "ui/gfx/rect_conversions.h" 33 #include "ui/gfx/screen.h" 34 #include "ui/gfx/vector2d.h" 35 #include "ui/gfx/vector3d_f.h" 36 #include "ui/wm/core/window_util.h" 37 #include "ui/wm/core/wm_core_switches.h" 38 #include "ui/wm/public/animation_host.h" 39 40 DECLARE_WINDOW_PROPERTY_TYPE(int) 41 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationType) 42 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationTransition) 43 DECLARE_WINDOW_PROPERTY_TYPE(float) 44 DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(WM_EXPORT, bool) 45 46 namespace wm { 47 namespace { 48 const float kWindowAnimation_Vertical_TranslateY = 15.f; 49 50 // A base class for hiding animation observer which has two roles: 51 // 1) Notifies AnimationHost at the end of hiding animation. 52 // 2) Detaches the window's layers for hiding animation and deletes 53 // them upon completion of the animation. This is necessary to a) 54 // ensure that the animation continues in the event of the window being 55 // deleted, and b) to ensure that the animation is visible even if the 56 // window gets restacked below other windows when focus or activation 57 // changes. 58 // The subclass will determine when the animation is completed. 59 class HidingWindowAnimationObserverBase : public aura::WindowObserver { 60 public: 61 HidingWindowAnimationObserverBase(aura::Window* window) : window_(window) { 62 window_->AddObserver(this); 63 } 64 virtual ~HidingWindowAnimationObserverBase() { 65 if (window_) 66 window_->RemoveObserver(this); 67 } 68 69 // aura::WindowObserver: 70 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 71 DCHECK_EQ(window, window_); 72 WindowInvalid(); 73 } 74 75 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 76 DCHECK_EQ(window, window_); 77 WindowInvalid(); 78 } 79 80 // Detach the current layers and create new layers for |window_|. 81 // Stack the original layers above |window_| and its transient 82 // children. If the window has transient children, the original 83 // layers will be moved above the top most transient child so that 84 // activation change does not put the window above the animating 85 // layer. 86 void DetachAndRecreateLayers() { 87 layer_owner_ = RecreateLayers(window_); 88 if (window_->parent()) { 89 const aura::Window::Windows& transient_children = 90 GetTransientChildren(window_); 91 aura::Window::Windows::const_iterator iter = 92 std::find(window_->parent()->children().begin(), 93 window_->parent()->children().end(), 94 window_); 95 DCHECK(iter != window_->parent()->children().end()); 96 aura::Window* topmost_transient_child = NULL; 97 for (++iter; iter != window_->parent()->children().end(); ++iter) { 98 if (std::find(transient_children.begin(), 99 transient_children.end(), 100 *iter) != transient_children.end()) { 101 topmost_transient_child = *iter; 102 } 103 } 104 if (topmost_transient_child) { 105 window_->parent()->layer()->StackAbove( 106 layer_owner_->root(), topmost_transient_child->layer()); 107 } 108 } 109 } 110 111 protected: 112 // Invoked when the hiding animation is completed. It will delete 113 // 'this', and no operation should be made on this object after this 114 // point. 115 void OnAnimationCompleted() { 116 // Window may have been destroyed by this point. 117 if (window_) { 118 aura::client::AnimationHost* animation_host = 119 aura::client::GetAnimationHost(window_); 120 if (animation_host) 121 animation_host->OnWindowHidingAnimationCompleted(); 122 window_->RemoveObserver(this); 123 } 124 delete this; 125 } 126 127 private: 128 // Invoked when the window is destroyed (or destroying). 129 void WindowInvalid() { 130 layer_owner_->root()->SuppressPaint(); 131 132 window_->RemoveObserver(this); 133 window_ = NULL; 134 } 135 136 aura::Window* window_; 137 138 // The owner of detached layers. 139 scoped_ptr<ui::LayerTreeOwner> layer_owner_; 140 141 DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserverBase); 142 }; 143 144 } // namespace 145 146 DEFINE_WINDOW_PROPERTY_KEY(int, 147 kWindowVisibilityAnimationTypeKey, 148 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); 149 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); 150 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, 151 kWindowVisibilityAnimationTransitionKey, 152 ANIMATE_BOTH); 153 DEFINE_WINDOW_PROPERTY_KEY(float, 154 kWindowVisibilityAnimationVerticalPositionKey, 155 kWindowAnimation_Vertical_TranslateY); 156 157 // A HidingWindowAnimationObserver that deletes observer and detached 158 // layers upon the completion of the implicit animation. 159 class ImplicitHidingWindowAnimationObserver 160 : public HidingWindowAnimationObserverBase, 161 public ui::ImplicitAnimationObserver { 162 public: 163 ImplicitHidingWindowAnimationObserver( 164 aura::Window* window, 165 ui::ScopedLayerAnimationSettings* settings); 166 virtual ~ImplicitHidingWindowAnimationObserver() {} 167 168 // ui::ImplicitAnimationObserver: 169 virtual void OnImplicitAnimationsCompleted() OVERRIDE; 170 171 private: 172 DISALLOW_COPY_AND_ASSIGN(ImplicitHidingWindowAnimationObserver); 173 }; 174 175 namespace { 176 177 const int kDefaultAnimationDurationForMenuMS = 150; 178 179 const float kWindowAnimation_HideOpacity = 0.f; 180 const float kWindowAnimation_ShowOpacity = 1.f; 181 const float kWindowAnimation_TranslateFactor = 0.5f; 182 const float kWindowAnimation_ScaleFactor = .95f; 183 184 const int kWindowAnimation_Rotate_DurationMS = 180; 185 const int kWindowAnimation_Rotate_OpacityDurationPercent = 90; 186 const float kWindowAnimation_Rotate_TranslateY = -20.f; 187 const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f; 188 const float kWindowAnimation_Rotate_DegreesX = 5.f; 189 const float kWindowAnimation_Rotate_ScaleFactor = .99f; 190 191 const float kWindowAnimation_Bounce_Scale = 1.02f; 192 const int kWindowAnimation_Bounce_DurationMS = 180; 193 const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40; 194 195 base::TimeDelta GetWindowVisibilityAnimationDuration( 196 const aura::Window& window) { 197 int duration = 198 window.GetProperty(kWindowVisibilityAnimationDurationKey); 199 if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) { 200 return base::TimeDelta::FromMilliseconds( 201 kDefaultAnimationDurationForMenuMS); 202 } 203 return base::TimeDelta::FromInternalValue(duration); 204 } 205 206 // Gets/sets the WindowVisibilityAnimationType associated with a window. 207 // TODO(beng): redundant/fold into method on public api? 208 int GetWindowVisibilityAnimationType(aura::Window* window) { 209 int type = window->GetProperty(kWindowVisibilityAnimationTypeKey); 210 if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) { 211 return (window->type() == ui::wm::WINDOW_TYPE_MENU || 212 window->type() == ui::wm::WINDOW_TYPE_TOOLTIP) 213 ? WINDOW_VISIBILITY_ANIMATION_TYPE_FADE 214 : WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; 215 } 216 return type; 217 } 218 219 void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { 220 const ui::Layer* root = layer; 221 while (root->parent()) 222 root = root->parent(); 223 layer->GetTargetTransformRelativeTo(root, transform); 224 } 225 226 gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer, 227 const gfx::Transform& transform) { 228 gfx::Transform in_world = transform; 229 GetTransformRelativeToRoot(layer, &in_world); 230 231 gfx::RectF transformed = layer->bounds(); 232 in_world.TransformRect(&transformed); 233 234 return gfx::ToEnclosingRect(transformed); 235 } 236 237 // Augment the host window so that the enclosing bounds of the full 238 // animation will fit inside of it. 239 void AugmentWindowSize(aura::Window* window, 240 const gfx::Transform& end_transform) { 241 aura::client::AnimationHost* animation_host = 242 aura::client::GetAnimationHost(window); 243 if (!animation_host) 244 return; 245 246 const gfx::Rect& world_at_start = window->bounds(); 247 gfx::Rect world_at_end = 248 GetLayerWorldBoundsAfterTransform(window->layer(), end_transform); 249 gfx::Rect union_in_window_space = 250 gfx::UnionRects(world_at_start, world_at_end); 251 252 // Calculate the top left and bottom right deltas to be added to the window 253 // bounds. 254 gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(), 255 world_at_start.y() - union_in_window_space.y()); 256 257 gfx::Vector2d bottom_right_delta( 258 union_in_window_space.x() + union_in_window_space.width() - 259 (world_at_start.x() + world_at_start.width()), 260 union_in_window_space.y() + union_in_window_space.height() - 261 (world_at_start.y() + world_at_start.height())); 262 263 DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 && 264 bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0); 265 266 animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta); 267 } 268 269 // Shows a window using an animation, animating its opacity from 0.f to 1.f, 270 // its visibility to true, and its transform from |start_transform| to 271 // |end_transform|. 272 void AnimateShowWindowCommon(aura::Window* window, 273 const gfx::Transform& start_transform, 274 const gfx::Transform& end_transform) { 275 AugmentWindowSize(window, end_transform); 276 277 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 278 window->layer()->SetTransform(start_transform); 279 window->layer()->SetVisible(true); 280 281 { 282 // Property sets within this scope will be implicitly animated. 283 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); 284 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); 285 if (duration.ToInternalValue() > 0) 286 settings.SetTransitionDuration(duration); 287 288 window->layer()->SetTransform(end_transform); 289 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 290 } 291 } 292 293 // Hides a window using an animation, animating its opacity from 1.f to 0.f, 294 // its visibility to false, and its transform to |end_transform|. 295 void AnimateHideWindowCommon(aura::Window* window, 296 const gfx::Transform& end_transform) { 297 AugmentWindowSize(window, end_transform); 298 299 // Property sets within this scope will be implicitly animated. 300 ScopedHidingAnimationSettings hiding_settings(window); 301 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); 302 if (duration.ToInternalValue() > 0) 303 hiding_settings.layer_animation_settings()->SetTransitionDuration(duration); 304 305 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 306 window->layer()->SetTransform(end_transform); 307 window->layer()->SetVisible(false); 308 } 309 310 static gfx::Transform GetScaleForWindow(aura::Window* window) { 311 gfx::Rect bounds = window->bounds(); 312 gfx::Transform scale = gfx::GetScaleTransform( 313 gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(), 314 kWindowAnimation_TranslateFactor * bounds.height()), 315 kWindowAnimation_ScaleFactor); 316 return scale; 317 } 318 319 // Show/Hide windows using a shrink animation. 320 void AnimateShowWindow_Drop(aura::Window* window) { 321 AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform()); 322 } 323 324 void AnimateHideWindow_Drop(aura::Window* window) { 325 AnimateHideWindowCommon(window, GetScaleForWindow(window)); 326 } 327 328 // Show/Hide windows using a vertical Glenimation. 329 void AnimateShowWindow_Vertical(aura::Window* window) { 330 gfx::Transform transform; 331 transform.Translate(0, window->GetProperty( 332 kWindowVisibilityAnimationVerticalPositionKey)); 333 AnimateShowWindowCommon(window, transform, gfx::Transform()); 334 } 335 336 void AnimateHideWindow_Vertical(aura::Window* window) { 337 gfx::Transform transform; 338 transform.Translate(0, window->GetProperty( 339 kWindowVisibilityAnimationVerticalPositionKey)); 340 AnimateHideWindowCommon(window, transform); 341 } 342 343 // Show/Hide windows using a fade. 344 void AnimateShowWindow_Fade(aura::Window* window) { 345 AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform()); 346 } 347 348 void AnimateHideWindow_Fade(aura::Window* window) { 349 AnimateHideWindowCommon(window, gfx::Transform()); 350 } 351 352 ui::LayerAnimationElement* CreateGrowShrinkElement( 353 aura::Window* window, bool grow) { 354 scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale( 355 gfx::Point3F(kWindowAnimation_Bounce_Scale, 356 kWindowAnimation_Bounce_Scale, 357 1), 358 gfx::Point3F(1, 1, 1))); 359 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 360 new ui::InterpolatedTransformAboutPivot( 361 gfx::Point(window->bounds().width() * 0.5, 362 window->bounds().height() * 0.5), 363 scale.release())); 364 scale_about_pivot->SetReversed(grow); 365 scoped_ptr<ui::LayerAnimationElement> transition( 366 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 367 scale_about_pivot.release(), 368 base::TimeDelta::FromMilliseconds( 369 kWindowAnimation_Bounce_DurationMS * 370 kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100))); 371 transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); 372 return transition.release(); 373 } 374 375 void AnimateBounce(aura::Window* window) { 376 ui::ScopedLayerAnimationSettings scoped_settings( 377 window->layer()->GetAnimator()); 378 scoped_settings.SetPreemptionStrategy( 379 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); 380 scoped_ptr<ui::LayerAnimationSequence> sequence( 381 new ui::LayerAnimationSequence); 382 sequence->AddElement(CreateGrowShrinkElement(window, true)); 383 sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( 384 ui::LayerAnimationElement::BOUNDS, 385 base::TimeDelta::FromMilliseconds( 386 kWindowAnimation_Bounce_DurationMS * 387 (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) / 388 100))); 389 sequence->AddElement(CreateGrowShrinkElement(window, false)); 390 window->layer()->GetAnimator()->StartAnimation(sequence.release()); 391 } 392 393 // A HidingWindowAnimationObserver that deletes observer and detached 394 // layers when the last_sequence has been completed or aborted. 395 class RotateHidingWindowAnimationObserver 396 : public HidingWindowAnimationObserverBase, 397 public ui::LayerAnimationObserver { 398 public: 399 RotateHidingWindowAnimationObserver(aura::Window* window) 400 : HidingWindowAnimationObserverBase(window), last_sequence_(NULL) {} 401 virtual ~RotateHidingWindowAnimationObserver() {} 402 403 void set_last_sequence(ui::LayerAnimationSequence* last_sequence) { 404 last_sequence_ = last_sequence; 405 } 406 407 // ui::LayerAnimationObserver: 408 virtual void OnLayerAnimationEnded( 409 ui::LayerAnimationSequence* sequence) OVERRIDE { 410 if (last_sequence_ == sequence) 411 OnAnimationCompleted(); 412 } 413 virtual void OnLayerAnimationAborted( 414 ui::LayerAnimationSequence* sequence) OVERRIDE { 415 if (last_sequence_ == sequence) 416 OnAnimationCompleted(); 417 } 418 virtual void OnLayerAnimationScheduled( 419 ui::LayerAnimationSequence* sequence) OVERRIDE {} 420 421 private: 422 ui::LayerAnimationSequence* last_sequence_; 423 424 DISALLOW_COPY_AND_ASSIGN(RotateHidingWindowAnimationObserver); 425 }; 426 427 void AddLayerAnimationsForRotate(aura::Window* window, bool show) { 428 if (show) 429 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 430 431 base::TimeDelta duration = base::TimeDelta::FromMilliseconds( 432 kWindowAnimation_Rotate_DurationMS); 433 434 RotateHidingWindowAnimationObserver* observer = NULL; 435 436 if (!show) { 437 observer = new RotateHidingWindowAnimationObserver(window); 438 window->layer()->GetAnimator()->SchedulePauseForProperties( 439 duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, 440 ui::LayerAnimationElement::OPACITY); 441 } 442 scoped_ptr<ui::LayerAnimationElement> opacity( 443 ui::LayerAnimationElement::CreateOpacityElement( 444 show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity, 445 duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100)); 446 opacity->set_tween_type(gfx::Tween::EASE_IN_OUT); 447 window->layer()->GetAnimator()->ScheduleAnimation( 448 new ui::LayerAnimationSequence(opacity.release())); 449 450 float xcenter = window->bounds().width() * 0.5; 451 452 gfx::Transform transform; 453 transform.Translate(xcenter, 0); 454 transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth); 455 transform.Translate(-xcenter, 0); 456 scoped_ptr<ui::InterpolatedTransform> perspective( 457 new ui::InterpolatedConstantTransform(transform)); 458 459 scoped_ptr<ui::InterpolatedTransform> scale( 460 new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor)); 461 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 462 new ui::InterpolatedTransformAboutPivot( 463 gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY), 464 scale.release())); 465 466 scoped_ptr<ui::InterpolatedTransform> translation( 467 new ui::InterpolatedTranslation(gfx::Point(), gfx::Point( 468 0, kWindowAnimation_Rotate_TranslateY))); 469 470 scoped_ptr<ui::InterpolatedTransform> rotation( 471 new ui::InterpolatedAxisAngleRotation( 472 gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX)); 473 474 scale_about_pivot->SetChild(perspective.release()); 475 translation->SetChild(scale_about_pivot.release()); 476 rotation->SetChild(translation.release()); 477 rotation->SetReversed(show); 478 479 scoped_ptr<ui::LayerAnimationElement> transition( 480 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 481 rotation.release(), duration)); 482 ui::LayerAnimationSequence* last_sequence = 483 new ui::LayerAnimationSequence(transition.release()); 484 window->layer()->GetAnimator()->ScheduleAnimation(last_sequence); 485 if (observer) { 486 observer->set_last_sequence(last_sequence); 487 observer->DetachAndRecreateLayers(); 488 } 489 } 490 491 void AnimateShowWindow_Rotate(aura::Window* window) { 492 AddLayerAnimationsForRotate(window, true); 493 } 494 495 void AnimateHideWindow_Rotate(aura::Window* window) { 496 AddLayerAnimationsForRotate(window, false); 497 } 498 499 bool AnimateShowWindow(aura::Window* window) { 500 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 501 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 502 // Since hide animation may have changed opacity and transform, 503 // reset them to show the window. 504 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 505 window->layer()->SetTransform(gfx::Transform()); 506 } 507 return false; 508 } 509 510 switch (GetWindowVisibilityAnimationType(window)) { 511 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 512 AnimateShowWindow_Drop(window); 513 return true; 514 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 515 AnimateShowWindow_Vertical(window); 516 return true; 517 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 518 AnimateShowWindow_Fade(window); 519 return true; 520 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 521 AnimateShowWindow_Rotate(window); 522 return true; 523 default: 524 return false; 525 } 526 } 527 528 bool AnimateHideWindow(aura::Window* window) { 529 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 530 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 531 // Since show animation may have changed opacity and transform, 532 // reset them, though the change should be hidden. 533 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 534 window->layer()->SetTransform(gfx::Transform()); 535 } 536 return false; 537 } 538 539 switch (GetWindowVisibilityAnimationType(window)) { 540 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 541 AnimateHideWindow_Drop(window); 542 return true; 543 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 544 AnimateHideWindow_Vertical(window); 545 return true; 546 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 547 AnimateHideWindow_Fade(window); 548 return true; 549 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 550 AnimateHideWindow_Rotate(window); 551 return true; 552 default: 553 return false; 554 } 555 } 556 557 } // namespace 558 559 //////////////////////////////////////////////////////////////////////////////// 560 // ImplicitHidingWindowAnimationObserver 561 562 ImplicitHidingWindowAnimationObserver::ImplicitHidingWindowAnimationObserver( 563 aura::Window* window, 564 ui::ScopedLayerAnimationSettings* settings) 565 : HidingWindowAnimationObserverBase(window) { 566 settings->AddObserver(this); 567 } 568 569 void ImplicitHidingWindowAnimationObserver::OnImplicitAnimationsCompleted() { 570 OnAnimationCompleted(); 571 } 572 573 //////////////////////////////////////////////////////////////////////////////// 574 // ScopedHidingAnimationSettings 575 576 ScopedHidingAnimationSettings::ScopedHidingAnimationSettings( 577 aura::Window* window) 578 : layer_animation_settings_(window->layer()->GetAnimator()), 579 observer_(new ImplicitHidingWindowAnimationObserver( 580 window, 581 &layer_animation_settings_)) { 582 } 583 584 ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() { 585 observer_->DetachAndRecreateLayers(); 586 } 587 588 //////////////////////////////////////////////////////////////////////////////// 589 // External interface 590 591 void SetWindowVisibilityAnimationType(aura::Window* window, int type) { 592 window->SetProperty(kWindowVisibilityAnimationTypeKey, type); 593 } 594 595 int GetWindowVisibilityAnimationType(aura::Window* window) { 596 return window->GetProperty(kWindowVisibilityAnimationTypeKey); 597 } 598 599 void SetWindowVisibilityAnimationTransition( 600 aura::Window* window, 601 WindowVisibilityAnimationTransition transition) { 602 window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition); 603 } 604 605 bool HasWindowVisibilityAnimationTransition( 606 aura::Window* window, 607 WindowVisibilityAnimationTransition transition) { 608 WindowVisibilityAnimationTransition prop = window->GetProperty( 609 kWindowVisibilityAnimationTransitionKey); 610 return (prop & transition) != 0; 611 } 612 613 void SetWindowVisibilityAnimationDuration(aura::Window* window, 614 const base::TimeDelta& duration) { 615 window->SetProperty(kWindowVisibilityAnimationDurationKey, 616 static_cast<int>(duration.ToInternalValue())); 617 } 618 619 base::TimeDelta GetWindowVisibilityAnimationDuration( 620 const aura::Window& window) { 621 return base::TimeDelta::FromInternalValue( 622 window.GetProperty(kWindowVisibilityAnimationDurationKey)); 623 } 624 625 void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, 626 float position) { 627 window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); 628 } 629 630 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { 631 if (WindowAnimationsDisabled(window)) 632 return false; 633 if (visible) 634 return AnimateShowWindow(window); 635 // Don't start hiding the window again if it's already being hidden. 636 return window->layer()->GetTargetOpacity() != 0.0f && 637 AnimateHideWindow(window); 638 } 639 640 bool AnimateWindow(aura::Window* window, WindowAnimationType type) { 641 switch (type) { 642 case WINDOW_ANIMATION_TYPE_BOUNCE: 643 AnimateBounce(window); 644 return true; 645 default: 646 NOTREACHED(); 647 return false; 648 } 649 } 650 651 bool WindowAnimationsDisabled(aura::Window* window) { 652 return (!gfx::Animation::ShouldRenderRichAnimation() || (window && 653 window->GetProperty(aura::client::kAnimationsDisabledKey)) || 654 CommandLine::ForCurrentProcess()->HasSwitch( 655 switches::kWindowAnimationsDisabled)); 656 } 657 658 } // namespace wm 659