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 "ash/wm/window_animations.h"
6 
7 #include <math.h>
8 #include <algorithm>
9 #include <utility>
10 #include <vector>
11 
12 #include "ash/home_screen/home_launcher_gesture_handler.h"
13 #include "ash/home_screen/home_screen_controller.h"
14 #include "ash/public/cpp/metrics_util.h"
15 #include "ash/public/cpp/window_animation_types.h"
16 #include "ash/shelf/shelf.h"
17 #include "ash/shell.h"
18 #include "ash/wm/pip/pip_positioner.h"
19 #include "ash/wm/window_util.h"
20 #include "ash/wm/workspace_controller.h"
21 #include "base/check.h"
22 #include "base/i18n/rtl.h"
23 #include "base/metrics/histogram_functions.h"
24 #include "base/metrics/histogram_macros.h"
25 #include "base/notreached.h"
26 #include "base/optional.h"
27 #include "base/stl_util.h"
28 #include "base/time/time.h"
29 #include "ui/aura/client/aura_constants.h"
30 #include "ui/aura/window.h"
31 #include "ui/aura/window_observer.h"
32 #include "ui/base/class_property.h"
33 #include "ui/compositor/animation_throughput_reporter.h"
34 #include "ui/compositor/compositor_observer.h"
35 #include "ui/compositor/layer.h"
36 #include "ui/compositor/layer_animation_observer.h"
37 #include "ui/compositor/layer_animation_sequence.h"
38 #include "ui/compositor/layer_animator.h"
39 #include "ui/compositor/layer_tree_owner.h"
40 #include "ui/compositor/scoped_layer_animation_settings.h"
41 #include "ui/display/display.h"
42 #include "ui/display/screen.h"
43 #include "ui/gfx/interpolated_transform.h"
44 #include "ui/gfx/transform.h"
45 #include "ui/wm/core/coordinate_conversion.h"
46 #include "ui/wm/core/window_util.h"
47 
48 namespace ash {
49 namespace {
50 
51 const int kLayerAnimationsForMinimizeDurationMS = 200;
52 
53 // Amount of time for the cross fade animation.
54 constexpr base::TimeDelta kCrossFadeDuration =
55     base::TimeDelta::FromMilliseconds(200);
56 
57 constexpr base::TimeDelta kCrossFadeMaxDuration =
58     base::TimeDelta::FromMilliseconds(400);
59 
60 // Durations for the brightness/grayscale fade animation, in milliseconds.
61 const int kBrightnessGrayscaleFadeDurationMs = 1000;
62 
63 // Duration for fade in animation, in milliseconds.
64 const int kFadeInAnimationMs = 200;
65 
66 // Brightness/grayscale values for hide/show window animations.
67 const float kWindowAnimation_HideBrightnessGrayscale = 1.f;
68 const float kWindowAnimation_ShowBrightnessGrayscale = 0.f;
69 
70 const float kWindowAnimation_HideOpacity = 0.f;
71 const float kWindowAnimation_ShowOpacity = 1.f;
72 
73 // Duration for gfx::Tween::ZERO animation of showing window.
74 constexpr base::TimeDelta kZeroAnimationMs =
75     base::TimeDelta::FromMilliseconds(300);
76 
77 constexpr char kCrossFadeSmoothness[] =
78     "Ash.Window.AnimationSmoothness.CrossFade";
79 
GetCrossFadeDuration(aura::Window * window,const gfx::RectF & old_bounds,const gfx::Rect & new_bounds)80 base::TimeDelta GetCrossFadeDuration(aura::Window* window,
81                                      const gfx::RectF& old_bounds,
82                                      const gfx::Rect& new_bounds) {
83   if (::wm::WindowAnimationsDisabled(window))
84     return base::TimeDelta();
85 
86   int old_area = static_cast<int>(old_bounds.width() * old_bounds.height());
87   int new_area = new_bounds.width() * new_bounds.height();
88   int max_area = std::max(old_area, new_area);
89   // Avoid divide by zero.
90   if (max_area == 0)
91     return kCrossFadeDuration;
92 
93   int delta_area = std::abs(old_area - new_area);
94   // If the area didn't change, the animation is instantaneous.
95   if (delta_area == 0)
96     return kCrossFadeDuration;
97 
98   float factor = static_cast<float>(delta_area) / static_cast<float>(max_area);
99   const auto kRange = kCrossFadeMaxDuration - kCrossFadeDuration;
100   return kCrossFadeDuration + factor * kRange;
101 }
102 
103 // Observer for a window cross-fade animation. If either the window closes or
104 // the layer's animation completes, it deletes the layer and removes itself as
105 // an observer.
106 class CrossFadeObserver : public aura::WindowObserver,
107                           public ui::ImplicitAnimationObserver {
108  public:
109   // Observes |window| for destruction, but does not take ownership.
110   // Takes ownership of |layer_owner| and its child layers.
CrossFadeObserver(aura::Window * window,std::unique_ptr<ui::LayerTreeOwner> layer_owner,base::Optional<std::string> histogram_name)111   CrossFadeObserver(aura::Window* window,
112                     std::unique_ptr<ui::LayerTreeOwner> layer_owner,
113                     base::Optional<std::string> histogram_name)
114       : window_(window),
115         layer_(window->layer()),
116         layer_owner_(std::move(layer_owner)) {
117     window_->AddObserver(this);
118 
119     smoothness_tracker_ =
120         layer_->GetCompositor()->RequestNewThroughputTracker();
121     smoothness_tracker_->Start(metrics_util::ForSmoothness(base::BindRepeating(
122         [](const base::Optional<std::string>& histogram_name, int smoothness) {
123           if (histogram_name) {
124             DCHECK(!histogram_name->empty());
125             base::UmaHistogramPercentageObsoleteDoNotUse(*histogram_name,
126                                                          smoothness);
127           } else {
128             UMA_HISTOGRAM_PERCENTAGE(kCrossFadeSmoothness, smoothness);
129           }
130         },
131         std::move(histogram_name))));
132   }
133   CrossFadeObserver(const CrossFadeObserver&) = delete;
134   CrossFadeObserver& operator=(const CrossFadeObserver&) = delete;
~CrossFadeObserver()135   ~CrossFadeObserver() override {
136     smoothness_tracker_->Stop();
137     smoothness_tracker_.reset();
138 
139     // Stop the old animator to trigger aborts or ends on any observers it may
140     // have.
141     layer_owner_->root()->GetAnimator()->StopAnimating();
142 
143     window_->RemoveObserver(this);
144     window_ = nullptr;
145     layer_ = nullptr;
146   }
147 
148   // aura::WindowObserver:
OnWindowDestroying(aura::Window * window)149   void OnWindowDestroying(aura::Window* window) override { StopAnimating(); }
OnWindowRemovingFromRootWindow(aura::Window * window,aura::Window * new_root)150   void OnWindowRemovingFromRootWindow(aura::Window* window,
151                                       aura::Window* new_root) override {
152     StopAnimating();
153   }
OnWindowLayerRecreated(aura::Window * window)154   void OnWindowLayerRecreated(aura::Window* window) override {
155     // If the window layer is recreated. |layer_| will hold the LayerAnimator we
156     // were originally observing. Layer recreation is usually done when doing
157     // another window animation, so stop this current one and trigger
158     // OnImplicitAnimationsCompleted to delete ourselves.
159     layer_->GetAnimator()->StopAnimating();
160   }
161 
162   // ui::ImplicitAnimationObserver:
OnImplicitAnimationsCompleted()163   void OnImplicitAnimationsCompleted() override { delete this; }
164 
165  protected:
StopAnimating()166   void StopAnimating() {
167     // Trigger OnImplicitAnimationsCompleted() to be called and deletes us. If
168     // no animation is running then do the deletion ourselves.
169     DCHECK(window_);
170     window_->layer()->GetAnimator()->StopAnimating();
171   }
172 
173   // The window and the associated layer this observer is watching. The window
174   // layer may be recreated during the course of the animation so |layer_| will
175   // be different |window_->layer()| after construction.
176   aura::Window* window_;
177   ui::Layer* layer_;
178 
179   std::unique_ptr<ui::LayerTreeOwner> layer_owner_;
180 
181   base::Optional<ui::ThroughputTracker> smoothness_tracker_;
182 };
183 
184 // A version of CrossFadeObserver which updates its transform to match the
185 // visible bounds of the window it is cross-fading. It is expected users of this
186 // will not perform their own transform animation on the passed LayerTreeOwner.
187 class CrossFadeUpdateTransformObserver
188     : public CrossFadeObserver,
189       public ui::CompositorAnimationObserver {
190  public:
CrossFadeUpdateTransformObserver(aura::Window * window,std::unique_ptr<ui::LayerTreeOwner> layer_owner,base::Optional<std::string> histogram_name)191   CrossFadeUpdateTransformObserver(
192       aura::Window* window,
193       std::unique_ptr<ui::LayerTreeOwner> layer_owner,
194       base::Optional<std::string> histogram_name)
195       : CrossFadeObserver(window, std::move(layer_owner), histogram_name) {
196     compositor_ = window->layer()->GetCompositor();
197     compositor_->AddAnimationObserver(this);
198   }
199   CrossFadeUpdateTransformObserver(const CrossFadeUpdateTransformObserver&) =
200       delete;
201   CrossFadeUpdateTransformObserver& operator=(
202       const CrossFadeUpdateTransformObserver&) = delete;
~CrossFadeUpdateTransformObserver()203   ~CrossFadeUpdateTransformObserver() override {
204     compositor_->RemoveAnimationObserver(this);
205   }
206 
207   // CrossFadeObserver:
OnLayerAnimationStarted(ui::LayerAnimationSequence * sequence)208   void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override {
209     DCHECK(!layer_owner_->root()->GetAnimator()->IsAnimatingProperty(
210         ui::LayerAnimationElement::TRANSFORM));
211     CrossFadeObserver::OnLayerAnimationStarted(sequence);
212   }
213 
214   // ui::CompositorAnimationObserver:
OnAnimationStep(base::TimeTicks timestamp)215   void OnAnimationStep(base::TimeTicks timestamp) override {
216     // If these get shut down or destroyed we should delete ourselves.
217     DCHECK(compositor_);
218     DCHECK(window_);
219 
220     // Calculate the transform needed to place |layer_owner_| in the same bounds
221     // plus transform as |window_|.
222     gfx::RectF old_bounds(layer_owner_->root()->bounds());
223     gfx::RectF new_bounds(window_->bounds());
224     gfx::Transform new_transform = window_->transform();
225     DCHECK(new_transform.IsScaleOrTranslation());
226 
227     // Apply the transform on the bounds to get the location of |window_|.
228     // Transforms are calculated in a way where scale does not affect position,
229     // so use the same logic here.
230     gfx::RectF effective_bounds(new_bounds.size());
231     new_transform.TransformRect(&effective_bounds);
232     effective_bounds.set_x(effective_bounds.x() + new_bounds.x());
233     effective_bounds.set_y(effective_bounds.y() + new_bounds.y());
234 
235     const gfx::Transform old_transform =
236         gfx::TransformBetweenRects(old_bounds, effective_bounds);
237     layer_owner_->root()->SetTransform(old_transform);
238   }
239 
OnCompositingShuttingDown(ui::Compositor * compositor)240   void OnCompositingShuttingDown(ui::Compositor* compositor) override {
241     DCHECK_EQ(compositor_, compositor);
242     StopAnimating();
243   }
244 
245  private:
246   ui::Compositor* compositor_ = nullptr;
247 };
248 
249 // Internal implementation of a cross fade animation. If
250 // |animate_old_layer_transform| is true, both new and old layers will animate
251 // their opacities and transforms. Otherwise, the old layer will on animate its
252 // opacity; its transforms will be updated via an observer.
CrossFadeAnimationInternal(aura::Window * window,std::unique_ptr<ui::LayerTreeOwner> old_layer_owner,bool animate_old_layer_transform,base::Optional<base::TimeDelta> duration,base::Optional<gfx::Tween::Type> tween_type,base::Optional<std::string> histogram_name)253 void CrossFadeAnimationInternal(
254     aura::Window* window,
255     std::unique_ptr<ui::LayerTreeOwner> old_layer_owner,
256     bool animate_old_layer_transform,
257     base::Optional<base::TimeDelta> duration,
258     base::Optional<gfx::Tween::Type> tween_type,
259     base::Optional<std::string> histogram_name) {
260   ui::Layer* old_layer = old_layer_owner->root();
261   ui::Layer* new_layer = window->layer();
262 
263   DCHECK(old_layer);
264   const gfx::Rect old_bounds(old_layer_owner->root()->bounds());
265 
266   gfx::RectF old_transformed_bounds(old_bounds);
267   gfx::Transform old_transform(old_layer_owner->root()->transform());
268   gfx::Transform old_transform_in_root;
269   old_transform_in_root.Translate(old_bounds.x(), old_bounds.y());
270   old_transform_in_root.PreconcatTransform(old_transform);
271   old_transform_in_root.Translate(-old_bounds.x(), -old_bounds.y());
272   old_transform_in_root.TransformRect(&old_transformed_bounds);
273   const gfx::Rect new_bounds(window->bounds());
274   const bool old_on_top = (old_bounds.width() > new_bounds.width());
275 
276   // Ensure the higher-resolution layer is on top.
277   if (old_on_top)
278     old_layer->parent()->StackBelow(new_layer, old_layer);
279   else
280     old_layer->parent()->StackAbove(new_layer, old_layer);
281 
282   // Shorten the animation if there's not much visual movement.
283   const base::TimeDelta animation_duration = duration.value_or(
284       GetCrossFadeDuration(window, old_transformed_bounds, new_bounds));
285   const gfx::Tween::Type animation_tween_type =
286       tween_type.value_or(gfx::Tween::EASE_OUT);
287 
288   // Scale up the old layer while translating to new position.
289   {
290     ui::Layer* old_layer = old_layer_owner->root();
291     old_layer->GetAnimator()->StopAnimating();
292     old_layer->SetTransform(old_transform);
293     ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator());
294     settings.SetTransitionDuration(animation_duration);
295     settings.SetTweenType(animation_tween_type);
296     settings.DeferPaint();
297 
298     if (old_on_top) {
299       // Only caching render surface when there is an opacity animation and
300       // multiple layers.
301       if (!old_layer->children().empty())
302         settings.CacheRenderSurface();
303       // The old layer is on top, and should fade out. The new layer below will
304       // stay opaque to block the desktop.
305       old_layer->SetOpacity(kWindowAnimation_HideOpacity);
306     } else if (!animate_old_layer_transform) {
307       // If |animate_old_layer_transform| and |old_on_top| are both false, then
308       // the old layer will have no animations and the observer will delete
309       // itself (and the old layer) right away. To make sure the old layer stays
310       // behind the new layer with opacity 1.f for the duration of the
311       // animation, change the tween to zero.
312       settings.SetTweenType(gfx::Tween::ZERO);
313       old_layer->SetOpacity(kWindowAnimation_HideOpacity);
314     }
315 
316     if (animate_old_layer_transform) {
317       gfx::Transform out_transform;
318       float scale_x =
319           new_bounds.width() / static_cast<float>(old_bounds.width());
320       float scale_y =
321           new_bounds.height() / static_cast<float>(old_bounds.height());
322       out_transform.Translate(new_bounds.x() - old_bounds.x(),
323                               new_bounds.y() - old_bounds.y());
324       out_transform.Scale(scale_x, scale_y);
325       old_layer->SetTransform(out_transform);
326     }
327     // In tests |old_layer| is deleted here, as animations have zero duration.
328     old_layer = nullptr;
329   }
330 
331   // Set the new layer's current transform, such that the user sees a scaled
332   // version of the window with the original bounds at the original position.
333   gfx::Transform in_transform;
334   const float scale_x =
335       old_transformed_bounds.width() / static_cast<float>(new_bounds.width());
336   const float scale_y =
337       old_transformed_bounds.height() / static_cast<float>(new_bounds.height());
338   in_transform.Translate(old_transformed_bounds.x() - new_bounds.x(),
339                          old_transformed_bounds.y() - new_bounds.y());
340   in_transform.Scale(scale_x, scale_y);
341   new_layer->SetTransform(in_transform);
342   if (!old_on_top) {
343     // The new layer is on top and should fade in.  The old layer below will
344     // stay opaque and block the desktop.
345     new_layer->SetOpacity(kWindowAnimation_HideOpacity);
346   }
347   {
348     // Animation observer owns the old layer and deletes itself. It should be
349     // attached to the new layer so that if the new layer animation gets
350     // aborted, we can delete the old layer.
351     CrossFadeObserver* observer =
352         animate_old_layer_transform
353             ? new CrossFadeObserver(window, std::move(old_layer_owner),
354                                     histogram_name)
355             : new CrossFadeUpdateTransformObserver(
356                   window, std::move(old_layer_owner), histogram_name);
357 
358     // Animate the new layer to the identity transform, so the window goes to
359     // its newly set bounds.
360     ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator());
361     settings.AddObserver(observer);
362     settings.SetTransitionDuration(animation_duration);
363     settings.SetTweenType(animation_tween_type);
364     settings.DeferPaint();
365     if (!old_on_top) {
366       // Only caching render surface when there is an opacity animation and
367       // multiple layers.
368       if (!new_layer->children().empty())
369         settings.CacheRenderSurface();
370       // New layer is on top, fade it in.
371       new_layer->SetOpacity(kWindowAnimation_ShowOpacity);
372     }
373     new_layer->SetTransform(gfx::Transform());
374   }
375 }
376 
377 }  // namespace
378 
SetTransformForScaleAnimation(ui::Layer * layer,LayerScaleAnimationDirection type)379 void SetTransformForScaleAnimation(ui::Layer* layer,
380                                    LayerScaleAnimationDirection type) {
381   // Scales for windows above and below the current workspace.
382   constexpr float kLayerScaleAboveSize = 1.1f;
383   constexpr float kLayerScaleBelowSize = .9f;
384 
385   const float scale = type == LAYER_SCALE_ANIMATION_ABOVE
386                           ? kLayerScaleAboveSize
387                           : kLayerScaleBelowSize;
388   gfx::Transform transform;
389   transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2,
390                       -layer->bounds().height() * (scale - 1.0f) / 2);
391   transform.Scale(scale, scale);
392   layer->SetTransform(transform);
393 }
394 
AddLayerAnimationsForMinimize(aura::Window * window,bool show)395 void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
396   // Recalculate the transform at restore time since the launcher item may have
397   // moved while the window was minimized.
398   gfx::Rect bounds = window->bounds();
399   gfx::Rect target_bounds = GetMinimizeAnimationTargetBoundsInScreen(window);
400   ::wm::ConvertRectFromScreen(window->parent(), &target_bounds);
401 
402   float scale_x = static_cast<float>(target_bounds.width()) / bounds.width();
403   float scale_y = static_cast<float>(target_bounds.height()) / bounds.height();
404 
405   std::unique_ptr<ui::InterpolatedTransform> scale =
406       std::make_unique<ui::InterpolatedScale>(
407           gfx::Point3F(1, 1, 1), gfx::Point3F(scale_x, scale_y, 1));
408 
409   std::unique_ptr<ui::InterpolatedTransform> translation =
410       std::make_unique<ui::InterpolatedTranslation>(
411           gfx::PointF(), gfx::PointF(target_bounds.x() - bounds.x(),
412                                      target_bounds.y() - bounds.y()));
413 
414   scale->SetChild(std::move(translation));
415   scale->SetReversed(show);
416 
417   base::TimeDelta duration =
418       window->layer()->GetAnimator()->GetTransitionDuration();
419 
420   std::unique_ptr<ui::LayerAnimationElement> transition =
421       ui::LayerAnimationElement::CreateInterpolatedTransformElement(
422           std::move(scale), duration);
423 
424   transition->set_tween_type(show ? gfx::Tween::EASE_IN
425                                   : gfx::Tween::EASE_IN_OUT);
426 
427   window->layer()->GetAnimator()->ScheduleAnimation(
428       new ui::LayerAnimationSequence(std::move(transition)));
429 
430   // When hiding a window, turn off blending until the animation is 3 / 4 done
431   // to save bandwidth and reduce jank.
432   if (!show) {
433     window->layer()->GetAnimator()->SchedulePauseForProperties(
434         (duration * 3) / 4, ui::LayerAnimationElement::OPACITY);
435   }
436 
437   // Fade in and out quickly when the window is small to reduce jank.
438   float opacity = show ? 1.0f : 0.0f;
439   window->layer()->GetAnimator()->ScheduleAnimation(
440       new ui::LayerAnimationSequence(
441           ui::LayerAnimationElement::CreateOpacityElement(opacity,
442                                                           duration / 4)));
443 
444   // Reset the transform to identity when the minimize animation is completed.
445   window->layer()->GetAnimator()->ScheduleAnimation(
446       new ui::LayerAnimationSequence(
447           ui::LayerAnimationElement::CreateTransformElement(
448               gfx::Transform(), base::TimeDelta())));
449 }
450 
AnimateShowWindow_Minimize(aura::Window * window)451 void AnimateShowWindow_Minimize(aura::Window* window) {
452   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
453   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
454   base::TimeDelta duration =
455       base::TimeDelta::FromMilliseconds(kLayerAnimationsForMinimizeDurationMS);
456   settings.SetTransitionDuration(duration);
457   AddLayerAnimationsForMinimize(window, true);
458 
459   // Now that the window has been restored, we need to clear its animation style
460   // to default so that normal animation applies.
461   ::wm::SetWindowVisibilityAnimationType(
462       window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
463 }
464 
AnimateHideWindow_Minimize(aura::Window * window)465 void AnimateHideWindow_Minimize(aura::Window* window) {
466   // Property sets within this scope will be implicitly animated.
467   ::wm::ScopedHidingAnimationSettings hiding_settings(window);
468   base::TimeDelta duration =
469       base::TimeDelta::FromMilliseconds(kLayerAnimationsForMinimizeDurationMS);
470   hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);
471   window->layer()->SetVisible(false);
472 
473   AddLayerAnimationsForMinimize(window, false);
474 }
475 
AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window * window,bool show)476 void AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window* window,
477                                                      bool show) {
478   float start_value, end_value;
479   if (show) {
480     start_value = kWindowAnimation_HideBrightnessGrayscale;
481     end_value = kWindowAnimation_ShowBrightnessGrayscale;
482   } else {
483     start_value = kWindowAnimation_ShowBrightnessGrayscale;
484     end_value = kWindowAnimation_HideBrightnessGrayscale;
485   }
486 
487   window->layer()->SetLayerBrightness(start_value);
488   window->layer()->SetLayerGrayscale(start_value);
489   if (show) {
490     window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
491     window->layer()->SetVisible(true);
492   }
493 
494   base::TimeDelta duration =
495       base::TimeDelta::FromMilliseconds(kBrightnessGrayscaleFadeDurationMs);
496 
497   if (show) {
498     ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
499     window->layer()->GetAnimator()->ScheduleTogether(
500         CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
501   } else {
502     ::wm::ScopedHidingAnimationSettings hiding_settings(window);
503     window->layer()->GetAnimator()->ScheduleTogether(
504         CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
505     window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
506     window->layer()->SetVisible(false);
507   }
508 }
509 
AnimateShowWindow_BrightnessGrayscale(aura::Window * window)510 void AnimateShowWindow_BrightnessGrayscale(aura::Window* window) {
511   AnimateShowHideWindowCommon_BrightnessGrayscale(window, true);
512 }
513 
514 // TODO(edcourtney): Consolidate with AnimateShowWindow_Fade in ui/wm/core.
AnimateShowWindow_FadeIn(aura::Window * window)515 void AnimateShowWindow_FadeIn(aura::Window* window) {
516   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
517   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
518   settings.SetTransitionDuration(
519       base::TimeDelta::FromMilliseconds(kFadeInAnimationMs));
520   window->layer()->SetVisible(true);
521   window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
522 }
523 
AnimateHideWindow_BrightnessGrayscale(aura::Window * window)524 void AnimateHideWindow_BrightnessGrayscale(aura::Window* window) {
525   AnimateShowHideWindowCommon_BrightnessGrayscale(window, false);
526 }
527 
AnimateHideWindow_SlideOut(aura::Window * window)528 void AnimateHideWindow_SlideOut(aura::Window* window) {
529   base::TimeDelta duration =
530       base::TimeDelta::FromMilliseconds(PipPositioner::kPipDismissTimeMs);
531 
532   ::wm::ScopedHidingAnimationSettings settings(window);
533   settings.layer_animation_settings()->SetTransitionDuration(duration);
534   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
535   window->layer()->SetVisible(false);
536 
537   gfx::Rect bounds = window->GetBoundsInScreen();
538   display::Display display =
539       display::Screen::GetScreen()->GetDisplayNearestWindow(window);
540   gfx::Rect dismissed_bounds =
541       PipPositioner::GetDismissedPosition(display, bounds);
542   ::wm::ConvertRectFromScreen(window->parent(), &dismissed_bounds);
543   window->layer()->SetBounds(dismissed_bounds);
544 }
545 
AnimateShowWindow_StepEnd(aura::Window * window)546 void AnimateShowWindow_StepEnd(aura::Window* window) {
547   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
548   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
549   settings.SetTransitionDuration(kZeroAnimationMs);
550   settings.SetTweenType(gfx::Tween::ZERO);
551   window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
552 }
553 
AnimateHideWindow_StepEnd(aura::Window * window)554 void AnimateHideWindow_StepEnd(aura::Window* window) {
555   ::wm::ScopedHidingAnimationSettings settings(window);
556   settings.layer_animation_settings()->SetTransitionDuration(kZeroAnimationMs);
557   settings.layer_animation_settings()->SetTweenType(gfx::Tween::ZERO);
558   window->layer()->SetVisible(false);
559 }
560 
AnimateShowWindow(aura::Window * window)561 bool AnimateShowWindow(aura::Window* window) {
562   if (!::wm::HasWindowVisibilityAnimationTransition(window,
563                                                     ::wm::ANIMATE_SHOW)) {
564     return false;
565   }
566 
567   switch (::wm::GetWindowVisibilityAnimationType(window)) {
568     case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
569       AnimateShowWindow_Minimize(window);
570       return true;
571     case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
572       AnimateShowWindow_BrightnessGrayscale(window);
573       return true;
574     case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE_IN_SLIDE_OUT:
575       AnimateShowWindow_FadeIn(window);
576       return true;
577     case WINDOW_VISIBILITY_ANIMATION_TYPE_STEP_END:
578       AnimateShowWindow_StepEnd(window);
579       return true;
580     default:
581       NOTREACHED();
582       return false;
583   }
584 }
585 
AnimateHideWindow(aura::Window * window)586 bool AnimateHideWindow(aura::Window* window) {
587   if (!::wm::HasWindowVisibilityAnimationTransition(window,
588                                                     ::wm::ANIMATE_HIDE)) {
589     return false;
590   }
591 
592   switch (::wm::GetWindowVisibilityAnimationType(window)) {
593     case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
594       AnimateHideWindow_Minimize(window);
595       return true;
596     case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
597       AnimateHideWindow_BrightnessGrayscale(window);
598       return true;
599     case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE_IN_SLIDE_OUT:
600       AnimateHideWindow_SlideOut(window);
601       return true;
602     case WINDOW_VISIBILITY_ANIMATION_TYPE_STEP_END:
603       AnimateHideWindow_StepEnd(window);
604       return true;
605     default:
606       NOTREACHED();
607       return false;
608   }
609 }
610 
CrossFadeAnimation(aura::Window * window,std::unique_ptr<ui::LayerTreeOwner> old_layer_owner)611 void CrossFadeAnimation(aura::Window* window,
612                         std::unique_ptr<ui::LayerTreeOwner> old_layer_owner) {
613   CrossFadeAnimationInternal(
614       window, std::move(old_layer_owner), /*animate_old_layer=*/true,
615       /*duration=*/base::nullopt, /*tween_type=*/base::nullopt,
616       /*histogram_name=*/base::nullopt);
617 }
618 
CrossFadeAnimationAnimateNewLayerOnly(aura::Window * window,const gfx::Rect & target_bounds,base::TimeDelta duration,gfx::Tween::Type tween_type,const std::string & histogram_name)619 void CrossFadeAnimationAnimateNewLayerOnly(aura::Window* window,
620                                            const gfx::Rect& target_bounds,
621                                            base::TimeDelta duration,
622                                            gfx::Tween::Type tween_type,
623                                            const std::string& histogram_name) {
624   std::unique_ptr<ui::LayerTreeOwner> old_layer_owner =
625       ::wm::RecreateLayers(window);
626   window->SetBounds(target_bounds);
627   CrossFadeAnimationInternal(window, std::move(old_layer_owner),
628                              /*animate_old_layer=*/false, duration, tween_type,
629                              histogram_name);
630 }
631 
AnimateOnChildWindowVisibilityChanged(aura::Window * window,bool visible)632 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
633   if (::wm::WindowAnimationsDisabled(window))
634     return false;
635 
636   // Attempt to run CoreWm supplied animation types.
637   if (::wm::AnimateOnChildWindowVisibilityChanged(window, visible))
638     return true;
639 
640   // Otherwise try to run an Ash-specific animation.
641   if (visible)
642     return AnimateShowWindow(window);
643   // Don't start hiding the window again if it's already being hidden.
644   return window->layer()->GetTargetOpacity() != 0.0f &&
645          AnimateHideWindow(window);
646 }
647 
648 std::vector<ui::LayerAnimationSequence*>
CreateBrightnessGrayscaleAnimationSequence(float target_value,base::TimeDelta duration)649 CreateBrightnessGrayscaleAnimationSequence(float target_value,
650                                            base::TimeDelta duration) {
651   gfx::Tween::Type animation_type = gfx::Tween::EASE_OUT;
652   std::unique_ptr<ui::LayerAnimationSequence> brightness_sequence =
653       std::make_unique<ui::LayerAnimationSequence>();
654   std::unique_ptr<ui::LayerAnimationSequence> grayscale_sequence =
655       std::make_unique<ui::LayerAnimationSequence>();
656 
657   std::unique_ptr<ui::LayerAnimationElement> brightness_element =
658       ui::LayerAnimationElement::CreateBrightnessElement(target_value,
659                                                          duration);
660   brightness_element->set_tween_type(animation_type);
661   brightness_sequence->AddElement(std::move(brightness_element));
662 
663   std::unique_ptr<ui::LayerAnimationElement> grayscale_element =
664       ui::LayerAnimationElement::CreateGrayscaleElement(target_value, duration);
665   grayscale_element->set_tween_type(animation_type);
666   grayscale_sequence->AddElement(std::move(grayscale_element));
667 
668   std::vector<ui::LayerAnimationSequence*> animations;
669   animations.push_back(brightness_sequence.release());
670   animations.push_back(grayscale_sequence.release());
671 
672   return animations;
673 }
674 
GetMinimizeAnimationTargetBoundsInScreen(aura::Window * window)675 gfx::Rect GetMinimizeAnimationTargetBoundsInScreen(aura::Window* window) {
676   Shelf* shelf = Shelf::ForWindow(window);
677   gfx::Rect item_rect = shelf->GetScreenBoundsOfItemIconForWindow(window);
678 
679   // The launcher item is visible and has an icon.
680   if (!item_rect.IsEmpty())
681     return item_rect;
682 
683   // If both the icon width and height are 0, then there is no icon in the
684   // launcher for |window|. If the launcher is auto hidden, one of the height or
685   // width will be 0 but the position in the launcher and the major dimension
686   // are still reported correctly and the window can be animated to the launcher
687   // item's light bar.
688   if (item_rect.width() != 0 || item_rect.height() != 0) {
689     if (shelf->GetVisibilityState() == SHELF_AUTO_HIDE) {
690       gfx::Rect shelf_bounds = shelf->GetWindow()->GetBoundsInScreen();
691       if (shelf->alignment() == ShelfAlignment::kLeft)
692         item_rect.set_x(shelf_bounds.right());
693       else if (shelf->alignment() == ShelfAlignment::kRight)
694         item_rect.set_x(shelf_bounds.x());
695       else
696         item_rect.set_y(shelf_bounds.y());
697       return item_rect;
698     }
699   }
700 
701   // Coming here, there is no visible icon of that shelf item and we zoom back
702   // to the location of the application launcher (which is fixed as first item
703   // of the shelf).
704   gfx::Rect work_area =
705       display::Screen::GetScreen()->GetDisplayNearestWindow(window).work_area();
706   int ltr_adjusted_x = base::i18n::IsRTL() ? work_area.right() : work_area.x();
707   switch (shelf->alignment()) {
708     case ShelfAlignment::kBottom:
709     case ShelfAlignment::kBottomLocked:
710       return gfx::Rect(ltr_adjusted_x, work_area.bottom(), 0, 0);
711     case ShelfAlignment::kLeft:
712       return gfx::Rect(work_area.x(), work_area.y(), 0, 0);
713     case ShelfAlignment::kRight:
714       return gfx::Rect(work_area.right(), work_area.y(), 0, 0);
715   }
716   NOTREACHED();
717   return gfx::Rect();
718 }
719 
720 }  // namespace ash
721