Changeset 229530 in webkit


Ignore:
Timestamp:
Mar 12, 2018 5:56:14 AM (6 years ago)
Author:
graouts@webkit.org
Message:

[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:
Location:
trunk
Files:
4 added
45 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r229505 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Dean Jackson and Jon Lee.
     8
     9        Add a series of new tests to check CSSAnimation and CSSTransition objects are correctly created
     10        as CSS animation-* and CSS transition-* properties are used. We also update some existing tests
     11        to use a more concise API since we've implement Element.animate() since their creation.
     12
     13        * webanimations/animation-opacity-animation-crash.html:
     14        * webanimations/css-animations-expected.txt: Added.
     15        * webanimations/css-animations.html: Added.
     16        * webanimations/css-transitions-expected.txt: Added.
     17        * webanimations/css-transitions.html: Added.
     18        * webanimations/opacity-animation-no-longer-composited-upon-completion.html:
     19        * webanimations/opacity-animation-yields-compositing.html:
     20
    1212018-03-09  Zalan Bujtas  <zalan@apple.com>
    222
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r229181 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Dean Jackson and Jon Lee.
     8
     9        Since we've improved our implementation of getAnimations() we updated the expectations to mark
     10        the progressions. Both tests for getAnimations() now pass 100%. Another test now fails at a later
     11        stage and needed its expectation updated.
     12
     13        * web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
     14        * web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt:
     15        * web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt:
     16
    1172018-03-02  Youenn Fablet  <youenn@apple.com>
    218
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt

    r228702 r229530  
    119119PASS Element.animate() correctly sets the Animation's timeline when triggered on an element in a different document
    120120PASS Element.animate() calls play on the Animation
    121 FAIL CSSPseudoElement.animate() creates an Animation object assert_equals: expected Element node <div class="pseudo"></div> but got null
    122 FAIL CSSPseudoElement.animate() creates an Animation object targeting to the correct CSSPseudoElement object assert_equals: expected Element node <div class="pseudo"></div> but got null
     121FAIL CSSPseudoElement.animate() creates an Animation object assert_true: expected true got false
     122FAIL CSSPseudoElement.animate() creates an Animation object targeting to the correct CSSPseudoElement object assert_true: expected true got false
    123123
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/getAnimations-expected.txt

    r227598 r229530  
    44PASS Returns only the animations specific to each sibling element
    55PASS Returns only the animations specific to each parent/child element
    6 FAIL Does not return finished animations that do not fill forwards assert_array_equals: lengths differ, expected 0 got 1
     6PASS Does not return finished animations that do not fill forwards
    77PASS Returns finished animations that fill forwards
    88PASS Returns animations in their delay phase
    9 FAIL Returns animations based on dynamic changes to individual animations' duration assert_array_equals: Animation should not be returned when it is finished lengths differ, expected 0 got 1
    10 FAIL Returns animations based on dynamic changes to individual animations' end delay assert_array_equals: Animation should not be returned after setting a negative end delay such that the end time is less than the current time lengths differ, expected 0 got 1
    11 FAIL Returns animations based on dynamic changes to individual animations' iteration count assert_array_equals: Animation should not be returned when it is finished lengths differ, expected 0 got 1
    12 FAIL Returns animations based on dynamic changes to individual animations' current time assert_array_equals: Animation should not be returned after seeking to the clipped end of the active interval lengths differ, expected 0 got 1
     9PASS Returns animations based on dynamic changes to individual animations' duration
     10PASS Returns animations based on dynamic changes to individual animations' end delay
     11PASS Returns animations based on dynamic changes to individual animations' iteration count
     12PASS Returns animations based on dynamic changes to individual animations' current time
    1313
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Document/getAnimations-expected.txt

    r228333 r229530  
    11
    22PASS Test document.getAnimations for non-animated content
    3 FAIL Test document.getAnimations for script-generated animations assert_equals: getAnimation only returns running animations expected 0 but got 2
    4 FAIL Test the order of document.getAnimations with script generated animations assert_array_equals: getAnimations() returns running animations lengths differ, expected 2 got 4
    5 FAIL Test document.getAnimations with null target assert_equals: document.getAnimations() only returns animations targeting elements in this document expected 0 but got 5
     3PASS Test document.getAnimations for script-generated animations
     4PASS Test the order of document.getAnimations with script generated animations
     5PASS Test document.getAnimations with null target
    66
  • trunk/LayoutTests/webanimations/animation-opacity-animation-crash.html

    r224968 r229530  
    22<script>
    33
    4 const animation = new Animation(new KeyframeEffect(document.getElementById("target"), [
     4document.getElementById("target").animate([
    55    { opacity: 1 },
    66    { opacity: 0 }
    7 ]));
    8 animation.startTime = 0;
    9 animation.effect.timing.duration = 1000;
     7], 1000);
    108
    119</script>
  • trunk/LayoutTests/webanimations/opacity-animation-no-longer-composited-upon-completion.html

    r225128 r229530  
    33<script>
    44
    5 const animation = new Animation(new KeyframeEffect(document.getElementById("target"), [
     5const animation = document.getElementById("target").animate([
    66    { opacity: 1 },
    77    { opacity: 0 }
    8 ]));
    9 animation.startTime = 0;
    10 animation.effect.timing.duration = 100;
     8], 100);
    119
    1210testRunner.waitUntilDone();
  • trunk/LayoutTests/webanimations/opacity-animation-yields-compositing.html

    r225128 r229530  
    33<script>
    44
    5 const animation = new Animation(new KeyframeEffect(document.getElementById("target"), [
     5document.getElementById("target").animate([
    66    { opacity: 1 },
    77    { opacity: 0 }
    8 ]));
    9 animation.startTime = 0;
    10 animation.effect.timing.duration = 1000;
     8], 1000);
    119
    1210testRunner.dumpAsText();
  • trunk/Source/WebCore/ChangeLog

    r229525 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Dean Jackson and Jon Lee.
     8
     9        Tests: webanimations/css-animations.html
     10               webanimations/css-transitions.html
     11
     12        This patch implements CSS Animations and CSS Transitions as Web Animations. The main changes are:
     13
     14        * StyleTreeResolver: StyleTreeResolver now has a code path to add CSSAnimation and CSSTransition objects onto the DocumentTimeline
     15        to be picked up by the Web Animations engine. The previous CSSAnimationController code path is preserved if the runtime flag is disabled.
     16
     17        * AnimationTimeline: we add two new methods, updateCSSAnimationsForElement() and updateCSSTransitionsForElement() which are called from
     18        TreeResolver::createAnimatedElementUpdate(). These look at the AnimationList for the old and new RenderStyle objects and create, update
     19        and remove matching CSSAnimation and CSSTransition instances.
     20
     21        * DeclarativeAnimation: a new superclass to both CSSAnimation and CSSTransition which introduces the concept of a backingAnimation(),
     22        which is an Animation held by the RenderStyle objects, and two virtual methods with base implementations, initialize() which is called
     23        upon creating by create() methods in subclasses, and syncPropertiesWithBackingAnimation() which ensures that properties on the
     24        DeclarativeAnimation objects (Web Animations side) match the backing animation (CSS side).
     25
     26        * KeyframeEffectReadOnly: two new important methods to create blending keyframes (KeyframeList) based on backing Animation objects,
     27        computeCSSAnimationBlendingKeyframes() and computeCSSTransitionBlendingKeyframes().
     28
     29        * Sources.txt:
     30        * WebCore.xcodeproj/project.pbxproj:
     31        * animation/AnimationEffectReadOnly.h:
     32        (WebCore::AnimationEffectReadOnly::isKeyframeEffectReadOnly const): We fix this method such that calling it on a KeyframeEffect, which
     33        is a subclass of KeyframeEffectReadOnly, returns true.
     34        * animation/AnimationEffectTimingReadOnly.cpp: In order for DeclarativeAnimation::syncPropertiesWithBackingAnimation() to set the timing
     35        function for a declarative animation's effect, we need a public method to set an effect's timing function outside of just the "easing"
     36        property setter exposed via the JS API. So we introduce a setTimingFunction() method and call it from setEasing().
     37        (WebCore::AnimationEffectTimingReadOnly::setEasing):
     38        (WebCore::AnimationEffectTimingReadOnly::setTimingFunction):
     39        * animation/AnimationEffectTimingReadOnly.h:
     40        * animation/AnimationTimeline.cpp:
     41        (WebCore::AnimationTimeline::~AnimationTimeline): Clear all maps and sets containing WebAnimation references to ensure these get destructed
     42        when the AnimationTimeline is being destructed and should no longer hold a reference to them.
     43        (WebCore::AnimationTimeline::relevantMapForAnimation): We store various subclasses of WebAnimation in dedicated maps so we can composite
     44        animations in the correct order when animating. This function returns the correct map for a given animation such that animationWasAddedToElement()
     45        and animationWasRemovedFromElement() mutate the right map.
     46        (WebCore::AnimationTimeline::animationWasAddedToElement):
     47        (WebCore::AnimationTimeline::animationWasRemovedFromElement):
     48        (WebCore::AnimationTimeline::animationsForElement): Make sure to look for animations in the lists of CSS Animations and CSS Transitions as well
     49        as Web Animations.
     50        (WebCore::AnimationTimeline::updateCSSAnimationsForElement): This method is called by TreeResolver::createAnimatedElementUpdate() during style
     51        resolution. It compares the AnimationList of the previous style and the new style for a given element, checks that animations with a given name
     52        that were not present in the old AnimationList have a new matching CSSAnimation object for them added to the AnimationTimeline, that animations
     53        with a given name that are no longer present in the new AnimationList have their matching CSSAnimation object removed from the AnimationTimeline,
     54        and that animations with a given name that are present in both the old and new AnimationList have their matching CSSAnimation updated to match
     55        the current state of the animation in the AnimationList.
     56        (WebCore::AnimationTimeline::updateCSSTransitionsForElement): Similarly to updateCSSAnimationsForElement(), this method is called during style
     57        resolution by TreeResolver::createAnimatedElementUpdate(). Its role is to create or remove CSSTransition objects based on the AnimationList found
     58        in the old and new styles for a given element. It follows a slightly different logic than updateCSSAnimationsForElement() since for CSS Transitions,
     59        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
     60        property is changed, a whole new transition is initiated. However, it's important to check that different Animation objects and styles would actually
     61        result in different timing properties and blending keyframes, so check for this as well before creating new CSSTransition objects.
     62        * animation/AnimationTimeline.h:
     63        (WebCore::AnimationTimeline::animations const): Change the m_animations type from HashSet to ListHashSet to guarantee we preserve the insertion order which is
     64        required by getAnimations().
     65        (WebCore::AnimationTimeline::hasElementAnimations const): Indicates to DocumentTimeline::updateAnimations() that there are animations targeting the provided element.
     66        (WebCore::AnimationTimeline::elementToAnimationsMap):
     67        (WebCore::AnimationTimeline::elementToCSSAnimationsMap):
     68        (WebCore::AnimationTimeline::elementToCSSTransitionsMap):
     69        * animation/CSSAnimation.cpp: CSSAnimation is now a subclass of DeclarativeAnimation and subclasses initialize() and syncPropertiesWithBackingAnimation()
     70        to perform work specific to CSS Animations.
     71        (WebCore::CSSAnimation::create): Set the animationName property based on the provided backing animation.
     72        (WebCore::CSSAnimation::CSSAnimation):
     73        (WebCore::CSSAnimation::initialize): Create the blending keyframes for this CSSAnimation.
     74        (WebCore::CSSAnimation::syncPropertiesWithBackingAnimation): Reflect the animation-fill-mode, animation-direction, animation-iteration-count and
     75        animation-play-state CSS properties on the AnimationEffectTimingReadOnly object associated with this CSSAnimation.
     76        * animation/CSSAnimation.h:
     77        * animation/CSSTransition.cpp: CSSTransition is now a subclass of DeclarativeAnimation.
     78        (WebCore::CSSTransition::create): Set the transitionProperty property based on the provided backing animation.
     79        (WebCore::CSSTransition::CSSTransition):
     80        (WebCore::CSSTransition::matchesBackingAnimationAndStyles const):
     81        (WebCore::CSSTransition::canBeListed const): Subclass this method such that we also check that we have blending keyframes for a CSSTransition to be
     82        listed by calls to getAnimations().
     83        * animation/CSSTransition.h:
     84        * animation/DeclarativeAnimation.cpp: Added. This new WebAnimation subclass now is the common base class for both CSSAnimation and CSSTransition.
     85        It establishes a relationship with a "backing animation", which is an Animation obtained from a style's AnimationList while resolving styles.
     86        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
     87        of the Web Animations timing model in the new syncPropertiesWithBackingAnimation() virtual method, which subclasses can override to perform further
     88        work that is specific to a given declarative animation type. The initialize() method is called during create() methods to perform common animation
     89        setup work. Note that while both initialize() and syncPropertiesWithBackingAnimation() are called, we suspend invalidation to that animation's effect
     90        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
     91        updateStyleIfNeeded() on the target's document during invalidation.
     92        (WebCore::DeclarativeAnimation::DeclarativeAnimation):
     93        (WebCore::DeclarativeAnimation::setBackingAnimation):
     94        (WebCore::DeclarativeAnimation::initialize): Create a KeyframeEffectReadOnly for this animation and set the provided element as its target, set that
     95        element's document's timeline and play the animation if the backing animation's play state is playing.
     96        (WebCore::DeclarativeAnimation::syncPropertiesWithBackingAnimation): Reflect the {animation|transition}-delay, {animation|transition}-duration and
     97        {animation|transition}-timing-function properties as set on the backing animation.
     98        * animation/DeclarativeAnimation.h: Added.
     99        (WebCore::DeclarativeAnimation::backingAnimation const):
     100        * animation/DocumentTimeline.cpp:
     101        (WebCore::DocumentTimeline::updateAnimations): Trigger style invalidation for elements targeted not just by WebAnimation instances, but also by any
     102        of the DeclarativeAnimation subclasses. We also remove the call to updateFinishedState() which should have been removed when we implemented correct
     103        support for asynchronous WebAnimation operations.
     104        (WebCore::DocumentTimeline::animatedStyleForRenderer): Declarative animations are backed by KeyframeEffectReadOnly effects, so make sure we check
     105        for KeyframeEffectReadOnly or one of its subclasses and not just KeyframeEffect since there now are animation types that use the ReadOnly variant.
     106        (WebCore::DocumentTimeline::runningAnimationsForElementAreAllAccelerated): Same as for animatedStyleForRenderer, check for KeyframeEffectReadOnly
     107        and not simply KeyframeEffect.
     108        * animation/KeyframeEffectReadOnly.cpp:
     109        (WebCore::invalidateElement): Stop forcing a style resolution as we invalidate element, marking them as dirty is sufficient. Calls to getAnimations()
     110        already force a style resolution as needed.
     111        (WebCore::KeyframeEffectReadOnly::create): Add a new create() method that only provides a target and which is used by DeclarativeAnimation::initialize().
     112        (WebCore::KeyframeEffectReadOnly::getKeyframes): The previous implementation of getKeyframes() used the ParsedKeyframe list held as m_parsedKeyframes
     113        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
     114        to look for keyframe data.
     115        (WebCore::KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes): Called by CSSAnimation::initialize(), this function creates blending keyframes by
     116        looking up the keyframes date obtained from the @keyframes rule with this backing animation's name.
     117        (WebCore::KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes): Called by CSSTransition::create(), this function creates blending keyframes by
     118        creating a 0-offset keyframe with the old style and a 1-offset keyframe with the new style as provided during TreeResolver::createAnimatedElementUpdate().
     119        (WebCore::KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes const): Called by AnimationTimeline::updateCSSTransitionsForElement()
     120        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
     121        properties and keyframe CSS values for a given CSS transition to avoid the deletion and creation of CSSTransition objects.
     122        (WebCore::KeyframeEffectReadOnly::shouldRunAccelerated): We mistakenly assumed we always had blending keyframes, which is not always the case with a
     123        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
     124        keyframes at least, the function already returning false if it finds a blending keyframe animating a non-accelerated CSS property.
     125        (WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle): Check that there actually is a matching ParsedKeyframe to read the timing function from.
     126        * animation/KeyframeEffectReadOnly.h:
     127        (WebCore::KeyframeEffectReadOnly::hasBlendingKeyframes const):
     128        * animation/WebAnimation.cpp:
     129        (WebCore::WebAnimation::~WebAnimation): We used to do something very wrong when a WebAnimation was destroyed which uncovered crashes when dealing with
     130        declarative animations. In AnimationTimeline's updateCSSAnimationsForElement() and updateCSSTransitionsForElement(), when we identify that a DeclarativeAnimation
     131        no longer matches an Animation from the current style's AnimationList, we set that DeclarativeAnimation's effect to null and call removeAnimation() on
     132        the timeline. This removes all references from AnimationTimeline to this DeclarativeAnimation and leads to ~WebAnimation being called. Calling removeAnimation()
     133        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
     134        the WebAnimation destructor since an animation could never be destroyed if it were still registered on a timeline.
     135        (WebCore::WebAnimation::suspendEffectInvalidation): DeclarativeAnimation instances have their timing model properties set during style invalidation, so we need
     136        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
     137        calls to this method and unsuspendEffectInvalidation() and a isEffectInvalidationSuspended() method returning true whenever that count is positive.
     138        (WebCore::WebAnimation::unsuspendEffectInvalidation):
     139        (WebCore::WebAnimation::timingModelDidChange): Check that effect invalidation is not suspended before proceeding with invalidating the effect.
     140        (WebCore::WebAnimation::setEffect): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
     141        (WebCore::WebAnimation::setTimeline): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
     142        (WebCore::WebAnimation::scheduleMicrotaskIfNeeded): Ensure that the WebAnimation's lifecycle is extended at least to the completion of the scheduled microtask.
     143        This would otherwise cause crashes after declarative animations were destroyed when they were no longer applied.
     144        (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()
     145        are made as a result of updating the animation play state in CSSAnimation::syncPropertiesWithBackingAnimation().
     146        (WebCore::WebAnimation::runPendingPauseTask): Same as above but with multiple pause() calls.
     147        (WebCore::WebAnimation::startOrStopAccelerated): Check for KeyframeEffectReadOnly and not just KeyframeEffect since declarative animations have ReadOnly effects.
     148        (WebCore::WebAnimation::canBeListed const): This new method is called by {Document|Element}::getAnimations() to check that an animation is in the correct state to
     149        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
     150        this behavior as specified.
     151        * animation/WebAnimation.h:
     152        (WebCore::WebAnimation::isDeclarativeAnimation const):
     153        (WebCore::WebAnimation::isEffectInvalidationSuspended):
     154        * dom/Document.cpp:
     155        (WebCore::Document::getAnimations): Ensure that the document's pending styles are resolved before returning animations to ensure that any pending declarative
     156        animations are created. Additionally, we ensure that we only list qualifying animations that have effects targeting elements that are children of thi document.
     157        * dom/Element.cpp:
     158        (WebCore::Element::getAnimations): Same as Document::getAnimations().
     159        * style/StyleTreeResolver.cpp:
     160        (WebCore::Style::TreeResolver::createAnimatedElementUpdate): When resolving styles, call into the AnimationTimeline if the runtime flag to enable CSS Animations and
     161        CSS Transitions as Web Animations is on. Otherwise, use CSSAnimationController.
     162
    11632018-03-12  Michael Catanzaro  <mcatanzaro@igalia.com>
    2164
  • trunk/Source/WebCore/Sources.txt

    r229417 r229530  
    339339animation/CSSAnimation.cpp
    340340animation/CSSTransition.cpp
     341animation/DeclarativeAnimation.cpp
    341342animation/DocumentTimeline.cpp
    342343animation/KeyframeEffect.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r229421 r229530  
    19851985                71556CBD1F9F0A4900E78D08 /* JSAnimationEffectTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 71556CB91F9F09FD00E78D08 /* JSAnimationEffectTiming.h */; };
    19861986                71556CBE1F9F0A4900E78D08 /* JSKeyframeEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 71556CB71F9F09FC00E78D08 /* JSKeyframeEffect.h */; };
     1987                715AD7202050513200D592DC /* DeclarativeAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 715AD71D2050512400D592DC /* DeclarativeAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1988                715AD7212050513F00D592DC /* CSSTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 7123C186204739BA00789392 /* CSSTransition.h */; };
    19871989                71A1B6081DEE5AD70073BCFB /* modern-media-controls-localized-strings.js in Resources */ = {isa = PBXBuildFile; fileRef = 71A1B6061DEE5A820073BCFB /* modern-media-controls-localized-strings.js */; };
    19881990                71A57DF2154BE25C0009D120 /* SVGPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */; };
     
    89028904                7157E3D11DC1EE4B0094550E /* scrubbing-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "scrubbing-support.js"; sourceTree = "<group>"; };
    89038905                7157F061150B6564006EAABD /* SVGAnimatedTransformList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimatedTransformList.cpp; sourceTree = "<group>"; };
     8906                715AD71D2050512400D592DC /* DeclarativeAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeclarativeAnimation.h; sourceTree = "<group>"; };
     8907                715AD71F2050512400D592DC /* DeclarativeAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarativeAnimation.cpp; sourceTree = "<group>"; };
    89048908                715DA5D3201BB902002EF2B0 /* JSWebAnimationCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebAnimationCustom.cpp; sourceTree = "<group>"; };
    89058909                716C8DF11E48B269005BD0DA /* volume-down-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "volume-down-support.js"; sourceTree = "<group>"; };
     
    1921319217                                7123C186204739BA00789392 /* CSSTransition.h */,
    1921419218                                7123C185204739B900789392 /* CSSTransition.idl */,
     19219                                715AD71F2050512400D592DC /* DeclarativeAnimation.cpp */,
     19220                                715AD71D2050512400D592DC /* DeclarativeAnimation.h */,
    1921519221                                71025EC41F99F096004A250C /* DocumentTimeline.cpp */,
    1921619222                                71025EC51F99F096004A250C /* DocumentTimeline.h */,
     
    2721727223                                9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */,
    2721827224                                A882DA231593848D000115ED /* CSSToStyleMap.h in Headers */,
     27225                                715AD7212050513F00D592DC /* CSSTransition.h in Headers */,
    2721927226                                371F53E90D2704F900ECE0D5 /* CSSUnicodeRangeValue.h in Headers */,
    2722027227                                DD7CDF250A23CF9800069928 /* CSSUnknownRule.h in Headers */,
     
    2726527272                                0F6A12BE1A00923700C6DE72 /* DebugPageOverlays.h in Headers */,
    2726627273                                45FEA5D0156DDE8C00654101 /* Decimal.h in Headers */,
     27274                                715AD7202050513200D592DC /* DeclarativeAnimation.h in Headers */,
    2726727275                                A8C228A111D5722E00D5A7D3 /* DecodedDataDocumentParser.h in Headers */,
    2726827276                                CECCFC3B141973D5002A0AC1 /* DecodeEscapeSequences.h in Headers */,
  • trunk/Source/WebCore/animation/AnimationEffectReadOnly.h

    r228537 r229530  
    4242
    4343    bool isKeyframeEffect() const { return m_classType == KeyframeEffectClass; }
    44     bool isKeyframeEffectReadOnly() const { return m_classType == KeyframeEffectReadOnlyClass; }
     44    bool isKeyframeEffectReadOnly() const { return isKeyframeEffect() || m_classType == KeyframeEffectReadOnlyClass; }
    4545    AnimationEffectTimingReadOnly* timing() const { return m_timing.get(); }
    4646    ComputedTimingProperties getComputedTiming();
  • trunk/Source/WebCore/animation/AnimationEffectTimingReadOnly.cpp

    r228537 r229530  
    171171    if (timingFunctionResult.hasException())
    172172        return timingFunctionResult.releaseException();
    173     m_timingFunction = timingFunctionResult.returnValue();
    174     propertyDidChange();
     173    setTimingFunction(timingFunctionResult.returnValue());
    175174    return { };
    176175}
     
    228227
    229228    m_direction = direction;
     229    propertyDidChange();
     230}
     231
     232void AnimationEffectTimingReadOnly::setTimingFunction(const RefPtr<TimingFunction>& timingFunction)
     233{
     234    m_timingFunction = timingFunction;
    230235    propertyDidChange();
    231236}
  • trunk/Source/WebCore/animation/AnimationEffectTimingReadOnly.h

    r228537 r229530  
    8888
    8989    TimingFunction* timingFunction() const { return m_timingFunction.get(); }
     90    void setTimingFunction(const RefPtr<TimingFunction>&);
     91
    9092    Seconds endTime() const;
    9193    Seconds activeDuration() const;
  • trunk/Source/WebCore/animation/AnimationTimeline.cpp

    r228537 r229530  
    2828#include "AnimationTimeline.h"
    2929
     30#include "Animation.h"
     31#include "AnimationList.h"
     32#include "CSSAnimation.h"
     33#include "CSSPropertyAnimation.h"
     34#include "CSSTransition.h"
    3035#include "DocumentTimeline.h"
     36#include "Element.h"
     37#include "KeyframeEffectReadOnly.h"
     38#include "RenderStyle.h"
     39#include "RenderView.h"
    3140#include "WebAnimationUtilities.h"
    3241#include <wtf/text/TextStream.h>
     
    4251AnimationTimeline::~AnimationTimeline()
    4352{
     53    m_animations.clear();
     54    m_elementToAnimationsMap.clear();
     55    m_elementToCSSAnimationsMap.clear();
     56    m_elementToCSSTransitionsMap.clear();
     57    m_elementToCSSAnimationByName.clear();
     58    m_elementToCSSTransitionByCSSPropertyID.clear();
    4459}
    4560
     
    7085}
    7186
     87HashMap<Element*, Vector<RefPtr<WebAnimation>>>& AnimationTimeline::relevantMapForAnimation(WebAnimation& animation)
     88{
     89    if (animation.isCSSAnimation())
     90        return m_elementToCSSAnimationsMap;
     91    if (animation.isCSSTransition())
     92        return m_elementToCSSTransitionsMap;
     93    return m_elementToAnimationsMap;
     94}
     95
    7296void AnimationTimeline::animationWasAddedToElement(WebAnimation& animation, Element& element)
    7397{
    74     auto result = m_elementToAnimationsMap.ensure(&element, [] {
    75         return Vector<RefPtr<WebAnimation>>();
     98    auto result = relevantMapForAnimation(animation).ensure(&element, [] {
     99        return Vector<RefPtr<WebAnimation>> { };
    76100    });
    77101    result.iterator->value.append(&animation);
     
    80104void AnimationTimeline::animationWasRemovedFromElement(WebAnimation& animation, Element& element)
    81105{
    82     auto iterator = m_elementToAnimationsMap.find(&element);
    83     if (iterator == m_elementToAnimationsMap.end())
     106    auto& map = relevantMapForAnimation(animation);
     107    auto iterator = map.find(&element);
     108    if (iterator == map.end())
    84109        return;
    85110
     
    87112    animations.removeFirst(&animation);
    88113    if (!animations.size())
    89         m_elementToAnimationsMap.remove(iterator);
     114        map.remove(iterator);
    90115}
    91116
     
    93118{
    94119    Vector<RefPtr<WebAnimation>> animations;
     120    if (m_elementToCSSAnimationsMap.contains(&element))
     121        animations.appendVector(m_elementToCSSAnimationsMap.get(&element));
     122    if (m_elementToCSSTransitionsMap.contains(&element))
     123        animations.appendVector(m_elementToCSSTransitionsMap.get(&element));
    95124    if (m_elementToAnimationsMap.contains(&element))
    96         animations = m_elementToAnimationsMap.get(&element);
     125        animations.appendVector(m_elementToAnimationsMap.get(&element));
    97126    return animations;
     127}
     128
     129void AnimationTimeline::updateCSSAnimationsForElement(Element& element, const RenderStyle& newStyle, const RenderStyle* oldStyle)
     130{
     131    if (element.document().pageCacheState() != Document::NotInPageCache)
     132        return;
     133
     134    if (element.document().renderView()->printing())
     135        return;
     136
     137    // First, compile the list of animation names that were applied to this element up to this point.
     138    HashSet<String> namesOfPreviousAnimations;
     139    if (oldStyle && oldStyle->hasAnimations()) {
     140        auto* previousAnimations = oldStyle->animations();
     141        for (size_t i = 0; i < previousAnimations->size(); ++i) {
     142            auto& previousAnimation = previousAnimations->animation(i);
     143            if (previousAnimation.isValidAnimation())
     144                namesOfPreviousAnimations.add(previousAnimation.name());
     145        }
     146    }
     147
     148    // Create or get the CSSAnimations by animation name map for this element.
     149    auto& cssAnimationsByName = m_elementToCSSAnimationByName.ensure(&element, [] {
     150        return HashMap<String, RefPtr<CSSAnimation>> { };
     151    }).iterator->value;
     152
     153    if (auto* currentAnimations = newStyle.animations()) {
     154        for (size_t i = 0; i < currentAnimations->size(); ++i) {
     155            auto& currentAnimation = currentAnimations->animation(i);
     156            auto& name = currentAnimation.name();
     157            if (namesOfPreviousAnimations.contains(name)) {
     158                // We've found the name of this animation in our list of previous animations, this means we've already
     159                // created a CSSAnimation object for it and need to ensure that this CSSAnimation is backed by the current
     160                // animation object for this animation name.
     161                cssAnimationsByName.get(name)->setBackingAnimation(currentAnimation);
     162            } else if (currentAnimation.isValidAnimation()) {
     163                // Otherwise we are dealing with a new animation name and must create a CSSAnimation for it.
     164                cssAnimationsByName.set(name, CSSAnimation::create(element, currentAnimation));
     165            }
     166            // Remove the name of this animation from our list since it's now known to be current.
     167            namesOfPreviousAnimations.remove(name);
     168        }
     169    }
     170
     171    // The animations names left in namesOfPreviousAnimations are now known to no longer apply so we need to
     172    // remove the CSSAnimation object created for them.
     173    for (const auto& nameOfAnimationToRemove : namesOfPreviousAnimations) {
     174        auto cssAnimationToRemove = cssAnimationsByName.take(nameOfAnimationToRemove);
     175        cssAnimationToRemove->setEffect(nullptr);
     176        removeAnimation(cssAnimationToRemove.releaseNonNull());
     177    }
     178
     179    // Remove the map of CSSAnimations by animation name for this element if it's now empty.
     180    if (cssAnimationsByName.isEmpty())
     181        m_elementToCSSAnimationByName.remove(&element);
     182}
     183
     184void AnimationTimeline::updateCSSTransitionsForElement(Element& element, const RenderStyle& newStyle, const RenderStyle* oldStyle)
     185{
     186    if (element.document().pageCacheState() != Document::NotInPageCache)
     187        return;
     188
     189    if (element.document().renderView()->printing())
     190        return;
     191
     192    // FIXME: We do not handle "all" transitions yet.
     193
     194    // First, compile the list of backing animations and properties that were applied to this element up to this point.
     195    HashSet<CSSPropertyID> previousProperties;
     196    HashSet<const Animation*> previousBackingAnimations;
     197    if (oldStyle && oldStyle->hasTransitions()) {
     198        auto* previousTransitions = oldStyle->transitions();
     199        for (size_t i = 0; i < previousTransitions->size(); ++i) {
     200            auto& animation = previousTransitions->animation(i);
     201            auto previousTransitionProperty = animation.property();
     202            if (previousTransitionProperty != CSSPropertyInvalid) {
     203                previousProperties.add(previousTransitionProperty);
     204                previousBackingAnimations.add(&animation);
     205            }
     206        }
     207    }
     208
     209    // Create or get the CSSTransitions by CSS property name map for this element.
     210    auto& cssTransitionsByProperty = m_elementToCSSTransitionByCSSPropertyID.ensure(&element, [] {
     211        return HashMap<CSSPropertyID, RefPtr<CSSTransition>> { };
     212    }).iterator->value;
     213
     214    if (auto* currentTransitions = newStyle.transitions()) {
     215        for (size_t i = 0; i < currentTransitions->size(); ++i) {
     216            auto& backingAnimation = currentTransitions->animation(i);
     217            auto property = backingAnimation.property();
     218            if (property == CSSPropertyInvalid)
     219                continue;
     220            previousProperties.remove(property);
     221            // We've found a backing animation that we didn't know about for a valid property.
     222            if (!previousBackingAnimations.contains(&backingAnimation)) {
     223                // If we already had a CSSTransition for this property, check whether its timing properties match the current backing
     224                // animation's properties and whether its blending keyframes match the old and new styles. If they do, move on to the
     225                // next transition, otherwise delete the previous CSSTransition object, and create a new one.
     226                if (cssTransitionsByProperty.contains(property)) {
     227                    if (cssTransitionsByProperty.get(property)->matchesBackingAnimationAndStyles(backingAnimation, oldStyle, newStyle))
     228                        continue;
     229                    auto cssTransitionToRemove = cssTransitionsByProperty.take(property);
     230                    cssTransitionToRemove->setEffect(nullptr);
     231                    removeAnimation(cssTransitionToRemove.releaseNonNull());
     232                }
     233                // Now we can create a new CSSTransition with the new backing animation provided it has a valid
     234                // duration and the from and to values are distinct.
     235                if (backingAnimation.duration() > 0 && oldStyle && !CSSPropertyAnimation::propertiesEqual(property, oldStyle, &newStyle))
     236                    cssTransitionsByProperty.set(property, CSSTransition::create(element, backingAnimation, oldStyle, newStyle));
     237            }
     238        }
     239    }
     240
     241    // Remaining properties are no longer current and must be removed.
     242    for (const auto transitionPropertyToRemove : previousProperties) {
     243        if (!cssTransitionsByProperty.contains(transitionPropertyToRemove))
     244            continue;
     245        auto cssTransitionToRemove = cssTransitionsByProperty.take(transitionPropertyToRemove);
     246        cssTransitionToRemove->setEffect(nullptr);
     247        removeAnimation(cssTransitionToRemove.releaseNonNull());
     248    }
     249
     250    // Remove the map of CSSTransitions by property for this element if it's now empty.
     251    if (cssTransitionsByProperty.isEmpty())
     252        m_elementToCSSTransitionByCSSPropertyID.remove(&element);
    98253}
    99254
  • trunk/Source/WebCore/animation/AnimationTimeline.h

    r228537 r229530  
    2727#pragma once
    2828
     29#include "CSSValue.h"
     30#include "RenderStyle.h"
    2931#include "WebAnimation.h"
    3032#include <wtf/Forward.h>
    3133#include <wtf/HashMap.h>
    32 #include <wtf/HashSet.h>
     34#include <wtf/ListHashSet.h>
    3335#include <wtf/Optional.h>
    3436#include <wtf/Ref.h>
     
    3840namespace WebCore {
    3941
     42class CSSAnimation;
     43class CSSTransition;
    4044class Element;
    41 class WebAnimation;
    4245
    4346class AnimationTimeline : public RefCounted<AnimationTimeline> {
     
    5457    virtual void timingModelDidChange() { };
    5558
    56     const HashSet<RefPtr<WebAnimation>>& animations() const { return m_animations; }
     59    const ListHashSet<RefPtr<WebAnimation>>& animations() const { return m_animations; }
    5760    Vector<RefPtr<WebAnimation>> animationsForElement(Element&);
    5861    void animationWasAddedToElement(WebAnimation&, Element&);
    5962    void animationWasRemovedFromElement(WebAnimation&, Element&);
     63
     64    void updateCSSAnimationsForElement(Element&, const RenderStyle& newStyle, const RenderStyle* oldStyle);
     65    void updateCSSTransitionsForElement(Element&, const RenderStyle& newStyle, const RenderStyle* oldStyle);
    6066
    6167    virtual ~AnimationTimeline();
     
    7076    explicit AnimationTimeline(ClassType);
    7177
    72     const HashMap<RefPtr<Element>, Vector<RefPtr<WebAnimation>>>& elementToAnimationsMap() { return m_elementToAnimationsMap; }
     78    bool hasElementAnimations() const { return !m_elementToAnimationsMap.isEmpty() || !m_elementToCSSAnimationsMap.isEmpty() || !m_elementToCSSTransitionsMap.isEmpty(); }
     79
     80    const HashMap<Element*, Vector<RefPtr<WebAnimation>>>& elementToAnimationsMap() { return m_elementToAnimationsMap; }
     81    const HashMap<Element*, Vector<RefPtr<WebAnimation>>>& elementToCSSAnimationsMap() { return m_elementToCSSAnimationsMap; }
     82    const HashMap<Element*, Vector<RefPtr<WebAnimation>>>& elementToCSSTransitionsMap() { return m_elementToCSSTransitionsMap; }
    7383
    7484private:
     85    HashMap<Element*, Vector<RefPtr<WebAnimation>>>& relevantMapForAnimation(WebAnimation&);
     86
    7587    ClassType m_classType;
    7688    std::optional<Seconds> m_currentTime;
    77     HashMap<RefPtr<Element>, Vector<RefPtr<WebAnimation>>> m_elementToAnimationsMap;
    78     HashSet<RefPtr<WebAnimation>> m_animations;
     89    HashMap<Element*, Vector<RefPtr<WebAnimation>>> m_elementToAnimationsMap;
     90    HashMap<Element*, Vector<RefPtr<WebAnimation>>> m_elementToCSSAnimationsMap;
     91    HashMap<Element*, Vector<RefPtr<WebAnimation>>> m_elementToCSSTransitionsMap;
     92    ListHashSet<RefPtr<WebAnimation>> m_animations;
     93
     94    HashMap<Element*, HashMap<String, RefPtr<CSSAnimation>>> m_elementToCSSAnimationByName;
     95    HashMap<Element*, HashMap<CSSPropertyID, RefPtr<CSSTransition>>> m_elementToCSSTransitionByCSSPropertyID;
    7996};
    8097
  • trunk/Source/WebCore/animation/CSSAnimation.cpp

    r229327 r229530  
    3232namespace WebCore {
    3333
    34 Ref<CSSAnimation> CSSAnimation::create(Element& target, const Animation&)
     34Ref<CSSAnimation> CSSAnimation::create(Element& target, const Animation& backingAnimation)
    3535{
    36     auto& document = target.document();
    37 
    38     auto result = adoptRef(*new CSSAnimation(document));
    39 
     36    auto result = adoptRef(*new CSSAnimation(target.document(), backingAnimation));
     37    result->m_animationName = backingAnimation.name();
     38    result->initialize(target);
    4039    return result;
    4140}
    4241
    43 CSSAnimation::CSSAnimation(Document& document)
    44     : WebAnimation(document)
     42CSSAnimation::CSSAnimation(Document& document, const Animation& backingAnimation)
     43    : DeclarativeAnimation(document, backingAnimation)
    4544{
    4645}
    4746
     47void CSSAnimation::initialize(const Element& target)
     48{
     49    DeclarativeAnimation::initialize(target);
     50
     51    downcast<KeyframeEffectReadOnly>(effect())->computeCSSAnimationBlendingKeyframes();
     52}
     53
     54void CSSAnimation::syncPropertiesWithBackingAnimation()
     55{
     56    DeclarativeAnimation::syncPropertiesWithBackingAnimation();
     57
     58    suspendEffectInvalidation();
     59
     60    auto& animation = backingAnimation();
     61    auto* timing = effect()->timing();
     62
     63    switch (animation.fillMode()) {
     64    case AnimationFillModeNone:
     65        timing->setFill(FillMode::None);
     66        break;
     67    case AnimationFillModeBackwards:
     68        timing->setFill(FillMode::Backwards);
     69        break;
     70    case AnimationFillModeForwards:
     71        timing->setFill(FillMode::Forwards);
     72        break;
     73    case AnimationFillModeBoth:
     74        timing->setFill(FillMode::Both);
     75        break;
     76    }
     77
     78    switch (animation.direction()) {
     79    case Animation::AnimationDirectionNormal:
     80        timing->setDirection(PlaybackDirection::Normal);
     81        break;
     82    case Animation::AnimationDirectionAlternate:
     83        timing->setDirection(PlaybackDirection::Alternate);
     84        break;
     85    case Animation::AnimationDirectionReverse:
     86        timing->setDirection(PlaybackDirection::Reverse);
     87        break;
     88    case Animation::AnimationDirectionAlternateReverse:
     89        timing->setDirection(PlaybackDirection::AlternateReverse);
     90        break;
     91    }
     92
     93    timing->setIterations(animation.iterationCount());
     94
     95    // Synchronize the play state
     96    if (backingAnimation().playState() == AnimPlayStatePlaying && playState() == WebAnimation::PlayState::Paused)
     97        play();
     98    else if (backingAnimation().playState() == AnimPlayStatePaused && playState() == WebAnimation::PlayState::Running)
     99        pause();
     100
     101    unsuspendEffectInvalidation();
     102}
    48103
    49104} // namespace WebCore
  • trunk/Source/WebCore/animation/CSSAnimation.h

    r229327 r229530  
    2626#pragma once
    2727
    28 #include "WebAnimation.h"
     28#include "DeclarativeAnimation.h"
    2929#include <wtf/Ref.h>
    3030
     
    3434class Element;
    3535
    36 class CSSAnimation final : public WebAnimation {
     36class CSSAnimation final : public DeclarativeAnimation {
    3737public:
    3838    static Ref<CSSAnimation> create(Element&, const Animation&);
     
    4242    const String& animationName() const { return m_animationName; }
    4343
     44protected:
     45    void initialize(const Element&) final;
     46    void syncPropertiesWithBackingAnimation() final;
     47
    4448private:
    45     CSSAnimation(Document&);
     49    CSSAnimation(Document&, const Animation&);
    4650
    4751    String m_animationName;
  • trunk/Source/WebCore/animation/CSSTransition.cpp

    r229340 r229530  
    2929#include "Animation.h"
    3030#include "Element.h"
     31#include "KeyframeEffectReadOnly.h"
    3132
    3233namespace WebCore {
    3334
    34 Ref<CSSTransition> CSSTransition::create(Element& target, const Animation&)
     35Ref<CSSTransition> CSSTransition::create(Element& target, const Animation& backingAnimation, const RenderStyle* oldStyle, const RenderStyle& newStyle)
    3536{
    36     auto& document = target.document();
    37 
    38     auto result = adoptRef(*new CSSTransition(document));
    39 
     37    auto result = adoptRef(*new CSSTransition(target.document(), backingAnimation));
     38    result->m_transitionProperty = backingAnimation.property();
     39    result->initialize(target);
     40    downcast<KeyframeEffectReadOnly>(result->effect())->computeCSSTransitionBlendingKeyframes(oldStyle, newStyle);
    4041    return result;
    4142}
    4243
    43 CSSTransition::CSSTransition(Document& document)
    44     : WebAnimation(document)
     44CSSTransition::CSSTransition(Document& document, const Animation& backingAnimation)
     45    : DeclarativeAnimation(document, backingAnimation)
    4546{
    4647}
    4748
     49bool CSSTransition::matchesBackingAnimationAndStyles(const Animation& newBackingAnimation, const RenderStyle* oldStyle, const RenderStyle& newStyle) const
     50{
     51    bool backingAnimationsMatch = backingAnimation() == newBackingAnimation;
     52    if (!oldStyle)
     53        return backingAnimationsMatch;
     54    return backingAnimationsMatch && !downcast<KeyframeEffectReadOnly>(effect())->stylesWouldYieldNewCSSTransitionsBlendingKeyframes(*oldStyle, newStyle);
     55}
     56
     57bool CSSTransition::canBeListed() const
     58{
     59    if (!downcast<KeyframeEffectReadOnly>(effect())->hasBlendingKeyframes())
     60        return false;
     61    return WebAnimation::canBeListed();
     62}
     63
    4864} // namespace WebCore
  • trunk/Source/WebCore/animation/CSSTransition.h

    r229340 r229530  
    2727
    2828#include "CSSPropertyNames.h"
    29 #include "WebAnimation.h"
     29#include "DeclarativeAnimation.h"
    3030#include <wtf/Ref.h>
    3131
     
    3434class Animation;
    3535class Element;
     36class RenderStyle;
    3637
    37 class CSSTransition final : public WebAnimation {
     38class CSSTransition final : public DeclarativeAnimation {
    3839public:
    39     static Ref<CSSTransition> create(Element&, const Animation&);
     40    static Ref<CSSTransition> create(Element&, const Animation&, const RenderStyle* oldStyle, const RenderStyle& newStyle);
    4041    ~CSSTransition() = default;
    4142
     
    4344    String transitionProperty() const { return getPropertyNameString(m_transitionProperty); }
    4445
     46    bool matchesBackingAnimationAndStyles(const Animation&, const RenderStyle* oldStyle, const RenderStyle& newStyle) const;
     47    bool canBeListed() const final;
     48
    4549private:
    46     CSSTransition(Document&);
     50    CSSTransition(Document&, const Animation&);
    4751
    4852    CSSPropertyID m_transitionProperty;
  • trunk/Source/WebCore/animation/DeclarativeAnimation.cpp

    r229527 r229530  
    2525
    2626#include "config.h"
    27 #include "CSSAnimation.h"
     27#include "DeclarativeAnimation.h"
    2828
    2929#include "Animation.h"
     30#include "AnimationEffectTimingReadOnly.h"
    3031#include "Element.h"
     32#include "KeyframeEffectReadOnly.h"
    3133
    3234namespace WebCore {
    3335
    34 Ref<CSSAnimation> CSSAnimation::create(Element& target, const Animation&)
    35 {
    36     auto& document = target.document();
    37 
    38     auto result = adoptRef(*new CSSAnimation(document));
    39 
    40     return result;
    41 }
    42 
    43 CSSAnimation::CSSAnimation(Document& document)
     36DeclarativeAnimation::DeclarativeAnimation(Document& document, const Animation& backingAnimation)
    4437    : WebAnimation(document)
     38    , m_backingAnimation(const_cast<Animation&>(backingAnimation))
    4539{
    4640}
    4741
     42void DeclarativeAnimation::setBackingAnimation(const Animation& backingAnimation)
     43{
     44    m_backingAnimation = const_cast<Animation&>(backingAnimation);
     45    syncPropertiesWithBackingAnimation();
     46}
     47
     48void DeclarativeAnimation::initialize(const Element& target)
     49{
     50    // We need to suspend invalidation of the animation's keyframe effect during its creation
     51    // as it would otherwise trigger invalidation of the document's style and this would be
     52    // incorrect since it would happen during style invalidation.
     53    suspendEffectInvalidation();
     54
     55    setEffect(KeyframeEffectReadOnly::create(target));
     56    setTimeline(&target.document().timeline());
     57    syncPropertiesWithBackingAnimation();
     58    if (backingAnimation().playState() == AnimPlayStatePlaying)
     59        play();
     60
     61    unsuspendEffectInvalidation();
     62}
     63
     64void DeclarativeAnimation::syncPropertiesWithBackingAnimation()
     65{
     66    suspendEffectInvalidation();
     67
     68    auto* timing = effect()->timing();
     69    timing->setDelay(Seconds(m_backingAnimation->delay()));
     70    timing->setIterationDuration(Seconds(m_backingAnimation->duration()));
     71    timing->setTimingFunction(m_backingAnimation->timingFunction());
     72
     73    unsuspendEffectInvalidation();
     74}
    4875
    4976} // namespace WebCore
  • trunk/Source/WebCore/animation/DeclarativeAnimation.h

    r229527 r229530  
    3434class Element;
    3535
    36 class CSSAnimation final : public WebAnimation {
     36class DeclarativeAnimation : public WebAnimation {
    3737public:
    38     static Ref<CSSAnimation> create(Element&, const Animation&);
    39     ~CSSAnimation() = default;
     38    ~DeclarativeAnimation() = default;
    4039
    41     bool isCSSAnimation() const override { return true; }
    42     const String& animationName() const { return m_animationName; }
     40    bool isDeclarativeAnimation() const final { return true; }
     41
     42    const Animation& backingAnimation() const { return m_backingAnimation; }
     43    void setBackingAnimation(const Animation&);
     44
     45protected:
     46    DeclarativeAnimation(Document&, const Animation&);
     47
     48    virtual void initialize(const Element&);
     49    virtual void syncPropertiesWithBackingAnimation();
    4350
    4451private:
    45     CSSAnimation(Document&);
    46 
    47     String m_animationName;
     52    Ref<Animation> m_backingAnimation;
    4853
    4954};
     
    5156} // namespace WebCore
    5257
    53 SPECIALIZE_TYPE_TRAITS_WEB_ANIMATION(CSSAnimation, isCSSAnimation())
     58SPECIALIZE_TYPE_TRAITS_WEB_ANIMATION(DeclarativeAnimation, isDeclarativeAnimation())
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r228537 r229530  
    2727#include "DocumentTimeline.h"
    2828
     29#include "AnimationPlaybackEvent.h"
    2930#include "Chrome.h"
    3031#include "ChromeClient.h"
     
    163164void DocumentTimeline::updateAnimations()
    164165{
    165     if (m_document && !elementToAnimationsMap().isEmpty()) {
     166    if (m_document && hasElementAnimations()) {
    166167        for (const auto& elementToAnimationsMapItem : elementToAnimationsMap())
    167168            elementToAnimationsMapItem.key->invalidateStyleAndLayerComposition();
     169        for (const auto& elementToCSSAnimationsMapItem : elementToCSSAnimationsMap())
     170            elementToCSSAnimationsMapItem.key->invalidateStyleAndLayerComposition();
     171        for (const auto& elementToCSSTransitionsMapItem : elementToCSSTransitionsMap())
     172            elementToCSSTransitionsMapItem.key->invalidateStyleAndLayerComposition();
    168173        m_document->updateStyleIfNeeded();
    169174    }
     
    173178    m_acceleratedAnimationsPendingRunningStateChange.clear();
    174179
    175     for (const auto& animation : animations())
    176         animation->updateFinishedState(WebAnimation::DidSeek::No, WebAnimation::SynchronouslyNotify::No);
    177 
    178180    // Time has advanced, the timing model requires invalidation now.
    179181    timingModelDidChange();
     
    186188    if (auto* element = renderer.element()) {
    187189        for (auto animation : animationsForElement(*element)) {
    188             if (animation->effect() && animation->effect()->isKeyframeEffect())
    189                 downcast<KeyframeEffect>(animation->effect())->getAnimatedStyle(result);
     190            if (is<KeyframeEffectReadOnly>(animation->effect()))
     191                downcast<KeyframeEffectReadOnly>(animation->effect())->getAnimatedStyle(result);
    190192        }
    191193    }
     
    209211    auto animations = animationsForElement(element);
    210212    for (const auto& animation : animations) {
    211         if (animation->effect() && animation->effect()->isKeyframeEffect() && !downcast<KeyframeEffect>(animation->effect())->isRunningAccelerated())
     213        if (is<KeyframeEffectReadOnly>(animation->effect()) && !downcast<KeyframeEffectReadOnly>(animation->effect())->isRunningAccelerated())
    212214            return false;
    213215    }
  • trunk/Source/WebCore/animation/KeyframeEffectReadOnly.cpp

    r229327 r229530  
    2929#include "Animation.h"
    3030#include "AnimationEffectTimingReadOnly.h"
     31#include "CSSAnimation.h"
    3132#include "CSSComputedStyleDeclaration.h"
    3233#include "CSSPropertyAnimation.h"
     
    3435#include "CSSStyleDeclaration.h"
    3536#include "CSSTimingFunctionValue.h"
     37#include "CSSTransition.h"
    3638#include "Element.h"
    3739#include "FontCascade.h"
     
    4143#include "RenderElement.h"
    4244#include "RenderStyle.h"
     45#include "StylePendingResources.h"
    4346#include "StyleResolver.h"
    4447#include "TimingFunction.h"
     
    5154static inline void invalidateElement(Element* element)
    5255{
    53     if (!element)
    54         return;
    55 
    56     element->invalidateStyleAndLayerComposition();
    57     element->document().updateStyleIfNeeded();
     56    if (element)
     57        element->invalidateStyleAndLayerComposition();
    5858}
    5959
     
    447447}
    448448
     449Ref<KeyframeEffectReadOnly> KeyframeEffectReadOnly::create(const Element& target)
     450{
     451    return adoptRef(*new KeyframeEffectReadOnly(KeyframeEffectReadOnlyClass, AnimationEffectTimingReadOnly::create(), const_cast<Element*>(&target)));
     452}
     453
    449454KeyframeEffectReadOnly::KeyframeEffectReadOnly(ClassType classType, Ref<AnimationEffectTimingReadOnly>&& timing, Element* target)
    450455    : AnimationEffectReadOnly(classType, WTFMove(timing))
     
    501506
    502507    // 3. For each keyframe in keyframes perform the following steps:
    503     for (auto& parsedKeyframe : m_parsedKeyframes) {
    504         // 1. Initialize a dictionary object, output keyframe, using the following definition:
    505         //
    506         // dictionary BaseComputedKeyframe {
    507         //      double?             offset = null;
    508         //      double              computedOffset;
    509         //      DOMString           easing = "linear";
    510         //      CompositeOperation? composite = null;
    511         // };
    512 
    513         // 2. Set offset, computedOffset, easing, composite members of output keyframe to the respective values keyframe offset, computed keyframe
    514         // offset, keyframe-specific timing function and keyframe-specific composite operation of keyframe.
    515         BaseComputedKeyframe computedKeyframe;
    516         computedKeyframe.offset = parsedKeyframe.offset;
    517         computedKeyframe.computedOffset = parsedKeyframe.computedOffset;
    518         computedKeyframe.easing = parsedKeyframe.timingFunction->cssText();
    519         computedKeyframe.composite = parsedKeyframe.composite;
    520 
    521         auto outputKeyframe = convertDictionaryToJS(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), computedKeyframe);
    522 
    523         // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
    524         for (auto it = parsedKeyframe.unparsedStyle.begin(), end = parsedKeyframe.unparsedStyle.end(); it != end; ++it) {
    525             // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
    526             auto propertyName = CSSPropertyIDToIDLAttributeName(it->key);
    527             // 2. Let IDL value be the result of serializing the property value of declaration by passing declaration to the algorithm to serialize a CSS value.
    528             // 3. Let value be the result of converting IDL value to an ECMAScript String value.
    529             auto value = toJS<IDLDOMString>(state, it->value);
    530             // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
    531             //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
    532             JSObject::defineOwnProperty(outputKeyframe, &state, AtomicString(propertyName).impl(), PropertyDescriptor(value, 0), false);
    533         }
    534 
    535         // 4. Append output keyframe to result.
    536         result.append(JSC::Strong<JSC::JSObject> { state.vm(), outputKeyframe });
     508    if (is<DeclarativeAnimation>(animation())) {
     509        auto computedStyleExtractor = ComputedStyleExtractor(m_target.get());
     510        for (size_t i = 0; i < m_blendingKeyframes.size(); ++i) {
     511            // 1. Initialize a dictionary object, output keyframe, using the following definition:
     512            //
     513            // dictionary BaseComputedKeyframe {
     514            //      double?             offset = null;
     515            //      double              computedOffset;
     516            //      DOMString           easing = "linear";
     517            //      CompositeOperation? composite = null;
     518            // };
     519
     520            auto& keyframe = m_blendingKeyframes[i];
     521
     522            // 2. Set offset, computedOffset, easing members of output keyframe to the respective values keyframe offset, computed keyframe offset,
     523            // and keyframe-specific timing function of keyframe.
     524            BaseComputedKeyframe computedKeyframe;
     525            computedKeyframe.offset = keyframe.key();
     526            computedKeyframe.computedOffset = keyframe.key();
     527
     528            auto outputKeyframe = convertDictionaryToJS(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), computedKeyframe);
     529
     530            // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
     531            auto& style = *keyframe.style();
     532            for (auto cssPropertyId : keyframe.properties()) {
     533                // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
     534                auto propertyName = CSSPropertyIDToIDLAttributeName(cssPropertyId);
     535                // 2. Let IDL value be the result of serializing the property value of declaration by passing declaration to the algorithm to serialize a CSS value.
     536                auto idlValue = computedStyleExtractor.valueForPropertyinStyle(style, cssPropertyId)->cssText();
     537                // 3. Let value be the result of converting IDL value to an ECMAScript String value.
     538                auto value = toJS<IDLDOMString>(state, idlValue);
     539                // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
     540                //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
     541                JSObject::defineOwnProperty(outputKeyframe, &state, AtomicString(propertyName).impl(), PropertyDescriptor(value, 0), false);
     542            }
     543
     544            // 5. Append output keyframe to result.
     545            result.append(JSC::Strong<JSC::JSObject> { state.vm(), outputKeyframe });
     546        }
     547    } else {
     548        for (auto& parsedKeyframe : m_parsedKeyframes) {
     549            // 1. Initialize a dictionary object, output keyframe, using the following definition:
     550            //
     551            // dictionary BaseComputedKeyframe {
     552            //      double?             offset = null;
     553            //      double              computedOffset;
     554            //      DOMString           easing = "linear";
     555            //      CompositeOperation? composite = null;
     556            // };
     557
     558            // 2. Set offset, computedOffset, easing, composite members of output keyframe to the respective values keyframe offset, computed keyframe
     559            // offset, keyframe-specific timing function and keyframe-specific composite operation of keyframe.
     560            BaseComputedKeyframe computedKeyframe;
     561            computedKeyframe.offset = parsedKeyframe.offset;
     562            computedKeyframe.computedOffset = parsedKeyframe.computedOffset;
     563            computedKeyframe.easing = parsedKeyframe.timingFunction->cssText();
     564            computedKeyframe.composite = parsedKeyframe.composite;
     565
     566            auto outputKeyframe = convertDictionaryToJS(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), computedKeyframe);
     567
     568            // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
     569            for (auto it = parsedKeyframe.unparsedStyle.begin(), end = parsedKeyframe.unparsedStyle.end(); it != end; ++it) {
     570                // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
     571                auto propertyName = CSSPropertyIDToIDLAttributeName(it->key);
     572                // 2. Let IDL value be the result of serializing the property value of declaration by passing declaration to the algorithm to serialize a CSS value.
     573                // 3. Let value be the result of converting IDL value to an ECMAScript String value.
     574                auto value = toJS<IDLDOMString>(state, it->value);
     575                // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
     576                //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
     577                JSObject::defineOwnProperty(outputKeyframe, &state, AtomicString(propertyName).impl(), PropertyDescriptor(value, 0), false);
     578            }
     579
     580            // 4. Append output keyframe to result.
     581            result.append(JSC::Strong<JSC::JSObject> { state.vm(), outputKeyframe });
     582        }
    537583    }
    538584
     
    642688}
    643689
     690void KeyframeEffectReadOnly::computeCSSAnimationBlendingKeyframes()
     691{
     692    ASSERT(is<CSSAnimation>(animation()));
     693
     694    auto& backingAnimation = downcast<CSSAnimation>(animation())->backingAnimation();
     695    if (backingAnimation.name().isEmpty())
     696        return;
     697
     698    auto renderStyle = RenderStyle::createPtr();
     699    // We need to call update() on the FontCascade or we'll hit an ASSERT when parsing font-related properties.
     700    renderStyle->fontCascade().update(nullptr);
     701
     702    KeyframeList keyframeList(backingAnimation.name());
     703    if (auto* styleScope = Style::Scope::forOrdinal(*m_target, backingAnimation.nameStyleScopeOrdinal()))
     704        styleScope->resolver().keyframeStylesForAnimation(*m_target, renderStyle.get(), keyframeList);
     705
     706    // Ensure resource loads for all the frames.
     707    for (auto& keyframe : keyframeList.keyframes()) {
     708        if (auto* style = const_cast<RenderStyle*>(keyframe.style()))
     709            Style::loadPendingResources(*style, m_target->document(), m_target.get());
     710    }
     711
     712    m_blendingKeyframes = WTFMove(keyframeList);
     713
     714    computeStackingContextImpact();
     715}
     716
     717void KeyframeEffectReadOnly::computeCSSTransitionBlendingKeyframes(const RenderStyle* oldStyle, const RenderStyle& newStyle)
     718{
     719    ASSERT(is<CSSTransition>(animation()));
     720
     721    if (!oldStyle || m_blendingKeyframes.size())
     722        return;
     723
     724    auto& backingAnimation = downcast<CSSTransition>(animation())->backingAnimation();
     725
     726    auto toStyle = RenderStyle::clonePtr(newStyle);
     727    if (m_target)
     728        Style::loadPendingResources(*toStyle, m_target->document(), m_target.get());
     729
     730    KeyframeList keyframeList("keyframe-effect-" + createCanonicalUUIDString());
     731    keyframeList.addProperty(backingAnimation.property());
     732
     733    KeyframeValue fromKeyframeValue(0, RenderStyle::clonePtr(*oldStyle));
     734    fromKeyframeValue.addProperty(backingAnimation.property());
     735    keyframeList.insert(WTFMove(fromKeyframeValue));
     736
     737    KeyframeValue toKeyframeValue(1, WTFMove(toStyle));
     738    toKeyframeValue.addProperty(backingAnimation.property());
     739    keyframeList.insert(WTFMove(toKeyframeValue));
     740
     741    m_blendingKeyframes = WTFMove(keyframeList);
     742
     743    computeStackingContextImpact();
     744}
     745
     746bool KeyframeEffectReadOnly::stylesWouldYieldNewCSSTransitionsBlendingKeyframes(const RenderStyle& oldStyle, const RenderStyle& newStyle) const
     747{
     748    ASSERT(is<CSSTransition>(animation()));
     749    auto property = downcast<CSSTransition>(animation())->backingAnimation().property();
     750
     751    // If we didn't have blending keyframes yet, we would create new blending keyframes provided
     752    // the start and end styles hold different values for this property.
     753    if (!hasBlendingKeyframes())
     754        return !CSSPropertyAnimation::propertiesEqual(property, &oldStyle, &newStyle);
     755
     756    // Otherwise, we would create new blending keyframes provided the current start keyframe holds
     757    // a different value than the new start style or the current end keyframe holds a different value
     758    // than the new end style for this property.
     759    return !CSSPropertyAnimation::propertiesEqual(property, m_blendingKeyframes[0].style(), &oldStyle) || !CSSPropertyAnimation::propertiesEqual(property, m_blendingKeyframes[1].style(), &newStyle);
     760}
     761
    644762void KeyframeEffectReadOnly::computeStackingContextImpact()
    645763{
     
    719837            return false;
    720838    }
    721     return true;
     839    return hasBlendingKeyframes();
    722840}
    723841
     
    862980        //     passing interval distance as the input progress.
    863981        auto transformedDistance = intervalDistance;
    864         if (startKeyframeIndex) {
     982        // In case we're backing a CSSAnimation or CSSTransition we won't actually have parsed keyframes.
     983        if (startKeyframeIndex && startKeyframeIndex.value() + 1 <= m_parsedKeyframes.size()) {
    865984            if (auto iterationDuration = timing()->iterationDuration()) {
    866985                auto rangeDuration = (endOffset - startOffset) * iterationDuration.seconds();
  • trunk/Source/WebCore/animation/KeyframeEffectReadOnly.h

    r228717 r229530  
    4747    static ExceptionOr<Ref<KeyframeEffectReadOnly>> create(JSC::ExecState&, Element*, JSC::Strong<JSC::JSObject>&&, std::optional<Variant<double, KeyframeEffectOptions>>&&);
    4848    static ExceptionOr<Ref<KeyframeEffectReadOnly>> create(JSC::ExecState&, Ref<KeyframeEffectReadOnly>&&);
     49    static Ref<KeyframeEffectReadOnly> create(const Element&);
    4950    ~KeyframeEffectReadOnly() { }
    5051
     
    110111#endif
    111112
     113    void computeCSSAnimationBlendingKeyframes();
     114    void computeCSSTransitionBlendingKeyframes(const RenderStyle* oldStyle, const RenderStyle& newStyle);
     115    bool stylesWouldYieldNewCSSTransitionsBlendingKeyframes(const RenderStyle& oldStyle, const RenderStyle& newStyle) const;
     116    bool hasBlendingKeyframes() const { return m_blendingKeyframes.size(); }
     117
    112118protected:
    113119    void copyPropertiesFromSource(Ref<KeyframeEffectReadOnly>&&);
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r229069 r229530  
    6969WebAnimation::~WebAnimation()
    7070{
    71     if (m_timeline)
    72         m_timeline->removeAnimation(*this);
     71}
     72
     73void WebAnimation::suspendEffectInvalidation()
     74{
     75    ++m_suspendCount;
     76}
     77
     78void WebAnimation::unsuspendEffectInvalidation()
     79{
     80    ASSERT(m_suspendCount > 0);
     81    --m_suspendCount;
    7382}
    7483
    7584void WebAnimation::timingModelDidChange()
    7685{
    77     if (m_effect)
     86    if (!isEffectInvalidationSuspended() && m_effect)
    7887        m_effect->invalidate();
    7988    if (m_timeline)
     
    120129    if (oldEffect) {
    121130        oldEffect->setAnimation(nullptr);
    122         if (m_timeline && is<KeyframeEffect>(oldEffect)) {
    123             if (auto* target = downcast<KeyframeEffect>(oldEffect.get())->target())
     131        if (m_timeline && is<KeyframeEffectReadOnly>(oldEffect)) {
     132            if (auto* target = downcast<KeyframeEffectReadOnly>(oldEffect.get())->target())
    124133                m_timeline->animationWasRemovedFromElement(*this, *target);
    125134        }
     
    128137    if (m_effect) {
    129138        m_effect->setAnimation(this);
    130         if (m_timeline && is<KeyframeEffect>(m_effect)) {
    131             if (auto* target = downcast<KeyframeEffect>(m_effect.get())->target())
     139        if (m_timeline && is<KeyframeEffectReadOnly>(m_effect)) {
     140            if (auto* target = downcast<KeyframeEffectReadOnly>(m_effect.get())->target())
    132141                m_timeline->animationWasAddedToElement(*this, *target);
    133142        }
     
    156165        timeline->addAnimation(*this);
    157166
    158     if (is<KeyframeEffect>(m_effect)) {
    159         auto* keyframeEffect = downcast<KeyframeEffect>(m_effect.get());
     167    if (is<KeyframeEffectReadOnly>(m_effect)) {
     168        auto* keyframeEffect = downcast<KeyframeEffectReadOnly>(m_effect.get());
    160169        auto* target = keyframeEffect->target();
    161170        if (target) {
     
    662671
    663672    m_scheduledMicrotask = true;
    664     MicrotaskQueue::mainThreadQueue().append(std::make_unique<VoidMicrotask>(std::bind(&WebAnimation::performMicrotask, this)));
     673    MicrotaskQueue::mainThreadQueue().append(std::make_unique<VoidMicrotask>([this, protectedThis = makeRef(*this)] () {
     674        this->performMicrotask();
     675    }));
    665676}
    666677
     
    806817
    807818    // 4. Resolve animation's current ready promise with animation.
    808     m_readyPromise->resolve(*this);
     819    if (!m_readyPromise->isFulfilled())
     820        m_readyPromise->resolve(*this);
    809821
    810822    // 5. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.
     
    925937
    926938    // 4. Resolve animation's current ready promise with animation.
    927     m_readyPromise->resolve(*this);
     939    if (!m_readyPromise->isFulfilled())
     940        m_readyPromise->resolve(*this);
    928941
    929942    // 5. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the
     
    9911004void WebAnimation::startOrStopAccelerated()
    9921005{
    993     if (is<KeyframeEffect>(m_effect))
    994         downcast<KeyframeEffect>(*m_effect).startOrStopAccelerated();
     1006    if (is<KeyframeEffectReadOnly>(m_effect))
     1007        downcast<KeyframeEffectReadOnly>(*m_effect).startOrStopAccelerated();
    9951008}
    9961009
     
    10261039}
    10271040
     1041bool WebAnimation::canBeListed() const
     1042{
     1043    // To be listed in getAnimations() an animation needs a target effect which is current or in effect.
     1044    if (!m_effect)
     1045        return false;
     1046
     1047    // An animation effect is in effect if its active time is not unresolved.
     1048    if (m_effect->activeTime())
     1049        return true;
     1050
     1051    // An animation effect is current if either of the following conditions is true:
     1052    // - the animation effect is in the before phase, or
     1053    // - the animation effect is in play.
     1054
     1055    // An animation effect is in play if all of the following conditions are met:
     1056    // - the animation effect is in the active phase, and
     1057    // - the animation effect is associated with an animation that is not finished.
     1058    auto phase = m_effect->phase();
     1059    return phase == AnimationEffectReadOnly::Phase::Before || (phase == AnimationEffectReadOnly::Phase::Active && playState() != PlayState::Finished);
     1060}
     1061
    10281062} // namespace WebCore
  • trunk/Source/WebCore/animation/WebAnimation.h

    r229340 r229530  
    5353    ~WebAnimation();
    5454
     55    virtual bool isDeclarativeAnimation() const { return false; }
    5556    virtual bool isCSSAnimation() const { return false; }
    5657    virtual bool isCSSTransition() const { return false; }
     58
     59    virtual bool canBeListed() const;
    5760
    5861    const String& id() const { return m_id; }
     
    106109
    107110    void timingModelDidChange();
     111    void suspendEffectInvalidation();
     112    void unsuspendEffectInvalidation();
    108113
    109114    String description();
     
    114119protected:
    115120    explicit WebAnimation(Document&);
     121
     122    bool isEffectInvalidationSuspended() { return m_suspendCount; }
    116123
    117124private:
     
    146153    std::optional<Seconds> m_startTime;
    147154    std::optional<Seconds> m_holdTime;
     155    int m_suspendCount { 0 };
    148156    double m_playbackRate { 1 };
    149157    bool m_isStopped { false };
  • trunk/Source/WebCore/dom/Document.cpp

    r229505 r229530  
    112112#include "JSLazyEventListener.h"
    113113#include "KeyboardEvent.h"
     114#include "KeyframeEffectReadOnly.h"
    114115#include "LayoutDisallowedScope.h"
    115116#include "LoaderStrategy.h"
     
    76447645Vector<RefPtr<WebAnimation>> Document::getAnimations()
    76457646{
     7647    // FIXME: Filter and order the list as specified (webkit.org/b/179535).
     7648
     7649    // For the list of animations to be current, we need to account for any pending CSS changes,
     7650    // such as updates to CSS Animations and CSS Transitions.
     7651    updateStyleIfNeeded();
     7652
    76467653    Vector<RefPtr<WebAnimation>> animations;
    76477654    if (m_timeline) {
    7648         // FIXME: Filter and order the list as specified (webkit.org/b/179535).
    7649         for (auto& animation : m_timeline->animations())
    7650             animations.append(animation);
     7655        for (auto& animation : m_timeline->animations()) {
     7656            if (animation->canBeListed() && is<KeyframeEffectReadOnly>(animation->effect())) {
     7657                if (auto* target = downcast<KeyframeEffectReadOnly>(animation->effect())->target()) {
     7658                    if (target->isDescendantOf(this))
     7659                        animations.append(animation);
     7660                }
     7661            }
     7662        }
    76517663    }
    76527664    return animations;
  • trunk/Source/WebCore/dom/Element.cpp

    r229372 r229530  
    37693769{
    37703770    // FIXME: Filter and order the list as specified (webkit.org/b/179535).
    3771     if (auto timeline = document().existingTimeline())
    3772         return timeline->animationsForElement(*this);
    3773     return { };
     3771
     3772    // For the list of animations to be current, we need to account for any pending CSS changes,
     3773    // such as updates to CSS Animations and CSS Transitions.
     3774    // FIXME: We might be able to use ComputedStyleExtractor which is more optimized.
     3775    document().updateStyleIfNeeded();
     3776
     3777    Vector<RefPtr<WebAnimation>> animations;
     3778    if (auto timeline = document().existingTimeline()) {
     3779        for (auto& animation : timeline->animationsForElement(*this)) {
     3780            if (animation->canBeListed())
     3781                animations.append(animation);
     3782        }
     3783    }
     3784    return animations;
    37743785}
    37753786
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r228497 r229530  
    4545#include "RenderElement.h"
    4646#include "RenderView.h"
     47#include "RuntimeEnabledFeatures.h"
    4748#include "Settings.h"
    4849#include "ShadowRoot.h"
     
    287288    auto* oldStyle = renderOrDisplayContentsStyle(element);
    288289
    289     if (auto timeline = element.document().existingTimeline()) {
     290    // New code path for CSS Animations and CSS Transitions.
     291    if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     292        // First, we need to make sure that any new CSS animation occuring on this element has a matching WebAnimation
     293        // on the document timeline. Note that we get timeline() on the Document here because we need a timeline created
     294        // in case no Web Animations have been created through the JS API.
     295        if ((oldStyle && oldStyle->hasAnimations()) || newStyle->hasAnimations())
     296            m_document.timeline().updateCSSAnimationsForElement(element, *newStyle, oldStyle);
     297
     298        if ((oldStyle && oldStyle->hasTransitions()) || newStyle->hasTransitions())
     299            m_document.timeline().updateCSSTransitionsForElement(element, *newStyle, oldStyle);
     300    }
     301
     302    if (auto timeline = m_document.existingTimeline()) {
     303        // Now we can update all Web animations, which will include CSS Animations as well
     304        // as animations created via the JS API.
    290305        auto webAnimations = timeline->animationsForElement(element);
    291306        if (!webAnimations.isEmpty()) {
     
    297312    }
    298313
    299     auto& animationController = m_document.frame()->animation();
    300 
    301     auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
    302 
    303     if (animationUpdate.style)
    304         newStyle = WTFMove(animationUpdate.style);
     314    bool shouldRecompositeLayer = false;
     315
     316    // Old code path for CSS Animations and CSS Transitions.
     317    if (!RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
     318        auto& animationController = m_document.frame()->animation();
     319
     320        auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
     321        shouldRecompositeLayer = animationUpdate.stateChanged;
     322
     323        if (animationUpdate.style)
     324            newStyle = WTFMove(animationUpdate.style);
     325    }
    305326
    306327    auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
     
    310331        change = Detach;
    311332
    312     bool shouldRecompositeLayer = element.styleResolutionShouldRecompositeLayer() || animationUpdate.stateChanged;
     333    shouldRecompositeLayer |= element.styleResolutionShouldRecompositeLayer();
    313334
    314335    return { WTFMove(newStyle), change, shouldRecompositeLayer };
  • trunk/Source/WebKitLegacy/mac/ChangeLog

    r229511 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Dean Jackson and Jon Lee.
     8
     9        Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
     10        which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
     11
     12        * WebView/WebPreferenceKeysPrivate.h:
     13        * WebView/WebPreferences.mm:
     14        (+[WebPreferences initialize]):
     15        (-[WebPreferences setModernMediaControlsEnabled:]):
     16        (-[WebPreferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]):
     17        (-[WebPreferences setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:]):
     18        * WebView/WebPreferencesPrivate.h:
     19        * WebView/WebView.mm:
     20        (-[WebView _preferencesChanged:]):
     21
    1222018-03-10  Megan Gardner  <megan_gardner@apple.com>
    223
  • trunk/Source/WebKitLegacy/mac/WebView/WebPreferenceKeysPrivate.h

    r228486 r229530  
    196196#define WebKitConstantPropertiesEnabledPreferenceKey @"WebKitConstantPropertiesEnabled"
    197197#define WebKitFetchAPIKeepAliveEnabledPreferenceKey @"WebKitFetchAPIKeepAliveEnabled"
     198#define WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey @"WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled"
    198199
    199200#if !TARGET_OS_IPHONE
  • trunk/Source/WebKitLegacy/mac/WebView/WebPreferences.mm

    r228486 r229530  
    623623        [NSNumber numberWithBool:NO], WebKitCustomPasteboardDataEnabledPreferenceKey,
    624624        [NSNumber numberWithBool:YES], WebKitModernMediaControlsEnabledPreferenceKey,
     625        [NSNumber numberWithBool:NO], WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey,
     626
    625627#if ENABLE(WEBGL2)
    626628        [NSNumber numberWithBool:NO], WebKitWebGL2EnabledPreferenceKey,
     
    31163118}
    31173119
     3120- (BOOL)cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled
     3121{
     3122    return [self _boolValueForKey:WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey];
     3123}
     3124
     3125- (void)setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:(BOOL)flag
     3126{
     3127    [self _setBoolValue:flag forKey:WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey];
     3128}
     3129
    31183130- (BOOL)intersectionObserverEnabled
    31193131{
  • trunk/Source/WebKitLegacy/mac/WebView/WebPreferencesPrivate.h

    r228486 r229530  
    571571- (BOOL)modernMediaControlsEnabled;
    572572
     573- (void)setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled:(BOOL)flag;
     574- (BOOL)cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled;
     575
    573576- (void)setWebAuthenticationEnabled:(BOOL)flag;
    574577- (BOOL)webAuthenticationEnabled;
  • trunk/Source/WebKitLegacy/mac/WebView/WebView.mm

    r229511 r229530  
    30063006    RuntimeEnabledFeatures::sharedFeatures().setInteractiveFormValidationEnabled([self interactiveFormValidationEnabled]);
    30073007    RuntimeEnabledFeatures::sharedFeatures().setModernMediaControlsEnabled([preferences modernMediaControlsEnabled]);
     3008    RuntimeEnabledFeatures::sharedFeatures().setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled([preferences cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled]);
    30083009
    30093010    RuntimeEnabledFeatures::sharedFeatures().setCacheAPIEnabled([preferences cacheAPIEnabled]);
  • trunk/Source/WebKitLegacy/win/ChangeLog

    r229410 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Dean Jackson and Jon Lee.
     8
     9        Add the missing WebKitLegacy support the cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled flag
     10        which is required for the matching <!-- webkit-test-runner --> flag to work in DumpRenderTree.
     11
     12        * Interfaces/IWebPreferencesPrivate.idl:
     13        * WebPreferences.cpp:
     14        (WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
     15        (WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled):
     16        * WebPreferenceKeysPrivate.h
     17        * WebPreferences.h:
     18        * WebView.cpp:
     19        (WebView::notifyPreferencesChanged):
     20
    1212018-03-08  Yusuke Suzuki  <utatane.tea@gmail.com>
    222
  • trunk/Source/WebKitLegacy/win/Interfaces/IWebPreferencesPrivate.idl

    r229143 r229530  
    184184    HRESULT modernMediaControlsEnabled([out, retval] BOOL* enabled);
    185185    HRESULT setModernMediaControlsEnabled([in] BOOL enabled);
     186    HRESULT cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled([out, retval] BOOL* enabled);
     187    HRESULT setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled([in] BOOL enabled);
    186188}
    187189
  • trunk/Source/WebKitLegacy/win/WebPreferenceKeysPrivate.h

    r229143 r229530  
    183183#define WebKitWebAnimationsEnabledPreferenceKey "WebKitWebAnimationsEnabled"
    184184
     185#define WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey "WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled"
     186
    185187#define WebKitUserTimingEnabledPreferenceKey "WebKitUserTimingEnabled"
    186188
  • trunk/Source/WebKitLegacy/win/WebPreferences.cpp

    r229309 r229530  
    20302030}
    20312031
     2032HRESULT WebPreferences::cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(_Out_ BOOL* enabled)
     2033{
     2034    if (!enabled)
     2035        return E_POINTER;
     2036    *enabled = boolValueForKey(WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey);
     2037    return S_OK;
     2038}
     2039
     2040HRESULT WebPreferences::setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(BOOL enabled)
     2041{
     2042    setBoolValue(WebKitCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabledPreferenceKey, enabled);
     2043    return S_OK;
     2044}
     2045
    20322046HRESULT WebPreferences::fetchAPIKeepAliveEnabled(_Out_ BOOL* enabled)
    20332047{
  • trunk/Source/WebKitLegacy/win/WebPreferences.h

    r229143 r229530  
    241241    virtual HRESULT STDMETHODCALLTYPE modernMediaControlsEnabled(_Out_ BOOL*);
    242242    virtual HRESULT STDMETHODCALLTYPE setModernMediaControlsEnabled(BOOL);
    243 
     243    virtual HRESULT STDMETHODCALLTYPE cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(_Out_ BOOL*);
     244    virtual HRESULT STDMETHODCALLTYPE setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(BOOL);
     245   
    244246    // IWebPreferencesPrivate4
    245247    virtual HRESULT STDMETHODCALLTYPE setApplicationId(BSTR);
  • trunk/Source/WebKitLegacy/win/WebView.cpp

    r229309 r229530  
    52185218    RuntimeEnabledFeatures::sharedFeatures().setWebAnimationsEnabled(!!enabled);
    52195219
     5220    hr = prefsPrivate->cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(&enabled);
     5221    if (FAILED(hr))
     5222        return hr;
     5223    RuntimeEnabledFeatures::sharedFeatures().setCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(!!enabled);
     5224
    52205225    hr = prefsPrivate->userTimingEnabled(&enabled);
    52215226    if (FAILED(hr))
  • trunk/Tools/ChangeLog

    r229522 r229530  
     12018-03-12  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement CSS Animations and CSS Transitions as Web Animations
     4        https://bugs.webkit.org/show_bug.cgi?id=183504
     5        <rdar://problem/38372965>
     6
     7        Reviewed by Jon Lee.
     8
     9        Add a new <!-- webkit-test-runner --> flag to enable the CSS Animations and CSS Transitions
     10        as Web Animations runtime flag in the new tests we've created for this feature.
     11
     12        * DumpRenderTree/TestOptions.h:
     13        * DumpRenderTree/TestOptions.mm:
     14        (TestOptions::TestOptions):
     15        * DumpRenderTree/mac/DumpRenderTree.mm:
     16        (setWebPreferencesForTestOptions):
     17        * WebKitTestRunner/TestController.cpp:
     18        (WTR::TestController::resetPreferencesToConsistentValues):
     19        (WTR::updateTestOptionsFromTestHeader):
     20        * WebKitTestRunner/TestOptions.h:
     21        (WTR::TestOptions::hasSameInitializationOptions const):
     22
    1232018-03-11  Zalan Bujtas  <zalan@apple.com>
    224
  • trunk/Tools/DumpRenderTree/TestOptions.h

    r228486 r229530  
    3131struct TestOptions {
    3232    bool enableAttachmentElement { false };
     33    bool enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations { false };
    3334    bool useAcceleratedDrawing { false };
    3435    bool enableIntersectionObserver { false };
  • trunk/Tools/DumpRenderTree/TestOptions.mm

    r228486 r229530  
    105105        else if (key == "allowCrossOriginSubresourcesToAskForCredentials")
    106106            this->allowCrossOriginSubresourcesToAskForCredentials = parseBooleanTestHeaderValue(value);
     107        else if (key == "enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations")
     108            this->enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations = parseBooleanTestHeaderValue(value);
    107109        pairStart = pairEnd + 1;
    108110    }
  • trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm

    r229297 r229530  
    996996    preferences.inspectorAdditionsEnabled = options.enableInspectorAdditions;
    997997    preferences.allowCrossOriginSubresourcesToAskForCredentials = options.allowCrossOriginSubresourcesToAskForCredentials;
     998    preferences.CSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled = options.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations;
    998999}
    9991000
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r229390 r229530  
    694694    WKPreferencesSetIsSecureContextAttributeEnabled(preferences, options.enableIsSecureContextAttribute);
    695695    WKPreferencesSetAllowCrossOriginSubresourcesToAskForCredentials(preferences, options.allowCrossOriginSubresourcesToAskForCredentials);
     696    WKPreferencesSetCSSAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled(preferences, options.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations);
    696697
    697698    static WKStringRef defaultTextEncoding = WKStringCreateWithUTF8CString("ISO-8859-1");
     
    10881089        if (key == "allowCrossOriginSubresourcesToAskForCredentials")
    10891090            testOptions.allowCrossOriginSubresourcesToAskForCredentials = parseBooleanTestHeaderValue(value);
     1091        if (key == "enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations")
     1092            testOptions.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations = parseBooleanTestHeaderValue(value);
    10901093        pairStart = pairEnd + 1;
    10911094    }
  • trunk/Tools/WebKitTestRunner/TestOptions.h

    r228486 r229530  
    5656    bool dumpJSConsoleLogInStdErr { false };
    5757    bool allowCrossOriginSubresourcesToAskForCredentials { false };
     58    bool enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations { false };
    5859
    5960    float deviceScaleFactor { 1 };
     
    8586            || dumpJSConsoleLogInStdErr != options.dumpJSConsoleLogInStdErr
    8687            || applicationManifest != options.applicationManifest
    87             || allowCrossOriginSubresourcesToAskForCredentials != options.allowCrossOriginSubresourcesToAskForCredentials)
     88            || allowCrossOriginSubresourcesToAskForCredentials != options.allowCrossOriginSubresourcesToAskForCredentials
     89            || enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations != options.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations)
    8890            return false;
    8991
Note: See TracChangeset for help on using the changeset viewer.