[Payment Request] Crash in PaymentRequest::canMakePayment() when Apple Pay payment...
[WebKit-https.git] / Source / WebCore / animation / AnimationEffect.cpp
1 /*
2  * Copyright (C) 2017 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "AnimationEffect.h"
28
29 #include "AnimationEffectTiming.h"
30 #include "FillMode.h"
31 #include "JSComputedTimingProperties.h"
32 #include "WebAnimationUtilities.h"
33
34 namespace WebCore {
35
36 const auto timeEpsilon = Seconds::fromMilliseconds(0.001);
37
38 AnimationEffect::AnimationEffect(ClassType classType)
39     : m_classType(classType)
40 {
41     m_timing = AnimationEffectTiming::create();
42 }
43
44 std::optional<Seconds> AnimationEffect::localTime() const
45 {
46     if (m_animation)
47         return m_animation->currentTime();
48     return std::nullopt;
49 }
50
51 auto AnimationEffect::phase() const -> Phase
52 {
53     // 3.5.5. Animation effect phases and states
54     // https://drafts.csswg.org/web-animations-1/#animation-effect-phases-and-states
55
56     bool animationIsBackwards = m_animation && m_animation->playbackRate() < 0;
57     auto beforeActiveBoundaryTime = std::max(std::min(m_timing->delay(), m_timing->endTime()), 0_s);
58     auto activeAfterBoundaryTime = std::max(std::min(m_timing->delay() + m_timing->activeDuration(), m_timing->endTime()), 0_s);
59
60     // (This should be the last statement, but it's more efficient to cache the local time and return right away if it's not resolved.)
61     // Furthermore, it is often convenient to refer to the case when an animation effect is in none of the above phases
62     // as being in the idle phase.
63     auto effectLocalTime = localTime();
64     if (!effectLocalTime)
65         return Phase::Idle;
66
67     auto localTimeValue = effectLocalTime.value();
68
69     // An animation effect is in the before phase if the animation effect’s local time is not unresolved and
70     // either of the following conditions are met:
71     //     1. the local time is less than the before-active boundary time, or
72     //     2. the animation direction is ‘backwards’ and the local time is equal to the before-active boundary time.
73     if ((localTimeValue + timeEpsilon) < beforeActiveBoundaryTime || (animationIsBackwards && std::abs(localTimeValue.microseconds() - beforeActiveBoundaryTime.microseconds()) < timeEpsilon.microseconds()))
74         return Phase::Before;
75
76     // An animation effect is in the after phase if the animation effect’s local time is not unresolved and
77     // either of the following conditions are met:
78     //     1. the local time is greater than the active-after boundary time, or
79     //     2. the animation direction is ‘forwards’ and the local time is equal to the active-after boundary time.
80     if ((localTimeValue - timeEpsilon) > activeAfterBoundaryTime || (!animationIsBackwards && std::abs(localTimeValue.microseconds() - activeAfterBoundaryTime.microseconds()) < timeEpsilon.microseconds()))
81         return Phase::After;
82
83     // An animation effect is in the active phase if the animation effect’s local time is not unresolved and it is not
84     // in either the before phase nor the after phase.
85     // (No need to check, we've already established that local time was resolved).
86     return Phase::Active;
87 }
88
89 std::optional<Seconds> AnimationEffect::activeTime() const
90 {
91     // 3.8.3.1. Calculating the active time
92     // https://drafts.csswg.org/web-animations-1/#calculating-the-active-time
93
94     // The active time is based on the local time and start delay. However, it is only defined
95     // when the animation effect should produce an output and hence depends on its fill mode
96     // and phase as follows,
97
98     auto effectPhase = phase();
99
100     // If the animation effect is in the before phase, the result depends on the first matching
101     // condition from the following,
102     if (effectPhase == Phase::Before) {
103         // If the fill mode is backwards or both, return the result of evaluating
104         // max(local time - start delay, 0).
105         if (m_timing->fill() == FillMode::Backwards || m_timing->fill() == FillMode::Both)
106             return std::max(localTime().value() - m_timing->delay(), 0_s);
107         // Otherwise, return an unresolved time value.
108         return std::nullopt;
109     }
110
111     // If the animation effect is in the active phase, return the result of evaluating local time - start delay.
112     if (effectPhase == Phase::Active)
113         return localTime().value() - m_timing->delay();
114
115     // If the animation effect is in the after phase, the result depends on the first matching
116     // condition from the following,
117     if (effectPhase == Phase::After) {
118         // If the fill mode is forwards or both, return the result of evaluating
119         // max(min(local time - start delay, active duration), 0).
120         if (m_timing->fill() == FillMode::Forwards || m_timing->fill() == FillMode::Both)
121             return std::max(std::min(localTime().value() - m_timing->delay(), m_timing->activeDuration()), 0_s);
122         // Otherwise, return an unresolved time value.
123         return std::nullopt;
124     }
125
126     // Otherwise (the local time is unresolved), return an unresolved time value.
127     return std::nullopt;
128 }
129
130 std::optional<double> AnimationEffect::overallProgress() const
131 {
132     // 3.8.3.2. Calculating the overall progress
133     // https://drafts.csswg.org/web-animations-1/#calculating-the-overall-progress
134
135     // The overall progress describes the number of iterations that have completed (including partial iterations) and is defined as follows:
136
137     // 1. If the active time is unresolved, return unresolved.
138     auto effectActiveTime = activeTime();
139     if (!effectActiveTime)
140         return std::nullopt;
141
142     // 2. Calculate an initial value for overall progress based on the first matching condition from below,
143     double overallProgress;
144
145     if (!m_timing->iterationDuration()) {
146         // If the iteration duration is zero, if the animation effect is in the before phase, let overall progress be zero,
147         // otherwise, let it be equal to the iteration count.
148         overallProgress = phase() == Phase::Before ? 0 : m_timing->iterations();
149     } else {
150         // Otherwise, let overall progress be the result of calculating active time / iteration duration.
151         overallProgress = secondsToWebAnimationsAPITime(effectActiveTime.value()) / secondsToWebAnimationsAPITime(m_timing->iterationDuration());
152     }
153
154     // 3. Return the result of calculating overall progress + iteration start.
155     overallProgress += m_timing->iterationStart();
156     return std::abs(overallProgress);
157 }
158
159 std::optional<double> AnimationEffect::simpleIterationProgress() const
160 {
161     // 3.8.3.3. Calculating the simple iteration progress
162     // https://drafts.csswg.org/web-animations-1/#calculating-the-simple-iteration-progress
163
164     // The simple iteration progress is a fraction of the progress through the current iteration that
165     // ignores transformations to the time introduced by the playback direction or timing functions
166     // applied to the effect, and is calculated as follows:
167
168     // 1. If the overall progress is unresolved, return unresolved.
169     auto effectOverallProgress = overallProgress();
170     if (!effectOverallProgress)
171         return std::nullopt;
172
173     // 2. If overall progress is infinity, let the simple iteration progress be iteration start % 1.0,
174     // otherwise, let the simple iteration progress be overall progress % 1.0.
175     double overallProgressValue = effectOverallProgress.value();
176     double simpleIterationProgress = std::isinf(overallProgressValue) ? fmod(m_timing->iterationStart(), 1) : fmod(overallProgressValue, 1);
177
178     // 3. If all of the following conditions are true,
179     //
180     // the simple iteration progress calculated above is zero, and
181     // the animation effect is in the active phase or the after phase, and
182     // the active time is equal to the active duration, and
183     // the iteration count is not equal to zero.
184     // let the simple iteration progress be 1.0.
185     auto effectPhase = phase();
186     if (!simpleIterationProgress && (effectPhase == Phase::Active || effectPhase == Phase::After) && std::abs(activeTime().value().microseconds() - m_timing->activeDuration().microseconds()) < timeEpsilon.microseconds() && m_timing->iterations())
187         return 1;
188
189     return simpleIterationProgress;
190 }
191
192 std::optional<double> AnimationEffect::currentIteration() const
193 {
194     // 3.8.4. Calculating the current iteration
195     // https://drafts.csswg.org/web-animations-1/#calculating-the-current-iteration
196
197     // The current iteration can be calculated using the following steps:
198
199     // 1. If the active time is unresolved, return unresolved.
200     if (!activeTime())
201         return std::nullopt;
202
203     // 2. If the animation effect is in the after phase and the iteration count is infinity, return infinity.
204     if (phase() == Phase::After && std::isinf(m_timing->iterations()))
205         return std::numeric_limits<double>::infinity();
206
207     // 3. If the simple iteration progress is 1.0, return floor(overall progress) - 1.
208     if (simpleIterationProgress().value() == 1)
209         return floor(overallProgress().value()) - 1;
210
211     // 4. Otherwise, return floor(overall progress).
212     return floor(overallProgress().value());
213 }
214
215 AnimationEffect::ComputedDirection AnimationEffect::currentDirection() const
216 {
217     // 3.9.1. Calculating the directed progress
218     // https://drafts.csswg.org/web-animations-1/#calculating-the-directed-progress
219
220     // If playback direction is normal, let the current direction be forwards.
221     if (m_timing->direction() == PlaybackDirection::Normal)
222         return AnimationEffect::ComputedDirection::Forwards;
223     
224     // If playback direction is reverse, let the current direction be reverse.
225     if (m_timing->direction() == PlaybackDirection::Reverse)
226         return AnimationEffect::ComputedDirection::Reverse;
227     
228     // Otherwise, let d be the current iteration.
229     auto d = currentIteration().value();
230     // If playback direction is alternate-reverse increment d by 1.
231     if (m_timing->direction() == PlaybackDirection::AlternateReverse)
232         d++;
233     // If d % 2 == 0, let the current direction be forwards, otherwise let the current direction be reverse.
234     // If d is infinity, let the current direction be forwards.
235     if (std::isinf(d) || !fmod(d, 2))
236         return AnimationEffect::ComputedDirection::Forwards;
237     return AnimationEffect::ComputedDirection::Reverse;
238 }
239
240 std::optional<double> AnimationEffect::directedProgress() const
241 {
242     // 3.9.1. Calculating the directed progress
243     // https://drafts.csswg.org/web-animations-1/#calculating-the-directed-progress
244
245     // The directed progress is calculated from the simple iteration progress using the following steps:
246
247     // 1. If the simple iteration progress is unresolved, return unresolved.
248     auto effectSimpleIterationProgress = simpleIterationProgress();
249     if (!effectSimpleIterationProgress)
250         return std::nullopt;
251
252     // 2. Calculate the current direction (we implement this as a separate method).
253
254     // 3. If the current direction is forwards then return the simple iteration progress.
255     if (currentDirection() == AnimationEffect::ComputedDirection::Forwards)
256         return effectSimpleIterationProgress.value();
257
258     // Otherwise, return 1.0 - simple iteration progress.
259     return 1 - effectSimpleIterationProgress.value();
260 }
261
262 std::optional<double> AnimationEffect::transformedProgress() const
263 {
264     // 3.10.1. Calculating the transformed progress
265     // https://drafts.csswg.org/web-animations-1/#calculating-the-transformed-progress
266
267     // The transformed progress is calculated from the directed progress using the following steps:
268     //
269     // 1. If the directed progress is unresolved, return unresolved.
270     auto effectDirectedProgress = directedProgress();
271     if (!effectDirectedProgress)
272         return std::nullopt;
273
274     auto effectDirectedProgressValue = effectDirectedProgress.value();
275
276     if (auto iterationDuration = m_timing->iterationDuration().seconds()) {
277         bool before = false;
278         auto* timingFunction = m_timing->timingFunction();
279         // 2. Calculate the value of the before flag as follows:
280         if (is<StepsTimingFunction>(timingFunction)) {
281             // 1. Determine the current direction using the procedure defined in §3.9.1 Calculating the directed progress.
282             // 2. If the current direction is forwards, let going forwards be true, otherwise it is false.
283             bool goingForwards = currentDirection() == AnimationEffect::ComputedDirection::Forwards;
284             // 3. The before flag is set if the animation effect is in the before phase and going forwards is true;
285             //    or if the animation effect is in the after phase and going forwards is false.
286             auto effectPhase = phase();
287             before = (effectPhase == Phase::Before && goingForwards) || (effectPhase == Phase::After && !goingForwards);
288         }
289
290         // 3. Return the result of evaluating the animation effect’s timing function passing directed progress as the
291         //    input progress value and before flag as the before flag.
292         return timingFunction->transformTime(effectDirectedProgressValue, iterationDuration, before);
293     }
294
295     return effectDirectedProgressValue;
296 }
297
298 std::optional<double> AnimationEffect::iterationProgress() const
299 {
300     return transformedProgress();
301 }
302
303 ComputedTimingProperties AnimationEffect::getComputedTiming()
304 {
305     ComputedTimingProperties computedTiming;
306     computedTiming.delay = m_timing->bindingsDelay();
307     computedTiming.endDelay = m_timing->bindingsEndDelay();
308     auto fillMode = m_timing->fill();
309     computedTiming.fill = fillMode == FillMode::Auto ? FillMode::None : fillMode;
310     computedTiming.iterationStart = m_timing->iterationStart();
311     computedTiming.iterations = m_timing->iterations();
312     computedTiming.duration = secondsToWebAnimationsAPITime(m_timing->iterationDuration());
313     computedTiming.direction = m_timing->direction();
314     computedTiming.easing = m_timing->easing();
315     computedTiming.endTime = secondsToWebAnimationsAPITime(m_timing->endTime());
316     computedTiming.activeDuration = secondsToWebAnimationsAPITime(m_timing->activeDuration());
317     if (auto effectLocalTime = localTime())
318         computedTiming.localTime = secondsToWebAnimationsAPITime(effectLocalTime.value());
319     computedTiming.progress = iterationProgress();
320     computedTiming.currentIteration = currentIteration();
321     return computedTiming;
322 }
323
324 } // namespace WebCore