Diff
Modified: trunk/LayoutTests/ChangeLog (257137 => 257138)
--- trunk/LayoutTests/ChangeLog 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/LayoutTests/ChangeLog 2020-02-21 17:21:45 UTC (rev 257138)
@@ -1,3 +1,13 @@
+2020-02-21 Simon Fraser <[email protected]>
+
+ [Web Animations] Repeated animations on pseudo elements will fail to run after a while
+ https://bugs.webkit.org/show_bug.cgi?id=207993
+
+ Reviewed by Zalan Bujtas.
+
+ * animations/many-pseudo-animations-expected.txt: Added.
+ * animations/many-pseudo-animations.html: Added.
+
2020-02-21 Frederic Wang <[email protected]>
Update WPT tests for Intersection Observer
Added: trunk/LayoutTests/animations/many-pseudo-animations-expected.txt (0 => 257138)
--- trunk/LayoutTests/animations/many-pseudo-animations-expected.txt (rev 0)
+++ trunk/LayoutTests/animations/many-pseudo-animations-expected.txt 2020-02-21 17:21:45 UTC (rev 257138)
@@ -0,0 +1,19 @@
+Tests that animations on pseudo-elements do not eventually stop working.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS animationsStartedThisFrame is numElements
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/animations/many-pseudo-animations.html (0 => 257138)
--- trunk/LayoutTests/animations/many-pseudo-animations.html (rev 0)
+++ trunk/LayoutTests/animations/many-pseudo-animations.html 2020-02-21 17:21:45 UTC (rev 257138)
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ .box {
+ width: 20px;
+ height: 20px;
+ margin: 3px;
+ display: inline-block;
+ background-color: silver;
+ }
+
+ body.changed .box::before {
+ content: '';
+ display: block;
+ width: 10px;
+ height: 10px;
+ animation: fade 0.1s;
+ }
+
+ @keyframes fade {
+ from { background-color: red; }
+ to { background-color: green; }
+ }
+ </style>
+ <script src=""
+ <script>
+ window.jsTestIsAsync = true;
+
+ const numElements = 10;
+ let animationsStartedThisFrame = 0;
+
+ function makeElement(container)
+ {
+ let div = document.createElement('div');
+ div.className = 'box';
+ container.appendChild(div);
+
+ div.addEventListener('animationstart', (e) => {
+ ++animationsStartedThisFrame;
+ }, false);
+
+ div.addEventListener('animationend', (e) => {
+ startNextIterationSoon();
+ }, false);
+ }
+
+ function checkStartedAnimationsCount()
+ {
+ shouldBe('animationsStartedThisFrame', 'numElements');
+ }
+
+ let nextIterationStarted = false;
+ function startAnimationSet()
+ {
+ nextIterationStarted = false;
+ animationsStartedThisFrame = 0;
+
+ document.body.classList.add('changed');
+ requestAnimationFrame(checkStartedAnimationsCount);
+ }
+
+ const numTrials = 10;
+ let trialCount = 0;
+
+ function startNextIterationSoon()
+ {
+ if (nextIterationStarted)
+ return;
+
+ nextIterationStarted = true;
+
+ if (trialCount++ == numTrials) {
+ finishJSTest();
+ return;
+ }
+
+ document.body.classList.remove('changed');
+ document.body.offsetWidth; // Hack.
+ requestAnimationFrame(startAnimationSet);
+ }
+
+ function doTest()
+ {
+ description('Tests that animations on pseudo-elements do not eventually stop working.');
+
+ let container = document.getElementById('container');
+ for (let i = 0; i < numElements; ++i)
+ makeElement(container);
+
+ requestAnimationFrame(startNextIterationSoon);
+ }
+
+ window.addEventListener('load', doTest, false);
+ var successfullyParsed = true;
+ </script>
+</head>
+<body>
+ <div id="container"></div>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (257137 => 257138)
--- trunk/Source/WebCore/ChangeLog 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/ChangeLog 2020-02-21 17:21:45 UTC (rev 257138)
@@ -1,3 +1,34 @@
+2020-02-21 Simon Fraser <[email protected]>
+
+ [Web Animations] Repeated animations on pseudo elements will fail to run after a while
+ https://bugs.webkit.org/show_bug.cgi?id=207993
+ <rdar://problem/59428472>
+
+ Reviewed by Zalan Bujtas.
+
+ We failed to clear PseudoElement* from AnimationTimeline's various HashMaps on destruction,
+ causing animations to fail to run when those pointer addresses were reused.
+
+ Make DeclarativeAnimation::owningElement() be a WeakPtr<>.
+
+ Test: animations/many-pseudo-animations.html
+
+ * animation/AnimationTimeline.cpp:
+ (WebCore::AnimationTimeline::willDestoryRendererForElement):
+ (WebCore::AnimationTimeline::elementWasRemoved):
+ * animation/AnimationTimeline.h:
+ * animation/DeclarativeAnimation.cpp:
+ (WebCore::DeclarativeAnimation::DeclarativeAnimation):
+ (WebCore::DeclarativeAnimation::enqueueDOMEvent):
+ * animation/DeclarativeAnimation.h:
+ (WebCore::DeclarativeAnimation::owningElement const):
+ * dom/Element.cpp:
+ (WebCore::Element::removedFromAncestor):
+ * dom/PseudoElement.cpp:
+ (WebCore::PseudoElement::clearHostElement):
+ * rendering/updating/RenderTreeUpdater.cpp:
+ (WebCore::RenderTreeUpdater::tearDownRenderers):
+
2020-02-21 Lauro Moura <[email protected]>
[GStreamer] TextCombinerGStreamer is failing to compile with Gst1.14
Modified: trunk/Source/WebCore/animation/AnimationTimeline.cpp (257137 => 257138)
--- trunk/Source/WebCore/animation/AnimationTimeline.cpp 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/animation/AnimationTimeline.cpp 2020-02-21 17:21:45 UTC (rev 257138)
@@ -224,10 +224,11 @@
}
}
-void AnimationTimeline::elementWasRemoved(Element& element)
+void AnimationTimeline::willDestroyRendererForElement(Element& element)
{
for (auto& cssTransition : m_elementToCSSTransitionsMap.get(&element))
cssTransition->cancel(WebAnimation::Silently::Yes);
+
for (auto& cssAnimation : m_elementToCSSAnimationsMap.get(&element)) {
if (is<CSSAnimation>(cssAnimation))
removeCSSAnimationCreatedByMarkup(element, downcast<CSSAnimation>(*cssAnimation));
@@ -235,6 +236,17 @@
}
}
+void AnimationTimeline::elementWasRemoved(Element& element)
+{
+ willDestroyRendererForElement(element);
+
+ m_elementToAnimationsMap.remove(&element);
+ m_elementToCSSAnimationsMap.remove(&element);
+ m_elementToCSSTransitionsMap.remove(&element);
+ m_elementToRunningCSSTransitionByCSSPropertyID.remove(&element);
+ m_elementToCSSAnimationsCreatedByMarkupMap.remove(&element);
+}
+
void AnimationTimeline::removeAnimationsForElement(Element& element)
{
for (auto& animation : animationsForElement(element))
Modified: trunk/Source/WebCore/animation/AnimationTimeline.h (257137 => 257138)
--- trunk/Source/WebCore/animation/AnimationTimeline.h 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/animation/AnimationTimeline.h 2020-02-21 17:21:45 UTC (rev 257138)
@@ -59,12 +59,17 @@
enum class Ordering : uint8_t { Sorted, Unsorted };
Vector<RefPtr<WebAnimation>> animationsForElement(Element&, Ordering ordering = Ordering::Unsorted) const;
+
void elementWasRemoved(Element&);
void removeAnimationsForElement(Element&);
+
void willChangeRendererForElement(Element&);
+ void willDestroyRendererForElement(Element&);
void cancelDeclarativeAnimationsForElement(Element&);
+
virtual void animationWasAddedToElement(WebAnimation&, Element&);
virtual void animationWasRemovedFromElement(WebAnimation&, Element&);
+
void removeDeclarativeAnimationFromListsForOwningElement(WebAnimation&, Element&);
void updateCSSAnimationsForElement(Element&, const RenderStyle* currentStyle, const RenderStyle& afterChangeStyle);
Modified: trunk/Source/WebCore/animation/DeclarativeAnimation.cpp (257137 => 257138)
--- trunk/Source/WebCore/animation/DeclarativeAnimation.cpp 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/animation/DeclarativeAnimation.cpp 2020-02-21 17:21:45 UTC (rev 257138)
@@ -43,7 +43,7 @@
DeclarativeAnimation::DeclarativeAnimation(Element& owningElement, const Animation& backingAnimation)
: WebAnimation(owningElement.document())
- , m_owningElement(&owningElement)
+ , m_owningElement(makeWeakPtr(owningElement))
, m_backingAnimation(const_cast<Animation&>(backingAnimation))
{
}
@@ -52,6 +52,11 @@
{
}
+Element* DeclarativeAnimation::owningElement() const
+{
+ return m_owningElement.get();
+}
+
void DeclarativeAnimation::tick()
{
bool wasRelevant = isRelevant();
@@ -334,12 +339,14 @@
void DeclarativeAnimation::enqueueDOMEvent(const AtomString& eventType, Seconds elapsedTime)
{
- ASSERT(m_owningElement);
+ if (!m_owningElement)
+ return;
+
auto time = secondsToWebAnimationsAPITime(elapsedTime) / 1000;
const auto& pseudoId = PseudoElement::pseudoElementNameForEvents(m_owningElement->pseudoId());
auto timelineTime = timeline() ? timeline()->currentTime() : WTF::nullopt;
auto event = createEvent(eventType, time, pseudoId, timelineTime);
- event->setTarget(m_owningElement);
+ event->setTarget(m_owningElement.get());
enqueueAnimationEvent(WTFMove(event));
}
Modified: trunk/Source/WebCore/animation/DeclarativeAnimation.h (257137 => 257138)
--- trunk/Source/WebCore/animation/DeclarativeAnimation.h 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/animation/DeclarativeAnimation.h 2020-02-21 17:21:45 UTC (rev 257138)
@@ -29,6 +29,7 @@
#include "AnimationEffectPhase.h"
#include "WebAnimation.h"
#include <wtf/Ref.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
@@ -44,7 +45,7 @@
bool isDeclarativeAnimation() const final { return true; }
- Element* owningElement() const { return m_owningElement; }
+ Element* owningElement() const;
const Animation& backingAnimation() const { return m_backingAnimation; }
void setBackingAnimation(const Animation&);
void cancelFromStyle();
@@ -87,7 +88,7 @@
bool m_wasPending { false };
AnimationEffectPhase m_previousPhase { AnimationEffectPhase::Idle };
- Element* m_owningElement;
+ WeakPtr<Element> m_owningElement;
Ref<Animation> m_backingAnimation;
double m_previousIteration;
};
Modified: trunk/Source/WebCore/dom/Element.cpp (257137 => 257138)
--- trunk/Source/WebCore/dom/Element.cpp 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/dom/Element.cpp 2020-02-21 17:21:45 UTC (rev 257138)
@@ -2272,6 +2272,7 @@
RefPtr<Frame> frame = document().frame();
if (auto* timeline = document().existingTimeline())
timeline->elementWasRemoved(*this);
+
if (frame)
frame->animation().cancelAnimations(*this);
Modified: trunk/Source/WebCore/dom/PseudoElement.cpp (257137 => 257138)
--- trunk/Source/WebCore/dom/PseudoElement.cpp 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/dom/PseudoElement.cpp 2020-02-21 17:21:45 UTC (rev 257138)
@@ -90,7 +90,8 @@
InspectorInstrumentation::pseudoElementDestroyed(document().page(), *this);
if (auto* timeline = document().existingTimeline())
- timeline->removeAnimationsForElement(*this);
+ timeline->elementWasRemoved(*this);
+
if (auto* frame = document().frame())
frame->animation().cancelAnimations(*this);
Modified: trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp (257137 => 257138)
--- trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp 2020-02-21 17:06:43 UTC (rev 257137)
+++ trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp 2020-02-21 17:21:45 UTC (rev 257138)
@@ -570,7 +570,7 @@
case TeardownType::RendererUpdateCancelingAnimations:
if (timeline) {
if (document.renderTreeBeingDestroyed())
- timeline->elementWasRemoved(element);
+ timeline->willDestroyRendererForElement(element);
else if (teardownType == TeardownType::RendererUpdateCancelingAnimations)
timeline->cancelDeclarativeAnimationsForElement(element);
}