Changeset 252966 in webkit


Ignore:
Timestamp:
Dec 1, 2019 1:22:48 AM (4 years ago)
Author:
graouts@webkit.org
Message:

[Web Animations] Implement Animation.commitStyles()
https://bugs.webkit.org/show_bug.cgi?id=202193
<rdar://problem/55697790>

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

WPT test for Animation.commitStyles() now has 11 more PASS results.

  • web-platform-tests/web-animations/interfaces/Animation/commitStyles-expected.txt:

Source/WebCore:

We implement the Animation.commitStyles() method following the spec to the letter. We fail a few tests still because we don't support animation
composite operations and because of rounding errors when blending opacity styles.

  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • animation/KeyframeEffectStack.cpp:

(WebCore::KeyframeEffectStack::ensureEffectsAreSorted): Remove the animation sorting logic since it's now made available in WebAnimationUtilities.h.

  • animation/KeyframeEffectStack.h:

(WebCore::KeyframeEffectStack::cssAnimationNames const): New function needed to call compareAnimationsByCompositeOrder() in WebAnimation::commitStyles().

  • animation/WebAnimation.cpp:

(WebCore::WebAnimation::commitStyles): Implement the spec steps as specified in https://drafts.csswg.org/web-animations-1/#commit-computed-styles. We use
a CSSStyleDeclaration to copy the content of the existing inline "style" attribute, add the animated values and then serialize it into the "style" attribute.
Even though it would have been more convenient to use StyledElement::setInlineStyleProperty(), we do this to ensure mutation observers get notified of such
a change.

  • animation/WebAnimationUtilities.cpp: Added.

(WebCore::compareAnimationsByCompositeOrder): Copied the animation sorting logic previously implemented in KeyframeEffectStack::ensureEffectsAreSorted().

  • animation/WebAnimationUtilities.h:
Location:
trunk
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r252901 r252966  
     12019-11-30  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement Animation.commitStyles()
     4        https://bugs.webkit.org/show_bug.cgi?id=202193
     5        <rdar://problem/55697790>
     6
     7        Reviewed by Dean Jackson.
     8
     9        WPT test for Animation.commitStyles() now has 11 more PASS results.
     10
     11        * web-platform-tests/web-animations/interfaces/Animation/commitStyles-expected.txt:
     12
    1132019-11-27  Manuel Rego Casasnovas  <rego@igalia.com>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/commitStyles-expected.txt

    r250617 r252966  
    11
    2 FAIL Commits styles assert_approx_equals: expected 0.2 +/- 0.0001 but got 0.10000000149011612
    3 FAIL Commits styles for an animation that has been removed assert_approx_equals: expected 0.2 +/- 0.0001 but got 0.10000000149011612
    4 FAIL Commits shorthand styles assert_equals: expected "20px" but got "10px"
     2PASS Commits styles
     3PASS Commits styles for an animation that has been removed
     4PASS Commits shorthand styles
    55FAIL Commits logical properties assert_equals: expected "20px" but got "10px"
    6 FAIL Commits values calculated mid-interval assert_approx_equals: expected 0.45 +/- 0.0001 but got 1
    7 FAIL Commits variables as their computed values assert_approx_equals: expected 0.5 +/- 0.0001 but got 1
    8 FAIL Commits em units as pixel values assert_approx_equals: expected 100 +/- 0.0001 but got 784
    9 FAIL Commits the intermediate value of an animation in the middle of stack assert_approx_equals: expected 0.4 +/- 0.0001 but got 0.10000000149011612
    10 FAIL Triggers mutation observers when updating style assert_equals: Should have one mutation record expected 1 but got 0
    11 PASS Does NOT trigger mutation observers when the change to style is redundant
    12 FAIL Throws if the target element is a pseudo element assert_throws: function "() => {
    13     animation.commitStyles();
    14   }" did not throw
    15 FAIL Throws if the target element is not something with a style attribute assert_throws: function "() => {
    16     animation.commitStyles();
    17   }" did not throw
    18 FAIL Throws if the target effect is display:none assert_throws: function "() => {
    19     animation.commitStyles();
    20   }" did not throw
    21 FAIL Throws if the target effect's ancestor is display:none assert_throws: function "() => {
    22     animation.commitStyles();
    23   }" did not throw
     6PASS Commits values calculated mid-interval
     7PASS Commits variables as their computed values
     8FAIL Commits em units as pixel values assert_approx_equals: expected 100 +/- 0.0001 but got 0
     9FAIL Commits the intermediate value of an animation in the middle of stack assert_approx_equals: expected 0.4 +/- 0.0001 but got 0.20000000298023224
     10PASS Triggers mutation observers when updating style
     11FAIL Does NOT trigger mutation observers when the change to style is redundant assert_equals: Should have no mutation records expected 0 but got 1
     12PASS Throws if the target element is a pseudo element
     13PASS Throws if the target element is not something with a style attribute
     14PASS Throws if the target effect is display:none
     15PASS Throws if the target effect's ancestor is display:none
    2416PASS Treats display:contents as rendered
    25 FAIL Treats display:contents in a display:none subtree as not rendered assert_throws: function "() => {
    26     animation.commitStyles();
    27   }" did not throw
    28 FAIL Throws if the target effect is disconnected assert_throws: function "() => {
    29     animation.commitStyles();
    30   }" did not throw
     17PASS Treats display:contents in a display:none subtree as not rendered
     18PASS Throws if the target effect is disconnected
    3119FAIL Checks the pseudo element condition before the not rendered condition undefined is not an object (evaluating 'pseudo.element.remove')
    3220
  • trunk/Source/WebCore/ChangeLog

    r252965 r252966  
     12019-11-30  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Implement Animation.commitStyles()
     4        https://bugs.webkit.org/show_bug.cgi?id=202193
     5        <rdar://problem/55697790>
     6
     7        Reviewed by Dean Jackson.
     8
     9        We implement the Animation.commitStyles() method following the spec to the letter. We fail a few tests still because we don't support animation
     10        composite operations and because of rounding errors when blending opacity styles.
     11
     12        * Sources.txt:
     13        * WebCore.xcodeproj/project.pbxproj:
     14        * animation/KeyframeEffectStack.cpp:
     15        (WebCore::KeyframeEffectStack::ensureEffectsAreSorted): Remove the animation sorting logic since it's now made available in WebAnimationUtilities.h.
     16        * animation/KeyframeEffectStack.h:
     17        (WebCore::KeyframeEffectStack::cssAnimationNames const): New function needed to call compareAnimationsByCompositeOrder() in WebAnimation::commitStyles().
     18        * animation/WebAnimation.cpp:
     19        (WebCore::WebAnimation::commitStyles): Implement the spec steps as specified in https://drafts.csswg.org/web-animations-1/#commit-computed-styles. We use
     20        a CSSStyleDeclaration to copy the content of the existing inline "style" attribute, add the animated values and then serialize it into the "style" attribute.
     21        Even though it would have been more convenient to use StyledElement::setInlineStyleProperty(), we do this to ensure mutation observers get notified of such
     22        a change.
     23        * animation/WebAnimationUtilities.cpp: Added.
     24        (WebCore::compareAnimationsByCompositeOrder): Copied the animation sorting logic previously implemented in KeyframeEffectStack::ensureEffectsAreSorted().
     25        * animation/WebAnimationUtilities.h:
     26
    1272019-11-30  Tim Horton  <timothy_horton@apple.com>
    228
  • trunk/Source/WebCore/Sources.txt

    r252893 r252966  
    458458animation/KeyframeEffect.cpp
    459459animation/WebAnimation.cpp
     460animation/WebAnimationUtilities.cpp
    460461
    461462bindings/js/CachedModuleScriptLoader.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r252959 r252966  
    94989498                71B5AB2421F1D9E200376E5C /* PointerCaptureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PointerCaptureController.h; sourceTree = "<group>"; };
    94999499                71B5AB2521F1D9E300376E5C /* PointerCaptureController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointerCaptureController.cpp; sourceTree = "<group>"; };
     9500                71C25AF52392BF3C00D5C098 /* WebAnimationUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebAnimationUtilities.cpp; sourceTree = "<group>"; };
    95009501                71C29E2E203CE76B008F36D2 /* CSSAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSAnimation.cpp; sourceTree = "<group>"; };
    95019502                71C29E30203CE76B008F36D2 /* CSSAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSAnimation.h; sourceTree = "<group>"; };
     
    1664316644                                6F73918C2106CEDD006AF262 /* LayoutUnits.h */,
    1664416645                                6FE7AA2621C37B6300296DCD /* MarginTypes.h */,
     16646                                E4ABABDE2360893D00FA4345 /* RenderBlockFlowLineLayout.cpp */,
    1664516647                                E4ABABDB236088FD00FA4345 /* RenderBlockFlowLineLayout.h */,
    16646                                 E4ABABDE2360893D00FA4345 /* RenderBlockFlowLineLayout.cpp */,
    1664716648                                11FF02D520BA3C810083F25B /* Verification.cpp */,
    1664816649                        );
     
    2091420915                                71025EC21F99F096004A250C /* WebAnimation.h */,
    2091520916                                71025EC81F99F096004A250C /* WebAnimation.idl */,
     20917                                71C25AF52392BF3C00D5C098 /* WebAnimationUtilities.cpp */,
    2091620918                                7132444F20109D9B00AE7FB2 /* WebAnimationUtilities.h */,
    2091720919                        );
     
    3175631758                                BCEA4860097D93020094C9E4 /* RenderBlock.h in Headers */,
    3175731759                                BC10D76817D8EE71005E2626 /* RenderBlockFlow.h in Headers */,
     31760                                E4ABABDD236088FE00FA4345 /* RenderBlockFlowLineLayout.h in Headers */,
    3175831761                                BCEA4862097D93020094C9E4 /* RenderBox.h in Headers */,
    3175931762                                BCEB179C143379F50052EAE9 /* RenderBoxFragmentInfo.h in Headers */,
     
    3247132474                                081093DC1255F0E700ED9D29 /* SVGTextLayoutAttributesBuilder.h in Headers */,
    3247232475                                081668DA125603D5006F25DE /* SVGTextLayoutEngine.h in Headers */,
    32473                                 E4ABABDD236088FE00FA4345 /* RenderBlockFlowLineLayout.h in Headers */,
    3247432476                                080E49261255F3BD00EFCA27 /* SVGTextLayoutEngineBaseline.h in Headers */,
    3247532477                                080E49281255F3BD00EFCA27 /* SVGTextLayoutEngineSpacing.h in Headers */,
  • trunk/Source/WebCore/animation/KeyframeEffectStack.cpp

    r252911 r252966  
    3131#include "KeyframeEffect.h"
    3232#include "WebAnimation.h"
     33#include "WebAnimationUtilities.h"
    3334
    3435namespace WebCore {
     
    7879        ASSERT(rhsAnimation);
    7980
    80         bool lhsHasOwningElement = is<DeclarativeAnimation>(lhsAnimation) && downcast<DeclarativeAnimation>(lhsAnimation)->owningElement();
    81         bool rhsHasOwningElement = is<DeclarativeAnimation>(rhsAnimation) && downcast<DeclarativeAnimation>(rhsAnimation)->owningElement();
    82 
    83         // CSS Transitions sort first.
    84         bool lhsIsCSSTransition = lhsHasOwningElement && is<CSSTransition>(lhsAnimation);
    85         bool rhsIsCSSTransition = rhsHasOwningElement && is<CSSTransition>(rhsAnimation);
    86         if (lhsIsCSSTransition || rhsIsCSSTransition) {
    87             if (lhsIsCSSTransition == rhsIsCSSTransition) {
    88                 // Sort transitions first by their generation time, and then by transition-property.
    89                 // https://drafts.csswg.org/css-transitions-2/#animation-composite-order
    90                 auto* lhsCSSTransition = downcast<CSSTransition>(lhsAnimation);
    91                 auto* rhsCSSTransition = downcast<CSSTransition>(rhsAnimation);
    92                 if (lhsCSSTransition->generationTime() != rhsCSSTransition->generationTime())
    93                     return lhsCSSTransition->generationTime() < rhsCSSTransition->generationTime();
    94                 return lhsCSSTransition->transitionProperty().utf8() < rhsCSSTransition->transitionProperty().utf8();
    95             }
    96             return !rhsIsCSSTransition;
    97         }
    98 
    99         // CSS Animations sort next.
    100         bool lhsIsCSSAnimation = lhsHasOwningElement && is<CSSAnimation>(lhsAnimation);
    101         bool rhsIsCSSAnimation = rhsHasOwningElement && is<CSSAnimation>(rhsAnimation);
    102         if (lhsIsCSSAnimation || rhsIsCSSAnimation) {
    103             if (lhsIsCSSAnimation == rhsIsCSSAnimation) {
    104                 // https://drafts.csswg.org/css-animations-2/#animation-composite-order
    105                 // Sort A and B based on their position in the computed value of the animation-name property of the (common) owning element.
    106                 auto& lhsCSSAnimationName = downcast<CSSAnimation>(lhsAnimation)->backingAnimation().name();
    107                 auto& rhsCSSAnimationName = downcast<CSSAnimation>(rhsAnimation)->backingAnimation().name();
    108 
    109                 for (auto& animationName : m_cssAnimationNames) {
    110                     if (animationName == lhsCSSAnimationName)
    111                         return true;
    112                     if (animationName == rhsCSSAnimationName)
    113                         return false;
    114                 }
    115                 // We should have found either of those CSS animations in the CSS animations list.
    116                 ASSERT_NOT_REACHED();
    117             }
    118             return !rhsIsCSSAnimation;
    119         }
    120 
    121         // JS-originated animations sort last based on their position in the global animation list.
    122         // https://drafts.csswg.org/web-animations-1/#animation-composite-order
    123         return lhsAnimation->globalPosition() < rhsAnimation->globalPosition();
     81        return compareAnimationsByCompositeOrder(*lhsAnimation, *rhsAnimation, m_cssAnimationNames);
    12482    });
    12583
  • trunk/Source/WebCore/animation/KeyframeEffectStack.h

    r252911 r252966  
    4343    bool hasEffects() const { return !m_effects.isEmpty(); }
    4444    Vector<WeakPtr<KeyframeEffect>> sortedEffects();
     45    Vector<String> cssAnimationNames() const { return m_cssAnimationNames; }
    4546    void setCSSAnimationNames(Vector<String>&&);
    4647
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r252957 r252966  
    3030#include "AnimationPlaybackEvent.h"
    3131#include "AnimationTimeline.h"
     32#include "CSSComputedStyleDeclaration.h"
    3233#include "DOMPromiseProxy.h"
    3334#include "DeclarativeAnimation.h"
     
    4142#include "KeyframeEffectStack.h"
    4243#include "Microtasks.h"
     44#include "RenderElement.h"
     45#include "StyledElement.h"
    4346#include "WebAnimationUtilities.h"
    4447#include <wtf/IsoMallocInlines.h>
     
    12851288ExceptionOr<void> WebAnimation::commitStyles()
    12861289{
     1290    // https://drafts.csswg.org/web-animations-1/#commit-computed-styles
     1291
     1292    // 1. Let targets be the set of all effect targets for animation effects associated with animation.
     1293    auto* effect = is<KeyframeEffect>(m_effect) ? downcast<KeyframeEffect>(m_effect.get()) : nullptr;
     1294    auto* target = effect ? effect->target() : nullptr;
     1295
     1296    // 2. For each target in targets:
     1297    //
     1298    // 2.1 If target is not an element capable of having a style attribute (for example, it is a pseudo-element or is an element in a
     1299    // document format for which style attributes are not defined) throw a "NoModificationAllowedError" DOMException and abort these steps.
     1300    if (!is<StyledElement>(target))
     1301        return Exception { NoModificationAllowedError };
     1302
     1303    auto& styledElement = downcast<StyledElement>(*target);
     1304
     1305    // 2.2 If, after applying any pending style changes, target is not being rendered, throw an "InvalidStateError" DOMException and abort these steps.
     1306    styledElement.document().updateStyleIfNeeded();
     1307    auto* renderer = styledElement.renderer();
     1308    if (!renderer)
     1309        return Exception { InvalidStateError };
     1310
     1311    // 2.3 Let inline style be the result of getting the CSS declaration block corresponding to target’s style attribute. If target does not have a style
     1312    // attribute, let inline style be a new empty CSS declaration block with the readonly flag unset and owner node set to target.
     1313
     1314    // 2.4 Let targeted properties be the set of physical longhand properties that are a target property for at least one animation effect associated with
     1315    // animation whose effect target is target.
     1316
     1317    auto& style = renderer->style();
     1318    auto computedStyleExtractor = ComputedStyleExtractor(&styledElement);
     1319    auto inlineStyle = styledElement.document().createCSSStyleDeclaration();
     1320    inlineStyle->setCssText(styledElement.getAttribute("style"));
     1321
     1322    auto& keyframeStack = styledElement.ensureKeyframeEffectStack();
     1323    auto cssAnimationNames = keyframeStack.cssAnimationNames();
     1324
     1325    // 2.5 For each property, property, in targeted properties:
     1326    for (auto property : effect->animatedProperties()) {
     1327        // 1. Let partialEffectStack be a copy of the effect stack for property on target.
     1328        // 2. If animation's replace state is removed, add all animation effects associated with animation whose effect target is target and which include
     1329        // property as a target property to partialEffectStack.
     1330        // 3. Remove from partialEffectStack any animation effects whose associated animation has a higher composite order than animation.
     1331        // 4. Let effect value be the result of calculating the result of partialEffectStack for property using target's computed style (see § 5.4.3 Calculating
     1332        // the result of an effect stack).
     1333        // 5. Set a CSS declaration property for effect value in inline style.
     1334        // 6. Update style attribute for inline style.
     1335
     1336        // We actually perform those steps in a different way: instead of building a copy of the effect stack and then removing stuff, we iterate through the
     1337        // effect stack and stop when we've found this animation's effect or when we've found an effect associated with an animation with a higher composite order.
     1338        auto animatedStyle = RenderStyle::clonePtr(style);
     1339        for (const auto& effectInStack : keyframeStack.sortedEffects()) {
     1340            if (effectInStack->animation() != this && !compareAnimationsByCompositeOrder(*effectInStack->animation(), *this, cssAnimationNames))
     1341                break;
     1342            if (effectInStack->animatedProperties().contains(property))
     1343                effectInStack->animation()->resolve(*animatedStyle);
     1344            if (effectInStack->animation() == this)
     1345                break;
     1346        }
     1347        if (m_replaceState == ReplaceState::Removed)
     1348            effect->animation()->resolve(*animatedStyle);
     1349        if (auto cssValue = computedStyleExtractor.valueForPropertyInStyle(*animatedStyle, property, renderer))
     1350            inlineStyle->setPropertyInternal(property, cssValue->cssText(), false);
     1351    }
     1352
     1353    styledElement.setAttribute("style", inlineStyle->cssText());
     1354
    12871355    return { };
    12881356}
  • trunk/Source/WebCore/animation/WebAnimationUtilities.h

    r239820 r252966  
    3131namespace WebCore {
    3232
     33class WebAnimation;
     34
    3335inline double secondsToWebAnimationsAPITime(const Seconds time)
    3436{
     
    6163using MarkableDouble = Markable<double, WebAnimationsMarkableDoubleTraits>;
    6264
     65bool compareAnimationsByCompositeOrder(WebAnimation&, WebAnimation&, Vector<String>& cssAnimationNames);
     66
    6367} // namespace WebCore
    6468
Note: See TracChangeset for help on using the changeset viewer.