Changeset 228702 in webkit


Ignore:
Timestamp:
Feb 19, 2018 11:06:25 AM (6 years ago)
Author:
graouts@webkit.org
Message:

[Web Animations] Store all parsed keyframe input information in a single structure
https://bugs.webkit.org/show_bug.cgi?id=182903

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Update test expectations with progressions resulting from returning the style values as provided
by the keyframe input when calling getKeyframes().

  • web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
  • web-platform-tests/web-animations/interfaces/KeyframeEffect/constructor-expected.txt:
  • web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt:

Source/WebCore:

When parsing keyframe input provided through the JS API, we used to create several data structures.
During parsing we would create a Vector<ProcessedKeyframe> where we would store the validated values
for "offset", "easing" and "composite" as well as CSS properties and CSS values as strings.

Then we would create a KeyframeList, a class that pre-dates the work on Web Animations and is used
for hardware animations, with RenderStyle objects that are used for CSS property blending at runtime.
Once the KeyframeList was created, the Vector<ProcessedKeyframe> was discarded.

Since KeyframeList did not know about nullable offsets, timing functions and composite operations, and
because we do not with to modify a legacy class that we will eventually remove once all the Web Animations
work is complete, we also stored the parsed offsets as m_offsets, the timing functions as m_timingFunctions
and the composite operations as m_compositeOperations.

In this patch we rename the ProcessedKeyframe structure used temporarily during parsing to ParsedKeyframe and
store both the input and processed data related to a given keyframe in that single structure which we keep
around as m_parsedKeyframes when we finished processing the keyframes input. This update ParsedKeyframe structure
allows to keep around the original nullable offsets, the original CSS properties and CSS values as strings as
a HashMap<CSSPropertyID, String>, as well as the CSS properties and CSS values as CSSValue objects using a
MutableStyleProperties object.

This has the benefit of reducing the number of members, but also pave the way for supporting read-write targets
where we will be able to decouple parsing keyframes and creating a KeyframeList, which requires a valid target
to create RenderStyle objects used for blending, since the original parsing-time information is now stored.

Finally, this allowed getKeyframes() to be more compliant by returning the CSS values as originally provided in
the keyframe input with shorthand properties when provided, rather than the long-hands we used to read back
through RenderStyle objects.

The generated KeyframeList is now stored as m_blendingKeyframes and is only used for the purpose of interfacing
with hardware animations and CSS property blending.

While ProcessedKeyframe was copyable due to holding only simple types, ParsedKeyframe is not since it uses a Ref
to hold the MutableStyleProperties. This uncovered some cases where we copied ProcessedKeyframe objects, we now
ensure that the ParsedKeyframe objects are moved instead, which was the correct thing to do all along.

  • animation/KeyframeEffectReadOnly.cpp:

(WebCore::computeMissingKeyframeOffsets): While we used to store std::optional<double> for the computed offset,
we now store a simple double, which makes more sense since the computed offset is eventually a fully resolved
value after calling computeMissingKeyframeOffsets(). So we now compute the final computed offset without resorting
to intermediate nullable computed offsets.
(WebCore::processIterableKeyframes):
(WebCore::processPropertyIndexedKeyframes):
(WebCore::KeyframeEffectReadOnly::KeyframeEffectReadOnly):
(WebCore::KeyframeEffectReadOnly::copyPropertiesFromSource):
(WebCore::KeyframeEffectReadOnly::getKeyframes):
(WebCore::KeyframeEffectReadOnly::processKeyframes):
(WebCore::KeyframeEffectReadOnly::computeStackingContextImpact):
(WebCore::KeyframeEffectReadOnly::shouldRunAccelerated):
(WebCore::KeyframeEffectReadOnly::getAnimatedStyle):
(WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle):
(WebCore::KeyframeEffectReadOnly::startOrStopAccelerated):

  • animation/KeyframeEffectReadOnly.h:

(WebCore::KeyframeEffectReadOnly::ParsedKeyframe::ParsedKeyframe):

Location:
trunk
Files:
7 edited

Legend:

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

    r228694 r228702  
     12018-02-17  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Store all parsed keyframe input information in a single structure
     4        https://bugs.webkit.org/show_bug.cgi?id=182903
     5
     6        Reviewed by Dean Jackson.
     7
     8        Update test expectations with progressions resulting from returning the style values as provided
     9        by the keyframe input when calling getKeyframes().
     10
     11        * web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
     12        * web-platform-tests/web-animations/interfaces/KeyframeEffect/constructor-expected.txt:
     13        * web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt:
     14
    1152018-02-17  Antoine Quint  <graouts@apple.com>
    216
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt

    r228312 r228702  
    99PASS Element.animate() accepts empty keyframe lists (input: undefined)
    1010PASS Element.animate() accepts a one property two value property-indexed keyframes specification
    11 FAIL Element.animate() accepts a one shorthand property two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
    12 FAIL Element.animate() accepts a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     11PASS Element.animate() accepts a one shorthand property two value property-indexed keyframes specification
     12PASS Element.animate() accepts a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification
    1313PASS Element.animate() accepts a two property two value property-indexed keyframes specification
    1414PASS Element.animate() accepts a two property property-indexed keyframes specification with different numbers of values
    1515PASS Element.animate() accepts a property-indexed keyframes specification with an invalid value
    1616PASS Element.animate() accepts a one property two value property-indexed keyframes specification that needs to stringify its values
    17 FAIL Element.animate() accepts a property-indexed keyframes specification with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
    18 FAIL Element.animate() accepts a property-indexed keyframes specification with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     17PASS Element.animate() accepts a property-indexed keyframes specification with a CSS variable reference
     18PASS Element.animate() accepts a property-indexed keyframes specification with a CSS variable reference in a shorthand property
    1919PASS Element.animate() accepts a one property one value property-indexed keyframes specification
    2020PASS Element.animate() accepts a one property one non-array value property-indexed keyframes specification
     
    4848PASS Element.animate() accepts a one property two keyframe sequence
    4949PASS Element.animate() accepts a two property two keyframe sequence
    50 FAIL Element.animate() accepts a one shorthand property two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
    51 FAIL Element.animate() accepts a two property (a shorthand and one of its component longhands) two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     50PASS Element.animate() accepts a one shorthand property two keyframe sequence
     51PASS Element.animate() accepts a two property (a shorthand and one of its component longhands) two keyframe sequence
    5252PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the first keyframe
    5353PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the last keyframe
    5454PASS Element.animate() accepts a one property two keyframe sequence that needs to stringify its values
    55 FAIL Element.animate() accepts a keyframe sequence with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
    56 FAIL Element.animate() accepts a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     55PASS Element.animate() accepts a keyframe sequence with a CSS variable reference
     56PASS Element.animate() accepts a keyframe sequence with a CSS variable reference in a shorthand property
    5757FAIL Element.animate() accepts a keyframe sequence with duplicate values for a given interior offset Type error
    5858FAIL Element.animate() accepts a keyframe sequence with duplicate values for offsets 0 and 1 Type error
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/constructor-expected.txt

    r228694 r228702  
    88PASS A KeyframeEffectReadOnly can be constructed with a one property two value property-indexed keyframes specification
    99PASS A KeyframeEffectReadOnly constructed with a one property two value property-indexed keyframes specification roundtrips
    10 FAIL A KeyframeEffectReadOnly can be constructed with a one shorthand property two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     10PASS A KeyframeEffectReadOnly can be constructed with a one shorthand property two value property-indexed keyframes specification
    1111PASS A KeyframeEffectReadOnly constructed with a one shorthand property two value property-indexed keyframes specification roundtrips
    12 FAIL A KeyframeEffectReadOnly can be constructed with a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     12PASS A KeyframeEffectReadOnly can be constructed with a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification
    1313PASS A KeyframeEffectReadOnly constructed with a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification roundtrips
    1414PASS A KeyframeEffectReadOnly can be constructed with a two property two value property-indexed keyframes specification
     
    2020PASS A KeyframeEffectReadOnly can be constructed with a one property two value property-indexed keyframes specification that needs to stringify its values
    2121PASS A KeyframeEffectReadOnly constructed with a one property two value property-indexed keyframes specification that needs to stringify its values roundtrips
    22 FAIL A KeyframeEffectReadOnly can be constructed with a property-indexed keyframes specification with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
     22PASS A KeyframeEffectReadOnly can be constructed with a property-indexed keyframes specification with a CSS variable reference
    2323PASS A KeyframeEffectReadOnly constructed with a property-indexed keyframes specification with a CSS variable reference roundtrips
    24 FAIL A KeyframeEffectReadOnly can be constructed with a property-indexed keyframes specification with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     24PASS A KeyframeEffectReadOnly can be constructed with a property-indexed keyframes specification with a CSS variable reference in a shorthand property
    2525PASS A KeyframeEffectReadOnly constructed with a property-indexed keyframes specification with a CSS variable reference in a shorthand property roundtrips
    2626PASS A KeyframeEffectReadOnly can be constructed with a one property one value property-indexed keyframes specification
     
    8686PASS A KeyframeEffectReadOnly can be constructed with a two property two keyframe sequence
    8787PASS A KeyframeEffectReadOnly constructed with a two property two keyframe sequence roundtrips
    88 FAIL A KeyframeEffectReadOnly can be constructed with a one shorthand property two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     88PASS A KeyframeEffectReadOnly can be constructed with a one shorthand property two keyframe sequence
    8989PASS A KeyframeEffectReadOnly constructed with a one shorthand property two keyframe sequence roundtrips
    90 FAIL A KeyframeEffectReadOnly can be constructed with a two property (a shorthand and one of its component longhands) two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     90PASS A KeyframeEffectReadOnly can be constructed with a two property (a shorthand and one of its component longhands) two keyframe sequence
    9191PASS A KeyframeEffectReadOnly constructed with a two property (a shorthand and one of its component longhands) two keyframe sequence roundtrips
    9292PASS A KeyframeEffectReadOnly can be constructed with a two property keyframe sequence where one property is missing from the first keyframe
     
    9696PASS A KeyframeEffectReadOnly can be constructed with a one property two keyframe sequence that needs to stringify its values
    9797PASS A KeyframeEffectReadOnly constructed with a one property two keyframe sequence that needs to stringify its values roundtrips
    98 FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
     98PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference
    9999PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference roundtrips
    100 FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     100PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference in a shorthand property
    101101PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference in a shorthand property roundtrips
    102102FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with duplicate values for a given interior offset Type error
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt

    r228312 r228702  
    22PASS Keyframes can be replaced with an empty keyframe
    33PASS Keyframes can be replaced with a one property two value property-indexed keyframes specification
    4 FAIL Keyframes can be replaced with a one shorthand property two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
    5 FAIL Keyframes can be replaced with a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     4PASS Keyframes can be replaced with a one shorthand property two value property-indexed keyframes specification
     5PASS Keyframes can be replaced with a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification
    66PASS Keyframes can be replaced with a two property two value property-indexed keyframes specification
    77PASS Keyframes can be replaced with a two property property-indexed keyframes specification with different numbers of values
    88PASS Keyframes can be replaced with a property-indexed keyframes specification with an invalid value
    99PASS Keyframes can be replaced with a one property two value property-indexed keyframes specification that needs to stringify its values
    10 FAIL Keyframes can be replaced with a property-indexed keyframes specification with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
    11 FAIL Keyframes can be replaced with a property-indexed keyframes specification with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     10PASS Keyframes can be replaced with a property-indexed keyframes specification with a CSS variable reference
     11PASS Keyframes can be replaced with a property-indexed keyframes specification with a CSS variable reference in a shorthand property
    1212PASS Keyframes can be replaced with a one property one value property-indexed keyframes specification
    1313PASS Keyframes can be replaced with a one property one non-array value property-indexed keyframes specification
     
    4141PASS Keyframes can be replaced with a one property two keyframe sequence
    4242PASS Keyframes can be replaced with a two property two keyframe sequence
    43 FAIL Keyframes can be replaced with a one shorthand property two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
    44 FAIL Keyframes can be replaced with a two property (a shorthand and one of its component longhands) two keyframe sequence assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,marginTop,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     43PASS Keyframes can be replaced with a one shorthand property two keyframe sequence
     44PASS Keyframes can be replaced with a two property (a shorthand and one of its component longhands) two keyframe sequence
    4545PASS Keyframes can be replaced with a two property keyframe sequence where one property is missing from the first keyframe
    4646PASS Keyframes can be replaced with a two property keyframe sequence where one property is missing from the last keyframe
    4747PASS Keyframes can be replaced with a one property two keyframe sequence that needs to stringify its values
    48 FAIL Keyframes can be replaced with a keyframe sequence with a CSS variable reference assert_equals: value for 'left' on ComputedKeyframe #0 expected "var(--dist)" but got "auto"
    49 FAIL Keyframes can be replaced with a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "composite,computedOffset,easing,margin,offset" but got "composite,computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
     48PASS Keyframes can be replaced with a keyframe sequence with a CSS variable reference
     49PASS Keyframes can be replaced with a keyframe sequence with a CSS variable reference in a shorthand property
    5050FAIL Keyframes can be replaced with a keyframe sequence with duplicate values for a given interior offset Type error
    5151FAIL Keyframes can be replaced with a keyframe sequence with duplicate values for offsets 0 and 1 Type error
  • trunk/Source/WebCore/ChangeLog

    r228701 r228702  
     12018-02-17  Antoine Quint  <graouts@apple.com>
     2
     3        [Web Animations] Store all parsed keyframe input information in a single structure
     4        https://bugs.webkit.org/show_bug.cgi?id=182903
     5
     6        Reviewed by Dean Jackson.
     7
     8        When parsing keyframe input provided through the JS API, we used to create several data structures.
     9        During parsing we would create a Vector<ProcessedKeyframe> where we would store the validated values
     10        for "offset", "easing" and "composite" as well as CSS properties and CSS values as strings.
     11
     12        Then we would create a KeyframeList, a class that pre-dates the work on Web Animations and is used
     13        for hardware animations, with RenderStyle objects that are used for CSS property blending at runtime.
     14        Once the KeyframeList was created, the Vector<ProcessedKeyframe> was discarded.
     15
     16        Since KeyframeList did not know about nullable offsets, timing functions and composite operations, and
     17        because we do not with to modify a legacy class that we will eventually remove once all the Web Animations
     18        work is complete, we also stored the parsed offsets as m_offsets, the timing functions as m_timingFunctions
     19        and the composite operations as m_compositeOperations.
     20
     21        In this patch we rename the ProcessedKeyframe structure used temporarily during parsing to ParsedKeyframe and
     22        store both the input and processed data related to a given keyframe in that single structure which we keep
     23        around as m_parsedKeyframes when we finished processing the keyframes input. This update ParsedKeyframe structure
     24        allows to keep around the original nullable offsets, the original CSS properties and CSS values as strings as
     25        a HashMap<CSSPropertyID, String>, as well as the CSS properties and CSS values as CSSValue objects using a
     26        MutableStyleProperties object.
     27
     28        This has the benefit of reducing the number of members, but also pave the way for supporting read-write targets
     29        where we will be able to decouple parsing keyframes and creating a KeyframeList, which requires a valid target
     30        to create RenderStyle objects used for blending, since the original parsing-time information is now stored.
     31
     32        Finally, this allowed getKeyframes() to be more compliant by returning the CSS values as originally provided in
     33        the keyframe input with shorthand properties when provided, rather than the long-hands we used to read back
     34        through RenderStyle objects.
     35
     36        The generated KeyframeList is now stored as m_blendingKeyframes and is only used for the purpose of interfacing
     37        with hardware animations and CSS property blending.
     38
     39        While ProcessedKeyframe was copyable due to holding only simple types, ParsedKeyframe is not since it uses a Ref
     40        to hold the MutableStyleProperties. This uncovered some cases where we copied ProcessedKeyframe objects, we now
     41        ensure that the ParsedKeyframe objects are moved instead, which was the correct thing to do all along.
     42
     43        * animation/KeyframeEffectReadOnly.cpp:
     44        (WebCore::computeMissingKeyframeOffsets): While we used to store std::optional<double> for the computed offset,
     45        we now store a simple double, which makes more sense since the computed offset is eventually a fully resolved
     46        value after calling computeMissingKeyframeOffsets(). So we now compute the final computed offset without resorting
     47        to intermediate nullable computed offsets.
     48        (WebCore::processIterableKeyframes):
     49        (WebCore::processPropertyIndexedKeyframes):
     50        (WebCore::KeyframeEffectReadOnly::KeyframeEffectReadOnly):
     51        (WebCore::KeyframeEffectReadOnly::copyPropertiesFromSource):
     52        (WebCore::KeyframeEffectReadOnly::getKeyframes):
     53        (WebCore::KeyframeEffectReadOnly::processKeyframes):
     54        (WebCore::KeyframeEffectReadOnly::computeStackingContextImpact):
     55        (WebCore::KeyframeEffectReadOnly::shouldRunAccelerated):
     56        (WebCore::KeyframeEffectReadOnly::getAnimatedStyle):
     57        (WebCore::KeyframeEffectReadOnly::setAnimatedPropertiesInStyle):
     58        (WebCore::KeyframeEffectReadOnly::startOrStopAccelerated):
     59        * animation/KeyframeEffectReadOnly.h:
     60        (WebCore::KeyframeEffectReadOnly::ParsedKeyframe::ParsedKeyframe):
     61
    1622018-02-19  Zalan Bujtas  <zalan@apple.com>
    263
  • trunk/Source/WebCore/animation/KeyframeEffectReadOnly.cpp

    r228694 r228702  
    3737#include "JSKeyframeEffectReadOnly.h"
    3838#include "RenderStyle.h"
    39 #include "StyleProperties.h"
    4039#include "StyleResolver.h"
    4140#include "TimingFunction.h"
     
    7271}
    7372
    74 static inline void computeMissingKeyframeOffsets(Vector<KeyframeEffectReadOnly::ProcessedKeyframe>& keyframes)
     73static inline void computeMissingKeyframeOffsets(Vector<KeyframeEffectReadOnly::ParsedKeyframe>& keyframes)
    7574{
    7675    // https://drafts.csswg.org/web-animations-1/#compute-missing-keyframe-offsets
     
    8079
    8180    // 1. For each keyframe, in keyframes, let the computed keyframe offset of the keyframe be equal to its keyframe offset value.
     81    // In our implementation, we only set non-null values to avoid making computedOffset std::optional<double>. Instead, we'll know
     82    // that a keyframe hasn't had a computed offset by checking if it has a null offset and a 0 computedOffset, since the first
     83    // keyframe will already have a 0 computedOffset.
    8284    for (auto& keyframe : keyframes)
    83         keyframe.computedOffset = keyframe.offset;
     85        keyframe.computedOffset = keyframe.offset.value_or(0);
    8486
    8587    // 2. If keyframes contains more than one keyframe and the computed keyframe offset of the first keyframe in keyframes is null,
    8688    //    set the computed keyframe offset of the first keyframe to 0.
    87     if (keyframes.size() > 1 && !keyframes[0].computedOffset)
     89    if (keyframes.size() > 1 && !keyframes[0].offset)
    8890        keyframes[0].computedOffset = 0;
    8991
    9092    // 3. If the computed keyframe offset of the last keyframe in keyframes is null, set its computed keyframe offset to 1.
    91     if (!keyframes.last().computedOffset)
     93    if (!keyframes.last().offset)
    9294        keyframes.last().computedOffset = 1;
    9395
     
    109111            continue;
    110112
    111         double lastNonNullOffset = keyframes[indexOfLastKeyframeWithNonNullOffset].computedOffset.value();
    112         double offsetDelta = keyframe.computedOffset.value() - lastNonNullOffset;
     113        double lastNonNullOffset = keyframes[indexOfLastKeyframeWithNonNullOffset].computedOffset;
     114        double offsetDelta = keyframe.computedOffset - lastNonNullOffset;
    113115        double offsetIncrement = offsetDelta / (i - indexOfLastKeyframeWithNonNullOffset);
    114116        size_t indexOfFirstKeyframeWithNullOffset = indexOfLastKeyframeWithNonNullOffset + 1;
     
    120122}
    121123
    122 static inline ExceptionOr<void> processIterableKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, JSValue method, Vector<KeyframeEffectReadOnly::ProcessedKeyframe>& processedKeyframes)
     124static inline ExceptionOr<void> processIterableKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, JSValue method, Vector<KeyframeEffectReadOnly::ParsedKeyframe>& parsedKeyframes)
    123125{
    124126    VM& vm = state.vm();
     
    126128
    127129    // 1. Let iter be GetIterator(object, method).
    128     forEachInIterable(state, keyframesInput.get(), method, [&processedKeyframes](VM& vm, ExecState& state, JSValue nextValue) -> ExceptionOr<void> {
     130    forEachInIterable(state, keyframesInput.get(), method, [&parsedKeyframes](VM& vm, ExecState& state, JSValue nextValue) -> ExceptionOr<void> {
    129131        if (!nextValue || !nextValue.isObject())
    130132            return Exception { TypeError };
     
    137139        size_t numberOfProperties = ownPropertyNames.size();
    138140
    139         KeyframeEffectReadOnly::ProcessedKeyframe keyframeOutput;
     141        KeyframeEffectReadOnly::ParsedKeyframe keyframeOutput;
    140142
    141143        String easing("linear");
     
    154156            else {
    155157                auto cssPropertyId = IDLAttributeNameToAnimationPropertyName(ownPropertyName.string());
    156                 if (CSSPropertyAnimation::isPropertyAnimatable(cssPropertyId))
    157                     keyframeOutput.cssPropertiesAndValues.set(cssPropertyId, convert<IDLDOMString>(state, ownPropertyRawValue));
     158                if (CSSPropertyAnimation::isPropertyAnimatable(cssPropertyId)) {
     159                    auto stringValue = convert<IDLDOMString>(state, ownPropertyRawValue);
     160                    if (keyframeOutput.style->setProperty(cssPropertyId, stringValue))
     161                        keyframeOutput.unparsedStyle.set(cssPropertyId, stringValue);
     162                }
    158163            }
    159164            RETURN_IF_EXCEPTION(scope, Exception { TypeError });
     
    164169        keyframeOutput.composite = composite;
    165170
    166         processedKeyframes.append(WTFMove(keyframeOutput));
     171        parsedKeyframes.append(WTFMove(keyframeOutput));
    167172
    168173        return { };
     
    252257}
    253258
    254 static inline ExceptionOr<void> processPropertyIndexedKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, Vector<KeyframeEffectReadOnly::ProcessedKeyframe>& processedKeyframes, Vector<String>& unusedEasings)
     259static inline ExceptionOr<void> processPropertyIndexedKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, Vector<KeyframeEffectReadOnly::ParsedKeyframe>& parsedKeyframes, Vector<String>& unusedEasings)
    255260{
    256261    // 1. Let property-indexed keyframe be the result of running the procedure to process a keyframe-like object passing object as the keyframe input.
     
    270275        auto propertyValues = m.values;
    271276        // 4. Let property keyframes be an empty sequence of keyframes.
    272         Vector<KeyframeEffectReadOnly::ProcessedKeyframe> propertyKeyframes;
     277        Vector<KeyframeEffectReadOnly::ParsedKeyframe> propertyKeyframes;
    273278        // 5. For each value, v, in property values perform the following steps:
    274279        for (auto& v : propertyValues) {
    275280            // 1. Let k be a new keyframe with a null keyframe offset.
    276             KeyframeEffectReadOnly::ProcessedKeyframe k;
     281            KeyframeEffectReadOnly::ParsedKeyframe k;
    277282            // 2. Add the property-value pair, property name → v, to k.
    278             k.cssPropertiesAndValues.set(propertyName, v);
     283            if (k.style->setProperty(propertyName, v))
     284                k.unparsedStyle.set(propertyName, v);
    279285            // 3. Append k to property keyframes.
    280             propertyKeyframes.append(k);
     286            propertyKeyframes.append(WTFMove(k));
    281287        }
    282288        // 6. Apply the procedure to compute missing keyframe offsets to property keyframes.
     
    285291        // 7. Add keyframes in property keyframes to processed keyframes.
    286292        for (auto& keyframe : propertyKeyframes)
    287             processedKeyframes.append(keyframe);
     293            parsedKeyframes.append(WTFMove(keyframe));
    288294    }
    289295
    290296    // 3. Sort processed keyframes by the computed keyframe offset of each keyframe in increasing order.
    291     std::sort(processedKeyframes.begin(), processedKeyframes.end(), [](auto& lhs, auto& rhs) {
    292         return lhs.computedOffset.value() < rhs.computedOffset.value();
     297    std::sort(parsedKeyframes.begin(), parsedKeyframes.end(), [](auto& lhs, auto& rhs) {
     298        return lhs.computedOffset < rhs.computedOffset;
    293299    });
    294300
    295301    // 4. Merge adjacent keyframes in processed keyframes when they have equal computed keyframe offsets.
    296302    size_t i = 1;
    297     while (i < processedKeyframes.size()) {
    298         auto& keyframe = processedKeyframes[i];
    299         auto& previousKeyframe = processedKeyframes[i - 1];
     303    while (i < parsedKeyframes.size()) {
     304        auto& keyframe = parsedKeyframes[i];
     305        auto& previousKeyframe = parsedKeyframes[i - 1];
    300306        // If the offsets of this keyframe and the previous keyframe are different,
    301307        // this means that the two keyframes should not be merged and we can move
    302308        // on to the next keyframe.
    303         if (keyframe.computedOffset.value() != previousKeyframe.computedOffset.value()) {
     309        if (keyframe.computedOffset != previousKeyframe.computedOffset) {
    304310            i++;
    305311            continue;
    306312        }
    307313        // Otherwise, both this keyframe and the previous keyframe should be merged.
    308         // Unprocessed keyframes in processedKeyframes at this stage have a single
     314        // Unprocessed keyframes in parsedKeyframes at this stage have at most a single
    309315        // property in cssPropertiesAndValues, so just set this on the previous keyframe.
    310         auto singleValueInKeyframe = keyframe.cssPropertiesAndValues.begin();
    311         previousKeyframe.cssPropertiesAndValues.set(singleValueInKeyframe->key, singleValueInKeyframe->value);
     316        // In case an invalid or null value was originally provided, then the property
     317        // was not set and the property count is 0, in which case there is nothing to merge.
     318        if (keyframe.style->propertyCount()) {
     319            auto property = keyframe.style->propertyAt(0);
     320            previousKeyframe.style->setProperty(property.id(), property.value());
     321            previousKeyframe.unparsedStyle.set(property.id(), keyframe.unparsedStyle.get(property.id()));
     322        }
    312323        // Since we've processed this keyframe, we can remove it and keep i the same
    313324        // so that we process the next keyframe in the next loop iteration.
    314         processedKeyframes.remove(i);
     325        parsedKeyframes.remove(i);
    315326    }
    316327
     
    327338
    328339    // 6. Assign each value in offsets to the keyframe offset of the keyframe with corresponding position in property keyframes until the end of either sequence is reached.
    329     for (size_t i = 0; i < offsets.size() && i < processedKeyframes.size(); ++i)
    330         processedKeyframes[i].offset = offsets[i];
     340    for (size_t i = 0; i < offsets.size() && i < parsedKeyframes.size(); ++i)
     341        parsedKeyframes[i].offset = offsets[i];
    331342
    332343    // 7. Let easings be a sequence of DOMString values assigned based on the type of the “easing” member of the property-indexed keyframe as follows:
     
    345356    // 9. If easings has fewer items than property keyframes, repeat the elements in easings successively starting from the beginning of the list until easings has as many
    346357    //    items as property keyframes.
    347     if (easings.size() < processedKeyframes.size()) {
     358    if (easings.size() < parsedKeyframes.size()) {
    348359        size_t initialNumberOfEasings = easings.size();
    349         for (i = initialNumberOfEasings + 1; i <= processedKeyframes.size(); ++i)
     360        for (i = initialNumberOfEasings + 1; i <= parsedKeyframes.size(); ++i)
    350361            easings.append(easings[i % initialNumberOfEasings]);
    351362    }
    352363
    353364    // 10. If easings has more items than property keyframes, store the excess items as unused easings.
    354     while (easings.size() > processedKeyframes.size())
     365    while (easings.size() > parsedKeyframes.size())
    355366        unusedEasings.append(easings.takeLast());
    356367
    357368    // 11. Assign each value in easings to a property named “easing” on the keyframe with the corresponding position in property keyframes until the end of property keyframes
    358369    //     is reached.
    359     for (size_t i = 0; i < processedKeyframes.size(); ++i)
    360         processedKeyframes[i].easing = easings[i];
     370    for (size_t i = 0; i < parsedKeyframes.size(); ++i)
     371        parsedKeyframes[i].easing = easings[i];
    361372
    362373    // 12. If the “composite” member of the property-indexed keyframe is not an empty sequence:
     
    373384        // 2. As with easings, if composite modes has fewer items than property keyframes, repeat the elements in composite modes successively starting from the beginning of
    374385        //    the list until composite modes has as many items as property keyframes.
    375         if (compositeModes.size() < processedKeyframes.size()) {
     386        if (compositeModes.size() < parsedKeyframes.size()) {
    376387            size_t initialNumberOfCompositeModes = compositeModes.size();
    377             for (i = initialNumberOfCompositeModes + 1; i <= processedKeyframes.size(); ++i)
     388            for (i = initialNumberOfCompositeModes + 1; i <= parsedKeyframes.size(); ++i)
    378389                compositeModes.append(compositeModes[i % initialNumberOfCompositeModes]);
    379390        }
    380391        // 3. Assign each value in composite modes to the keyframe-specific composite operation on the keyframe with the corresponding position in property keyframes until
    381392        //    the end of property keyframes is reached.
    382         for (size_t i = 0; i < compositeModes.size() && i < processedKeyframes.size(); ++i)
    383             processedKeyframes[i].composite = compositeModes[i];
     393        for (size_t i = 0; i < compositeModes.size() && i < parsedKeyframes.size(); ++i)
     394            parsedKeyframes[i].composite = compositeModes[i];
    384395    }
    385396
     
    412423    : AnimationEffectReadOnly(classType, WTFMove(timing))
    413424    , m_target(target)
    414     , m_keyframes(emptyString())
     425    , m_blendingKeyframes(emptyString())
    415426{
    416427}
     
    419430{
    420431    m_target = source->m_target;
    421     m_offsets = source->m_offsets;
    422     m_timingFunctions = source->m_timingFunctions;
    423432    m_compositeOperation = source->m_compositeOperation;
    424     m_compositeOperations = source->m_compositeOperations;
    425433    m_iterationCompositeOperation = source->m_iterationCompositeOperation;
    426434
     435    Vector<ParsedKeyframe> parsedKeyframes;
     436    for (auto& sourceParsedKeyframe : source->m_parsedKeyframes) {
     437        ParsedKeyframe parsedKeyframe;
     438        parsedKeyframe.easing = sourceParsedKeyframe.easing;
     439        parsedKeyframe.offset = sourceParsedKeyframe.offset;
     440        parsedKeyframe.composite = sourceParsedKeyframe.composite;
     441        parsedKeyframe.unparsedStyle = sourceParsedKeyframe.unparsedStyle;
     442        parsedKeyframe.computedOffset = sourceParsedKeyframe.computedOffset;
     443        parsedKeyframe.timingFunction = sourceParsedKeyframe.timingFunction;
     444        parsedKeyframe.style = sourceParsedKeyframe.style->mutableCopy();
     445        parsedKeyframes.append(WTFMove(parsedKeyframe));
     446    }
     447    m_parsedKeyframes = WTFMove(parsedKeyframes);
     448
    427449    timing()->copyPropertiesFromSource(source->timing());
    428450
    429451    KeyframeList keyframeList("keyframe-effect-" + createCanonicalUUIDString());
    430     for (auto& keyframe : source->m_keyframes.keyframes()) {
     452    for (auto& keyframe : source->m_blendingKeyframes.keyframes()) {
    431453        KeyframeValue keyframeValue(keyframe.key(), RenderStyle::clonePtr(*keyframe.style()));
    432454        for (auto propertyId : keyframe.properties())
     
    434456        keyframeList.insert(WTFMove(keyframeValue));
    435457    }
    436     m_keyframes = WTFMove(keyframeList);
     458    m_blendingKeyframes = WTFMove(keyframeList);
    437459}
    438460
     
    452474
    453475    // 3. For each keyframe in keyframes perform the following steps:
    454     for (size_t i = 0; i < m_keyframes.size(); ++i) {
    455         auto& keyframe = m_keyframes[i];
    456 
     476    for (auto& parsedKeyframe : m_parsedKeyframes) {
    457477        // 1. Initialize a dictionary object, output keyframe, using the following definition:
    458478        //
     
    467487        // offset, keyframe-specific timing function and keyframe-specific composite operation of keyframe.
    468488        BaseComputedKeyframe computedKeyframe;
    469         computedKeyframe.offset = m_offsets[i];
    470         computedKeyframe.computedOffset = keyframe.key();
    471         computedKeyframe.easing = m_timingFunctions[i]->cssText();
    472         computedKeyframe.composite = m_compositeOperations[i];
     489        computedKeyframe.offset = parsedKeyframe.offset;
     490        computedKeyframe.computedOffset = parsedKeyframe.computedOffset;
     491        computedKeyframe.easing = parsedKeyframe.timingFunction->cssText();
     492        computedKeyframe.composite = parsedKeyframe.composite;
    473493
    474494        auto outputKeyframe = convertDictionaryToJS(state, *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), computedKeyframe);
    475495
    476         auto& style = *keyframe.style();
    477         auto computedStyleExtractor = ComputedStyleExtractor(m_target.get());
    478 
    479496        // 3. For each animation property-value pair specified on keyframe, declaration, perform the following steps:
    480         for (auto cssPropertyId : keyframe.properties()) {
     497        for (auto it = parsedKeyframe.unparsedStyle.begin(), end = parsedKeyframe.unparsedStyle.end(); it != end; ++it) {
    481498            // 1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.
    482             auto propertyName = CSSPropertyIDToIDLAttributeName(cssPropertyId);
     499            auto propertyName = CSSPropertyIDToIDLAttributeName(it->key);
    483500            // 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.
    484             auto idlValue = computedStyleExtractor.valueForPropertyinStyle(style, cssPropertyId)->cssText();
    485501            // 3. Let value be the result of converting IDL value to an ECMAScript String value.
    486             auto value = toJS<IDLDOMString>(state, idlValue);
     502            auto value = toJS<IDLDOMString>(state, it->value);
    487503            // 4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name,
    488504            //    Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.
     
    508524
    509525    // 2. Let processed keyframes be an empty sequence of keyframes.
    510     Vector<ProcessedKeyframe> processedKeyframes;
     526    Vector<ParsedKeyframe> parsedKeyframes;
    511527
    512528    // 3. Let method be the result of GetMethod(object, @@iterator).
     
    519535    Vector<String> unusedEasings;
    520536    if (!method.isUndefined())
    521         processIterableKeyframes(state, WTFMove(keyframesInput), WTFMove(method), processedKeyframes);
     537        processIterableKeyframes(state, WTFMove(keyframesInput), WTFMove(method), parsedKeyframes);
    522538    else
    523         processPropertyIndexedKeyframes(state, WTFMove(keyframesInput), processedKeyframes, unusedEasings);
     539        processPropertyIndexedKeyframes(state, WTFMove(keyframesInput), parsedKeyframes, unusedEasings);
    524540
    525541    // 6. If processed keyframes is not loosely sorted by offset, throw a TypeError and abort these steps.
     
    527543    //    zero or greater than one, throw a TypeError and abort these steps.
    528544    double lastNonNullOffset = -1;
    529     for (auto& keyframe : processedKeyframes) {
     545    for (auto& keyframe : parsedKeyframes) {
    530546        if (!keyframe.offset)
    531547            continue;
     
    538554    // We take a slight detour from the spec text and compute the missing keyframe offsets right away
    539555    // since they can be computed up-front.
    540     computeMissingKeyframeOffsets(processedKeyframes);
     556    computeMissingKeyframeOffsets(parsedKeyframes);
    541557
    542558    KeyframeList keyframeList("keyframe-effect-" + createCanonicalUUIDString());
    543     Vector<std::optional<double>> offsets;
    544     Vector<RefPtr<TimingFunction>> timingFunctions;
    545     Vector<std::optional<CompositeOperation>> compositeOperations;
    546 
    547559    StyleResolver& styleResolver = m_target->styleResolver();
    548     auto parserContext = CSSParserContext(HTMLStandardMode);
    549560
    550561    // 8. For each frame in processed keyframes, perform the following steps:
    551     for (auto& keyframe : processedKeyframes) {
    552         offsets.append(keyframe.offset);
    553         compositeOperations.append(keyframe.composite);
    554 
     562    for (auto& keyframe : parsedKeyframes) {
    555563        // 1. For each property-value pair in frame, parse the property value using the syntax specified for that property.
    556564        //    If the property value is invalid according to the syntax for the property, discard the property-value pair.
     
    558566        //    highlighting the invalid property value.
    559567
    560         StringBuilder cssText;
    561         for (auto it = keyframe.cssPropertiesAndValues.begin(), end = keyframe.cssPropertiesAndValues.end(); it != end; ++it) {
    562             cssText.append(getPropertyNameString(it->key));
    563             cssText.appendLiteral(": ");
    564             cssText.append(it->value);
    565             cssText.appendLiteral("; ");
    566         }
    567 
    568         KeyframeValue keyframeValue(keyframe.computedOffset.value(), nullptr);
     568        KeyframeValue keyframeValue(keyframe.computedOffset, nullptr);
    569569        auto renderStyle = RenderStyle::createPtr();
    570         auto styleProperties = MutableStyleProperties::create();
    571         styleProperties->parseDeclaration(cssText.toString(), parserContext);
    572         unsigned numberOfCSSProperties = styleProperties->propertyCount();
    573 
    574         for (unsigned i = 0; i < numberOfCSSProperties; ++i) {
     570        auto& styleProperties = keyframe.style;
     571        for (unsigned i = 0; i < styleProperties->propertyCount(); ++i) {
    575572            auto cssPropertyId = styleProperties->propertyAt(i).id();
    576573            keyframeValue.addProperty(cssPropertyId);
     
    589586        if (timingFunctionResult.hasException())
    590587            return timingFunctionResult.releaseException();
    591         timingFunctions.append(timingFunctionResult.returnValue());
     588        keyframe.timingFunction = timingFunctionResult.returnValue();
    592589    }
    593590
     
    601598    }
    602599
    603     m_offsets = WTFMove(offsets);
    604     m_keyframes = WTFMove(keyframeList);
    605     m_timingFunctions = WTFMove(timingFunctions);
    606     m_compositeOperations = WTFMove(compositeOperations);
     600    m_blendingKeyframes = WTFMove(keyframeList);
     601    m_parsedKeyframes = WTFMove(parsedKeyframes);
    607602
    608603    computeStackingContextImpact();
     
    614609{
    615610    m_triggersStackingContext = false;
    616     for (auto cssPropertyId : m_keyframes.properties()) {
     611    for (auto cssPropertyId : m_blendingKeyframes.properties()) {
    617612        if (WillChangeData::propertyCreatesStackingContext(cssPropertyId)) {
    618613            m_triggersStackingContext = true;
     
    667662bool KeyframeEffectReadOnly::shouldRunAccelerated()
    668663{
    669     for (auto cssPropertyId : m_keyframes.properties()) {
     664    for (auto cssPropertyId : m_blendingKeyframes.properties()) {
    670665        if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId))
    671666            return false;
     
    679674        return;
    680675
    681     if (!m_keyframes.size())
     676    if (!m_blendingKeyframes.size())
    682677        return;
    683678
     
    700695    // for a given iteration progress, current iteration and underlying value is calculated as follows.
    701696
    702     for (auto cssPropertyId : m_keyframes.properties()) {
     697    for (auto cssPropertyId : m_blendingKeyframes.properties()) {
    703698        // 1. If iteration progress is unresolved abort this procedure.
    704699        // 2. Let target property be the longhand property for which the effect value is to be calculated.
     
    712707        unsigned numberOfKeyframesWithOneOffset = 0;
    713708        Vector<std::optional<size_t>> propertySpecificKeyframes;
    714         for (size_t i = 0; i < m_keyframes.size(); ++i) {
    715             auto& keyframe = m_keyframes[i];
     709        for (size_t i = 0; i < m_blendingKeyframes.size(); ++i) {
     710            auto& keyframe = m_blendingKeyframes[i];
    716711            if (!keyframe.containsProperty(cssPropertyId))
    717712                continue;
     
    769764                    if (!keyframeIndex)
    770765                        return i ? 1 : 0;
    771                     return m_keyframes[keyframeIndex.value()].key();
     766                    return m_blendingKeyframes[keyframeIndex.value()].key();
    772767                }();
    773768                if (!offset)
     
    795790        if (intervalEndpoints.size() == 1) {
    796791            auto keyframeIndex = intervalEndpoints[0];
    797             auto keyframeStyle = !keyframeIndex ? &targetStyle : m_keyframes[keyframeIndex.value()].style();
     792            auto keyframeStyle = !keyframeIndex ? &targetStyle : m_blendingKeyframes[keyframeIndex.value()].style();
    798793            CSSPropertyAnimation::blendProperties(this, cssPropertyId, &targetStyle, keyframeStyle, keyframeStyle, 0);
    799794            continue;
     
    802797        // 14. Let start offset be the computed keyframe offset of the first keyframe in interval endpoints.
    803798        auto startKeyframeIndex = intervalEndpoints.first();
    804         auto startOffset = !startKeyframeIndex ? 0 : m_keyframes[startKeyframeIndex.value()].key();
     799        auto startOffset = !startKeyframeIndex ? 0 : m_blendingKeyframes[startKeyframeIndex.value()].key();
    805800
    806801        // 15. Let end offset be the computed keyframe offset of last keyframe in interval endpoints.
    807802        auto endKeyframeIndex = intervalEndpoints.last();
    808         auto endOffset = !endKeyframeIndex ? 1 : m_keyframes[endKeyframeIndex.value()].key();
     803        auto endOffset = !endKeyframeIndex ? 1 : m_blendingKeyframes[endKeyframeIndex.value()].key();
    809804
    810805        // 16. Let interval distance be the result of evaluating (iteration progress - start offset) / (end offset - start offset).
     
    817812            if (auto iterationDuration = timing()->iterationDuration()) {
    818813                auto rangeDuration = (endOffset - startOffset) * iterationDuration.seconds();
    819                 transformedDistance = m_timingFunctions[startKeyframeIndex.value()]->transformTime(intervalDistance, rangeDuration);
     814                transformedDistance = m_parsedKeyframes[startKeyframeIndex.value()].timingFunction->transformTime(intervalDistance, rangeDuration);
    820815            }
    821816        }
     
    824819        //     property specified on the two keyframes in interval endpoints taking the first such value as Vstart and the second as Vend and using transformed
    825820        //     distance as the interpolation parameter p.
    826         auto startStyle = !startKeyframeIndex ? &targetStyle : m_keyframes[startKeyframeIndex.value()].style();
    827         auto endStyle = !endKeyframeIndex ? &targetStyle : m_keyframes[endKeyframeIndex.value()].style();
     821        auto startStyle = !startKeyframeIndex ? &targetStyle : m_blendingKeyframes[startKeyframeIndex.value()].style();
     822        auto endStyle = !endKeyframeIndex ? &targetStyle : m_blendingKeyframes[endKeyframeIndex.value()].style();
    828823        CSSPropertyAnimation::blendProperties(this, cssPropertyId, &targetStyle, startStyle, endStyle, transformedDistance);
    829824    }
     
    840835        auto animation = Animation::create();
    841836        animation->setDuration(timing()->iterationDuration().seconds());
    842         compositedRenderer->startAnimation(0, animation.ptr(), m_keyframes);
     837        compositedRenderer->startAnimation(0, animation.ptr(), m_blendingKeyframes);
    843838    } else {
    844         compositedRenderer->animationFinished(m_keyframes.animationName());
     839        compositedRenderer->animationFinished(m_blendingKeyframes.animationName());
    845840        if (!m_target->document().renderTreeBeingDestroyed())
    846841            m_target->invalidateStyleAndLayerComposition();
  • trunk/Source/WebCore/animation/KeyframeEffectReadOnly.h

    r228694 r228702  
    3535#include "KeyframeList.h"
    3636#include "RenderStyle.h"
     37#include "StyleProperties.h"
    3738#include <wtf/Ref.h>
    3839
     
    6465    };
    6566
    66     struct ProcessedKeyframe {
     67    struct ParsedKeyframe {
     68        std::optional<double> offset;
     69        double computedOffset;
     70        std::optional<CompositeOperation> composite;
    6771        String easing;
    68         std::optional<double> offset;
    69         std::optional<double> computedOffset;
    70         std::optional<CompositeOperation> composite;
    71         HashMap<CSSPropertyID, String> cssPropertiesAndValues;
     72        RefPtr<TimingFunction> timingFunction;
     73        Ref<MutableStyleProperties> style;
     74        HashMap<CSSPropertyID, String> unparsedStyle;
     75
     76        ParsedKeyframe()
     77            : style(MutableStyleProperties::create())
     78        {
     79        }
    7280    };
    7381
     
    114122    bool shouldRunAccelerated();
    115123
    116     Vector<std::optional<double>> m_offsets;
    117     Vector<RefPtr<TimingFunction>> m_timingFunctions;
    118     Vector<std::optional<CompositeOperation>> m_compositeOperations;
    119124    bool m_triggersStackingContext { false };
    120125    bool m_started { false };
     
    122127
    123128    RefPtr<Element> m_target;
    124     KeyframeList m_keyframes;
     129    KeyframeList m_blendingKeyframes;
     130    Vector<ParsedKeyframe> m_parsedKeyframes;
    125131};
    126132
Note: See TracChangeset for help on using the changeset viewer.