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/TimedItem.h" 33 34 #include "core/animation/Player.h" 35 #include "core/animation/TimedItemCalculations.h" 36 37 namespace WebCore { 38 39 TimedItem::TimedItem(const Timing& timing, PassOwnPtr<EventDelegate> eventDelegate) 40 : m_parent(0) 41 , m_startTime(0) 42 , m_player(0) 43 , m_specified(timing) 44 , m_eventDelegate(eventDelegate) 45 , m_calculated() 46 , m_isFirstSample(true) 47 , m_needsUpdate(true) 48 , m_lastUpdateTime(nullValue()) 49 { 50 m_specified.assertValid(); 51 } 52 53 bool TimedItem::updateInheritedTime(double inheritedTime) const 54 { 55 bool needsUpdate = m_needsUpdate || (m_lastUpdateTime != inheritedTime && !(isNull(m_lastUpdateTime) && isNull(inheritedTime))); 56 m_needsUpdate = false; 57 m_lastUpdateTime = inheritedTime; 58 59 const double previousIteration = m_calculated.currentIteration; 60 const Phase previousPhase = m_calculated.phase; 61 62 const double localTime = inheritedTime - m_startTime; 63 double timeToNextIteration = std::numeric_limits<double>::infinity(); 64 if (needsUpdate) { 65 const double iterationDuration = m_specified.hasIterationDuration 66 ? m_specified.iterationDuration 67 : intrinsicIterationDuration(); 68 ASSERT(iterationDuration >= 0); 69 70 // When iterationDuration = 0 and iterationCount = infinity, or vice- 71 // versa, repeatedDuration should be 0, not NaN as operator*() would give. 72 // FIXME: The spec is unclear about this. 73 const double repeatedDuration = multiplyZeroAlwaysGivesZero(iterationDuration, m_specified.iterationCount); 74 ASSERT(repeatedDuration >= 0); 75 const double activeDuration = m_specified.playbackRate 76 ? repeatedDuration / abs(m_specified.playbackRate) 77 : std::numeric_limits<double>::infinity(); 78 ASSERT(activeDuration >= 0); 79 80 const Phase currentPhase = calculatePhase(activeDuration, localTime, m_specified); 81 // FIXME: parentPhase depends on groups being implemented. 82 const TimedItem::Phase parentPhase = TimedItem::PhaseActive; 83 const double activeTime = calculateActiveTime(activeDuration, localTime, parentPhase, currentPhase, m_specified); 84 85 double currentIteration; 86 double timeFraction; 87 if (iterationDuration) { 88 const double startOffset = multiplyZeroAlwaysGivesZero(m_specified.iterationStart, iterationDuration); 89 ASSERT(startOffset >= 0); 90 const double scaledActiveTime = calculateScaledActiveTime(activeDuration, activeTime, startOffset, m_specified); 91 const double iterationTime = calculateIterationTime(iterationDuration, repeatedDuration, scaledActiveTime, startOffset, m_specified); 92 93 currentIteration = calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, m_specified); 94 timeFraction = calculateTransformedTime(currentIteration, iterationDuration, iterationTime, m_specified) / iterationDuration; 95 96 if (!isNull(iterationTime)) { 97 timeToNextIteration = (iterationDuration - iterationTime) / abs(m_specified.playbackRate); 98 if (activeDuration - activeTime < timeToNextIteration) 99 timeToNextIteration = std::numeric_limits<double>::infinity(); 100 } 101 } else { 102 const double localIterationDuration = 1; 103 const double localRepeatedDuration = localIterationDuration * m_specified.iterationCount; 104 ASSERT(localRepeatedDuration >= 0); 105 const double localActiveDuration = m_specified.playbackRate ? localRepeatedDuration / abs(m_specified.playbackRate) : std::numeric_limits<double>::infinity(); 106 ASSERT(localActiveDuration >= 0); 107 const double localLocalTime = localTime < m_specified.startDelay ? localTime : localActiveDuration + m_specified.startDelay; 108 const TimedItem::Phase localCurrentPhase = calculatePhase(localActiveDuration, localLocalTime, m_specified); 109 const double localActiveTime = calculateActiveTime(localActiveDuration, localLocalTime, parentPhase, localCurrentPhase, m_specified); 110 const double startOffset = m_specified.iterationStart * localIterationDuration; 111 ASSERT(startOffset >= 0); 112 const double scaledActiveTime = calculateScaledActiveTime(localActiveDuration, localActiveTime, startOffset, m_specified); 113 const double iterationTime = calculateIterationTime(localIterationDuration, localRepeatedDuration, scaledActiveTime, startOffset, m_specified); 114 115 currentIteration = calculateCurrentIteration(localIterationDuration, iterationTime, scaledActiveTime, m_specified); 116 timeFraction = calculateTransformedTime(currentIteration, localIterationDuration, iterationTime, m_specified); 117 } 118 119 m_calculated.currentIteration = currentIteration; 120 m_calculated.activeDuration = activeDuration; 121 m_calculated.timeFraction = timeFraction; 122 123 m_calculated.phase = currentPhase; 124 m_calculated.isInEffect = !isNull(activeTime); 125 m_calculated.isInPlay = phase() == PhaseActive && (!m_parent || m_parent->isInPlay()); 126 m_calculated.isCurrent = phase() == PhaseBefore || isInPlay() || (m_parent && m_parent->isCurrent()); 127 } 128 129 // Test for events even if timing didn't need an update as the player may have gained a start time. 130 // FIXME: Refactor so that we can ASSERT(m_player) here, this is currently required to be nullable for testing. 131 if (!m_player || m_player->hasStartTime()) { 132 // This logic is specific to CSS animation events and assumes that all 133 // animations start after the DocumentTimeline has started. 134 if (m_eventDelegate && (m_isFirstSample || previousPhase != phase() || (phase() == PhaseActive && previousIteration != m_calculated.currentIteration))) 135 m_eventDelegate->onEventCondition(this, m_isFirstSample, previousPhase, previousIteration); 136 m_isFirstSample = false; 137 } 138 139 bool didTriggerStyleRecalc = false; 140 if (needsUpdate) { 141 // FIXME: This probably shouldn't be recursive. 142 didTriggerStyleRecalc = updateChildrenAndEffects(); 143 m_calculated.timeToEffectChange = calculateTimeToEffectChange(localTime, timeToNextIteration); 144 } 145 return didTriggerStyleRecalc; 146 } 147 148 } // namespace WebCore 149