Skip to content
Permalink
Browse files
[css-transitions] support transitions of custom properties
https://bugs.webkit.org/show_bug.cgi?id=249399
rdar://103404742

Reviewed by Antti Koivisto.

We now account for custom properties when considering what properties are eligible to run
a transition under Styleable::updateCSSTransitions().

The first task to make this possible was to add new mode for custom properties to the
Animation object representing a transition on RenderStyle. We leverage the same mechanism
previously used for unknown properties and make it so we can track a custom property as well.

Then we had to finish the implementation of two CSSPropertyAnimation methods to deal with
custom properties. As we consider properties for a transition in Styleable::updateCSSTransitions(),
we call CSSPropertyAnimation::canPropertyBeInterpolated() and CSSPropertyAnimation::propertiesEqual()
to determine we can even transition between two values of a given property or whether the underlying
value of a property has changed while a transition is in-flight.

We now fully implement the custom property path of these CSSPropertyAnimation methods. This required
a little extra work. First, we had to provide a Document to these methods to access initial values
in the case where explicit values for custom properties are not set on RenderStyle.

Then, we had to determine which syntax value types support interpolation, which is most except for
<custom-ident>, <image> and <url>.

Finally, we had to introduce a new TransformSyntaxValue wrapper for RefPtr<TransformOperation> values
to provide a custom operator== to not run simply pointer equality but actually compare the transform
operations.

We added comprehensive tests for CSS Transitions and custom properties, with two notable new failures
tracked by bugs 249640 and bugs 249641.

* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-angle-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-angle.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-color-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-color.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-custom-ident-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-custom-ident.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-image-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-image.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-inherited-used-by-standard-property-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-inherited-used-by-standard-property.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-integer-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-integer.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-length-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-length-percentage-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-length-percentage.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-length.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-mismatched-list-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-mismatched-list.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-non-inherited-used-by-standard-property-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-non-inherited-used-by-standard-property.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-number-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-number.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-percentage-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-percentage.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-resolution-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-resolution.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-time-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-time.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-transform-function-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-transform-function.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-transform-list-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-transform-list.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-url-expected.txt: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/animation/custom-property-transition-url.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/at-property-animation-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-properties-values-api/resources/utils.js:
(async no_transition_test):
* Source/WebCore/animation/CSSPropertyAnimation.cpp:
(WebCore::blendSyntaxValues):
(WebCore::firstValueInSyntaxValueLists):
(WebCore::blendSyntaxValueLists):
(WebCore::blendCustomProperty):
(WebCore::CSSPropertyAnimation::propertyRequiresBlendingForAccumulativeIteration):
(WebCore::CSSPropertyAnimation::propertiesEqual):
(WebCore::typeOfSyntaxValueCanBeInterpolated):
(WebCore::CSSPropertyAnimation::canPropertyBeInterpolated):
* Source/WebCore/animation/CSSPropertyAnimation.h:
* Source/WebCore/animation/KeyframeEffectStack.cpp:
(WebCore::KeyframeEffectStack::applyKeyframeEffects):
* Source/WebCore/css/CSSCustomPropertyValue.cpp:
(WebCore::CSSCustomPropertyValue::customCSSText const):
* Source/WebCore/css/CSSCustomPropertyValue.h:
* Source/WebCore/css/CSSToStyleMap.cpp:
(WebCore::CSSToStyleMap::mapAnimationProperty):
* Source/WebCore/css/ComputedStyleExtractor.cpp:
(WebCore::createTransitionPropertyValue):
* Source/WebCore/css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::parseTypedCustomPropertyValue):
* Source/WebCore/platform/animation/Animation.cpp:
(WebCore::Animation::Animation):
(WebCore::Animation::animationsMatch const):
(WebCore::operator<<):
* Source/WebCore/platform/animation/Animation.h:
(WebCore::Animation::customOrUnknownProperty const):
(WebCore::Animation::setCustomOrUnknownProperty):
(WebCore::Animation::unknownProperty const): Deleted.
(WebCore::Animation::setUnknownProperty): Deleted.
* Source/WebCore/style/Styleable.cpp:
(WebCore::propertyInStyleMatchesValueForTransitionInMap):
(WebCore::transitionMatchesProperty):
(WebCore::compileTransitionPropertiesInStyle):
(WebCore::updateCSSTransitionsForStyleableAndProperty):
(WebCore::Styleable::updateCSSTransitions const):

Canonical link: https://commits.webkit.org/258134@main
  • Loading branch information
graouts committed Dec 20, 2022
1 parent 9b508cf commit 56d4a17a7f6bb0043f4c1f320a5eaf748ac03835
Show file tree
Hide file tree
Showing 47 changed files with 716 additions and 58 deletions.
@@ -0,0 +1,3 @@

PASS A custom property of type <angle> can yield a CSS Transition

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

transition_test({
syntax: "<angle>",
from: "100deg",
to: "200deg",
expected: "150deg"
}, 'A custom property of type <angle> can yield a CSS Transition');

</script>
@@ -0,0 +1,3 @@

PASS A custom property of type <color> can yield a CSS Transition

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

transition_test({
syntax: "<color>",
from: "rgb(100, 100, 100)",
to: "rgb(200, 200, 200)",
expected: "rgb(150, 150, 150)"
}, 'A custom property of type <color> can yield a CSS Transition');

</script>
@@ -0,0 +1,3 @@

PASS A custom property of type <custom-ident> cannot yield a CSS Transition

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

no_transition_test({
syntax: "<custom-ident>",
from: "from",
to: "to",
}, 'A custom property of type <custom-ident> cannot yield a CSS Transition');

</script>
@@ -0,0 +1,3 @@

PASS A custom property of type <image> cannot yield a CSS Transition

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

no_transition_test({
syntax: "<image>",
from: 'url("https://example.com/from")',
to: 'url("https://example.com/to")',
}, 'A custom property of type <image> cannot yield a CSS Transition');

</script>
@@ -0,0 +1,3 @@

FAIL Running a transition an inherited CSS variable is reflected on a standard property using that variable as a value assert_equals: expected "150px" but got "100px"

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="container">
<div id="target"></div>
</div>
<script>

test(() => {
const customProperty = "--my-length";

CSS.registerProperty({
name: customProperty,
syntax: "<length>",
inherits: true,
initialValue: "100px"
});

target.style.marginLeft = `var(${customProperty})`;
assert_equals(getComputedStyle(target).marginLeft, "100px");
assert_equals(getComputedStyle(target).getPropertyValue(customProperty), "100px");

container.style.transition = `${customProperty} 1s -500ms linear`;
container.style.setProperty(customProperty, "200px");

assert_equals(getComputedStyle(target).marginLeft, "150px");
}, "Running a transition an inherited CSS variable is reflected on a standard property using that variable as a value");

</script>
@@ -0,0 +1,3 @@

PASS A custom property of type <integer> can yield a CSS Transition

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

transition_test({
syntax: "<integer>",
from: "100",
to: "200",
expected: "150"
}, 'A custom property of type <integer> can yield a CSS Transition');

</script>
@@ -0,0 +1,3 @@

PASS A custom property of type <length> can yield a CSS Transition

@@ -0,0 +1,3 @@

PASS A custom property of type <length-percentage> can yield a CSS Transition

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

transition_test({
syntax: "<length-percentage>",
from: "100px",
to: "100%",
expected: "calc(50% + 50px)"
}, 'A custom property of type <length-percentage> can yield a CSS Transition');

</script>
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

transition_test({
syntax: "<length>",
from: "100px",
to: "200px",
expected: "150px"
}, 'A custom property of type <length> can yield a CSS Transition');

</script>
@@ -0,0 +1,26 @@

PASS A custom property of type <angle># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <angle>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <color># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <color>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <custom-ident># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <custom-ident>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <image># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <image>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <integer># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <integer>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <length-percentage># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <length-percentage>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <length># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <length>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <number># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <number>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <percentage># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <percentage>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <resolution># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <resolution>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <time># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <time>+ does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <url># does not yield a CSS Transition if the lists do not contain the same number of values
PASS A custom property of type <url>+ does not yield a CSS Transition if the lists do not contain the same number of values

@@ -0,0 +1,153 @@
<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/utils.js"></script>
<div id="target"></div>
<script>

no_transition_test({
syntax: "<angle>#",
from: '100deg, 200deg',
to: '300deg',
}, 'A custom property of type <angle># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<angle>+",
from: '100deg 200deg',
to: '300deg',
}, 'A custom property of type <angle>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<color>#",
from: 'rgb(100, 100, 100), rgb(150, 150, 150)',
to: 'rgb(200, 200, 200)',
}, 'A custom property of type <color># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<color>+",
from: 'rgb(100, 100, 100) rgb(150, 150, 150)',
to: 'rgb(200, 200, 200)',
}, 'A custom property of type <color>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<custom-ident>#",
from: 'foo, bar',
to: 'baz',
}, 'A custom property of type <custom-ident># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<custom-ident>+",
from: 'foo bar',
to: 'baz',
}, 'A custom property of type <custom-ident>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<image>#",
from: 'url("https://example.com/foo"), url("https://example.com/bar")',
to: 'url("https://example.com/to")',
}, 'A custom property of type <image># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<image>+",
from: 'url("https://example.com/foo") url("https://example.com/bar")',
to: 'url("https://example.com/to")',
}, 'A custom property of type <image>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<integer>#",
from: '100, 200',
to: '300',
}, 'A custom property of type <integer># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<integer>+",
from: '100 200',
to: '300',
}, 'A custom property of type <integer>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<length-percentage>#",
from: '100px, 200px',
to: '300%',
}, 'A custom property of type <length-percentage># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<length-percentage>+",
from: '100px 200px',
to: '300%',
}, 'A custom property of type <length-percentage>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<length>#",
from: '100px, 200px',
to: '300px',
}, 'A custom property of type <length># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<length>+",
from: '100px 200px',
to: '300px',
}, 'A custom property of type <length>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<number>#",
from: '100, 200',
to: '300',
}, 'A custom property of type <number># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<number>+",
from: '100 200',
to: '300',
}, 'A custom property of type <number>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<percentage>#",
from: '100%, 200%',
to: '300%',
}, 'A custom property of type <percentage># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<percentage>+",
from: '100% 200%',
to: '300%',
}, 'A custom property of type <percentage>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<resolution>#",
from: '100dppx, 200dppx',
to: '300dppx',
}, 'A custom property of type <resolution># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<resolution>+",
from: '100dppx 200dppx',
to: '300dppx',
}, 'A custom property of type <resolution>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<time>#",
from: '100s, 200s',
to: '300s',
}, 'A custom property of type <time># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<time>+",
from: '100s 200s',
to: '300s',
}, 'A custom property of type <time>+ does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<url>#",
from: 'url("https://example.com/foo"), url("https://example.com/bar")',
to: 'url("https://example.com/to")',
}, 'A custom property of type <url># does not yield a CSS Transition if the lists do not contain the same number of values');

no_transition_test({
syntax: "<url>+",
from: 'url("https://example.com/foo") url("https://example.com/bar")',
to: 'url("https://example.com/to")',
}, 'A custom property of type <url>+ does not yield a CSS Transition if the lists do not contain the same number of values');

</script>
@@ -0,0 +1,3 @@

FAIL Running a transition a non-inherited CSS variable is reflected on a standard property using that variable as a value assert_equals: expected "150px" but got "200px"

0 comments on commit 56d4a17

Please sign in to comment.