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 #ifndef TimingCalculations_h 32 #define TimingCalculations_h 33 34 #include "core/animation/AnimationNode.h" 35 #include "core/animation/Timing.h" 36 #include "platform/animation/AnimationUtilities.h" 37 #include "wtf/MathExtras.h" 38 39 namespace blink { 40 41 static inline double multiplyZeroAlwaysGivesZero(double x, double y) 42 { 43 ASSERT(!isNull(x)); 44 ASSERT(!isNull(y)); 45 return x && y ? x * y : 0; 46 } 47 48 static inline AnimationNode::Phase calculatePhase(double activeDuration, double localTime, const Timing& specified) 49 { 50 ASSERT(activeDuration >= 0); 51 if (isNull(localTime)) 52 return AnimationNode::PhaseNone; 53 if (localTime < specified.startDelay) 54 return AnimationNode::PhaseBefore; 55 if (localTime >= specified.startDelay + activeDuration) 56 return AnimationNode::PhaseAfter; 57 return AnimationNode::PhaseActive; 58 } 59 60 static inline bool isActiveInParentPhase(AnimationNode::Phase parentPhase, Timing::FillMode fillMode) 61 { 62 switch (parentPhase) { 63 case AnimationNode::PhaseBefore: 64 return fillMode == Timing::FillModeBackwards || fillMode == Timing::FillModeBoth; 65 case AnimationNode::PhaseActive: 66 return true; 67 case AnimationNode::PhaseAfter: 68 return fillMode == Timing::FillModeForwards || fillMode == Timing::FillModeBoth; 69 default: 70 ASSERT_NOT_REACHED(); 71 return false; 72 } 73 } 74 75 static inline double calculateActiveTime(double activeDuration, Timing::FillMode fillMode, double localTime, AnimationNode::Phase parentPhase, AnimationNode::Phase phase, const Timing& specified) 76 { 77 ASSERT(activeDuration >= 0); 78 ASSERT(phase == calculatePhase(activeDuration, localTime, specified)); 79 80 switch (phase) { 81 case AnimationNode::PhaseBefore: 82 if (fillMode == Timing::FillModeBackwards || fillMode == Timing::FillModeBoth) 83 return 0; 84 return nullValue(); 85 case AnimationNode::PhaseActive: 86 if (isActiveInParentPhase(parentPhase, fillMode)) 87 return localTime - specified.startDelay; 88 return nullValue(); 89 case AnimationNode::PhaseAfter: 90 if (fillMode == Timing::FillModeForwards || fillMode == Timing::FillModeBoth) 91 return activeDuration; 92 return nullValue(); 93 case AnimationNode::PhaseNone: 94 ASSERT(isNull(localTime)); 95 return nullValue(); 96 default: 97 ASSERT_NOT_REACHED(); 98 return nullValue(); 99 } 100 } 101 102 static inline double calculateScaledActiveTime(double activeDuration, double activeTime, double startOffset, const Timing& specified) 103 { 104 ASSERT(activeDuration >= 0); 105 ASSERT(startOffset >= 0); 106 107 if (isNull(activeTime)) 108 return nullValue(); 109 110 ASSERT(activeTime >= 0 && activeTime <= activeDuration); 111 return multiplyZeroAlwaysGivesZero(specified.playbackRate < 0 ? activeTime - activeDuration : activeTime, specified.playbackRate) + startOffset; 112 } 113 114 static inline bool endsOnIterationBoundary(double iterationCount, double iterationStart) 115 { 116 ASSERT(std::isfinite(iterationCount)); 117 return !fmod(iterationCount + iterationStart, 1); 118 } 119 120 static inline double calculateIterationTime(double iterationDuration, double repeatedDuration, double scaledActiveTime, double startOffset, const Timing& specified) 121 { 122 ASSERT(iterationDuration > 0); 123 ASSERT(repeatedDuration == multiplyZeroAlwaysGivesZero(iterationDuration, specified.iterationCount)); 124 125 if (isNull(scaledActiveTime)) 126 return nullValue(); 127 128 ASSERT(scaledActiveTime >= 0); 129 ASSERT(scaledActiveTime <= repeatedDuration + startOffset); 130 131 if (!std::isfinite(scaledActiveTime) 132 || (scaledActiveTime - startOffset == repeatedDuration && specified.iterationCount && endsOnIterationBoundary(specified.iterationCount, specified.iterationStart))) 133 return iterationDuration; 134 135 ASSERT(std::isfinite(scaledActiveTime)); 136 return fmod(scaledActiveTime, iterationDuration); 137 } 138 139 static inline double calculateCurrentIteration(double iterationDuration, double iterationTime, double scaledActiveTime, const Timing& specified) 140 { 141 ASSERT(iterationDuration > 0); 142 ASSERT(isNull(iterationTime) || iterationTime >= 0); 143 144 if (isNull(scaledActiveTime)) 145 return nullValue(); 146 147 ASSERT(iterationTime >= 0); 148 ASSERT(iterationTime <= iterationDuration); 149 ASSERT(scaledActiveTime >= 0); 150 151 if (!scaledActiveTime) 152 return 0; 153 154 if (iterationTime == iterationDuration) 155 return specified.iterationStart + specified.iterationCount - 1; 156 157 return floor(scaledActiveTime / iterationDuration); 158 } 159 160 static inline double calculateDirectedTime(double currentIteration, double iterationDuration, double iterationTime, const Timing& specified) 161 { 162 ASSERT(isNull(currentIteration) || currentIteration >= 0); 163 ASSERT(iterationDuration > 0); 164 165 if (isNull(iterationTime)) 166 return nullValue(); 167 168 ASSERT(currentIteration >= 0); 169 ASSERT(iterationTime >= 0); 170 ASSERT(iterationTime <= iterationDuration); 171 172 const bool currentIterationIsOdd = fmod(currentIteration, 2) >= 1; 173 const bool currentDirectionIsForwards = specified.direction == Timing::PlaybackDirectionNormal 174 || (specified.direction == Timing::PlaybackDirectionAlternate && !currentIterationIsOdd) 175 || (specified.direction == Timing::PlaybackDirectionAlternateReverse && currentIterationIsOdd); 176 177 return currentDirectionIsForwards ? iterationTime : iterationDuration - iterationTime; 178 } 179 180 static inline double calculateTransformedTime(double currentIteration, double iterationDuration, double iterationTime, const Timing& specified) 181 { 182 ASSERT(isNull(currentIteration) || currentIteration >= 0); 183 ASSERT(iterationDuration > 0); 184 ASSERT(isNull(iterationTime) || (iterationTime >= 0 && iterationTime <= iterationDuration)); 185 186 double directedTime = calculateDirectedTime(currentIteration, iterationDuration, iterationTime, specified); 187 if (isNull(directedTime)) 188 return nullValue(); 189 if (!std::isfinite(iterationDuration)) 190 return directedTime; 191 double timeFraction = directedTime / iterationDuration; 192 ASSERT(timeFraction >= 0 && timeFraction <= 1); 193 return multiplyZeroAlwaysGivesZero(iterationDuration, specified.timingFunction->evaluate(timeFraction, accuracyForDuration(iterationDuration))); 194 } 195 196 } // namespace blink 197 198 #endif 199