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/views/corewm/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/animation_host.h" 19 #include "ui/aura/client/aura_constants.h" 20 #include "ui/aura/window.h" 21 #include "ui/aura/window_delegate.h" 22 #include "ui/aura/window_observer.h" 23 #include "ui/aura/window_property.h" 24 #include "ui/compositor/compositor_observer.h" 25 #include "ui/compositor/layer.h" 26 #include "ui/compositor/layer_animation_observer.h" 27 #include "ui/compositor/layer_animation_sequence.h" 28 #include "ui/compositor/layer_animator.h" 29 #include "ui/compositor/scoped_layer_animation_settings.h" 30 #include "ui/gfx/interpolated_transform.h" 31 #include "ui/gfx/rect_conversions.h" 32 #include "ui/gfx/screen.h" 33 #include "ui/gfx/vector2d.h" 34 #include "ui/gfx/vector3d_f.h" 35 #include "ui/views/corewm/corewm_switches.h" 36 #include "ui/views/corewm/window_util.h" 37 #include "ui/views/view.h" 38 #include "ui/views/widget/widget.h" 39 40 DECLARE_WINDOW_PROPERTY_TYPE(int) 41 DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::WindowVisibilityAnimationType) 42 DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::WindowVisibilityAnimationTransition) 43 DECLARE_WINDOW_PROPERTY_TYPE(float) 44 DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(VIEWS_EXPORT, bool) 45 46 using aura::Window; 47 using base::TimeDelta; 48 using ui::Layer; 49 50 namespace views { 51 namespace corewm { 52 namespace { 53 const float kWindowAnimation_Vertical_TranslateY = 15.f; 54 } // namespace 55 56 DEFINE_WINDOW_PROPERTY_KEY(int, 57 kWindowVisibilityAnimationTypeKey, 58 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); 59 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); 60 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, 61 kWindowVisibilityAnimationTransitionKey, 62 ANIMATE_BOTH); 63 DEFINE_WINDOW_PROPERTY_KEY(float, 64 kWindowVisibilityAnimationVerticalPositionKey, 65 kWindowAnimation_Vertical_TranslateY); 66 67 namespace { 68 69 const int kDefaultAnimationDurationForMenuMS = 150; 70 71 const float kWindowAnimation_HideOpacity = 0.f; 72 const float kWindowAnimation_ShowOpacity = 1.f; 73 const float kWindowAnimation_TranslateFactor = 0.5f; 74 const float kWindowAnimation_ScaleFactor = .95f; 75 76 const int kWindowAnimation_Rotate_DurationMS = 180; 77 const int kWindowAnimation_Rotate_OpacityDurationPercent = 90; 78 const float kWindowAnimation_Rotate_TranslateY = -20.f; 79 const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f; 80 const float kWindowAnimation_Rotate_DegreesX = 5.f; 81 const float kWindowAnimation_Rotate_ScaleFactor = .99f; 82 83 const float kWindowAnimation_Bounce_Scale = 1.02f; 84 const int kWindowAnimation_Bounce_DurationMS = 180; 85 const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40; 86 87 base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) { 88 int duration = 89 window->GetProperty(kWindowVisibilityAnimationDurationKey); 90 if (duration == 0 && window->type() == aura::client::WINDOW_TYPE_MENU) { 91 return base::TimeDelta::FromMilliseconds( 92 kDefaultAnimationDurationForMenuMS); 93 } 94 return TimeDelta::FromInternalValue(duration); 95 } 96 97 // Gets/sets the WindowVisibilityAnimationType associated with a window. 98 // TODO(beng): redundant/fold into method on public api? 99 int GetWindowVisibilityAnimationType(aura::Window* window) { 100 int type = window->GetProperty(kWindowVisibilityAnimationTypeKey); 101 if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) { 102 return (window->type() == aura::client::WINDOW_TYPE_MENU || 103 window->type() == aura::client::WINDOW_TYPE_TOOLTIP) ? 104 WINDOW_VISIBILITY_ANIMATION_TYPE_FADE : 105 WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; 106 } 107 return type; 108 } 109 110 // Observes a hide animation. 111 // A window can be hidden for a variety of reasons. Sometimes, Hide() will be 112 // called and life is simple. Sometimes, the window is actually bound to a 113 // views::Widget and that Widget is closed, and life is a little more 114 // complicated. When a Widget is closed the aura::Window* is actually not 115 // destroyed immediately - it is actually just immediately hidden and then 116 // destroyed when the stack unwinds. To handle this case, we start the hide 117 // animation immediately when the window is hidden, then when the window is 118 // subsequently destroyed this object acquires ownership of the window's layer, 119 // so that it can continue animating it until the animation completes. 120 // Regardless of whether or not the window is destroyed, this object deletes 121 // itself when the animation completes. 122 class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, 123 public aura::WindowObserver { 124 public: 125 explicit HidingWindowAnimationObserver(aura::Window* window) 126 : window_(window) { 127 window_->AddObserver(this); 128 } 129 virtual ~HidingWindowAnimationObserver() { 130 STLDeleteElements(&layers_); 131 } 132 133 private: 134 // Overridden from ui::ImplicitAnimationObserver: 135 virtual void OnImplicitAnimationsCompleted() OVERRIDE { 136 // Window may have been destroyed by this point. 137 if (window_) { 138 aura::client::AnimationHost* animation_host = 139 aura::client::GetAnimationHost(window_); 140 if (animation_host) 141 animation_host->OnWindowHidingAnimationCompleted(); 142 window_->RemoveObserver(this); 143 } 144 delete this; 145 } 146 147 // Overridden from aura::WindowObserver: 148 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 149 DCHECK_EQ(window, window_); 150 DCHECK(layers_.empty()); 151 AcquireAllLayers(window_); 152 153 // If the Widget has views with layers, then it is necessary to take 154 // ownership of those layers too. 155 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); 156 const views::Widget* const_widget = widget; 157 if (widget && const_widget->GetRootView() && widget->GetContentsView()) 158 AcquireAllViewLayers(widget->GetContentsView()); 159 window_->RemoveObserver(this); 160 window_ = NULL; 161 } 162 163 void AcquireAllLayers(aura::Window* window) { 164 ui::Layer* layer = window->AcquireLayer(); 165 DCHECK(layer); 166 layers_.push_back(layer); 167 for (aura::Window::Windows::const_iterator it = window->children().begin(); 168 it != window->children().end(); 169 ++it) 170 AcquireAllLayers(*it); 171 } 172 173 void AcquireAllViewLayers(views::View* view) { 174 for (int i = 0; i < view->child_count(); ++i) 175 AcquireAllViewLayers(view->child_at(i)); 176 if (view->layer()) { 177 ui::Layer* layer = view->RecreateLayer(); 178 if (layer) { 179 layer->SuppressPaint(); 180 layers_.push_back(layer); 181 } 182 } 183 } 184 185 aura::Window* window_; 186 std::vector<ui::Layer*> layers_; 187 188 DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver); 189 }; 190 191 void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { 192 const Layer* root = layer; 193 while (root->parent()) 194 root = root->parent(); 195 layer->GetTargetTransformRelativeTo(root, transform); 196 } 197 198 gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer, 199 const gfx::Transform& transform) { 200 gfx::Transform in_world = transform; 201 GetTransformRelativeToRoot(layer, &in_world); 202 203 gfx::RectF transformed = layer->bounds(); 204 in_world.TransformRect(&transformed); 205 206 return gfx::ToEnclosingRect(transformed); 207 } 208 209 // Augment the host window so that the enclosing bounds of the full 210 // animation will fit inside of it. 211 void AugmentWindowSize(aura::Window* window, 212 const gfx::Transform& end_transform) { 213 aura::client::AnimationHost* animation_host = 214 aura::client::GetAnimationHost(window); 215 if (!animation_host) 216 return; 217 218 const gfx::Rect& world_at_start = window->bounds(); 219 gfx::Rect world_at_end = 220 GetLayerWorldBoundsAfterTransform(window->layer(), end_transform); 221 gfx::Rect union_in_window_space = 222 gfx::UnionRects(world_at_start, world_at_end); 223 224 // Calculate the top left and bottom right deltas to be added to the window 225 // bounds. 226 gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(), 227 world_at_start.y() - union_in_window_space.y()); 228 229 gfx::Vector2d bottom_right_delta( 230 union_in_window_space.x() + union_in_window_space.width() - 231 (world_at_start.x() + world_at_start.width()), 232 union_in_window_space.y() + union_in_window_space.height() - 233 (world_at_start.y() + world_at_start.height())); 234 235 DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 && 236 bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0); 237 238 animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta); 239 } 240 241 // Shows a window using an animation, animating its opacity from 0.f to 1.f, 242 // its visibility to true, and its transform from |start_transform| to 243 // |end_transform|. 244 void AnimateShowWindowCommon(aura::Window* window, 245 const gfx::Transform& start_transform, 246 const gfx::Transform& end_transform) { 247 window->layer()->set_delegate(window); 248 249 AugmentWindowSize(window, end_transform); 250 251 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 252 window->layer()->SetTransform(start_transform); 253 window->layer()->SetVisible(true); 254 255 { 256 // Property sets within this scope will be implicitly animated. 257 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); 258 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window); 259 if (duration.ToInternalValue() > 0) 260 settings.SetTransitionDuration(duration); 261 262 window->layer()->SetTransform(end_transform); 263 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 264 } 265 } 266 267 // Hides a window using an animation, animating its opacity from 1.f to 0.f, 268 // its visibility to false, and its transform to |end_transform|. 269 void AnimateHideWindowCommon(aura::Window* window, 270 const gfx::Transform& end_transform) { 271 AugmentWindowSize(window, end_transform); 272 window->layer()->set_delegate(NULL); 273 274 // Property sets within this scope will be implicitly animated. 275 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); 276 settings.AddObserver(new HidingWindowAnimationObserver(window)); 277 278 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window); 279 if (duration.ToInternalValue() > 0) 280 settings.SetTransitionDuration(duration); 281 282 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 283 window->layer()->SetTransform(end_transform); 284 window->layer()->SetVisible(false); 285 } 286 287 static gfx::Transform GetScaleForWindow(aura::Window* window) { 288 gfx::Rect bounds = window->bounds(); 289 gfx::Transform scale = gfx::GetScaleTransform( 290 gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(), 291 kWindowAnimation_TranslateFactor * bounds.height()), 292 kWindowAnimation_ScaleFactor); 293 return scale; 294 } 295 296 // Show/Hide windows using a shrink animation. 297 void AnimateShowWindow_Drop(aura::Window* window) { 298 AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform()); 299 } 300 301 void AnimateHideWindow_Drop(aura::Window* window) { 302 AnimateHideWindowCommon(window, GetScaleForWindow(window)); 303 } 304 305 // Show/Hide windows using a vertical Glenimation. 306 void AnimateShowWindow_Vertical(aura::Window* window) { 307 gfx::Transform transform; 308 transform.Translate(0, window->GetProperty( 309 kWindowVisibilityAnimationVerticalPositionKey)); 310 AnimateShowWindowCommon(window, transform, gfx::Transform()); 311 } 312 313 void AnimateHideWindow_Vertical(aura::Window* window) { 314 gfx::Transform transform; 315 transform.Translate(0, window->GetProperty( 316 kWindowVisibilityAnimationVerticalPositionKey)); 317 AnimateHideWindowCommon(window, transform); 318 } 319 320 // Show/Hide windows using a fade. 321 void AnimateShowWindow_Fade(aura::Window* window) { 322 AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform()); 323 } 324 325 void AnimateHideWindow_Fade(aura::Window* window) { 326 AnimateHideWindowCommon(window, gfx::Transform()); 327 } 328 329 ui::LayerAnimationElement* CreateGrowShrinkElement( 330 aura::Window* window, bool grow) { 331 scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale( 332 gfx::Point3F(kWindowAnimation_Bounce_Scale, 333 kWindowAnimation_Bounce_Scale, 334 1), 335 gfx::Point3F(1, 1, 1))); 336 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 337 new ui::InterpolatedTransformAboutPivot( 338 gfx::Point(window->bounds().width() * 0.5, 339 window->bounds().height() * 0.5), 340 scale.release())); 341 scale_about_pivot->SetReversed(grow); 342 scoped_ptr<ui::LayerAnimationElement> transition( 343 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 344 scale_about_pivot.release(), 345 base::TimeDelta::FromMilliseconds( 346 kWindowAnimation_Bounce_DurationMS * 347 kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100))); 348 transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); 349 return transition.release(); 350 } 351 352 void AnimateBounce(aura::Window* window) { 353 ui::ScopedLayerAnimationSettings scoped_settings( 354 window->layer()->GetAnimator()); 355 scoped_settings.SetPreemptionStrategy( 356 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); 357 window->layer()->set_delegate(window); 358 scoped_ptr<ui::LayerAnimationSequence> sequence( 359 new ui::LayerAnimationSequence); 360 sequence->AddElement(CreateGrowShrinkElement(window, true)); 361 ui::LayerAnimationElement::AnimatableProperties paused_properties; 362 paused_properties.insert(ui::LayerAnimationElement::BOUNDS); 363 sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( 364 paused_properties, 365 base::TimeDelta::FromMilliseconds( 366 kWindowAnimation_Bounce_DurationMS * 367 (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) / 368 100))); 369 sequence->AddElement(CreateGrowShrinkElement(window, false)); 370 window->layer()->GetAnimator()->StartAnimation(sequence.release()); 371 } 372 373 void AddLayerAnimationsForRotate(aura::Window* window, bool show) { 374 window->layer()->set_delegate(window); 375 if (show) 376 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 377 378 base::TimeDelta duration = base::TimeDelta::FromMilliseconds( 379 kWindowAnimation_Rotate_DurationMS); 380 381 if (!show) { 382 new HidingWindowAnimationObserver(window); 383 window->layer()->GetAnimator()->SchedulePauseForProperties( 384 duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, 385 ui::LayerAnimationElement::OPACITY, 386 -1); 387 } 388 scoped_ptr<ui::LayerAnimationElement> opacity( 389 ui::LayerAnimationElement::CreateOpacityElement( 390 show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity, 391 duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100)); 392 opacity->set_tween_type(gfx::Tween::EASE_IN_OUT); 393 window->layer()->GetAnimator()->ScheduleAnimation( 394 new ui::LayerAnimationSequence(opacity.release())); 395 396 float xcenter = window->bounds().width() * 0.5; 397 398 gfx::Transform transform; 399 transform.Translate(xcenter, 0); 400 transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth); 401 transform.Translate(-xcenter, 0); 402 scoped_ptr<ui::InterpolatedTransform> perspective( 403 new ui::InterpolatedConstantTransform(transform)); 404 405 scoped_ptr<ui::InterpolatedTransform> scale( 406 new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor)); 407 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 408 new ui::InterpolatedTransformAboutPivot( 409 gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY), 410 scale.release())); 411 412 scoped_ptr<ui::InterpolatedTransform> translation( 413 new ui::InterpolatedTranslation(gfx::Point(), gfx::Point( 414 0, kWindowAnimation_Rotate_TranslateY))); 415 416 scoped_ptr<ui::InterpolatedTransform> rotation( 417 new ui::InterpolatedAxisAngleRotation( 418 gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX)); 419 420 scale_about_pivot->SetChild(perspective.release()); 421 translation->SetChild(scale_about_pivot.release()); 422 rotation->SetChild(translation.release()); 423 rotation->SetReversed(show); 424 425 scoped_ptr<ui::LayerAnimationElement> transition( 426 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 427 rotation.release(), duration)); 428 429 window->layer()->GetAnimator()->ScheduleAnimation( 430 new ui::LayerAnimationSequence(transition.release())); 431 } 432 433 void AnimateShowWindow_Rotate(aura::Window* window) { 434 AddLayerAnimationsForRotate(window, true); 435 } 436 437 void AnimateHideWindow_Rotate(aura::Window* window) { 438 AddLayerAnimationsForRotate(window, false); 439 } 440 441 bool AnimateShowWindow(aura::Window* window) { 442 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 443 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 444 // Since hide animation may have changed opacity and transform, 445 // reset them to show the window. 446 window->layer()->set_delegate(window); 447 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 448 window->layer()->SetTransform(gfx::Transform()); 449 } 450 return false; 451 } 452 453 switch (GetWindowVisibilityAnimationType(window)) { 454 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 455 AnimateShowWindow_Drop(window); 456 return true; 457 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 458 AnimateShowWindow_Vertical(window); 459 return true; 460 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 461 AnimateShowWindow_Fade(window); 462 return true; 463 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 464 AnimateShowWindow_Rotate(window); 465 return true; 466 default: 467 return false; 468 } 469 } 470 471 bool AnimateHideWindow(aura::Window* window) { 472 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 473 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 474 // Since show animation may have changed opacity and transform, 475 // reset them, though the change should be hidden. 476 window->layer()->set_delegate(NULL); 477 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 478 window->layer()->SetTransform(gfx::Transform()); 479 } 480 return false; 481 } 482 483 switch (GetWindowVisibilityAnimationType(window)) { 484 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 485 AnimateHideWindow_Drop(window); 486 return true; 487 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 488 AnimateHideWindow_Vertical(window); 489 return true; 490 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 491 AnimateHideWindow_Fade(window); 492 return true; 493 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 494 AnimateHideWindow_Rotate(window); 495 return true; 496 default: 497 return false; 498 } 499 } 500 501 } // namespace 502 503 //////////////////////////////////////////////////////////////////////////////// 504 // External interface 505 506 void SetWindowVisibilityAnimationType(aura::Window* window, int type) { 507 window->SetProperty(kWindowVisibilityAnimationTypeKey, type); 508 } 509 510 int GetWindowVisibilityAnimationType(aura::Window* window) { 511 return window->GetProperty(kWindowVisibilityAnimationTypeKey); 512 } 513 514 void SetWindowVisibilityAnimationTransition( 515 aura::Window* window, 516 WindowVisibilityAnimationTransition transition) { 517 window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition); 518 } 519 520 bool HasWindowVisibilityAnimationTransition( 521 aura::Window* window, 522 WindowVisibilityAnimationTransition transition) { 523 WindowVisibilityAnimationTransition prop = window->GetProperty( 524 kWindowVisibilityAnimationTransitionKey); 525 return (prop & transition) != 0; 526 } 527 528 void SetWindowVisibilityAnimationDuration(aura::Window* window, 529 const TimeDelta& duration) { 530 window->SetProperty(kWindowVisibilityAnimationDurationKey, 531 static_cast<int>(duration.ToInternalValue())); 532 } 533 534 void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, 535 float position) { 536 window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); 537 } 538 539 ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( 540 aura::Window* window) { 541 return new HidingWindowAnimationObserver(window); 542 } 543 544 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { 545 if (WindowAnimationsDisabled(window)) 546 return false; 547 if (visible) 548 return AnimateShowWindow(window); 549 // Don't start hiding the window again if it's already being hidden. 550 return window->layer()->GetTargetOpacity() != 0.0f && 551 AnimateHideWindow(window); 552 } 553 554 bool AnimateWindow(aura::Window* window, WindowAnimationType type) { 555 switch (type) { 556 case WINDOW_ANIMATION_TYPE_BOUNCE: 557 AnimateBounce(window); 558 return true; 559 default: 560 NOTREACHED(); 561 return false; 562 } 563 } 564 565 bool WindowAnimationsDisabled(aura::Window* window) { 566 return (window && 567 window->GetProperty(aura::client::kAnimationsDisabledKey)) || 568 CommandLine::ForCurrentProcess()->HasSwitch( 569 switches::kWindowAnimationsDisabled); 570 } 571 572 } // namespace corewm 573 } // namespace views 574