123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/wm/window_animations.h"
- #include <math.h>
- #include <algorithm>
- #include <utility>
- #include <vector>
- #include "ash/public/cpp/metrics_util.h"
- #include "ash/public/cpp/window_animation_types.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/wm/pip/pip_positioner.h"
- #include "ash/wm/window_util.h"
- #include "ash/wm/workspace_controller.h"
- #include "base/bind.h"
- #include "base/check.h"
- #include "base/i18n/rtl.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/notreached.h"
- #include "base/time/time.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_observer.h"
- #include "ui/base/class_property.h"
- #include "ui/compositor/animation_throughput_reporter.h"
- #include "ui/compositor/compositor.h"
- #include "ui/compositor/compositor_observer.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_animation_observer.h"
- #include "ui/compositor/layer_animation_sequence.h"
- #include "ui/compositor/layer_animator.h"
- #include "ui/compositor/layer_tree_owner.h"
- #include "ui/compositor/scoped_layer_animation_settings.h"
- #include "ui/display/display.h"
- #include "ui/display/screen.h"
- #include "ui/gfx/geometry/transform.h"
- #include "ui/gfx/interpolated_transform.h"
- #include "ui/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- const int kLayerAnimationsForMinimizeDurationMS = 200;
- // Amount of time for the cross fade animation.
- constexpr base::TimeDelta kCrossFadeDuration = base::Milliseconds(200);
- constexpr base::TimeDelta kCrossFadeMaxDuration = base::Milliseconds(400);
- // Durations for the brightness/grayscale fade animation, in milliseconds.
- const int kBrightnessGrayscaleFadeDurationMs = 1000;
- // Duration for fade in animation, in milliseconds.
- const int kFadeInAnimationMs = 200;
- // Brightness/grayscale values for hide/show window animations.
- const float kWindowAnimation_HideBrightnessGrayscale = 1.f;
- const float kWindowAnimation_ShowBrightnessGrayscale = 0.f;
- const float kWindowAnimation_HideOpacity = 0.f;
- const float kWindowAnimation_ShowOpacity = 1.f;
- // Duration for gfx::Tween::ZERO animation of showing window.
- constexpr base::TimeDelta kZeroAnimationMs = base::Milliseconds(300);
- constexpr char kCrossFadeSmoothness[] =
- "Ash.Window.AnimationSmoothness.CrossFade";
- base::TimeDelta GetCrossFadeDuration(aura::Window* window,
- const gfx::RectF& old_bounds,
- const gfx::Rect& new_bounds) {
- if (::wm::WindowAnimationsDisabled(window))
- return base::TimeDelta();
- int old_area = static_cast<int>(old_bounds.width() * old_bounds.height());
- int new_area = new_bounds.width() * new_bounds.height();
- int max_area = std::max(old_area, new_area);
- // Avoid divide by zero.
- if (max_area == 0)
- return kCrossFadeDuration;
- int delta_area = std::abs(old_area - new_area);
- // If the area didn't change, the animation is instantaneous.
- if (delta_area == 0)
- return kCrossFadeDuration;
- float factor = static_cast<float>(delta_area) / static_cast<float>(max_area);
- const auto kRange = kCrossFadeMaxDuration - kCrossFadeDuration;
- return kCrossFadeDuration + factor * kRange;
- }
- // Observer for a window cross-fade animation. If either the window closes or
- // the layer's animation completes, it deletes the layer and removes itself as
- // an observer.
- class CrossFadeObserver : public aura::WindowObserver,
- public ui::ImplicitAnimationObserver {
- public:
- // Observes |window| for destruction, but does not take ownership.
- // Takes ownership of |layer_owner| and its child layers.
- CrossFadeObserver(aura::Window* window,
- std::unique_ptr<ui::LayerTreeOwner> layer_owner,
- absl::optional<std::string> histogram_name)
- : window_(window),
- layer_(window->layer()),
- layer_owner_(std::move(layer_owner)) {
- window_->AddObserver(this);
- smoothness_tracker_ =
- layer_->GetCompositor()->RequestNewThroughputTracker();
- smoothness_tracker_->Start(metrics_util::ForSmoothness(base::BindRepeating(
- [](const absl::optional<std::string>& histogram_name, int smoothness) {
- if (histogram_name) {
- DCHECK(!histogram_name->empty());
- base::UmaHistogramPercentage(*histogram_name, smoothness);
- } else {
- UMA_HISTOGRAM_PERCENTAGE(kCrossFadeSmoothness, smoothness);
- }
- },
- std::move(histogram_name))));
- }
- CrossFadeObserver(const CrossFadeObserver&) = delete;
- CrossFadeObserver& operator=(const CrossFadeObserver&) = delete;
- ~CrossFadeObserver() override {
- smoothness_tracker_->Stop();
- smoothness_tracker_.reset();
- // Stop the old animator to trigger aborts or ends on any observers it may
- // have.
- layer_owner_->root()->GetAnimator()->StopAnimating();
- window_->RemoveObserver(this);
- window_ = nullptr;
- layer_ = nullptr;
- }
- // aura::WindowObserver:
- void OnWindowDestroying(aura::Window* window) override { StopAnimating(); }
- void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) override {
- StopAnimating();
- }
- void OnWindowLayerRecreated(aura::Window* window) override {
- // If the window layer is recreated. |layer_| will hold the LayerAnimator we
- // were originally observing. Layer recreation is usually done when doing
- // another window animation, so stop this current one and trigger
- // OnImplicitAnimationsCompleted to delete ourselves.
- layer_->GetAnimator()->StopAnimating();
- }
- // ui::ImplicitAnimationObserver:
- void OnImplicitAnimationsCompleted() override { delete this; }
- protected:
- void StopAnimating() {
- // Trigger OnImplicitAnimationsCompleted() to be called and deletes us. If
- // no animation is running then do the deletion ourselves.
- DCHECK(window_);
- window_->layer()->GetAnimator()->StopAnimating();
- }
- // The window and the associated layer this observer is watching. The window
- // layer may be recreated during the course of the animation so |layer_| will
- // be different |window_->layer()| after construction.
- aura::Window* window_;
- ui::Layer* layer_;
- std::unique_ptr<ui::LayerTreeOwner> layer_owner_;
- absl::optional<ui::ThroughputTracker> smoothness_tracker_;
- };
- // A version of CrossFadeObserver which updates its transform to match the
- // visible bounds of the window it is cross-fading. It is expected users of this
- // will not perform their own transform animation on the passed LayerTreeOwner.
- class CrossFadeUpdateTransformObserver
- : public CrossFadeObserver,
- public ui::CompositorAnimationObserver {
- public:
- CrossFadeUpdateTransformObserver(
- aura::Window* window,
- std::unique_ptr<ui::LayerTreeOwner> layer_owner,
- absl::optional<std::string> histogram_name)
- : CrossFadeObserver(window, std::move(layer_owner), histogram_name) {
- compositor_ = window->layer()->GetCompositor();
- compositor_->AddAnimationObserver(this);
- }
- CrossFadeUpdateTransformObserver(const CrossFadeUpdateTransformObserver&) =
- delete;
- CrossFadeUpdateTransformObserver& operator=(
- const CrossFadeUpdateTransformObserver&) = delete;
- ~CrossFadeUpdateTransformObserver() override {
- compositor_->RemoveAnimationObserver(this);
- }
- // CrossFadeObserver:
- void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override {
- DCHECK(!layer_owner_->root()->GetAnimator()->IsAnimatingProperty(
- ui::LayerAnimationElement::TRANSFORM));
- CrossFadeObserver::OnLayerAnimationStarted(sequence);
- }
- // ui::CompositorAnimationObserver:
- void OnAnimationStep(base::TimeTicks timestamp) override {
- // If these get shut down or destroyed we should delete ourselves.
- DCHECK(compositor_);
- DCHECK(window_);
- // Calculate the transform needed to place |layer_owner_| in the same bounds
- // plus transform as |window_|.
- gfx::RectF old_bounds(layer_owner_->root()->bounds());
- gfx::RectF new_bounds(window_->bounds());
- gfx::Transform new_transform = window_->transform();
- DCHECK(new_transform.IsScaleOrTranslation());
- // Apply the transform on the bounds to get the location of |window_|.
- // Transforms are calculated in a way where scale does not affect position,
- // so use the same logic here.
- gfx::RectF effective_bounds(new_bounds.size());
- new_transform.TransformRect(&effective_bounds);
- effective_bounds.set_x(effective_bounds.x() + new_bounds.x());
- effective_bounds.set_y(effective_bounds.y() + new_bounds.y());
- const gfx::Transform old_transform =
- gfx::TransformBetweenRects(old_bounds, effective_bounds);
- layer_owner_->root()->SetTransform(old_transform);
- }
- void OnCompositingShuttingDown(ui::Compositor* compositor) override {
- DCHECK_EQ(compositor_, compositor);
- StopAnimating();
- }
- private:
- ui::Compositor* compositor_ = nullptr;
- };
- // Internal implementation of a cross fade animation. If
- // |animate_old_layer_transform| is true, both new and old layers will animate
- // their opacities and transforms. Otherwise, the old layer will on animate its
- // opacity; its transforms will be updated via an observer.
- void CrossFadeAnimationInternal(
- aura::Window* window,
- std::unique_ptr<ui::LayerTreeOwner> old_layer_owner,
- bool animate_old_layer_transform,
- absl::optional<base::TimeDelta> duration,
- absl::optional<gfx::Tween::Type> tween_type,
- absl::optional<std::string> histogram_name) {
- ui::Layer* old_layer = old_layer_owner->root();
- ui::Layer* new_layer = window->layer();
- DCHECK(old_layer);
- const gfx::Rect old_bounds(old_layer_owner->root()->bounds());
- gfx::RectF old_transformed_bounds(old_bounds);
- gfx::Transform old_transform(old_layer_owner->root()->transform());
- gfx::Transform old_transform_in_root;
- old_transform_in_root.Translate(old_bounds.x(), old_bounds.y());
- old_transform_in_root.PreconcatTransform(old_transform);
- old_transform_in_root.Translate(-old_bounds.x(), -old_bounds.y());
- old_transform_in_root.TransformRect(&old_transformed_bounds);
- const gfx::Rect new_bounds(window->bounds());
- const bool old_on_top = (old_bounds.width() > new_bounds.width());
- // Ensure the higher-resolution layer is on top.
- if (old_on_top)
- old_layer->parent()->StackBelow(new_layer, old_layer);
- else
- old_layer->parent()->StackAbove(new_layer, old_layer);
- // Shorten the animation if there's not much visual movement.
- const base::TimeDelta animation_duration = duration.value_or(
- GetCrossFadeDuration(window, old_transformed_bounds, new_bounds));
- const gfx::Tween::Type animation_tween_type =
- tween_type.value_or(gfx::Tween::EASE_OUT);
- // Scale up the old layer while translating to new position.
- {
- ui::Layer* old_layer = old_layer_owner->root();
- old_layer->GetAnimator()->StopAnimating();
- // If Overview exit animation is in the sequence, stopping animation may
- // trigger `OverviewController::OnEndingAnimationComplete` which may finally
- // start the frame animation.
- // 'FrameHeader::FrameAnimatorView::StartAnimation' recreates the window
- // layer such that the `new_layer` is no longer the window's current layer.
- // Therefore, we should update the `new_layer`. Refer to
- // https://crbug.com/1313977.
- // TODO(zxdan): find a way to change the window state after exiting Overview
- // or avoid frame animation when setting bounds.
- new_layer = window->layer();
- old_layer->SetTransform(old_transform);
- ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator());
- settings.SetTransitionDuration(animation_duration);
- settings.SetTweenType(animation_tween_type);
- settings.DeferPaint();
- if (old_on_top) {
- // Only caching render surface when there is an opacity animation and
- // multiple layers.
- if (!old_layer->children().empty())
- settings.CacheRenderSurface();
- // The old layer is on top, and should fade out. The new layer below will
- // stay opaque to block the desktop.
- old_layer->SetOpacity(kWindowAnimation_HideOpacity);
- } else if (!animate_old_layer_transform) {
- // If |animate_old_layer_transform| and |old_on_top| are both false, then
- // the old layer will have no animations and the observer will delete
- // itself (and the old layer) right away. To make sure the old layer stays
- // behind the new layer with opacity 1.f for the duration of the
- // animation, change the tween to zero.
- settings.SetTweenType(gfx::Tween::ZERO);
- old_layer->SetOpacity(kWindowAnimation_HideOpacity);
- }
- if (animate_old_layer_transform) {
- gfx::Transform out_transform;
- float scale_x =
- new_bounds.width() / static_cast<float>(old_bounds.width());
- float scale_y =
- new_bounds.height() / static_cast<float>(old_bounds.height());
- out_transform.Translate(new_bounds.x() - old_bounds.x(),
- new_bounds.y() - old_bounds.y());
- out_transform.Scale(scale_x, scale_y);
- old_layer->SetTransform(out_transform);
- }
- // In tests |old_layer| is deleted here, as animations have zero duration.
- old_layer = nullptr;
- }
- // Set the new layer's current transform, such that the user sees a scaled
- // version of the window with the original bounds at the original position.
- gfx::Transform in_transform;
- const float scale_x =
- old_transformed_bounds.width() / static_cast<float>(new_bounds.width());
- const float scale_y =
- old_transformed_bounds.height() / static_cast<float>(new_bounds.height());
- in_transform.Translate(old_transformed_bounds.x() - new_bounds.x(),
- old_transformed_bounds.y() - new_bounds.y());
- in_transform.Scale(scale_x, scale_y);
- new_layer->SetTransform(in_transform);
- if (!old_on_top) {
- // The new layer is on top and should fade in. The old layer below will
- // stay opaque and block the desktop.
- new_layer->SetOpacity(kWindowAnimation_HideOpacity);
- }
- {
- // Animation observer owns the old layer and deletes itself. It should be
- // attached to the new layer so that if the new layer animation gets
- // aborted, we can delete the old layer.
- CrossFadeObserver* observer =
- animate_old_layer_transform
- ? new CrossFadeObserver(window, std::move(old_layer_owner),
- histogram_name)
- : new CrossFadeUpdateTransformObserver(
- window, std::move(old_layer_owner), histogram_name);
- // Animate the new layer to the identity transform, so the window goes to
- // its newly set bounds.
- ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator());
- settings.AddObserver(observer);
- settings.SetTransitionDuration(animation_duration);
- settings.SetTweenType(animation_tween_type);
- settings.DeferPaint();
- if (!old_on_top) {
- // Only caching render surface when there is an opacity animation and
- // multiple layers.
- if (!new_layer->children().empty())
- settings.CacheRenderSurface();
- // New layer is on top, fade it in.
- new_layer->SetOpacity(kWindowAnimation_ShowOpacity);
- }
- new_layer->SetTransform(gfx::Transform());
- }
- }
- } // namespace
- void SetTransformForScaleAnimation(ui::Layer* layer,
- LayerScaleAnimationDirection type) {
- // Scales for windows above and below the current workspace.
- constexpr float kLayerScaleAboveSize = 1.1f;
- constexpr float kLayerScaleBelowSize = .9f;
- const float scale = type == LAYER_SCALE_ANIMATION_ABOVE
- ? kLayerScaleAboveSize
- : kLayerScaleBelowSize;
- gfx::Transform transform;
- transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2,
- -layer->bounds().height() * (scale - 1.0f) / 2);
- transform.Scale(scale, scale);
- layer->SetTransform(transform);
- }
- void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
- // Recalculate the transform at restore time since the launcher item may have
- // moved while the window was minimized.
- gfx::Rect bounds = window->bounds();
- gfx::Rect target_bounds = GetMinimizeAnimationTargetBoundsInScreen(window);
- ::wm::ConvertRectFromScreen(window->parent(), &target_bounds);
- float scale_x = static_cast<float>(target_bounds.width()) / bounds.width();
- float scale_y = static_cast<float>(target_bounds.height()) / bounds.height();
- std::unique_ptr<ui::InterpolatedTransform> scale =
- std::make_unique<ui::InterpolatedScale>(
- gfx::Point3F(1, 1, 1), gfx::Point3F(scale_x, scale_y, 1));
- std::unique_ptr<ui::InterpolatedTransform> translation =
- std::make_unique<ui::InterpolatedTranslation>(
- gfx::PointF(), gfx::PointF(target_bounds.x() - bounds.x(),
- target_bounds.y() - bounds.y()));
- scale->SetChild(std::move(translation));
- scale->SetReversed(show);
- base::TimeDelta duration =
- window->layer()->GetAnimator()->GetTransitionDuration();
- std::unique_ptr<ui::LayerAnimationElement> transition =
- ui::LayerAnimationElement::CreateInterpolatedTransformElement(
- std::move(scale), duration);
- transition->set_tween_type(show ? gfx::Tween::EASE_IN
- : gfx::Tween::EASE_IN_OUT);
- window->layer()->GetAnimator()->ScheduleAnimation(
- new ui::LayerAnimationSequence(std::move(transition)));
- // When hiding a window, turn off blending until the animation is 3 / 4 done
- // to save bandwidth and reduce jank.
- if (!show) {
- window->layer()->GetAnimator()->SchedulePauseForProperties(
- (duration * 3) / 4, ui::LayerAnimationElement::OPACITY);
- }
- // Fade in and out quickly when the window is small to reduce jank.
- float opacity = show ? 1.0f : 0.0f;
- window->layer()->GetAnimator()->ScheduleAnimation(
- new ui::LayerAnimationSequence(
- ui::LayerAnimationElement::CreateOpacityElement(opacity,
- duration / 4)));
- // Reset the transform to identity when the minimize animation is completed.
- window->layer()->GetAnimator()->ScheduleAnimation(
- new ui::LayerAnimationSequence(
- ui::LayerAnimationElement::CreateTransformElement(
- gfx::Transform(), base::TimeDelta())));
- }
- void AnimateShowWindow_Minimize(aura::Window* window) {
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- ui::AnimationThroughputReporter reporter(
- settings.GetAnimator(),
- metrics_util::ForSmoothness(
- base::BindRepeating(static_cast<void (*)(const char*, int)>(
- &base::UmaHistogramPercentage),
- "Ash.Window.AnimationSmoothness.Unminimize")));
- base::TimeDelta duration =
- base::Milliseconds(kLayerAnimationsForMinimizeDurationMS);
- settings.SetTransitionDuration(duration);
- AddLayerAnimationsForMinimize(window, true);
- // Now that the window has been restored, we need to clear its animation style
- // to default so that normal animation applies.
- ::wm::SetWindowVisibilityAnimationType(
- window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
- }
- void AnimateHideWindow_Minimize(aura::Window* window) {
- // Property sets within this scope will be implicitly animated.
- ::wm::ScopedHidingAnimationSettings hiding_settings(window);
- // Report animation smoothness for animations created within this scope.
- ui::AnimationThroughputReporter reporter(
- hiding_settings.layer_animation_settings()->GetAnimator(),
- metrics_util::ForSmoothness(
- base::BindRepeating(static_cast<void (*)(const char*, int)>(
- &base::UmaHistogramPercentage),
- "Ash.Window.AnimationSmoothness.Minimize")));
- base::TimeDelta duration =
- base::Milliseconds(kLayerAnimationsForMinimizeDurationMS);
- hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);
- window->layer()->SetVisible(false);
- AddLayerAnimationsForMinimize(window, false);
- }
- void AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window* window,
- bool show) {
- float start_value, end_value;
- if (show) {
- start_value = kWindowAnimation_HideBrightnessGrayscale;
- end_value = kWindowAnimation_ShowBrightnessGrayscale;
- } else {
- start_value = kWindowAnimation_ShowBrightnessGrayscale;
- end_value = kWindowAnimation_HideBrightnessGrayscale;
- }
- window->layer()->SetLayerBrightness(start_value);
- window->layer()->SetLayerGrayscale(start_value);
- if (show) {
- window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
- window->layer()->SetVisible(true);
- }
- base::TimeDelta duration =
- base::Milliseconds(kBrightnessGrayscaleFadeDurationMs);
- if (show) {
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- window->layer()->GetAnimator()->ScheduleTogether(
- CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
- } else {
- ::wm::ScopedHidingAnimationSettings hiding_settings(window);
- window->layer()->GetAnimator()->ScheduleTogether(
- CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- window->layer()->SetVisible(false);
- }
- }
- void AnimateShowWindow_BrightnessGrayscale(aura::Window* window) {
- AnimateShowHideWindowCommon_BrightnessGrayscale(window, true);
- }
- // TODO(edcourtney): Consolidate with AnimateShowWindow_Fade in ui/wm/core.
- void AnimateShowWindow_FadeIn(aura::Window* window) {
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- settings.SetTransitionDuration(base::Milliseconds(kFadeInAnimationMs));
- window->layer()->SetVisible(true);
- window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
- }
- void AnimateHideWindow_BrightnessGrayscale(aura::Window* window) {
- AnimateShowHideWindowCommon_BrightnessGrayscale(window, false);
- }
- void AnimateHideWindow_SlideOut(aura::Window* window) {
- base::TimeDelta duration =
- base::Milliseconds(PipPositioner::kPipDismissTimeMs);
- ::wm::ScopedHidingAnimationSettings settings(window);
- settings.layer_animation_settings()->SetTransitionDuration(duration);
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- window->layer()->SetVisible(false);
- gfx::Rect bounds = window->GetBoundsInScreen();
- display::Display display =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window);
- gfx::Rect dismissed_bounds =
- PipPositioner::GetDismissedPosition(display, bounds);
- ::wm::ConvertRectFromScreen(window->parent(), &dismissed_bounds);
- window->layer()->SetBounds(dismissed_bounds);
- }
- void AnimateShowWindow_StepEnd(aura::Window* window) {
- window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
- ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- settings.SetTransitionDuration(kZeroAnimationMs);
- settings.SetTweenType(gfx::Tween::ZERO);
- window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
- }
- void AnimateHideWindow_StepEnd(aura::Window* window) {
- ::wm::ScopedHidingAnimationSettings settings(window);
- settings.layer_animation_settings()->SetTransitionDuration(kZeroAnimationMs);
- settings.layer_animation_settings()->SetTweenType(gfx::Tween::ZERO);
- window->layer()->SetVisible(false);
- }
- bool AnimateShowWindow(aura::Window* window) {
- if (!::wm::HasWindowVisibilityAnimationTransition(window,
- ::wm::ANIMATE_SHOW)) {
- return false;
- }
- switch (::wm::GetWindowVisibilityAnimationType(window)) {
- case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
- AnimateShowWindow_Minimize(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
- AnimateShowWindow_BrightnessGrayscale(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE_IN_SLIDE_OUT:
- AnimateShowWindow_FadeIn(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_STEP_END:
- AnimateShowWindow_StepEnd(window);
- return true;
- default:
- NOTREACHED();
- return false;
- }
- }
- bool AnimateHideWindow(aura::Window* window) {
- if (!::wm::HasWindowVisibilityAnimationTransition(window,
- ::wm::ANIMATE_HIDE)) {
- return false;
- }
- switch (::wm::GetWindowVisibilityAnimationType(window)) {
- case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
- AnimateHideWindow_Minimize(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
- AnimateHideWindow_BrightnessGrayscale(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE_IN_SLIDE_OUT:
- AnimateHideWindow_SlideOut(window);
- return true;
- case WINDOW_VISIBILITY_ANIMATION_TYPE_STEP_END:
- AnimateHideWindow_StepEnd(window);
- return true;
- default:
- NOTREACHED();
- return false;
- }
- }
- void CrossFadeAnimation(aura::Window* window,
- std::unique_ptr<ui::LayerTreeOwner> old_layer_owner) {
- CrossFadeAnimationInternal(
- window, std::move(old_layer_owner), /*animate_old_layer=*/true,
- /*duration=*/absl::nullopt, /*tween_type=*/absl::nullopt,
- /*histogram_name=*/absl::nullopt);
- }
- void CrossFadeAnimationAnimateNewLayerOnly(aura::Window* window,
- const gfx::Rect& target_bounds,
- base::TimeDelta duration,
- gfx::Tween::Type tween_type,
- const std::string& histogram_name) {
- std::unique_ptr<ui::LayerTreeOwner> old_layer_owner =
- ::wm::RecreateLayers(window);
- window->SetBounds(target_bounds);
- CrossFadeAnimationInternal(window, std::move(old_layer_owner),
- /*animate_old_layer=*/false, duration, tween_type,
- histogram_name);
- }
- bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
- if (::wm::WindowAnimationsDisabled(window))
- return false;
- // Attempt to run CoreWm supplied animation types.
- if (::wm::AnimateOnChildWindowVisibilityChanged(window, visible))
- return true;
- // Otherwise try to run an Ash-specific animation.
- if (visible)
- return AnimateShowWindow(window);
- // Don't start hiding the window again if it's already being hidden.
- return window->layer()->GetTargetOpacity() != 0.0f &&
- AnimateHideWindow(window);
- }
- std::vector<ui::LayerAnimationSequence*>
- CreateBrightnessGrayscaleAnimationSequence(float target_value,
- base::TimeDelta duration) {
- gfx::Tween::Type animation_type = gfx::Tween::EASE_OUT;
- std::unique_ptr<ui::LayerAnimationSequence> brightness_sequence =
- std::make_unique<ui::LayerAnimationSequence>();
- std::unique_ptr<ui::LayerAnimationSequence> grayscale_sequence =
- std::make_unique<ui::LayerAnimationSequence>();
- std::unique_ptr<ui::LayerAnimationElement> brightness_element =
- ui::LayerAnimationElement::CreateBrightnessElement(target_value,
- duration);
- brightness_element->set_tween_type(animation_type);
- brightness_sequence->AddElement(std::move(brightness_element));
- std::unique_ptr<ui::LayerAnimationElement> grayscale_element =
- ui::LayerAnimationElement::CreateGrayscaleElement(target_value, duration);
- grayscale_element->set_tween_type(animation_type);
- grayscale_sequence->AddElement(std::move(grayscale_element));
- std::vector<ui::LayerAnimationSequence*> animations;
- animations.push_back(brightness_sequence.release());
- animations.push_back(grayscale_sequence.release());
- return animations;
- }
- gfx::Rect GetMinimizeAnimationTargetBoundsInScreen(aura::Window* window) {
- Shelf* shelf = Shelf::ForWindow(window);
- gfx::Rect item_rect = shelf->GetScreenBoundsOfItemIconForWindow(window);
- // The launcher item is visible and has an icon.
- if (!item_rect.IsEmpty())
- return item_rect;
- // If both the icon width and height are 0, then there is no icon in the
- // launcher for |window|. If the launcher is auto hidden, one of the height or
- // width will be 0 but the position in the launcher and the major dimension
- // are still reported correctly and the window can be animated to the launcher
- // item's light bar.
- if (item_rect.width() != 0 || item_rect.height() != 0) {
- if (shelf->GetVisibilityState() == SHELF_AUTO_HIDE) {
- gfx::Rect shelf_bounds = shelf->GetWindow()->GetBoundsInScreen();
- if (shelf->alignment() == ShelfAlignment::kLeft)
- item_rect.set_x(shelf_bounds.right());
- else if (shelf->alignment() == ShelfAlignment::kRight)
- item_rect.set_x(shelf_bounds.x());
- else
- item_rect.set_y(shelf_bounds.y());
- return item_rect;
- }
- }
- // Coming here, there is no visible icon of that shelf item and we zoom back
- // to the location of the application launcher (which is fixed as first item
- // of the shelf).
- gfx::Rect work_area =
- display::Screen::GetScreen()->GetDisplayNearestWindow(window).work_area();
- int ltr_adjusted_x = base::i18n::IsRTL() ? work_area.right() : work_area.x();
- switch (shelf->alignment()) {
- case ShelfAlignment::kBottom:
- case ShelfAlignment::kBottomLocked:
- return gfx::Rect(ltr_adjusted_x, work_area.bottom(), 0, 0);
- case ShelfAlignment::kLeft:
- return gfx::Rect(work_area.x(), work_area.y(), 0, 0);
- case ShelfAlignment::kRight:
- return gfx::Rect(work_area.right(), work_area.y(), 0, 0);
- }
- NOTREACHED();
- return gfx::Rect();
- }
- } // namespace ash
|