Title: [288560] trunk/Source/WebCore
Revision
288560
Author
grao...@webkit.org
Date
2022-01-25 09:36:35 -0800 (Tue, 25 Jan 2022)

Log Message

Refactor KeyframeEffect::getKeyframes()
https://bugs.webkit.org/show_bug.cgi?id=235504

Reviewed by Chris Dumez.

We move all the JS conversion code to a new custom implementation for JSKeyframeEffect::getKeyframes()
such that KeyframeEffect::getKeyframes() is simply in the business of compiling the list of computed
keyframes.

To do this, we start by changing the way the various KeyframeEffect structs are organized. We make
BaseComputedKeyframe extend BaseKeyframe, then ComputedKeyframe extend BaseComputedKeyframe by adding
a map of CSSPropertyID to String values, then ParsedKeyframe can simply extend ComputedKeyframe.
This makes it easy to copy ParsedKeyframe into a ComputedKeyframe for the properties relevant
to the output of getKeyframes().

We also take the opportunity to merge what used to be two methods, getBindingsKeyframes() and getKeyframes(),
into a single method since getKeyframes() is only ever called through the JS bindings.

Finally, we remove the big if/else statement in KeyframeEffect::getKeyframes() to have a small if block
for the case where the keyframes are already set via the setKeyframes() API and return early.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::CSSPropertyIDToIDLAttributeName):
(WebCore::IDLAttributeNameToAnimationPropertyName):
(WebCore::processIterableKeyframes):
(WebCore::processPropertyIndexedKeyframes):
(WebCore::KeyframeEffect::copyPropertiesFromSource):
(WebCore::KeyframeEffect::getKeyframes):
(WebCore::KeyframeEffect::animatedProperties):
(WebCore::KeyframeEffect::animatesProperty const):
(WebCore::CSSPropertyIDToIDLAttributeName): Deleted.
(WebCore::KeyframeEffect::getBindingsKeyframes): Deleted.
* animation/KeyframeEffect.h:
* animation/KeyframeEffect.idl:
* bindings/js/JSKeyframeEffectCustom.cpp: Added.
(WebCore::JSKeyframeEffect::getKeyframes):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (288559 => 288560)


--- trunk/Source/WebCore/ChangeLog	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/ChangeLog	2022-01-25 17:36:35 UTC (rev 288560)
@@ -1,3 +1,44 @@
+2022-01-25  Antoine Quint  <grao...@webkit.org>
+
+        Refactor KeyframeEffect::getKeyframes()
+        https://bugs.webkit.org/show_bug.cgi?id=235504
+
+        Reviewed by Chris Dumez.
+
+        We move all the JS conversion code to a new custom implementation for JSKeyframeEffect::getKeyframes()
+        such that KeyframeEffect::getKeyframes() is simply in the business of compiling the list of computed
+        keyframes.
+
+        To do this, we start by changing the way the various KeyframeEffect structs are organized. We make
+        BaseComputedKeyframe extend BaseKeyframe, then ComputedKeyframe extend BaseComputedKeyframe by adding
+        a map of CSSPropertyID to String values, then ParsedKeyframe can simply extend ComputedKeyframe.
+        This makes it easy to copy ParsedKeyframe into a ComputedKeyframe for the properties relevant
+        to the output of getKeyframes().
+
+        We also take the opportunity to merge what used to be two methods, getBindingsKeyframes() and getKeyframes(),
+        into a single method since getKeyframes() is only ever called through the JS bindings.
+
+        Finally, we remove the big if/else statement in KeyframeEffect::getKeyframes() to have a small if block
+        for the case where the keyframes are already set via the setKeyframes() API and return early.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * animation/KeyframeEffect.cpp:
+        (WebCore::KeyframeEffect::CSSPropertyIDToIDLAttributeName):
+        (WebCore::IDLAttributeNameToAnimationPropertyName):
+        (WebCore::processIterableKeyframes):
+        (WebCore::processPropertyIndexedKeyframes):
+        (WebCore::KeyframeEffect::copyPropertiesFromSource):
+        (WebCore::KeyframeEffect::getKeyframes):
+        (WebCore::KeyframeEffect::animatedProperties):
+        (WebCore::KeyframeEffect::animatesProperty const):
+        (WebCore::CSSPropertyIDToIDLAttributeName): Deleted.
+        (WebCore::KeyframeEffect::getBindingsKeyframes): Deleted.
+        * animation/KeyframeEffect.h:
+        * animation/KeyframeEffect.idl:
+        * bindings/js/JSKeyframeEffectCustom.cpp: Added.
+        (WebCore::JSKeyframeEffect::getKeyframes):
+
 2022-01-25  Pablo Saavedra  <psaave...@igalia.com>
 
         [WPE][GTK] Build error in ARMv7 Neon targets after r286152

Modified: trunk/Source/WebCore/Sources.txt (288559 => 288560)


--- trunk/Source/WebCore/Sources.txt	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/Sources.txt	2022-01-25 17:36:35 UTC (rev 288560)
@@ -570,6 +570,7 @@
 bindings/js/JSImageDataCustom.cpp
 bindings/js/JSIntersectionObserverCustom.cpp
 bindings/js/JSIntersectionObserverEntryCustom.cpp
+bindings/js/JSKeyframeEffectCustom.cpp
 bindings/js/JSLazyEventListener.cpp
 bindings/js/JSLocationCustom.cpp
 bindings/js/JSMediaStreamTrackCustom.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (288559 => 288560)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-01-25 17:36:35 UTC (rev 288560)
@@ -11126,6 +11126,7 @@
 		715AD71D2050512400D592DC /* DeclarativeAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeclarativeAnimation.h; sourceTree = "<group>"; };
 		715AD71F2050512400D592DC /* DeclarativeAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarativeAnimation.cpp; sourceTree = "<group>"; };
 		715DA5D3201BB902002EF2B0 /* JSWebAnimationCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebAnimationCustom.cpp; sourceTree = "<group>"; };
+		71601718279F2D7E005A25AE /* JSKeyframeEffectCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSKeyframeEffectCustom.cpp; sourceTree = "<group>"; };
 		716A55AB26FA349B00C96D69 /* range-button.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = "range-button.css"; sourceTree = "<group>"; };
 		716A55AD26FA349C00C96D69 /* volume-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = "volume-button.js"; sourceTree = "<group>"; };
 		716A55AE26FA349C00C96D69 /* range-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = "range-button.js"; sourceTree = "<group>"; };
@@ -24835,6 +24836,7 @@
 				A7D0318D0E93540300E24ACD /* JSImageDataCustom.cpp */,
 				5868C7D52546E0B300BF9DF3 /* JSIntersectionObserverCustom.cpp */,
 				77C13F042165658A002D9C5F /* JSIntersectionObserverEntryCustom.cpp */,
+				71601718279F2D7E005A25AE /* JSKeyframeEffectCustom.cpp */,
 				AD726FE716D9F204003A4E6D /* JSMediaListCustom.h */,
 				415CDAF61E6CE0D3004F11EE /* JSMediaStreamTrackCustom.cpp */,
 				E1A5F99A0E7EAA2500AF85EA /* JSMessageChannelCustom.cpp */,

Modified: trunk/Source/WebCore/animation/KeyframeEffect.cpp (288559 => 288560)


--- trunk/Source/WebCore/animation/KeyframeEffect.cpp	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/animation/KeyframeEffect.cpp	2022-01-25 17:36:35 UTC (rev 288560)
@@ -75,7 +75,7 @@
         styleable->element.invalidateStyleInternal();
 }
 
-static inline String CSSPropertyIDToIDLAttributeName(CSSPropertyID cssPropertyId)
+String KeyframeEffect::CSSPropertyIDToIDLAttributeName(CSSPropertyID cssPropertyId)
 {
     // https://drafts.csswg.org/web-animations-1/#animation-property-name-to-idl-attribute-name
     // 1. If property follows the <custom-property-name> production, return property.
@@ -110,7 +110,7 @@
 
     // We need to check that converting the property back to IDL form yields the same result such that a property passed
     // in non-IDL form is rejected, for instance "font-size".
-    if (idlAttributeName != CSSPropertyIDToIDLAttributeName(cssPropertyId))
+    if (idlAttributeName != KeyframeEffect::CSSPropertyIDToIDLAttributeName(cssPropertyId))
         return CSSPropertyInvalid;
 
     return cssPropertyId;
@@ -327,7 +327,7 @@
             ASSERT(propertyAndValue.values.size() == 1);
             auto stringValue = propertyAndValue.values[0];
             if (keyframeOutput.style->setProperty(cssPropertyId, stringValue, false, parserContext))
-                keyframeOutput.unparsedStyle.set(cssPropertyId, stringValue);
+                keyframeOutput.styleStrings.set(cssPropertyId, stringValue);
         }
 
         parsedKeyframes.append(WTFMove(keyframeOutput));
@@ -365,7 +365,7 @@
             KeyframeEffect::ParsedKeyframe k;
             // 2. Add the property-value pair, property name → v, to k.
             if (k.style->setProperty(propertyName, v, false, parserContext))
-                k.unparsedStyle.set(propertyName, v);
+                k.styleStrings.set(propertyName, v);
             // 3. Append k to property keyframes.
             propertyKeyframes.append(WTFMove(k));
         }
@@ -402,7 +402,7 @@
         if (keyframe.style->propertyCount()) {
             auto property = keyframe.style->propertyAt(0);
             previousKeyframe.style->setProperty(property.id(), property.value());
-            previousKeyframe.unparsedStyle.set(property.id(), keyframe.unparsedStyle.get(property.id()));
+            previousKeyframe.styleStrings.set(property.id(), keyframe.styleStrings.get(property.id()));
         }
         // Since we've processed this keyframe, we can remove it and keep i the same
         // so that we process the next keyframe in the next loop iteration.
@@ -559,7 +559,7 @@
         parsedKeyframe.easing = sourceParsedKeyframe.easing;
         parsedKeyframe.offset = sourceParsedKeyframe.offset;
         parsedKeyframe.composite = sourceParsedKeyframe.composite;
-        parsedKeyframe.unparsedStyle = sourceParsedKeyframe.unparsedStyle;
+        parsedKeyframe.styleStrings = sourceParsedKeyframe.styleStrings;
         parsedKeyframe.computedOffset = sourceParsedKeyframe.computedOffset;
         parsedKeyframe.timingFunction = sourceParsedKeyframe.timingFunction;
         parsedKeyframe.style = sourceParsedKeyframe.style->mutableCopy();
@@ -582,214 +582,141 @@
     setBlendingKeyframes(keyframeList);
 }
 
-Vector<Strong<JSObject>> KeyframeEffect::getBindingsKeyframes(JSGlobalObject& lexicalGlobalObject, Document& document)
+auto KeyframeEffect::getKeyframes(Document& document) -> Vector<ComputedKeyframe>
 {
-    if (is<DeclarativeAnimation>(animation()))
-        downcast<DeclarativeAnimation>(*animation()).flushPendingStyleChanges();
-    return getKeyframes(lexicalGlobalObject, document);
-}
-
-Vector<Strong<JSObject>> KeyframeEffect::getKeyframes(JSGlobalObject& lexicalGlobalObject, Document& document)
-{
     // https://drafts.csswg.org/web-animations-1/#dom-keyframeeffectreadonly-getkeyframes
 
-    auto supportsCompositeOperation = document.settings().webAnimationsCompositeOperationsEnabled();
+    if (auto* declarativeAnimation = dynamicDowncast<DeclarativeAnimation>(animation()))
+        declarativeAnimation->flushPendingStyleChanges();
 
-    auto lock = JSLockHolder { &lexicalGlobalObject };
+    Vector<ComputedKeyframe> computedKeyframes;
 
-    // Since keyframes are represented by a partially open-ended dictionary type that is not currently able to be expressed with WebIDL,
-    // the procedure used to prepare the result of this method is defined in prose below:
-    //
-    // 1. Let result be an empty sequence of objects.
-    Vector<Strong<JSObject>> result;
+    if (!m_parsedKeyframes.isEmpty() || m_blendingKeyframesSource == BlendingKeyframesSource::WebAnimation || !m_blendingKeyframes.containsAnimatableProperty()) {
+        for (size_t i = 0; i < m_parsedKeyframes.size(); ++i) {
+            ComputedKeyframe computedKeyframe { m_parsedKeyframes[i] };
+            computedKeyframe.easing = timingFunctionForKeyframeAtIndex(i)->cssText();
+            computedKeyframes.append(WTFMove(computedKeyframe));
+        }
+        return computedKeyframes;
+    }
 
-    // 2. Let keyframes be the result of applying the procedure to compute missing keyframe offsets to the keyframes for this keyframe effect.
+    auto* target = m_target.get();
+    auto* renderer = this->renderer();
+    auto* lastStyleChangeEventStyle = targetStyleable()->lastStyleChangeEventStyle();
 
-    // 3. For each keyframe in keyframes perform the following steps:
-    if (m_parsedKeyframes.isEmpty() && m_blendingKeyframesSource != BlendingKeyframesSource::WebAnimation && m_blendingKeyframes.containsAnimatableProperty()) {
-        auto* target = m_target.get();
-        auto* renderer = this->renderer();
-        auto* lastStyleChangeEventStyle = targetStyleable()->lastStyleChangeEventStyle();
+    ComputedStyleExtractor computedStyleExtractor { target, false, m_pseudoId };
 
-        auto computedStyleExtractor = ComputedStyleExtractor(target, false, m_pseudoId);
+    KeyframeList computedKeyframeList(m_blendingKeyframes.animationName());
+    computedKeyframeList.copyKeyframes(m_blendingKeyframes);
+    computedKeyframeList.fillImplicitKeyframes(*m_target, m_target->styleResolver(), lastStyleChangeEventStyle, nullptr);
 
-        KeyframeList computedKeyframes(m_blendingKeyframes.animationName());
-        computedKeyframes.copyKeyframes(m_blendingKeyframes);
-        computedKeyframes.fillImplicitKeyframes(*m_target, m_target->styleResolver(), lastStyleChangeEventStyle, nullptr);
+    auto keyframeRules = [&]() -> const Vector<Ref<StyleRuleKeyframe>> {
+        if (!is<CSSAnimation>(animation()))
+            return { };
 
-        auto keyframeRules = [&]() -> const Vector<Ref<StyleRuleKeyframe>> {
-            if (!is<CSSAnimation>(animation()))
-                return { };
+        auto& backingAnimation = downcast<CSSAnimation>(*animation()).backingAnimation();
+        auto* styleScope = Style::Scope::forOrdinal(*m_target, backingAnimation.nameStyleScopeOrdinal());
+        if (!styleScope)
+            return { };
 
-            auto& backingAnimation = downcast<CSSAnimation>(*animation()).backingAnimation();
-            auto* styleScope = Style::Scope::forOrdinal(*m_target, backingAnimation.nameStyleScopeOrdinal());
-            if (!styleScope)
-                return { };
+        return styleScope->resolver().keyframeRulesForName(computedKeyframeList.animationName());
+    }();
 
-            return styleScope->resolver().keyframeRulesForName(computedKeyframes.animationName());
-        }();
-
-        auto keyframeRuleForKey = [&](double key) -> StyleRuleKeyframe* {
-            for (auto& keyframeRule : keyframeRules) {
-                for (auto keyframeRuleKey : keyframeRule->keys()) {
-                    if (keyframeRuleKey == key)
-                        return keyframeRule.ptr();
-                }
+    auto keyframeRuleForKey = [&](double key) -> StyleRuleKeyframe* {
+        for (auto& keyframeRule : keyframeRules) {
+            for (auto keyframeRuleKey : keyframeRule->keys()) {
+                if (keyframeRuleKey == key)
+                    return keyframeRule.ptr();
             }
-            return nullptr;
-        };
+        }
+        return nullptr;
+    };
 
-        auto styleProperties = MutableStyleProperties::create();
-        if (m_blendingKeyframesSource == BlendingKeyframesSource::CSSAnimation) {
-            auto matchingRules = m_target->styleResolver().pseudoStyleRulesForElement(target, m_pseudoId, Style::Resolver::AllCSSRules);
-            for (auto& matchedRule : matchingRules)
-                styleProperties->mergeAndOverrideOnConflict(matchedRule->properties());
-            if (is<StyledElement>(m_target) && m_pseudoId == PseudoId::None) {
-                if (auto* inlineProperties = downcast<StyledElement>(*m_target).inlineStyle())
-                    styleProperties->mergeAndOverrideOnConflict(*inlineProperties);
-            }
+    auto styleProperties = MutableStyleProperties::create();
+    if (m_blendingKeyframesSource == BlendingKeyframesSource::CSSAnimation) {
+        auto matchingRules = m_target->styleResolver().pseudoStyleRulesForElement(target, m_pseudoId, Style::Resolver::AllCSSRules);
+        for (auto& matchedRule : matchingRules)
+            styleProperties->mergeAndOverrideOnConflict(matchedRule->properties());
+        if (is<StyledElement>(m_target) && m_pseudoId == PseudoId::None) {
+            if (auto* inlineProperties = downcast<StyledElement>(*m_target).inlineStyle())
+                styleProperties->mergeAndOverrideOnConflict(*inlineProperties);
         }
+    }
 
-        // We need to establish which properties are implicit for 0% and 100%.
-        HashSet<CSSPropertyID> zeroKeyframeProperties = computedKeyframes.properties();
-        HashSet<CSSPropertyID> _oneKeyframeProperties_ = computedKeyframes.properties();
-        zeroKeyframeProperties.remove(CSSPropertyCustom);
-        oneKeyframeProperties.remove(CSSPropertyCustom);
-        for (size_t i = 0; i < computedKeyframes.size(); ++i) {
-            auto& keyframe = computedKeyframes[i];
-            if (!keyframe.key()) {
-                for (auto cssPropertyId : keyframe.properties())
-                    zeroKeyframeProperties.remove(cssPropertyId);
-            } else if (keyframe.key() == 1) {
-                for (auto cssPropertyId : keyframe.properties())
-                    oneKeyframeProperties.remove(cssPropertyId);
-            }
+    // We need to establish which properties are implicit for 0% and 100%.
+    auto zeroKeyframeProperties = computedKeyframeList.properties();
+    auto _oneKeyframeProperties_ = computedKeyframeList.properties();
+    zeroKeyframeProperties.remove(CSSPropertyCustom);
+    oneKeyframeProperties.remove(CSSPropertyCustom);
+    for (auto& keyframe : computedKeyframeList.keyframes()) {
+        if (!keyframe.key()) {
+            for (auto cssPropertyId : keyframe.properties())
+                zeroKeyframeProperties.remove(cssPropertyId);
+        } else if (keyframe.key() == 1) {
+            for (auto cssPropertyId : keyframe.properties())
+                oneKeyframeProperties.remove(cssPropertyId);
         }
+    }
 
-        for (size_t i = 0; i < computedKeyframes.size(); ++i) {
-            // 1. Initialize a dictionary object, output keyframe, using the following definition:
-            //
-            // dictionary BaseComputedKeyframe {
-            //      double?                  offset = null;
-            //      double                   computedOffset;
-            //      DOMString                easing = "linear";
-            //      CompositeOperationOrAuto composite = "auto";
-            // };
+    for (auto& keyframe : computedKeyframeList.keyframes()) {
+        auto& style = *keyframe.style();
+        auto* keyframeRule = keyframeRuleForKey(keyframe.key());
 
-            auto& keyframe = computedKeyframes[i];
-            auto& style = *keyframe.style();
-            auto* keyframeRule = keyframeRuleForKey(keyframe.key());
+        ComputedKeyframe computedKeyframe;
+        computedKeyframe.offset = keyframe.key();
+        computedKeyframe.computedOffset = keyframe.key();
+        // For CSS transitions, all keyframes should return "linear" since the effect's global timing function applies.
+        computedKeyframe.easing = is<CSSTransition>(animation()) ? "linear" : timingFunctionForBlendingKeyframe(keyframe)->cssText();
 
-            // 2. Set offset, computedOffset, easing members of output keyframe to the respective values keyframe offset, computed keyframe offset,
-            // and keyframe-specific timing function of keyframe.
-            BaseComputedKeyframe computedKeyframe;
-            computedKeyframe.offset = keyframe.key();
-            computedKeyframe.computedOffset = keyframe.key();
-            // For CSS transitions, all keyframes should return "linear" since the effect's global timing function applies.
-            computedKeyframe.easing = is<CSSTransition>(animation()) ? "linear" : timingFunctionForBlendingKeyframe(keyframe)->cssText();
+        if (document.settings().webAnimationsCompositeOperationsEnabled()) {
+            if (auto compositeOperation = keyframe.compositeOperation())
+                computedKeyframe.composite = toCompositeOperationOrAuto(*compositeOperation);
+        }
 
-            if (supportsCompositeOperation) {
-                if (auto compositeOperation = keyframe.compositeOperation())
-                    computedKeyframe.composite = toCompositeOperationOrAuto(*compositeOperation);
-            }
-
-            auto outputKeyframe = convertDictionaryToJS(lexicalGlobalObject, *jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject), computedKeyframe);
-
-            auto addPropertyToKeyframe = [&](CSSPropertyID cssPropertyId) {
-                // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
-                auto propertyName = CSSPropertyIDToIDLAttributeName(cssPropertyId);
-                // 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.
-                String idlValue = "";
-                if (keyframeRule) {
-                    if (auto cssValue = keyframeRule->properties().getPropertyCSSValue(cssPropertyId)) {
-                        if (!cssValue->hasVariableReferences())
-                            idlValue = keyframeRule->properties().getPropertyValue(cssPropertyId);
-                    }
+        auto addPropertyToKeyframe = [&](CSSPropertyID cssPropertyId) {
+            String styleString = emptyString();
+            if (keyframeRule) {
+                if (auto cssValue = keyframeRule->properties().getPropertyCSSValue(cssPropertyId)) {
+                    if (!cssValue->hasVariableReferences())
+                        styleString = keyframeRule->properties().getPropertyValue(cssPropertyId);
                 }
-                if (idlValue.isEmpty()) {
-                    if (auto cssValue = styleProperties->getPropertyCSSValue(cssPropertyId)) {
-                        if (!cssValue->hasVariableReferences())
-                            idlValue = styleProperties->getPropertyValue(cssPropertyId);
-                    }
-                }
-                if (idlValue.isEmpty()) {
-                    if (auto cssValue = computedStyleExtractor.valueForPropertyInStyle(style, cssPropertyId, renderer))
-                        idlValue = cssValue->cssText();
-                }
-                // 3. Let value be the result of converting IDL value to an ECMAScript String value.
-                auto value = toJS<IDLDOMString>(lexicalGlobalObject, idlValue);
-                // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
-                //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
-                JSObject::defineOwnProperty(outputKeyframe, &lexicalGlobalObject, AtomString(propertyName).impl(), PropertyDescriptor(value, 0), false);
-            };
-
-            // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
-            for (auto cssPropertyId : keyframe.properties()) {
-                if (cssPropertyId == CSSPropertyCustom)
-                    continue;
-                addPropertyToKeyframe(cssPropertyId);
             }
-
-            // Now add the implicit properties in case there are any and we're dealing with a 0% or 100% keyframe.
-            if (lastStyleChangeEventStyle) {
-                if (!keyframe.key()) {
-                    for (auto cssPropertyId : zeroKeyframeProperties)
-                        addPropertyToKeyframe(cssPropertyId);
-                    zeroKeyframeProperties.clear();
-                } else if (keyframe.key() == 1) {
-                    for (auto cssPropertyId : oneKeyframeProperties)
-                        addPropertyToKeyframe(cssPropertyId);
-                    oneKeyframeProperties.clear();
+            if (styleString.isEmpty()) {
+                if (auto cssValue = styleProperties->getPropertyCSSValue(cssPropertyId)) {
+                    if (!cssValue->hasVariableReferences())
+                        styleString = styleProperties->getPropertyValue(cssPropertyId);
                 }
             }
+            if (styleString.isEmpty()) {
+                if (auto cssValue = computedStyleExtractor.valueForPropertyInStyle(style, cssPropertyId, renderer))
+                    styleString = cssValue->cssText();
+            }
+            computedKeyframe.styleStrings.set(cssPropertyId, styleString);
+        };
 
-            // 5. Append output keyframe to result.
-            result.append(JSC::Strong<JSC::JSObject> { lexicalGlobalObject.vm(), outputKeyframe });
+        for (auto cssPropertyId : keyframe.properties()) {
+            if (cssPropertyId == CSSPropertyCustom)
+                continue;
+            addPropertyToKeyframe(cssPropertyId);
         }
-    } else {
-        for (size_t i = 0; i < m_parsedKeyframes.size(); ++i) {
-            // 1. Initialize a dictionary object, output keyframe, using the following definition:
-            //
-            // dictionary BaseComputedKeyframe {
-            //      double?                  offset = null;
-            //      double                   computedOffset;
-            //      DOMString                easing = "linear";
-            //      CompositeOperationOrAuto composite = "auto";
-            // };
 
-            auto& parsedKeyframe = m_parsedKeyframes[i];
-
-            // 2. Set offset, computedOffset, easing, composite members of output keyframe to the respective values keyframe offset, computed keyframe
-            // offset, keyframe-specific timing function and keyframe-specific composite operation of keyframe.
-            BaseComputedKeyframe computedKeyframe;
-            computedKeyframe.offset = parsedKeyframe.offset;
-            computedKeyframe.computedOffset = parsedKeyframe.computedOffset;
-            computedKeyframe.easing = timingFunctionForKeyframeAtIndex(i)->cssText();
-
-            if (supportsCompositeOperation)
-                computedKeyframe.composite = parsedKeyframe.composite;
-
-            auto outputKeyframe = convertDictionaryToJS(lexicalGlobalObject, *jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject), computedKeyframe);
-
-            // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
-            for (auto it = parsedKeyframe.unparsedStyle.begin(), end = parsedKeyframe.unparsedStyle.end(); it != end; ++it) {
-                // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
-                auto propertyName = CSSPropertyIDToIDLAttributeName(it->key);
-                // 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.
-                // 3. Let value be the result of converting IDL value to an ECMAScript String value.
-                auto value = toJS<IDLDOMString>(lexicalGlobalObject, it->value);
-                // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
-                //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
-                JSObject::defineOwnProperty(outputKeyframe, &lexicalGlobalObject, AtomString(propertyName).impl(), PropertyDescriptor(value, 0), false);
+        // Now add the implicit properties in case there are any and we're dealing with a 0% or 100% keyframe.
+        if (lastStyleChangeEventStyle) {
+            if (!keyframe.key()) {
+                for (auto cssPropertyId : zeroKeyframeProperties)
+                    addPropertyToKeyframe(cssPropertyId);
+                zeroKeyframeProperties.clear();
+            } else if (keyframe.key() == 1) {
+                for (auto cssPropertyId : oneKeyframeProperties)
+                    addPropertyToKeyframe(cssPropertyId);
+                oneKeyframeProperties.clear();
             }
+        }
 
-            // 4. Append output keyframe to result.
-            result.append(JSC::Strong<JSC::JSObject> { lexicalGlobalObject.vm(), outputKeyframe });
-        }
+        computedKeyframes.append(WTFMove(computedKeyframe));
     }
 
-    // 4. Return result.
-    return result;
+    return computedKeyframes;
 }
 
 ExceptionOr<void> KeyframeEffect::setBindingsKeyframes(JSGlobalObject& lexicalGlobalObject, Document& document, Strong<JSObject>&& keyframesInput)
@@ -936,7 +863,7 @@
 
     if (m_animatedProperties.isEmpty()) {
         for (auto& keyframe : m_parsedKeyframes) {
-            for (auto keyframeProperty : keyframe.unparsedStyle.keys())
+            for (auto keyframeProperty : keyframe.styleStrings.keys())
                 m_animatedProperties.add(keyframeProperty);
         }
     }
@@ -950,7 +877,7 @@
         return m_blendingKeyframes.properties().contains(property);
 
     for (auto& keyframe : m_parsedKeyframes) {
-        for (auto keyframeProperty : keyframe.unparsedStyle.keys()) {
+        for (auto keyframeProperty : keyframe.styleStrings.keys()) {
             if (keyframeProperty == property)
                 return true;
         }

Modified: trunk/Source/WebCore/animation/KeyframeEffect.h (288559 => 288560)


--- trunk/Source/WebCore/animation/KeyframeEffect.h	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/animation/KeyframeEffect.h	2022-01-25 17:36:35 UTC (rev 288560)
@@ -80,14 +80,17 @@
         Vector<PropertyAndValues> propertiesAndValues;
     };
 
-    struct ParsedKeyframe {
-        MarkableDouble offset;
+    struct BaseComputedKeyframe : BaseKeyframe {
         double computedOffset;
-        CompositeOperationOrAuto composite { CompositeOperationOrAuto::Auto };
-        String easing;
+    };
+
+    struct ComputedKeyframe : BaseComputedKeyframe {
+        HashMap<CSSPropertyID, String> styleStrings;
+    };
+
+    struct ParsedKeyframe : ComputedKeyframe {
         RefPtr<TimingFunction> timingFunction;
         Ref<MutableStyleProperties> style;
-        HashMap<CSSPropertyID, String> unparsedStyle;
 
         ParsedKeyframe()
             : style(MutableStyleProperties::create())
@@ -95,13 +98,6 @@
         }
     };
 
-    struct BaseComputedKeyframe {
-        MarkableDouble offset;
-        double computedOffset;
-        String easing { "linear" };
-        CompositeOperationOrAuto composite { CompositeOperationOrAuto::Auto };
-    };
-
     const Vector<ParsedKeyframe>& parsedKeyframes() const { return m_parsedKeyframes; }
 
     Element* target() const { return m_target.get(); }
@@ -114,8 +110,7 @@
 
     const std::optional<const Styleable> targetStyleable() const;
 
-    Vector<JSC::Strong<JSC::JSObject>> getBindingsKeyframes(JSC::JSGlobalObject&, Document&);
-    Vector<JSC::Strong<JSC::JSObject>> getKeyframes(JSC::JSGlobalObject&, Document&);
+    Vector<ComputedKeyframe> getKeyframes(Document&);
     ExceptionOr<void> setBindingsKeyframes(JSC::JSGlobalObject&, Document&, JSC::Strong<JSC::JSObject>&&);
     ExceptionOr<void> setKeyframes(JSC::JSGlobalObject&, Document&, JSC::Strong<JSC::JSObject>&&);
 
@@ -173,6 +168,8 @@
 
     void keyframesRuleDidChange();
 
+    static String CSSPropertyIDToIDLAttributeName(CSSPropertyID);
+
 private:
     KeyframeEffect(Element*, PseudoId);
 

Modified: trunk/Source/WebCore/animation/KeyframeEffect.idl (288559 => 288560)


--- trunk/Source/WebCore/animation/KeyframeEffect.idl	2022-01-25 17:34:49 UTC (rev 288559)
+++ trunk/Source/WebCore/animation/KeyframeEffect.idl	2022-01-25 17:36:35 UTC (rev 288560)
@@ -36,7 +36,7 @@
     attribute CSSOMString? pseudoElement;
     [EnabledBySetting=WebAnimationsCompositeOperationsEnabled] attribute IterationCompositeOperation iterationComposite;
     [EnabledBySetting=WebAnimationsCompositeOperationsEnabled, ImplementedAs=bindingsComposite] attribute CompositeOperation composite;
-    [CallWith=GlobalObject&Document, ImplementedAs=getBindingsKeyframes] sequence<object> getKeyframes();
+    [Custom] sequence<object> getKeyframes();
     [CallWith=GlobalObject&Document, ImplementedAs=setBindingsKeyframes] undefined setKeyframes(object? keyframes);
 };
 

Added: trunk/Source/WebCore/bindings/js/JSKeyframeEffectCustom.cpp (0 => 288560)


--- trunk/Source/WebCore/bindings/js/JSKeyframeEffectCustom.cpp	                        (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSKeyframeEffectCustom.cpp	2022-01-25 17:36:35 UTC (rev 288560)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSKeyframeEffect.h"
+
+#include "CSSPropertyNames.h"
+
+namespace WebCore {
+
+using namespace JSC;
+
+JSValue JSKeyframeEffect::getKeyframes(JSGlobalObject& lexicalGlobalObject, CallFrame&)
+{
+    auto lock = JSLockHolder { &lexicalGlobalObject };
+
+    auto* context = jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject)->scriptExecutionContext();
+    if (UNLIKELY(!context))
+        return jsUndefined();
+    ASSERT(context->isDocument());
+
+    auto& domGlobalObject = *jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject);
+    auto computedKeyframes = wrapped().getKeyframes(downcast<Document>(*context));
+    auto keyframeObjects = computedKeyframes.map([&](auto& computedKeyframe) -> Strong<JSObject> {
+        auto keyframeObject = convertDictionaryToJS(lexicalGlobalObject, domGlobalObject, { computedKeyframe });
+        for (auto& [propertyID, propertyValue] : computedKeyframe.styleStrings) {
+            auto propertyName = KeyframeEffect::CSSPropertyIDToIDLAttributeName(propertyID);
+            auto value = toJS<IDLDOMString>(lexicalGlobalObject, propertyValue);
+            JSObject::defineOwnProperty(keyframeObject, &lexicalGlobalObject, AtomString(propertyName).impl(), PropertyDescriptor(value, 0), false);
+        }
+        return { lexicalGlobalObject.vm(), keyframeObject };
+    });
+
+    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject.vm());
+    return toJS<IDLSequence<IDLObject>>(lexicalGlobalObject, domGlobalObject, throwScope, keyframeObjects);
+}
+
+} // namespace WebCore
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to