| // 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_events.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) { |
| std::unique_ptr<ScrollOffsetAnimationCurve> curve = |
| ScrollOffsetAnimationCurve::Create( |
| target_offset, CubicBezierTimingFunction::CreatePreset( |
| CubicBezierTimingFunction::EaseType::EASE_IN_OUT), |
| ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA); |
| curve->SetInitialValue(current_offset); |
| |
| std::unique_ptr<Animation> animation = Animation::Create( |
| std::move(curve), AnimationIdProvider::NextAnimationId(), |
| AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_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) { |
| 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_->element_animations()->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); |
| |
| curve->UpdateTarget( |
| animation->TrimTimeToCurrentIteration(frame_monotonic_time).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_->element_animations()->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, |
| TargetProperty::Type 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 |