blob: 9186717e618a4f7b895f58083d3579f809700398 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS 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 "window_manager/compositor/animation.h"
#include <cmath>
#include "base/logging.h"
using base::TimeDelta;
using base::TimeTicks;
using std::vector;
namespace window_manager {
Animation::Animation(float start_value, const TimeTicks& start_time)
: start_keyframe_(start_value, start_time),
end_keyframe_(start_value, start_time) {
}
Animation::~Animation() {
}
bool Animation::IsDone(const TimeTicks& now) const {
return (now >= end_keyframe_.timestamp);
}
float Animation::GetValue(const TimeTicks& now) const {
if (now <= start_keyframe_.timestamp)
return start_keyframe_.value;
if (now >= end_keyframe_.timestamp)
return end_keyframe_.value;
const int num_keyframes_in_vector =
(keyframes_.get() ? static_cast<int>(keyframes_->size()) : 0);
const Keyframe* prev_keyframe = &start_keyframe_;
const Keyframe* next_keyframe =
(num_keyframes_in_vector ? &((*keyframes_)[0]) : &end_keyframe_);
int next_keyframe_index = 1;
// Walk through the keyframes in-order until we find one that starts later
// than |now|. Our current position falls between that keyframe
// (|next_keyframe|) and the one before it (|prev_keyframe|).
while (now > next_keyframe->timestamp) {
prev_keyframe = next_keyframe;
next_keyframe_index++;
next_keyframe =
(next_keyframe_index <= num_keyframes_in_vector) ?
&((*keyframes_)[next_keyframe_index - 1]) :
&end_keyframe_;
DCHECK_NE(prev_keyframe, next_keyframe);
}
TimeDelta time_between_keyframes =
next_keyframe->timestamp - prev_keyframe->timestamp;
TimeDelta time_since_prev_keyframe = now - prev_keyframe->timestamp;
float ease_factor = M_PI / time_between_keyframes.InMilliseconds();
float fraction =
(1.0f - cosf(ease_factor * time_since_prev_keyframe.InMilliseconds())) /
2.0f;
return prev_keyframe->value +
fraction * (next_keyframe->value - prev_keyframe->value);
}
float Animation::GetEndValue() const {
return end_keyframe_.value;
}
void Animation::AppendKeyframe(float value,
const TimeDelta& delay_from_last_keyframe) {
DCHECK_GT(delay_from_last_keyframe.InMilliseconds(), 0LL);
// |start_keyframe_| and |end_keyframe_| initially both contain the starting
// keyframe. If a keyframe has already been added, then we need to insert a
// new one and copy the previous ending keyframe to it.
if (end_keyframe_.timestamp > start_keyframe_.timestamp) {
if (!keyframes_.get())
keyframes_.reset(new vector<Keyframe>);
keyframes_->push_back(end_keyframe_);
}
// End at the new value.
end_keyframe_.value = value;
end_keyframe_.timestamp += delay_from_last_keyframe;
}
AnimationPair::AnimationPair(Animation* first_animation,
Animation* second_animation)
: first_animation_(first_animation),
second_animation_(second_animation) {
}
AnimationPair::~AnimationPair() {
}
void AnimationPair::AppendKeyframe(float first_value,
float second_value,
const TimeDelta& delay_from_last_keyframe) {
first_animation_->AppendKeyframe(first_value, delay_from_last_keyframe);
second_animation_->AppendKeyframe(second_value, delay_from_last_keyframe);
}
} // namespace window_manager