[Web Animations] Schedule animations registered on the document timeline
[WebKit-https.git] / Source / WebCore / animation / WebAnimation.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 "WebAnimation.h"
28
29 #include "AnimationEffect.h"
30 #include "AnimationTimeline.h"
31 #include "Document.h"
32 #include <wtf/text/WTFString.h>
33
34 namespace WebCore {
35
36 Ref<WebAnimation> WebAnimation::create(Document& document, AnimationEffect* effect, AnimationTimeline* timeline)
37 {
38     auto result = adoptRef(*new WebAnimation());
39
40     result->setEffect(effect);
41     
42     // FIXME: the spec mandates distinguishing between an omitted timeline parameter
43     // and an explicit null or undefined value (webkit.org/b/179065).
44     result->setTimeline(timeline ? timeline : &document.timeline());
45
46     return result;
47 }
48
49 WebAnimation::WebAnimation()
50 {
51 }
52
53 WebAnimation::~WebAnimation()
54 {
55     if (m_timeline)
56         m_timeline->removeAnimation(*this);
57 }
58
59 void WebAnimation::setEffect(RefPtr<AnimationEffect>&& effect)
60 {
61     if (effect == m_effect)
62         return;
63
64     m_effect = WTFMove(effect);
65 }
66
67 void WebAnimation::setTimeline(RefPtr<AnimationTimeline>&& timeline)
68 {
69     if (timeline == m_timeline)
70         return;
71
72     // FIXME: If the animation start time of animation is resolved, make animation’s
73     // hold time unresolved (webkit.org/b/178932).
74
75     if (m_timeline)
76         m_timeline->removeAnimation(*this);
77
78     if (timeline)
79         timeline->addAnimation(*this);
80
81     m_timeline = WTFMove(timeline);
82 }
83     
84 std::optional<double> WebAnimation::bindingsStartTime() const
85 {
86     if (m_startTime)
87         return m_startTime->value();
88     return std::nullopt;
89 }
90
91 void WebAnimation::setBindingsStartTime(std::optional<double> startTime)
92 {
93     if (startTime == std::nullopt)
94         setStartTime(std::nullopt);
95     else
96         setStartTime(Seconds(startTime.value()));
97 }
98
99 std::optional<Seconds> WebAnimation::startTime() const
100 {
101     return m_startTime;
102 }
103
104 void WebAnimation::setStartTime(std::optional<Seconds> startTime)
105 {
106     if (startTime == m_startTime)
107         return;
108
109     m_startTime = startTime;
110     
111     if (m_timeline)
112         m_timeline->animationTimingModelDidChange();
113 }
114
115 std::optional<double> WebAnimation::bindingsCurrentTime() const
116 {
117     auto time = currentTime();
118     if (!time)
119         return std::nullopt;
120     return time->value();
121 }
122
123 ExceptionOr<void> WebAnimation::setBindingsCurrentTime(std::optional<double> currentTime)
124 {
125     if (!currentTime)
126         return Exception { TypeError };
127     setCurrentTime(Seconds(currentTime.value()));
128     return { };
129 }
130
131 std::optional<Seconds> WebAnimation::currentTime() const
132 {
133     // FIXME: return the hold time when we support pausing (webkit.org/b/178932).
134
135     if (!m_timeline || !m_startTime)
136         return std::nullopt;
137
138     auto timelineTime = m_timeline->currentTime();
139     if (!timelineTime)
140         return std::nullopt;
141
142     return (timelineTime.value() - m_startTime.value()) * m_playbackRate;
143 }
144
145 void WebAnimation::setCurrentTime(std::optional<Seconds> seekTime)
146 {
147     // FIXME: account for hold time when we support it (webkit.org/b/178932),
148     // including situations where playbackRate is 0.
149
150     if (!m_timeline) {
151         setStartTime(std::nullopt);
152         return;
153     }
154
155     auto timelineTime = m_timeline->currentTime();
156     if (!timelineTime) {
157         setStartTime(std::nullopt);
158         return;
159     }
160
161     setStartTime(timelineTime.value() - (seekTime.value() / m_playbackRate));
162 }
163
164 void WebAnimation::setPlaybackRate(double newPlaybackRate)
165 {
166     if (m_playbackRate == newPlaybackRate)
167         return;
168
169     // 3.5.17.1. Updating the playback rate of an animation
170     // Changes to the playback rate trigger a compensatory seek so that that the animation's current time
171     // is unaffected by the change to the playback rate.
172     auto previousTime = currentTime();
173     m_playbackRate = newPlaybackRate;
174     if (previousTime)
175         setCurrentTime(previousTime);
176 }
177
178 Seconds WebAnimation::timeToNextRequiredTick(Seconds timelineTime) const
179 {
180     if (!m_timeline || !m_startTime || !m_effect || !m_playbackRate)
181         return Seconds::infinity();
182
183     auto startTime = m_startTime.value();
184     auto endTime = startTime + (m_effect->timing()->duration() / m_playbackRate);
185
186     // If we haven't started yet, return the interval until our active start time.
187     auto activeStartTime = std::min(startTime, endTime);
188     if (timelineTime <= activeStartTime)
189         return activeStartTime - timelineTime;
190
191     // If we're in the middle of our active duration, we want to be called as soon as possible.
192     auto activeEndTime = std::max(startTime, endTime);
193     if (timelineTime <= activeEndTime)
194         return 0_ms;
195
196     // If none of the previous cases match, then we're already past our active duration
197     // and do not need scheduling.
198     return Seconds::infinity();
199 }
200
201 String WebAnimation::description()
202 {
203     return "Animation";
204 }
205
206 } // namespace WebCore