blob: a41c1eedfdc43facf13d471ec0ec8021addca9d8 [file] [log] [blame]
// Copyright 2013 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 "cc/animation/scroll_offset_animations_impl.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_player.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/timing_function.h"
namespace cc {
ScrollOffsetAnimationsImpl::ScrollOffsetAnimationsImpl(
AnimationHost* animation_host)
: animation_host_(animation_host),
scroll_offset_timeline_(
AnimationTimeline::Create(AnimationIdProvider::NextTimelineId())),
scroll_offset_animation_player_(
AnimationPlayer::Create(AnimationIdProvider::NextPlayerId())) {
scroll_offset_timeline_->set_is_impl_only(true);
scroll_offset_animation_player_->set_animation_delegate(this);
animation_host_->AddAnimationTimeline(scroll_offset_timeline_.get());
scroll_offset_timeline_->AttachPlayer(scroll_offset_animation_player_.get());
}
ScrollOffsetAnimationsImpl::~ScrollOffsetAnimationsImpl() {
scroll_offset_timeline_->DetachPlayer(scroll_offset_animation_player_.get());
animation_host_->RemoveAnimationTimeline(scroll_offset_timeline_.get());
}
void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
const gfx::ScrollOffset& current_offset,
base::TimeDelta delayed_by,
base::TimeDelta animation_start_offset) {
std::unique_ptr<ScrollOffsetAnimationCurve> curve =
ScrollOffsetAnimationCurve::Create(
target_offset, CubicBezierTimingFunction::CreatePreset(
CubicBezierTimingFunction::EaseType::EASE_IN_OUT),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA);
curve->SetInitialValue(current_offset, delayed_by);
std::unique_ptr<Animation> animation = Animation::Create(
std::move(curve), AnimationIdProvider::NextAnimationId(),
AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_OFFSET);
animation->set_time_offset(animation_start_offset);
animation->set_is_impl_only(true);
DCHECK(scroll_offset_animation_player_);
DCHECK(scroll_offset_animation_player_->animation_timeline());
ReattachScrollOffsetPlayerIfNeeded(element_id);
scroll_offset_animation_player_->AddAnimation(std::move(animation));
}
bool ScrollOffsetAnimationsImpl::ScrollAnimationUpdateTarget(
ElementId element_id,
const gfx::Vector2dF& scroll_delta,
const gfx::ScrollOffset& max_scroll_offset,
base::TimeTicks frame_monotonic_time,
base::TimeDelta delayed_by) {
DCHECK(scroll_offset_animation_player_);
if (!scroll_offset_animation_player_->element_animations())
return false;
DCHECK_EQ(element_id, scroll_offset_animation_player_->element_id());
Animation* animation = scroll_offset_animation_player_->GetAnimation(
TargetProperty::SCROLL_OFFSET);
if (!animation) {
scroll_offset_animation_player_->DetachElement();
return false;
}
if (scroll_delta.IsZero())
return true;
ScrollOffsetAnimationCurve* curve =
animation->curve()->ToScrollOffsetAnimationCurve();
gfx::ScrollOffset new_target =
gfx::ScrollOffsetWithDelta(curve->target_value(), scroll_delta);
new_target.SetToMax(gfx::ScrollOffset());
new_target.SetToMin(max_scroll_offset);
// TODO(ymalik): Animation::TrimTimeToCurrentIteration should probably check
// for run_state == Animation::WAITING_FOR_TARGET_AVAILABILITY.
base::TimeDelta trimmed =
animation->run_state() == Animation::WAITING_FOR_TARGET_AVAILABILITY
? base::TimeDelta()
: animation->TrimTimeToCurrentIteration(frame_monotonic_time);
// Re-target taking the delay into account. Note that if the duration of the
// animation is 0, trimmed will be 0 and UpdateTarget will be called with
// t = -delayed_by.
trimmed -= delayed_by;
curve->UpdateTarget(trimmed.InSecondsF(), new_target);
return true;
}
void ScrollOffsetAnimationsImpl::ScrollAnimationApplyAdjustment(
ElementId element_id,
const gfx::Vector2dF& adjustment) {
DCHECK(scroll_offset_animation_player_);
if (element_id != scroll_offset_animation_player_->element_id())
return;
if (!scroll_offset_animation_player_->element_animations())
return;
Animation* animation = scroll_offset_animation_player_->GetAnimation(
TargetProperty::SCROLL_OFFSET);
if (!animation)
return;
std::unique_ptr<ScrollOffsetAnimationCurve> new_curve =
animation->curve()
->ToScrollOffsetAnimationCurve()
->CloneToScrollOffsetAnimationCurve();
new_curve->ApplyAdjustment(adjustment);
std::unique_ptr<Animation> new_animation = Animation::Create(
std::move(new_curve), AnimationIdProvider::NextAnimationId(),
AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_OFFSET);
new_animation->set_start_time(animation->start_time());
new_animation->set_is_impl_only(true);
new_animation->set_affects_active_elements(false);
// Abort the old animation.
ScrollAnimationAbort(/* needs_completion */ false);
// Start a new one with the adjusment.
scroll_offset_animation_player_->AddAnimation(std::move(new_animation));
}
void ScrollOffsetAnimationsImpl::ScrollAnimationAbort(bool needs_completion) {
DCHECK(scroll_offset_animation_player_);
scroll_offset_animation_player_->AbortAnimations(
TargetProperty::SCROLL_OFFSET, needs_completion);
}
void ScrollOffsetAnimationsImpl::NotifyAnimationFinished(
base::TimeTicks monotonic_time,
int target_property,
int group) {
DCHECK_EQ(target_property, TargetProperty::SCROLL_OFFSET);
DCHECK(animation_host_->mutator_host_client());
animation_host_->mutator_host_client()->ScrollOffsetAnimationFinished();
}
void ScrollOffsetAnimationsImpl::ReattachScrollOffsetPlayerIfNeeded(
ElementId element_id) {
if (scroll_offset_animation_player_->element_id() != element_id) {
if (scroll_offset_animation_player_->element_id())
scroll_offset_animation_player_->DetachElement();
if (element_id)
scroll_offset_animation_player_->AttachElement(element_id);
}
}
} // namespace cc