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