1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "core/animation/AnimationNode.h"
33
34#include "core/animation/AnimationNodeTiming.h"
35#include "core/animation/AnimationPlayer.h"
36#include "core/animation/TimingCalculations.h"
37
38namespace blink {
39
40namespace {
41
42Timing::FillMode resolvedFillMode(Timing::FillMode fillMode, bool isAnimation)
43{
44    if (fillMode != Timing::FillModeAuto)
45        return fillMode;
46    if (isAnimation)
47        return Timing::FillModeNone;
48    return Timing::FillModeBoth;
49}
50
51} // namespace
52
53AnimationNode::AnimationNode(const Timing& timing, PassOwnPtrWillBeRawPtr<EventDelegate> eventDelegate)
54    : m_parent(nullptr)
55    , m_startTime(0)
56    , m_player(nullptr)
57    , m_timing(timing)
58    , m_eventDelegate(eventDelegate)
59    , m_calculated()
60    , m_needsUpdate(true)
61    , m_lastUpdateTime(nullValue())
62{
63    m_timing.assertValid();
64}
65
66double AnimationNode::iterationDuration() const
67{
68    double result = std::isnan(m_timing.iterationDuration) ? intrinsicIterationDuration() : m_timing.iterationDuration;
69    ASSERT(result >= 0);
70    return result;
71}
72
73double AnimationNode::repeatedDuration() const
74{
75    const double result = multiplyZeroAlwaysGivesZero(iterationDuration(), m_timing.iterationCount);
76    ASSERT(result >= 0);
77    return result;
78}
79
80double AnimationNode::activeDurationInternal() const
81{
82    const double result = m_timing.playbackRate
83        ? repeatedDuration() / std::abs(m_timing.playbackRate)
84        : std::numeric_limits<double>::infinity();
85    ASSERT(result >= 0);
86    return result;
87}
88
89void AnimationNode::updateSpecifiedTiming(const Timing& timing)
90{
91    // FIXME: Test whether the timing is actually different?
92    m_timing = timing;
93    invalidate();
94    if (m_player)
95        m_player->setOutdated();
96    specifiedTimingChanged();
97}
98
99void AnimationNode::updateInheritedTime(double inheritedTime, TimingUpdateReason reason) const
100{
101    bool needsUpdate = m_needsUpdate || (m_lastUpdateTime != inheritedTime && !(isNull(m_lastUpdateTime) && isNull(inheritedTime)));
102    m_needsUpdate = false;
103    m_lastUpdateTime = inheritedTime;
104
105    const double localTime = inheritedTime - m_startTime;
106    double timeToNextIteration = std::numeric_limits<double>::infinity();
107    if (needsUpdate) {
108        const double activeDuration = this->activeDurationInternal();
109
110        const Phase currentPhase = calculatePhase(activeDuration, localTime, m_timing);
111        // FIXME: parentPhase depends on groups being implemented.
112        const AnimationNode::Phase parentPhase = AnimationNode::PhaseActive;
113        const double activeTime = calculateActiveTime(activeDuration, resolvedFillMode(m_timing.fillMode, isAnimation()), localTime, parentPhase, currentPhase, m_timing);
114
115        double currentIteration;
116        double timeFraction;
117        if (const double iterationDuration = this->iterationDuration()) {
118            const double startOffset = multiplyZeroAlwaysGivesZero(m_timing.iterationStart, iterationDuration);
119            ASSERT(startOffset >= 0);
120            const double scaledActiveTime = calculateScaledActiveTime(activeDuration, activeTime, startOffset, m_timing);
121            const double iterationTime = calculateIterationTime(iterationDuration, repeatedDuration(), scaledActiveTime, startOffset, m_timing);
122
123            currentIteration = calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, m_timing);
124            timeFraction = calculateTransformedTime(currentIteration, iterationDuration, iterationTime, m_timing) / iterationDuration;
125
126            if (!isNull(iterationTime)) {
127                timeToNextIteration = (iterationDuration - iterationTime) / std::abs(m_timing.playbackRate);
128                if (activeDuration - activeTime < timeToNextIteration)
129                    timeToNextIteration = std::numeric_limits<double>::infinity();
130            }
131        } else {
132            const double localIterationDuration = 1;
133            const double localRepeatedDuration = localIterationDuration * m_timing.iterationCount;
134            ASSERT(localRepeatedDuration >= 0);
135            const double localActiveDuration = m_timing.playbackRate ? localRepeatedDuration / std::abs(m_timing.playbackRate) : std::numeric_limits<double>::infinity();
136            ASSERT(localActiveDuration >= 0);
137            const double localLocalTime = localTime < m_timing.startDelay ? localTime : localActiveDuration + m_timing.startDelay;
138            const AnimationNode::Phase localCurrentPhase = calculatePhase(localActiveDuration, localLocalTime, m_timing);
139            const double localActiveTime = calculateActiveTime(localActiveDuration, resolvedFillMode(m_timing.fillMode, isAnimation()), localLocalTime, parentPhase, localCurrentPhase, m_timing);
140            const double startOffset = m_timing.iterationStart * localIterationDuration;
141            ASSERT(startOffset >= 0);
142            const double scaledActiveTime = calculateScaledActiveTime(localActiveDuration, localActiveTime, startOffset, m_timing);
143            const double iterationTime = calculateIterationTime(localIterationDuration, localRepeatedDuration, scaledActiveTime, startOffset, m_timing);
144
145            currentIteration = calculateCurrentIteration(localIterationDuration, iterationTime, scaledActiveTime, m_timing);
146            timeFraction = calculateTransformedTime(currentIteration, localIterationDuration, iterationTime, m_timing);
147        }
148
149        m_calculated.currentIteration = currentIteration;
150        m_calculated.timeFraction = timeFraction;
151
152        m_calculated.phase = currentPhase;
153        m_calculated.isInEffect = !isNull(activeTime);
154        m_calculated.isInPlay = phase() == PhaseActive && (!m_parent || m_parent->isInPlay());
155        m_calculated.isCurrent = phase() == PhaseBefore || isInPlay() || (m_parent && m_parent->isCurrent());
156        m_calculated.localTime = m_lastUpdateTime - m_startTime;
157    }
158
159    // Test for events even if timing didn't need an update as the player may have gained a start time.
160    // FIXME: Refactor so that we can ASSERT(m_player) here, this is currently required to be nullable for testing.
161    if (reason == TimingUpdateForAnimationFrame && (!m_player || m_player->hasStartTime() || m_player->paused())) {
162        if (m_eventDelegate)
163            m_eventDelegate->onEventCondition(this);
164    }
165
166    if (needsUpdate)  {
167        // FIXME: This probably shouldn't be recursive.
168        updateChildrenAndEffects();
169        m_calculated.timeToForwardsEffectChange = calculateTimeToEffectChange(true, localTime, timeToNextIteration);
170        m_calculated.timeToReverseEffectChange = calculateTimeToEffectChange(false, localTime, timeToNextIteration);
171    }
172}
173
174const AnimationNode::CalculatedTiming& AnimationNode::ensureCalculated() const
175{
176    if (!m_player)
177        return m_calculated;
178    if (m_player->outdated())
179        m_player->update(TimingUpdateOnDemand);
180    ASSERT(!m_player->outdated());
181    return m_calculated;
182}
183
184PassRefPtrWillBeRawPtr<AnimationNodeTiming> AnimationNode::timing()
185{
186    return AnimationNodeTiming::create(this);
187}
188
189void AnimationNode::trace(Visitor* visitor)
190{
191    visitor->trace(m_parent);
192    visitor->trace(m_player);
193    visitor->trace(m_eventDelegate);
194}
195
196} // namespace blink
197