This source file includes following definitions.
- Round64
- GetCrossFadeDuration
- AddLayerAnimationsForMinimize
- AnimateShowWindow_Minimize
- AnimateHideWindow_Minimize
- AnimateShowHideWindowCommon_BrightnessGrayscale
- AnimateShowWindow_BrightnessGrayscale
- AnimateHideWindow_BrightnessGrayscale
- AnimateShowWindow
- AnimateHideWindow
- layer_owner_
- OnCompositingDidCommit
- OnCompositingStarted
- OnCompositingEnded
- OnCompositingAborted
- OnCompositingLockStateChanged
- OnWindowDestroying
- OnWindowRemovingFromRootWindow
- OnImplicitAnimationsCompleted
- CrossFadeAnimation
- AnimateOnChildWindowVisibilityChanged
- CreateBrightnessGrayscaleAnimationSequence
- SetTransformForScaleAnimation
- GetMinimizeAnimationTargetBoundsInScreen
#include "ash/wm/window_animations.h"
#include <math.h>
#include <algorithm>
#include <vector>
#include "ash/screen_util.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/wm/window_util.h"
#include "ash/wm/workspace_controller.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_property.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/gfx/interpolated_transform.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/vector3d_f.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace ash {
namespace {
const int kLayerAnimationsForMinimizeDurationMS = 200;
const float kCrossFadeDurationMinMs = 200.f;
const float kCrossFadeDurationMaxMs = 400.f;
const int kBrightnessGrayscaleFadeDurationMs = 1000;
const float kWindowAnimation_HideBrightnessGrayscale = 1.f;
const float kWindowAnimation_ShowBrightnessGrayscale = 0.f;
const float kWindowAnimation_HideOpacity = 0.f;
const float kWindowAnimation_ShowOpacity = 1.f;
const float kLayerScaleAboveSize = 1.1f;
const float kLayerScaleBelowSize = .9f;
int64 Round64(float f) {
return static_cast<int64>(f + 0.5f);
}
base::TimeDelta GetCrossFadeDuration(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
if (::wm::WindowAnimationsDisabled(window))
return base::TimeDelta();
int old_area = old_bounds.width() * old_bounds.height();
int new_area = new_bounds.width() * new_bounds.height();
int max_area = std::max(old_area, new_area);
if (max_area == 0)
return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
int delta_area = std::abs(old_area - new_area);
if (delta_area == 0)
return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
float factor =
static_cast<float>(delta_area) / static_cast<float>(max_area);
const float kRange = kCrossFadeDurationMaxMs - kCrossFadeDurationMinMs;
return base::TimeDelta::FromMilliseconds(
Round64(kCrossFadeDurationMinMs + (factor * kRange)));
}
}
const int kCrossFadeDurationMS = 200;
void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
gfx::Rect bounds = window->bounds();
gfx::Rect target_bounds = GetMinimizeAnimationTargetBoundsInScreen(window);
target_bounds =
ScreenUtil::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();
scoped_ptr<ui::InterpolatedTransform> scale(
new ui::InterpolatedScale(gfx::Point3F(1, 1, 1),
gfx::Point3F(scale_x, scale_y, 1)));
scoped_ptr<ui::InterpolatedTransform> translation(
new ui::InterpolatedTranslation(
gfx::Point(),
gfx::Point(target_bounds.x() - bounds.x(),
target_bounds.y() - bounds.y())));
scale->SetChild(translation.release());
scale->SetReversed(show);
base::TimeDelta duration = window->layer()->GetAnimator()->
GetTransitionDuration();
scoped_ptr<ui::LayerAnimationElement> transition(
ui::LayerAnimationElement::CreateInterpolatedTransformElement(
scale.release(), duration));
transition->set_tween_type(
show ? gfx::Tween::EASE_IN : gfx::Tween::EASE_IN_OUT);
window->layer()->GetAnimator()->ScheduleAnimation(
new ui::LayerAnimationSequence(transition.release()));
if (!show) {
window->layer()->GetAnimator()->SchedulePauseForProperties(
(duration * 3) / 4, ui::LayerAnimationElement::OPACITY);
}
float opacity = show ? 1.0f : 0.0f;
window->layer()->GetAnimator()->ScheduleAnimation(
new ui::LayerAnimationSequence(
ui::LayerAnimationElement::CreateOpacityElement(
opacity, duration / 4)));
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());
base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
kLayerAnimationsForMinimizeDurationMS);
settings.SetTransitionDuration(duration);
AddLayerAnimationsForMinimize(window, true);
::wm::SetWindowVisibilityAnimationType(
window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
}
void AnimateHideWindow_Minimize(aura::Window* window) {
::wm::ScopedHidingAnimationSettings hiding_settings(window);
base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
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::TimeDelta::FromMilliseconds(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);
}
void AnimateHideWindow_BrightnessGrayscale(aura::Window* window) {
AnimateShowHideWindowCommon_BrightnessGrayscale(window, 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;
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;
default:
NOTREACHED();
return false;
}
}
class CrossFadeObserver : public ui::CompositorObserver,
public aura::WindowObserver,
public ui::ImplicitAnimationObserver {
public:
CrossFadeObserver(aura::Window* window,
scoped_ptr<ui::LayerTreeOwner> layer_owner)
: window_(window),
layer_owner_(layer_owner.Pass()) {
window_->AddObserver(this);
layer_owner_->root()->GetCompositor()->AddObserver(this);
}
virtual ~CrossFadeObserver() {
window_->RemoveObserver(this);
window_ = NULL;
layer_owner_->root()->GetCompositor()->RemoveObserver(this);
}
virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {
}
virtual void OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) OVERRIDE {
}
virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE {
}
virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {
layer_owner_->root()->GetAnimator()->StopAnimating();
}
virtual void OnCompositingLockStateChanged(
ui::Compositor* compositor) OVERRIDE {
}
virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
layer_owner_->root()->GetAnimator()->StopAnimating();
}
virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
aura::Window* new_root) OVERRIDE {
layer_owner_->root()->GetAnimator()->StopAnimating();
}
virtual void OnImplicitAnimationsCompleted() OVERRIDE {
delete this;
}
private:
aura::Window* window_;
scoped_ptr<ui::LayerTreeOwner> layer_owner_;
DISALLOW_COPY_AND_ASSIGN(CrossFadeObserver);
};
base::TimeDelta CrossFadeAnimation(
aura::Window* window,
scoped_ptr<ui::LayerTreeOwner> old_layer_owner,
gfx::Tween::Type tween_type) {
DCHECK(old_layer_owner->root());
const gfx::Rect old_bounds(old_layer_owner->root()->bounds());
const gfx::Rect new_bounds(window->bounds());
const bool old_on_top = (old_bounds.width() > new_bounds.width());
const base::TimeDelta duration = GetCrossFadeDuration(window,
old_bounds, new_bounds);
{
ui::Layer* old_layer = old_layer_owner->root();
old_layer->GetAnimator()->StopAnimating();
ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator());
settings.AddObserver(new CrossFadeObserver(window, old_layer_owner.Pass()));
settings.SetTransitionDuration(duration);
settings.SetTweenType(tween_type);
gfx::Transform out_transform;
float scale_x = static_cast<float>(new_bounds.width()) /
static_cast<float>(old_bounds.width());
float scale_y = static_cast<float>(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);
if (old_on_top) {
old_layer->SetOpacity(kWindowAnimation_HideOpacity);
}
old_layer = NULL;
}
gfx::Transform in_transform;
const float scale_x = static_cast<float>(old_bounds.width()) /
static_cast<float>(new_bounds.width());
const float scale_y = static_cast<float>(old_bounds.height()) /
static_cast<float>(new_bounds.height());
in_transform.Translate(old_bounds.x() - new_bounds.x(),
old_bounds.y() - new_bounds.y());
in_transform.Scale(scale_x, scale_y);
window->layer()->SetTransform(in_transform);
if (!old_on_top) {
window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
}
{
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
settings.SetTransitionDuration(duration);
settings.SetTweenType(tween_type);
window->layer()->SetTransform(gfx::Transform());
if (!old_on_top) {
window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
}
}
return duration;
}
bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
if (::wm::WindowAnimationsDisabled(window))
return false;
if (::wm::AnimateOnChildWindowVisibilityChanged(window, visible))
return true;
if (visible)
return AnimateShowWindow(window);
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;
scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
new ui::LayerAnimationSequence());
scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
new ui::LayerAnimationSequence());
scoped_ptr<ui::LayerAnimationElement> brightness_element(
ui::LayerAnimationElement::CreateBrightnessElement(
target_value, duration));
brightness_element->set_tween_type(animation_type);
brightness_sequence->AddElement(brightness_element.release());
scoped_ptr<ui::LayerAnimationElement> grayscale_element(
ui::LayerAnimationElement::CreateGrayscaleElement(
target_value, duration));
grayscale_element->set_tween_type(animation_type);
grayscale_sequence->AddElement(grayscale_element.release());
std::vector<ui::LayerAnimationSequence*> animations;
animations.push_back(brightness_sequence.release());
animations.push_back(grayscale_sequence.release());
return animations;
}
void SetTransformForScaleAnimation(ui::Layer* layer,
LayerScaleAnimationDirection type) {
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);
}
gfx::Rect GetMinimizeAnimationTargetBoundsInScreen(aura::Window* window) {
Shelf* shelf = Shelf::ForWindow(window);
if (!shelf)
return gfx::Rect();
gfx::Rect item_rect = shelf->GetScreenBoundsOfItemIconForWindow(window);
if (!item_rect.IsEmpty())
return item_rect;
if (item_rect.width() != 0 || item_rect.height() != 0) {
ShelfLayoutManager* layout_manager = ShelfLayoutManager::ForShelf(window);
if (layout_manager->visibility_state() == SHELF_AUTO_HIDE) {
gfx::Rect shelf_bounds = shelf->shelf_widget()->GetWindowBoundsInScreen();
switch (layout_manager->GetAlignment()) {
case SHELF_ALIGNMENT_BOTTOM:
item_rect.set_y(shelf_bounds.y());
break;
case SHELF_ALIGNMENT_LEFT:
item_rect.set_x(shelf_bounds.right());
break;
case SHELF_ALIGNMENT_RIGHT:
item_rect.set_x(shelf_bounds.x());
break;
case SHELF_ALIGNMENT_TOP:
item_rect.set_y(shelf_bounds.bottom());
break;
}
return item_rect;
}
}
gfx::Rect work_area =
Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
return gfx::Rect(work_area.right(), work_area.bottom(), 0, 0);
}
}