1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/animation/AnimationStack.h"
7
8#include "core/animation/ActiveAnimations.h"
9#include "core/animation/AnimationClock.h"
10#include "core/animation/AnimationTimeline.h"
11#include "core/animation/KeyframeEffectModel.h"
12#include "core/animation/LegacyStyleInterpolation.h"
13#include "core/animation/animatable/AnimatableDouble.h"
14#include <gtest/gtest.h>
15
16namespace blink {
17
18class AnimationAnimationStackTest : public ::testing::Test {
19protected:
20    virtual void SetUp()
21    {
22        document = Document::create();
23        document->animationClock().resetTimeForTesting();
24        timeline = AnimationTimeline::create(document.get());
25        element = document->createElement("foo", ASSERT_NO_EXCEPTION);
26    }
27
28    AnimationPlayer* play(Animation* animation, double startTime)
29    {
30        AnimationPlayer* player = timeline->createAnimationPlayer(animation);
31        player->setStartTimeInternal(startTime);
32        player->update(TimingUpdateOnDemand);
33        return player;
34    }
35
36    void updateTimeline(double time)
37    {
38        document->animationClock().updateTime(time);
39        timeline->serviceAnimations(TimingUpdateForAnimationFrame);
40    }
41
42    const WillBeHeapVector<OwnPtrWillBeMember<SampledEffect> >& effects()
43    {
44        return element->ensureActiveAnimations().defaultStack().m_effects;
45    }
46
47    PassRefPtrWillBeRawPtr<AnimationEffect> makeAnimationEffect(CSSPropertyID id, PassRefPtrWillBeRawPtr<AnimatableValue> value)
48    {
49        AnimatableValueKeyframeVector keyframes(2);
50        keyframes[0] = AnimatableValueKeyframe::create();
51        keyframes[0]->setOffset(0.0);
52        keyframes[0]->setPropertyValue(id, value.get());
53        keyframes[1] = AnimatableValueKeyframe::create();
54        keyframes[1]->setOffset(1.0);
55        keyframes[1]->setPropertyValue(id, value.get());
56        return AnimatableValueKeyframeEffectModel::create(keyframes);
57    }
58
59    PassRefPtrWillBeRawPtr<InertAnimation> makeInertAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect)
60    {
61        Timing timing;
62        timing.fillMode = Timing::FillModeBoth;
63        return InertAnimation::create(effect, timing, false);
64    }
65
66    PassRefPtrWillBeRawPtr<Animation> makeAnimation(PassRefPtrWillBeRawPtr<AnimationEffect> effect, double duration = 10)
67    {
68        Timing timing;
69        timing.fillMode = Timing::FillModeBoth;
70        timing.iterationDuration = duration;
71        return Animation::create(element.get(), effect, timing);
72    }
73
74    AnimatableValue* interpolationValue(Interpolation* interpolation)
75    {
76        return toLegacyStyleInterpolation(interpolation)->currentValue().get();
77    }
78
79    RefPtrWillBePersistent<Document> document;
80    RefPtrWillBePersistent<AnimationTimeline> timeline;
81    RefPtrWillBePersistent<Element> element;
82};
83
84TEST_F(AnimationAnimationStackTest, ActiveAnimationsSorted)
85{
86    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 10);
87    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(2))).get(), 15);
88    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3))).get(), 5);
89    WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
90    EXPECT_EQ(1u, result.size());
91    EXPECT_TRUE(interpolationValue(result.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
92}
93
94TEST_F(AnimationAnimationStackTest, NewAnimations)
95{
96    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 15);
97    play(makeAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(2))).get(), 10);
98    WillBeHeapVector<RawPtrWillBeMember<InertAnimation> > newAnimations;
99    RefPtrWillBeRawPtr<InertAnimation> inert1 = makeInertAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3)));
100    RefPtrWillBeRawPtr<InertAnimation> inert2 = makeInertAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(4)));
101    newAnimations.append(inert1.get());
102    newAnimations.append(inert2.get());
103    WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), &newAnimations, 0, Animation::DefaultPriority, 10);
104    EXPECT_EQ(2u, result.size());
105    EXPECT_TRUE(interpolationValue(result.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
106    EXPECT_TRUE(interpolationValue(result.get(CSSPropertyZIndex))->equals(AnimatableDouble::create(4).get()));
107}
108
109TEST_F(AnimationAnimationStackTest, CancelledAnimationPlayers)
110{
111    WillBeHeapHashSet<RawPtrWillBeMember<const AnimationPlayer> > cancelledAnimationPlayers;
112    RefPtrWillBeRawPtr<AnimationPlayer> player = play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 0);
113    cancelledAnimationPlayers.add(player.get());
114    play(makeAnimation(makeAnimationEffect(CSSPropertyZIndex, AnimatableDouble::create(2))).get(), 0);
115    WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > result = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, &cancelledAnimationPlayers, Animation::DefaultPriority, 0);
116    EXPECT_EQ(1u, result.size());
117    EXPECT_TRUE(interpolationValue(result.get(CSSPropertyZIndex))->equals(AnimatableDouble::create(2).get()));
118}
119
120TEST_F(AnimationAnimationStackTest, ForwardsFillDiscarding)
121{
122    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(1))).get(), 2);
123    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(2))).get(), 6);
124    play(makeAnimation(makeAnimationEffect(CSSPropertyFontSize, AnimatableDouble::create(3))).get(), 4);
125    document->compositorPendingAnimations().update();
126    WillBeHeapHashMap<CSSPropertyID, RefPtrWillBeMember<Interpolation> > interpolations;
127
128    updateTimeline(11);
129    Heap::collectAllGarbage();
130    interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
131    EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
132    EXPECT_EQ(3u, effects().size());
133    EXPECT_EQ(1u, interpolations.size());
134
135    updateTimeline(13);
136    Heap::collectAllGarbage();
137    interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
138    EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
139    EXPECT_EQ(3u, effects().size());
140
141    updateTimeline(15);
142    Heap::collectAllGarbage();
143    interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
144    EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
145    EXPECT_EQ(2u, effects().size());
146
147    updateTimeline(17);
148    Heap::collectAllGarbage();
149    interpolations = AnimationStack::activeInterpolations(&element->activeAnimations()->defaultStack(), 0, 0, Animation::DefaultPriority, 0);
150    EXPECT_TRUE(interpolationValue(interpolations.get(CSSPropertyFontSize))->equals(AnimatableDouble::create(3).get()));
151    EXPECT_EQ(1u, effects().size());
152}
153
154}
155