2020-09-17 12:39:28 +00:00
<!DOCTYPE html>
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
< meta charset = utf-8 >
< title > CSS Animations< / title >
< style type = "text/css" media = "screen" >
@keyframes animation {
from { left: 50px; }
to { left: 100px; }
}
@keyframes animation-top {
from { top: 50px; }
to { top: 100px; }
}
< / style >
< body >
< script src = "../resources/testharness.js" > < / script >
< script src = "../resources/testharnessreport.js" > < / script >
< script >
'use strict';
function targetTest(testCallback, description)
{
test(() => {
const target = document.body.appendChild(document.createElement("div"));
testCallback(target);
target.remove();
}, description);
}
targetTest(target => {
assert_array_equals(target.getAnimations(), [], "An element should not have any animations initially.");
target.style.animationDelay = "-3s";
target.style.animationDuration = "2s";
target.style.animationTimingFunction = "linear";
target.style.animationFillMode = "forwards";
target.style.animationDirection = "alternate";
target.style.animationIterationCount = "2";
target.style.animationName = "animation";
const animation = target.getAnimations()[0];
assert_true(animation instanceof Animation, "The animation is an Animation.");
assert_true(animation instanceof CSSAnimation, "The animation is a CSSAnimation.");
assert_equals(animation.timeline, target.ownerDocument.timeline, "The animation's timeline is set to the element's document timeline.");
assert_equals(animation.playState, "running", "The animation is running as soon as it's created.");
assert_equals(animation.animationName, "animation", "The animation's animationName is set.");
const effect = animation.effect;
2018-11-06 11:16:48 +00:00
assert_true(effect instanceof KeyframeEffect, "The animation's effect is a KeyframeEffect.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
assert_equals(effect.target, target, "The animation's effect is targeting the target.");
2018-11-06 11:16:48 +00:00
const timing = animation.effect.getTiming();
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
assert_equals(timing.fill, "forwards", "The animation's fill property matches the animation-fill-mode property.");
assert_equals(timing.delay, -3000, "The animation's delay property matches the animation-delay property.");
assert_equals(timing.duration, 2000, "The animation's duration property matches the animation-duration property.");
assert_equals(timing.iterations, 2, "The animation's iterations property matches the animation-iteration-count property.");
assert_equals(timing.direction, "alternate", "The animation's direction property matches the animation-direction property.");
const computedTiming = animation.effect.getComputedTiming();
assert_equals(computedTiming.activeDuration, 4000, "The animations's computed timing activeDuration property matches the properties set by CSS");
assert_equals(computedTiming.currentIteration, 1, "The animations's computed timing currentIteration property matches the properties set by CSS");
assert_equals(computedTiming.delay, -3000, "The animations's computed timing delay property matches the properties set by CSS");
assert_equals(computedTiming.duration, 2000, "The animations's computed timing duration property matches the properties set by CSS");
assert_equals(computedTiming.endDelay, 0, "The animations's computed timing endDelay property matches the properties set by CSS");
assert_equals(computedTiming.endTime, 1000, "The animations's computed timing endTime property matches the properties set by CSS");
assert_equals(computedTiming.iterationStart, 0, "The animations's computed timing iterationStart property matches the properties set by CSS");
assert_equals(computedTiming.iterations, 2, "The animations's computed timing iterations property matches the properties set by CSS");
assert_equals(computedTiming.localTime, 0, "The animations's computed timing localTime property matches the properties set by CSS");
assert_equals(computedTiming.progress, 0.5, "The animations's computed timing progress property matches the properties set by CSS");
assert_equals(computedTiming.fill, "forwards", "The animations's computed timing fill property matches the properties set by CSS");
assert_equals(computedTiming.easing, "linear", "The animations's computed timing easing property matches the properties set by CSS");
assert_equals(computedTiming.direction, "alternate", "The animations's computed timing direction property matches the properties set by CSS");
const keyframes = animation.effect.getKeyframes();
assert_equals(keyframes.length, 2, "The animation's effect has two keyframes.");
assert_equals(keyframes[0].offset, 0, "The animation's effect's first keyframe has a 0 offset.");
assert_equals(keyframes[0].left, "50px", "The animation's effect's first keyframe has its left property set to 50px.");
assert_equals(keyframes[1].offset, 1, "The animation's effect's first keyframe has a 1 offset.");
assert_equals(keyframes[1].left, "100px", "The animation's effect's first keyframe has its left property set to 100px.");
assert_equals(getComputedStyle(effect.target).left, "75px", "The animation's target's computed style reflects the animation state.");
}, "A CSS Animation should be reflected entirely as a CSSAnimation object on the timeline.");
targetTest(target => {
target.style.animationDelay = "-1s";
target.style.animationDuration = "2s";
target.style.animationName = "animation";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().delay, -1000, "The animation's delay matches the initial animation-delay property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
2019-10-28 17:01:55 +00:00
target.style.animationDelay = "0s";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().delay, 0, "The animation's delay matches the updated animation-delay property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}, "Web Animations should reflect the animation-delay property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationName = "animation";
for (let direction of ["reverse", "alternate", "normal", "alternate-reverse"]) {
target.style.animationDirection = direction;
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().direction, direction, `The animation's direction matches the "${direction}" CSS value.`);
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}
target.style.removeProperty("animation-direction");
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().direction, "normal", "The animation's easing matches the default animation-direction value when the property is not set.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}, "Web Animations should reflect the animation-direction property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationName = "animation";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().duration, 2000, "The animation's duration matches the initial animation-duration property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
target.style.animationDuration = "1s";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().duration, 1000, "The animation's duration matches the updated animation-duration property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}, "Web Animations should reflect the animation-duration property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationName = "animation";
for (let fillMode of ["forwards", "backwards", "none", "both"]) {
target.style.animationFillMode = fillMode;
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().fill, fillMode, `The animation's fill mode matches the "${fillMode}" CSS value.`);
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}
target.style.removeProperty("animation-fill-mode");
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().fill, "none", "The animation's easing matches the default animation-fill-mode value when the property is not set.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
}, "Web Animations should reflect the animation-fill-mode property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationName = "animation";
target.style.animationIterationCount = 2;
const initialAnimation = target.getAnimations()[0];
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().iterations, 2, "The animation's duration matches the initial animation-iteration-count property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
target.style.animationIterationCount = 1;
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().iterations, 1, "The animation's duration matches the updated animation-iteration-count property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
assert_equals(target.getAnimations()[0], initialAnimation, "The animation object remained the same instance throughout the test.");
}, "Web Animations should reflect the animation-iteration-count property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationName = "animation";
const initialAnimation = target.getAnimations()[0];
assert_equals(target.getAnimations()[0].animationName, "animation", "The animation's name matches the initial animation-name CSS property.");
const initialKeyframes = initialAnimation.effect.getKeyframes();
assert_equals(initialKeyframes.length, 2);
assert_equals(initialKeyframes[0].offset, 0);
assert_equals(initialKeyframes[0].left, "50px");
assert_equals(initialKeyframes[1].offset, 1);
assert_equals(initialKeyframes[1].left, "100px");
target.style.animationName = "animation-top";
const updatedAnimation = target.getAnimations()[0];
assert_not_equals(updatedAnimation, initialAnimation, "Changing the animation-name property generates a different CSSAnimation object.");
assert_equals(updatedAnimation.animationName, "animation-top", "The animation's name matches the updated animation-name CSS property.");
const updatedKeyframes = updatedAnimation.effect.getKeyframes();
assert_equals(updatedKeyframes.length, 2);
assert_equals(updatedKeyframes[0].offset, 0);
assert_equals(updatedKeyframes[0].top, "50px");
assert_equals(updatedKeyframes[1].offset, 1);
assert_equals(updatedKeyframes[1].top, "100px");
}, "Web Animations should reflect the animation-name property.");
targetTest(target => {
target.style.animationDelay = "-1s";
target.style.animationDuration = "2s";
target.style.animationName = "animation";
const initialAnimation = target.getAnimations()[0];
assert_equals(target.getAnimations()[0].playState, "running", "Setting animation-play-state to running should resume the animation.");
target.style.animationPlayState = "paused";
assert_equals(target.getAnimations()[0].playState, "paused", "Setting animation-play-state back to paused should pause the animation.");
target.style.removeProperty("animation-play-state");
assert_equals(target.getAnimations()[0].playState, "running", "Removing the animation-play-state property should resume the animation.");
assert_equals(target.getAnimations()[0], initialAnimation, "The animation object remained the same instance throughout the test.");
}, "Web Animations should reflect the animation-play-state property.");
targetTest(target => {
target.style.animationDuration = "2s";
target.style.animationTimingFunction = "ease-out";
target.style.animationName = "animation";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().easing, "linear", "The animation's easing does not match the initial animation-timing-function property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
target.style.animationTimingFunction = "ease-in";
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().easing, "linear", "The animation's easing does not match the updated animation-timing-function property.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
target.style.removeProperty("animation-timing-function");
2018-11-06 11:16:48 +00:00
assert_equals(target.getAnimations()[0].effect.getTiming().easing, "linear", "The animation's easing does not match the default animation-timing-function value when the property is not set.");
[Web Animations] Correctly handle timing functions specified by CSS Animations and CSS Transitions
https://bugs.webkit.org/show_bug.cgi?id=183935
Reviewed by Dean Jackson.
LayoutTests/imported/mozilla:
Record progressions of Mozilla tests.
* css-animations/test_animation-computed-timing-expected.txt:
* css-transitions/test_animation-computed-timing-expected.txt:
* css-transitions/test_keyframeeffect-getkeyframes-expected.txt:
Source/WebCore:
We were incorrectly reflecting the animation-timing-function and transition-timing-function values on the generated
DeclarativeAnimation effect timing "easing" property. In fact, those values should only be represented on the keyframes.
In the case of a CSS Animation, the animation-timing-function property set on the element's style serves as the default
value used for all keyframes, and individual keyframes can specify an overriding animation-timing-function. For a CSS
Transition, the transition-timing-function property set on the element's style serves as the timing function of the
from keyframe.
To correctly reflect this, we provide a new timingFunctionForKeyframeAtIndex() function on KeyframeEffectReadOnly
which will return the right TimingFunction object at a given index, regardless of the animation type. In the case
of getKeyframes(), we manually return "linear" for the "to" keyframe since timingFunctionForKeyframeAtIndex()
would otherwise return the same timing function as the "from" keyframe. This avoids creating an extra
LinearTimingFunction object.
As a result, a number of Mozilla imported tests progress since we have correct information on the "easing" property
of objects returned by getKeyframes() and the "progress" reported by getComputedTiming() now always uses a linear
timing function.
* animation/DeclarativeAnimation.cpp:
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): The timing function of the backing Animation should
not be reflected on the effect's timing object.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::KeyframeEffectReadOnly::getKeyframes): Return the correct timing function for a keyframe, and use a "linear"
value for the "to" keyframe of a CSS Transition.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle):
(WebCore::KeyframeEffectReadOnly::timingFunctionForKeyframeAtIndex):
* animation/KeyframeEffectReadOnly.h:
LayoutTests:
We now pass 2 additional Mozilla tests completely, so they no longer need to be marked as flaky failures or timeouts.
We also update tests that we wrote ourselves and which incorrectly assumed that the effect's timing would reflect
the timing function set by CSS.
* TestExpectations:
* webanimations/css-animations-expected.txt:
* webanimations/css-animations.html:
* webanimations/css-transitions-expected.txt:
* webanimations/css-transitions.html:
Canonical link: https://commits.webkit.org/199613@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-26 19:08:01 +00:00
}, "Web Animations should not reflect the animation-timing-function property on the effect's timing.");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
function runAnimationCompletionTest(finalAssertionCallback, description)
{
targetTest(target => {
target.style.animationName = "animation";
assert_array_equals(target.getAnimations(), [], "Seting the animation-name property alone does not yield a CSSAnimation.");
target.style.animationDuration = "1s";
assert_equals(target.getAnimations().length, 1, "Seting the animation-duration property on top of the animation-name yields a CSSAnimation.");
assert_equals(target.getAnimations()[0].playState, "running", "Seting the animation-duration property on top of the animation-name yields a running CSSAnimation.");
finalAssertionCallback(target.getAnimations()[0]);
assert_array_equals(target.getAnimations(), [], `${description} no longer lists the animation.`);
}, `${description} no longer lists the animation after it has been running.`);
}
runAnimationCompletionTest(animation => animation.finish(), "Calling finish() on the animation");
2018-11-06 11:16:48 +00:00
runAnimationCompletionTest(animation => animation.currentTime = animation.effect.getTiming().duration, "Seeking the animation to its end time");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
runAnimationCompletionTest(animation => animation.effect.target.style.animationName = "none", "Setting the target's animation-name to none");
2019-10-28 17:01:55 +00:00
runAnimationCompletionTest(animation => animation.effect.target.style.animationDuration = "0s", "Setting the target's animation-duration to 0s");
[Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
https://bugs.webkit.org/show_bug.cgi?id=183504
<rdar://problem/38372965>
LayoutTests/imported/w3c:
Reviewed by Dean Jackson and Jon Lee.
Since we've improved our implementation of getAnimations() we updated the expectations to mark
the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
stage and needed its expectation updated.
* web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
* web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
* web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
Source/WebCore:
Reviewed by Dean Jackson and Jon Lee.
Tests: webanimations/css-animations.html
webanimations/css-transitions.html
This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
* StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
* AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
and remove matching CSSAnimation and CSSTransition instances.
* DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
* KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/AnimationEffectReadOnly.h:
(WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
is a subclass of KeyframeEffectReadOnly, returns true.
* animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
(WebCore::AnimationEffectTimingReadOnly::setEasing):
(WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
* animation/AnimationEffectTimingReadOnly.h:
* animation/AnimationTimeline.cpp:
(WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
when the AnimationTimeline is being destructed and should no longer hold a reference to them.
(WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
and animationWasRemovedFromElement() mutate the right map.
(WebCore::AnimationTimeline::animationWasAddedToElement):
(WebCore::AnimationTimeline::animationWasRemovedFromElement):
(WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
as Web Animations.
(WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
the current state of the animation in the AnimationList.
(WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
there is no need to update CSSTransition objects for a CSS property existing in both the old and new AnimationList, since when a CSS transitions
property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
required by getAnimations().
(WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
(WebCore::AnimationTimeline::elementToAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSAnimationsMap):
(WebCore::AnimationTimeline::elementToCSSTransitionsMap):
* animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
to perform work specific to CSS Animations.
(WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
(WebCore::CSSAnimation::CSSAnimation):
(WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
(WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
* animation/CSSAnimation.h:
* animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
(WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
(WebCore::CSSTransition::CSSTransition):
(WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
(WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
listed by calls to getAnimations().
* animation/CSSTransition.h:
* animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
These backing animations contain all of the parsed CSS styles related to CSS Animations and CSS Transitions and we use those to set matching properties
of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
since these methods are meant to be called during style invalidation and we would hit an assertion if we followed the usual route of calling
updateStyleIfNeeded() on the target's document during invalidation.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::setBackingAnimation):
(WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
element's document's timeline and play the animation if the backing animation's play state is playing.
(WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
{animation|transition}-timing-function properties as set on the backing animation.
* animation/DeclarativeAnimation.h: Added.
(WebCore::DeclarativeAnimation::backingAnimation const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
support for asynchronous WebAnimation operations.
(WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
(WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
and not simply KeyframeEffect.
* animation/KeyframeEffectReadOnly.cpp:
(WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
already force a style resolution as needed.
(WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
(WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
to compute keyframes. In the case of declarative animations, there are no ParsedKeyframe since the JS API was not involved, so we use the blending keyframes
to look for keyframe data.
(WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
(WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
(WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
to check that a provided backing Animation and a pair of old and new RenderStyles that may be different objects actually would yield different timing
properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
CSSTransition where the transition style itself might be set first, but the target value after. So we should only run accelerated provided there are blending
keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
* animation/KeyframeEffectReadOnly.h:
(WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
again in the destructor means that we'd hit ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun) in ref(). It was also meaningless to perform this work in
the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
(WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
a mechanism to allow the usual effect invalidation to be suspended in this case. We now maintain a simple m_suspendCount count that increases and decreases with
calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
(WebCore::WebAnimation::unsuspendEffectInvalidation):
(WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
(WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
(WebCore::WebAnimation::runPendingPlayTask): Only fulfill the "ready" promise if it hasn't already been, which might have been the case if multiple calls to play()
are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
(WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
(WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
(WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
be listed. The Web Animations spec explains that only animations "that have an associated target effect which is current or in effect" can be listed. We implement
this behavior as specified.
* animation/WebAnimation.h:
(WebCore::WebAnimation::isDeclarativeAnimation const):
(WebCore::WebAnimation::isEffectInvalidationSuspended):
* dom/Document.cpp:
(WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
* dom/Element.cpp:
(WebCore::Element::getAnimations): Same as Document::getAnimations().
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
Source/WebKitLegacy/mac:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* WebView/WebPreferenceKeysPrivate.h:
* WebView/WebPreferences.mm:
(+[WebPreferences initialize]):
(-[WebPreferences setModernMediaControlsEnabled:]):
(-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
(-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
* WebView/WebPreferencesPrivate.h:
* WebView/WebView.mm:
(-[WebView _preferencesChanged:]):
Source/WebKitLegacy/win:
Reviewed by Dean Jackson and Jon Lee.
Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
* Interfaces/IWebPreferencesPrivate.idl:
* WebPreferences.cpp:
(WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
(WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
* WebPreferenceKeysPrivate.h
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):
Tools:
Reviewed by Jon Lee.
Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
as Web Animations runtime flag in the new tests we've created for this feature.
* DumpRenderTree/TestOptions.h:
* DumpRenderTree/TestOptions.mm:
(TestOptions::TestOptions):
* DumpRenderTree/mac/DumpRenderTree.mm:
(setWebPreferencesForTestOptions):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetPreferencesToConsistentValues):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
LayoutTests:
Reviewed by Dean Jackson and Jon Lee.
Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
to use a more concise API since we've implement Element.animate() since their creation.
* webanimations/animation-opacity-animation-crash.html:
* webanimations/css-animations-expected.txt: Added.
* webanimations/css-animations.html: Added.
* webanimations/css-transitions-expected.txt: Added.
* webanimations/css-transitions.html: Added.
* webanimations/opacity-animation-no-longer-composited-upon-completion.html:
* webanimations/opacity-animation-yields-compositing.html:
Canonical link: https://commits.webkit.org/199224@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229530 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-03-12 12:56:14 +00:00
< / script >
< / body >