[Web Animations] Ensure elements overlapping with elements animating also get composited
[WebKit-https.git] / Source / WebCore / animation / DocumentTimeline.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 "DocumentTimeline.h"
28
29 #include "AnimationPlaybackEvent.h"
30 #include "Chrome.h"
31 #include "ChromeClient.h"
32 #include "DOMWindow.h"
33 #include "DeclarativeAnimation.h"
34 #include "DisplayRefreshMonitor.h"
35 #include "DisplayRefreshMonitorManager.h"
36 #include "Document.h"
37 #include "KeyframeEffect.h"
38 #include "Page.h"
39 #include "RenderElement.h"
40
41 static const Seconds animationInterval { 15_ms };
42
43 namespace WebCore {
44
45 Ref<DocumentTimeline> DocumentTimeline::create(Document& document, PlatformDisplayID displayID)
46 {
47     return adoptRef(*new DocumentTimeline(document, displayID));
48 }
49
50 DocumentTimeline::DocumentTimeline(Document& document, PlatformDisplayID displayID)
51     : AnimationTimeline(DocumentTimelineClass)
52     , m_document(&document)
53     , m_animationScheduleTimer(*this, &DocumentTimeline::animationScheduleTimerFired)
54 #if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
55     , m_animationResolutionTimer(*this, &DocumentTimeline::animationResolutionTimerFired)
56 #endif
57 {
58     windowScreenDidChange(displayID);
59 }
60
61 DocumentTimeline::~DocumentTimeline()
62 {
63     m_invalidationTaskQueue.close();
64     m_eventDispatchTaskQueue.close();
65 }
66
67 void DocumentTimeline::detachFromDocument()
68 {
69     m_document = nullptr;
70 }
71
72 std::optional<Seconds> DocumentTimeline::currentTime()
73 {
74     if (m_paused || !m_document || !m_document->domWindow())
75         return AnimationTimeline::currentTime();
76
77     if (!m_cachedCurrentTime) {
78         m_cachedCurrentTime = Seconds(m_document->domWindow()->nowTimestamp());
79         scheduleInvalidationTaskIfNeeded();
80     }
81     return m_cachedCurrentTime;
82 }
83
84 void DocumentTimeline::pause()
85 {
86     m_paused = true;
87 }
88
89 void DocumentTimeline::timingModelDidChange()
90 {
91     if (m_needsUpdateAnimationSchedule)
92         return;
93
94     m_needsUpdateAnimationSchedule = true;
95
96     // We know that we will resolve animations again, so we can cancel the timer right away.
97     if (m_animationScheduleTimer.isActive())
98         m_animationScheduleTimer.stop();
99
100     scheduleInvalidationTaskIfNeeded();
101 }
102
103 void DocumentTimeline::scheduleInvalidationTaskIfNeeded()
104 {
105     if (m_invalidationTaskQueue.hasPendingTasks())
106         return;
107
108     m_invalidationTaskQueue.enqueueTask(std::bind(&DocumentTimeline::performInvalidationTask, this));
109 }
110
111 void DocumentTimeline::performInvalidationTask()
112 {
113     // Now that the timing model has changed we can see if there are DOM events to dispatch for declarative animations.
114     for (auto& animation : animations()) {
115         if (is<DeclarativeAnimation>(animation))
116             downcast<DeclarativeAnimation>(*animation).invalidateDOMEvents();
117     }
118
119     updateAnimationSchedule();
120     m_cachedCurrentTime = std::nullopt;
121 }
122
123 void DocumentTimeline::updateAnimationSchedule()
124 {
125     if (!m_needsUpdateAnimationSchedule)
126         return;
127
128     m_needsUpdateAnimationSchedule = false;
129
130     if (!m_acceleratedAnimationsPendingRunningStateChange.isEmpty()) {
131         scheduleAnimationResolution();
132         return;
133     }
134
135     Seconds scheduleDelay = Seconds::infinity();
136
137     for (const auto& animation : animations()) {
138         auto animationTimeToNextRequiredTick = animation->timeToNextRequiredTick();
139         if (animationTimeToNextRequiredTick < animationInterval) {
140             scheduleAnimationResolution();
141             return;
142         }
143         scheduleDelay = std::min(scheduleDelay, animationTimeToNextRequiredTick);
144     }
145
146     if (scheduleDelay < Seconds::infinity())
147         m_animationScheduleTimer.startOneShot(scheduleDelay);
148 }
149
150 void DocumentTimeline::animationScheduleTimerFired()
151 {
152     scheduleAnimationResolution();
153 }
154
155 void DocumentTimeline::scheduleAnimationResolution()
156 {
157 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
158     DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this);
159 #else
160     // FIXME: We need to use the same logic as ScriptedAnimationController here,
161     // which will be addressed by the refactor tracked by webkit.org/b/179293.
162     m_animationResolutionTimer.startOneShot(animationInterval);
163 #endif
164 }
165
166 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
167 void DocumentTimeline::displayRefreshFired()
168 #else
169 void DocumentTimeline::animationResolutionTimerFired()
170 #endif
171 {
172     updateAnimations();
173 }
174
175 void DocumentTimeline::updateAnimations()
176 {
177     if (m_document && hasElementAnimations()) {
178         for (const auto& elementToAnimationsMapItem : elementToAnimationsMap())
179             elementToAnimationsMapItem.key->invalidateStyleAndLayerComposition();
180         for (const auto& elementToCSSAnimationsMapItem : elementToCSSAnimationsMap())
181             elementToCSSAnimationsMapItem.key->invalidateStyleAndLayerComposition();
182         for (const auto& elementToCSSTransitionsMapItem : elementToCSSTransitionsMap())
183             elementToCSSTransitionsMapItem.key->invalidateStyleAndLayerComposition();
184         m_document->updateStyleIfNeeded();
185     }
186
187     applyPendingAcceleratedAnimations();
188
189     // Time has advanced, the timing model requires invalidation now.
190     timingModelDidChange();
191 }
192
193 bool DocumentTimeline::computeExtentOfAnimation(RenderElement& renderer, LayoutRect& bounds) const
194 {
195     if (!renderer.element())
196         return true;
197
198     KeyframeEffectReadOnly* matchingEffect;
199     for (const auto& animation : animationsForElement(*renderer.element())) {
200         auto* effect = animation->effect();
201         if (is<KeyframeEffectReadOnly>(effect)) {
202             auto* keyframeEffect = downcast<KeyframeEffectReadOnly>(effect);
203             if (keyframeEffect->animatedProperties().contains(CSSPropertyTransform))
204                 matchingEffect = downcast<KeyframeEffectReadOnly>(effect);
205         }
206     }
207
208     if (matchingEffect)
209         return matchingEffect->computeExtentOfTransformAnimation(bounds);
210
211     return true;
212 }
213
214 bool DocumentTimeline::isRunningAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property) const
215 {
216     if (!renderer.element())
217         return false;
218
219     for (const auto& animation : animationsForElement(*renderer.element())) {
220         auto playState = animation->playState();
221         if (playState != WebAnimation::PlayState::Running && playState != WebAnimation::PlayState::Paused)
222             continue;
223         auto* effect = animation->effect();
224         if (is<KeyframeEffectReadOnly>(effect) && downcast<KeyframeEffectReadOnly>(effect)->animatedProperties().contains(property))
225             return true;
226     }
227
228     return false;
229 }
230
231 bool DocumentTimeline::isRunningAcceleratedAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property) const
232 {
233     if (!renderer.element())
234         return false;
235
236     for (const auto& animation : animationsForElement(*renderer.element())) {
237         auto playState = animation->playState();
238         if (playState != WebAnimation::PlayState::Running && playState != WebAnimation::PlayState::Paused)
239             continue;
240         auto* effect = animation->effect();
241         if (is<KeyframeEffectReadOnly>(effect)) {
242             auto* keyframeEffect = downcast<KeyframeEffectReadOnly>(effect);
243             if (keyframeEffect->isRunningAccelerated() && keyframeEffect->animatedProperties().contains(property))
244                 return true;
245         }
246     }
247
248     return false;
249 }
250
251 std::unique_ptr<RenderStyle> DocumentTimeline::animatedStyleForRenderer(RenderElement& renderer)
252 {
253     std::unique_ptr<RenderStyle> result;
254
255     if (auto* element = renderer.element()) {
256         for (const auto& animation : animationsForElement(*element)) {
257             if (is<KeyframeEffectReadOnly>(animation->effect()))
258                 downcast<KeyframeEffectReadOnly>(animation->effect())->getAnimatedStyle(result);
259         }
260     }
261
262     if (!result)
263         result = RenderStyle::clonePtr(renderer.style());
264
265     return result;
266 }
267
268 void DocumentTimeline::animationAcceleratedRunningStateDidChange(WebAnimation& animation)
269 {
270     m_acceleratedAnimationsPendingRunningStateChange.add(&animation);
271 }
272
273 void DocumentTimeline::applyPendingAcceleratedAnimations()
274 {
275     for (auto& animation : m_acceleratedAnimationsPendingRunningStateChange)
276         animation->applyPendingAcceleratedActions();
277     m_acceleratedAnimationsPendingRunningStateChange.clear();
278 }
279
280 bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element)
281 {
282     // FIXME: This will let animations run using hardware compositing even if later in the active
283     // span of the current animations a new animation should require hardware compositing to be
284     // disabled (webkit.org/b/179974).
285     auto animations = animationsForElement(element);
286     for (const auto& animation : animations) {
287         if (is<KeyframeEffectReadOnly>(animation->effect()) && !downcast<KeyframeEffectReadOnly>(animation->effect())->isRunningAccelerated())
288             return false;
289     }
290     return !animations.isEmpty();
291 }
292
293 void DocumentTimeline::enqueueAnimationPlaybackEvent(AnimationPlaybackEvent& event)
294 {
295     m_pendingAnimationEvents.append(event);
296
297     if (!m_eventDispatchTaskQueue.hasPendingTasks())
298         m_eventDispatchTaskQueue.enqueueTask(std::bind(&DocumentTimeline::performEventDispatchTask, this));
299 }
300
301 static inline bool compareAnimationPlaybackEvents(const Ref<WebCore::AnimationPlaybackEvent>& lhs, const Ref<WebCore::AnimationPlaybackEvent>& rhs)
302 {
303     // Sort the events by their scheduled event time such that events that were scheduled to occur earlier, sort before events scheduled to occur later
304     // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time.
305     if (lhs->timelineTime() && !rhs->timelineTime())
306         return false;
307     if (!lhs->timelineTime() && rhs->timelineTime())
308         return true;
309     if (!lhs->timelineTime() && !rhs->timelineTime())
310         return true;
311     return lhs->timelineTime().value() < rhs->timelineTime().value();
312 }
313
314 void DocumentTimeline::performEventDispatchTask()
315 {
316     if (m_pendingAnimationEvents.isEmpty())
317         return;
318
319     auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents);
320
321     std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), compareAnimationPlaybackEvents);
322     for (auto& pendingEvent : pendingAnimationEvents)
323         pendingEvent->target()->dispatchEvent(pendingEvent);
324 }
325
326 void DocumentTimeline::windowScreenDidChange(PlatformDisplayID displayID)
327 {
328 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
329     DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this);
330 #else
331     UNUSED_PARAM(displayID);
332 #endif
333 }
334
335 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
336 RefPtr<DisplayRefreshMonitor> DocumentTimeline::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
337 {
338     if (!m_document || !m_document->page())
339         return nullptr;
340
341     if (auto monitor = m_document->page()->chrome().client().createDisplayRefreshMonitor(displayID))
342         return monitor;
343
344     return DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(displayID);
345 }
346 #endif
347
348 } // namespace WebCore