[Web Animations] Ensure renderers with accelerated animations have layers
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 17:44:39 +0000 (17:44 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 17:44:39 +0000 (17:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189990

Reviewed by Simon Fraser.

In r236501 we added code that would make a RenderBox and a RenderInline query the document timeline for whether a given element has
accelerated animations running on it. Since the calls to requiresLayer() are in a hot path, we instead keep a list of elements with
exclusively accelerated animations running.

No new tests, this is already covered by webanimations/accelerated-animation-with-delay.html and webanimations/opacity-animation-yields-compositing-span.html
which respectively check that we can apply an accelerated animation to a non-positioned block and an inline element.

* animation/AnimationTimeline.h:
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::detachFromDocument):
(WebCore::DocumentTimeline::animationWasAddedToElement):
(WebCore::DocumentTimeline::animationWasRemovedFromElement):
(WebCore::DocumentTimeline::animationAcceleratedRunningStateDidChange):
(WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement): Iterate over an element's animations to determine
whether all of its animations are running accelerated, then update the HashSet containing elements running accelerated animations to remove or
add this element.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated const): Make a simple contains() call on the HashSet containing elements
running accelerated animations.
* animation/DocumentTimeline.h:
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::KeyframeEffectReadOnly::updateAcceleratedAnimationState):
(WebCore::KeyframeEffectReadOnly::applyPendingAcceleratedActions):
* rendering/RenderBoxModelObject.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236670 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/animation/AnimationTimeline.h
Source/WebCore/animation/DocumentTimeline.cpp
Source/WebCore/animation/DocumentTimeline.h
Source/WebCore/animation/KeyframeEffectReadOnly.cpp
Source/WebCore/rendering/RenderBoxModelObject.h

index e0b34da..e6a5649 100644 (file)
@@ -1,3 +1,34 @@
+2018-10-01  Antoine Quint  <graouts@apple.com>
+
+        [Web Animations] Ensure renderers with accelerated animations have layers
+        https://bugs.webkit.org/show_bug.cgi?id=189990
+
+        Reviewed by Simon Fraser.
+
+        In r236501 we added code that would make a RenderBox and a RenderInline query the document timeline for whether a given element has
+        accelerated animations running on it. Since the calls to requiresLayer() are in a hot path, we instead keep a list of elements with
+        exclusively accelerated animations running.
+
+        No new tests, this is already covered by webanimations/accelerated-animation-with-delay.html and webanimations/opacity-animation-yields-compositing-span.html
+        which respectively check that we can apply an accelerated animation to a non-positioned block and an inline element.
+
+        * animation/AnimationTimeline.h:
+        * animation/DocumentTimeline.cpp:
+        (WebCore::DocumentTimeline::detachFromDocument):
+        (WebCore::DocumentTimeline::animationWasAddedToElement):
+        (WebCore::DocumentTimeline::animationWasRemovedFromElement):
+        (WebCore::DocumentTimeline::animationAcceleratedRunningStateDidChange):
+        (WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement): Iterate over an element's animations to determine
+        whether all of its animations are running accelerated, then update the HashSet containing elements running accelerated animations to remove or
+        add this element.
+        (WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated const): Make a simple contains() call on the HashSet containing elements
+        running accelerated animations.
+        * animation/DocumentTimeline.h:
+        * animation/KeyframeEffectReadOnly.cpp:
+        (WebCore::KeyframeEffectReadOnly::updateAcceleratedAnimationState):
+        (WebCore::KeyframeEffectReadOnly::applyPendingAcceleratedActions):
+        * rendering/RenderBoxModelObject.h:
+
 2018-10-01  Alicia Boya GarcĂ­a  <aboya@igalia.com>
 
         [GStreamer] Fix abort in gst_sample_get_info()
index 8848ca6..754cf03 100644 (file)
@@ -63,8 +63,8 @@ public:
     void elementWasRemoved(Element&);
     void removeAnimationsForElement(Element&);
     void cancelDeclarativeAnimationsForElement(Element&);
-    void animationWasAddedToElement(WebAnimation&, Element&);
-    void animationWasRemovedFromElement(WebAnimation&, Element&);
+    virtual void animationWasAddedToElement(WebAnimation&, Element&);
+    virtual void animationWasRemovedFromElement(WebAnimation&, Element&);
 
     void updateCSSAnimationsForElement(Element&, const RenderStyle* currentStyle, const RenderStyle& afterChangeStyle);
     void updateCSSTransitionsForElement(Element&, const RenderStyle& currentStyle, const RenderStyle& afterChangeStyle);
index 7564258..893be02 100644 (file)
@@ -72,6 +72,7 @@ void DocumentTimeline::detachFromDocument()
     m_invalidationTaskQueue.close();
     m_eventDispatchTaskQueue.close();
     m_animationScheduleTimer.stop();
+    m_elementsWithRunningAcceleratedAnimations.clear();
 
     auto& animationsToRemove = animations();
     while (!animationsToRemove.isEmpty())
@@ -397,9 +398,43 @@ std::unique_ptr<RenderStyle> DocumentTimeline::animatedStyleForRenderer(RenderEl
     return result;
 }
 
+void DocumentTimeline::animationWasAddedToElement(WebAnimation& animation, Element& element)
+{
+    AnimationTimeline::animationWasAddedToElement(animation, element);
+    updateListOfElementsWithRunningAcceleratedAnimationsForElement(element);
+}
+
+void DocumentTimeline::animationWasRemovedFromElement(WebAnimation& animation, Element& element)
+{
+    AnimationTimeline::animationWasRemovedFromElement(animation, element);
+    updateListOfElementsWithRunningAcceleratedAnimationsForElement(element);
+}
+
 void DocumentTimeline::animationAcceleratedRunningStateDidChange(WebAnimation& animation)
 {
     m_acceleratedAnimationsPendingRunningStateChange.add(&animation);
+
+    if (is<KeyframeEffectReadOnly>(animation.effect())) {
+        if (auto* target = downcast<KeyframeEffectReadOnly>(animation.effect())->target())
+            updateListOfElementsWithRunningAcceleratedAnimationsForElement(*target);
+    }
+}
+
+void DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element& element)
+{
+    auto animations = animationsForElement(element);
+    bool runningAnimationsForElementAreAllAccelerated = !animations.isEmpty();
+    for (const auto& animation : animations) {
+        if (is<KeyframeEffectReadOnly>(animation->effect()) && !downcast<KeyframeEffectReadOnly>(animation->effect())->isRunningAccelerated()) {
+            runningAnimationsForElementAreAllAccelerated = false;
+            break;
+        }
+    }
+
+    if (runningAnimationsForElementAreAllAccelerated)
+        m_elementsWithRunningAcceleratedAnimations.add(&element);
+    else
+        m_elementsWithRunningAcceleratedAnimations.remove(&element);
 }
 
 void DocumentTimeline::applyPendingAcceleratedAnimations()
@@ -448,15 +483,7 @@ bool DocumentTimeline::resolveAnimationsForElement(Element& element, RenderStyle
 
 bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element) const
 {
-    // FIXME: This will let animations run using hardware compositing even if later in the active
-    // span of the current animations a new animation should require hardware compositing to be
-    // disabled (webkit.org/b/179974).
-    auto animations = animationsForElement(element);
-    for (const auto& animation : animations) {
-        if (is<KeyframeEffectReadOnly>(animation->effect()) && !downcast<KeyframeEffectReadOnly>(animation->effect())->isRunningAccelerated())
-            return false;
-    }
-    return !animations.isEmpty();
+    return m_elementsWithRunningAcceleratedAnimations.contains(&element);
 }
 
 void DocumentTimeline::enqueueAnimationPlaybackEvent(AnimationPlaybackEvent& event)
index 714eca2..c2f0b56 100644 (file)
@@ -50,6 +50,9 @@ public:
 
     void timingModelDidChange() override;
 
+    void animationWasAddedToElement(WebAnimation&, Element&) final;
+    void animationWasRemovedFromElement(WebAnimation&, Element&) final;
+
     // If possible, compute the visual extent of any transform animation on the given renderer
     // using the given rect, returning the result in the rect. Return false if there is some
     // transform animation but we were unable to cheaply compute its effect on the extent.
@@ -89,6 +92,7 @@ private:
     void updateAnimations();
     void performEventDispatchTask();
     void maybeClearCachedCurrentTime();
+    void updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element&);
 
     RefPtr<Document> m_document;
     Seconds m_originTime;
@@ -103,6 +107,7 @@ private:
     HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange;
     Vector<Ref<AnimationPlaybackEvent>> m_pendingAnimationEvents;
     unsigned m_numberOfAnimationTimelineInvalidationsForTesting { 0 };
+    HashSet<Element*> m_elementsWithRunningAcceleratedAnimations;
 
 #if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     void animationResolutionTimerFired();
index 97372b7..2537083 100644 (file)
@@ -1231,6 +1231,7 @@ void KeyframeEffectReadOnly::updateAcceleratedAnimationState()
         else {
             m_lastRecordedAcceleratedAction = AcceleratedAction::Stop;
             m_pendingAcceleratedActions.clear();
+            animation()->acceleratedStateDidChange();
         }
         return;
     }
@@ -1294,6 +1295,7 @@ void KeyframeEffectReadOnly::applyPendingAcceleratedActions()
             if (!compositedRenderer->startAnimation(timeOffset, backingAnimationForCompositedRenderer().ptr(), m_blendingKeyframes)) {
                 m_shouldRunAccelerated = false;
                 m_lastRecordedAcceleratedAction = AcceleratedAction::Stop;
+                animation()->acceleratedStateDidChange();
                 return;
             }
             break;
index 6eeb8a4..94b69a1 100644 (file)
@@ -241,6 +241,8 @@ public:
     void removeFromContinuationChain();
 
     virtual LayoutRect paintRectToClipOutFromBorder(const LayoutRect&) { return LayoutRect(); };
+
+    bool hasRunningAcceleratedAnimations() const;
     
 protected:
     RenderBoxModelObject(Element&, RenderStyle&&, BaseTypeFlags);
@@ -270,8 +272,6 @@ protected:
 
     DecodingMode decodingModeForImageDraw(const Image&, const PaintInfo&) const;
 
-    bool hasRunningAcceleratedAnimations() const;
-
 public:
     // For RenderBlocks and RenderInlines with m_style->styleType() == PseudoId::FirstLetter, this tracks their remaining text fragments
     RenderTextFragment* firstLetterRemainingText() const;