blob: b900cd037a439aef3a1528fc22238a6c62cb8350 [file] [log] [blame]
// Copyright (c) 2011 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 "ui/gfx/compositor/layer_animation_manager.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "ui/base/animation/animation_container.h"
#include "ui/base/animation/animation.h"
#include "ui/base/animation/tween.h"
#include "ui/gfx/compositor/compositor.h"
#include "ui/gfx/compositor/layer.h"
#include "ui/gfx/compositor/layer_animator_delegate.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/rect.h"
namespace {
void SetMatrixElement(SkMatrix44& matrix, int index, SkMScalar value) {
int row = index / 4;
int col = index % 4;
matrix.set(row, col, value);
}
SkMScalar GetMatrixElement(const SkMatrix44& matrix, int index) {
int row = index / 4;
int col = index % 4;
return matrix.get(row, col);
}
} // anonymous namespace
namespace ui {
LayerAnimationManager::LayerAnimationManager(Layer* layer)
: layer_(layer),
got_initial_tick_(false) {
}
LayerAnimationManager::~LayerAnimationManager() {
}
void LayerAnimationManager::SetAnimation(Animation* animation) {
animation_.reset(animation);
if (animation_.get()) {
static ui::AnimationContainer* container = NULL;
if (!container) {
container = new AnimationContainer;
container->AddRef();
}
animation_->set_delegate(this);
animation_->SetContainer(container);
got_initial_tick_ = false;
}
}
void LayerAnimationManager::AnimateToPoint(const gfx::Point& target) {
StopAnimating(LOCATION);
const gfx::Rect& layer_bounds = layer_->bounds();
if (target == layer_bounds.origin())
return; // Already there.
Params& element = elements_[LOCATION];
element.location.target_x = target.x();
element.location.target_y = target.y();
element.location.start_x = layer_bounds.origin().x();
element.location.start_y = layer_bounds.origin().y();
}
void LayerAnimationManager::AnimateTransform(const Transform& transform) {
StopAnimating(TRANSFORM);
const Transform& layer_transform = layer_->transform();
if (transform == layer_transform)
return; // Already there.
Params& element = elements_[TRANSFORM];
for (int i = 0; i < 16; ++i) {
element.transform.start[i] =
GetMatrixElement(layer_transform.matrix(), i);
element.transform.target[i] =
GetMatrixElement(transform.matrix(), i);
}
}
void LayerAnimationManager::AnimateOpacity(float target_opacity) {
StopAnimating(OPACITY);
if (layer_->opacity() == target_opacity)
return;
Params& element = elements_[OPACITY];
element.opacity.start = layer_->opacity();
element.opacity.target = target_opacity;
}
gfx::Point LayerAnimationManager::GetTargetPoint() {
return IsAnimating(LOCATION) ?
gfx::Point(elements_[LOCATION].location.target_x,
elements_[LOCATION].location.target_y) :
layer_->bounds().origin();
}
float LayerAnimationManager::GetTargetOpacity() {
return IsAnimating(OPACITY) ?
elements_[OPACITY].opacity.target : layer_->opacity();
}
ui::Transform LayerAnimationManager::GetTargetTransform() {
if (IsAnimating(TRANSFORM)) {
Transform transform;
for (int i = 0; i < 16; ++i) {
SetMatrixElement(transform.matrix(), i,
elements_[TRANSFORM].transform.target[i]);
}
return transform;
}
return layer_->transform();
}
bool LayerAnimationManager::IsAnimating(AnimationProperty property) const {
return elements_.count(property) > 0;
}
bool LayerAnimationManager::IsRunning() const {
return animation_.get() && animation_->is_animating();
}
void LayerAnimationManager::AnimationProgressed(
const ui::Animation* animation) {
got_initial_tick_ = true;
for (Elements::const_iterator i = elements_.begin(); i != elements_.end();
++i) {
switch (i->first) {
case LOCATION: {
const gfx::Rect& current_bounds(layer_->bounds());
gfx::Rect new_bounds = animation_->CurrentValueBetween(
gfx::Rect(gfx::Point(i->second.location.start_x,
i->second.location.start_y),
current_bounds.size()),
gfx::Rect(gfx::Point(i->second.location.target_x,
i->second.location.target_y),
current_bounds.size()));
delegate()->SetBoundsFromAnimator(new_bounds);
break;
}
case TRANSFORM: {
Transform transform;
for (int j = 0; j < 16; ++j) {
SkMScalar value = animation_->CurrentValueBetween(
i->second.transform.start[j],
i->second.transform.target[j]);
SetMatrixElement(transform.matrix(), j, value);
}
delegate()->SetTransformFromAnimator(transform);
break;
}
case OPACITY: {
delegate()->SetOpacityFromAnimator(animation_->CurrentValueBetween(
i->second.opacity.start, i->second.opacity.target));
break;
}
default:
NOTREACHED();
}
}
layer_->ScheduleDraw();
}
void LayerAnimationManager::AnimationEnded(const ui::Animation* animation) {
AnimationProgressed(animation);
if (layer_->delegate())
layer_->delegate()->OnLayerAnimationEnded(animation);
}
void LayerAnimationManager::StopAnimating(AnimationProperty property) {
if (!IsAnimating(property))
return;
elements_.erase(property);
}
LayerAnimatorDelegate* LayerAnimationManager::delegate() {
return static_cast<LayerAnimatorDelegate*>(layer_);
}
} // namespace ui