mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
LibWeb: Implement the animation-composition property
This commit is contained in:
parent
968a8e618c
commit
e502f19fa7
Notes:
github-actions[bot]
2025-09-19 09:11:25 +00:00
Author: https://github.com/tcl3
Commit: e502f19fa7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6233
Reviewed-by: https://github.com/AtkinsSJ ✅
14 changed files with 222 additions and 7 deletions
|
|
@ -67,6 +67,7 @@
|
||||||
"absolute",
|
"absolute",
|
||||||
"accentcolor",
|
"accentcolor",
|
||||||
"accentcolortext",
|
"accentcolortext",
|
||||||
|
"accumulate",
|
||||||
"active",
|
"active",
|
||||||
"activeborder",
|
"activeborder",
|
||||||
"activecaption",
|
"activecaption",
|
||||||
|
|
@ -424,6 +425,7 @@
|
||||||
"repeat",
|
"repeat",
|
||||||
"repeat-x",
|
"repeat-x",
|
||||||
"repeat-y",
|
"repeat-y",
|
||||||
|
"replace",
|
||||||
"reverse",
|
"reverse",
|
||||||
"revert",
|
"revert",
|
||||||
"revert-layer",
|
"revert-layer",
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,17 @@
|
||||||
"animation-fill-mode"
|
"animation-fill-mode"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"animation-composition": {
|
||||||
|
"affects-layout": false,
|
||||||
|
"animation-type": "none",
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "replace",
|
||||||
|
"valid-identifiers": [
|
||||||
|
"replace",
|
||||||
|
"add",
|
||||||
|
"accumulate"
|
||||||
|
]
|
||||||
|
},
|
||||||
"animation-delay": {
|
"animation-delay": {
|
||||||
"affects-layout": false,
|
"affects-layout": false,
|
||||||
"animation-type": "none",
|
"animation-type": "none",
|
||||||
|
|
|
||||||
|
|
@ -1243,6 +1243,20 @@ static void apply_animation_properties(DOM::Document& document, CascadedProperti
|
||||||
if (auto timing_property = cascaded_properties.property(PropertyID::AnimationTimingFunction); timing_property && timing_property->is_easing())
|
if (auto timing_property = cascaded_properties.property(PropertyID::AnimationTimingFunction); timing_property && timing_property->is_easing())
|
||||||
timing_function = timing_property->as_easing().function();
|
timing_function = timing_property->as_easing().function();
|
||||||
|
|
||||||
|
Bindings::CompositeOperation composite_operation { Bindings::CompositeOperation::Replace };
|
||||||
|
if (auto composite_property = cascaded_properties.property(PropertyID::AnimationComposition); composite_property) {
|
||||||
|
switch (composite_property->to_keyword()) {
|
||||||
|
case Keyword::Add:
|
||||||
|
composite_operation = Bindings::CompositeOperation::Add;
|
||||||
|
break;
|
||||||
|
case Keyword::Accumulate:
|
||||||
|
composite_operation = Bindings::CompositeOperation::Accumulate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto iteration_duration = duration.has_value()
|
auto iteration_duration = duration.has_value()
|
||||||
? Variant<double, String> { duration.release_value().to_milliseconds() }
|
? Variant<double, String> { duration.release_value().to_milliseconds() }
|
||||||
: "auto"_string;
|
: "auto"_string;
|
||||||
|
|
@ -1252,6 +1266,7 @@ static void apply_animation_properties(DOM::Document& document, CascadedProperti
|
||||||
effect.set_timing_function(move(timing_function));
|
effect.set_timing_function(move(timing_function));
|
||||||
effect.set_fill_mode(Animations::css_fill_mode_to_bindings_fill_mode(fill_mode));
|
effect.set_fill_mode(Animations::css_fill_mode_to_bindings_fill_mode(fill_mode));
|
||||||
effect.set_playback_direction(Animations::css_animation_direction_to_bindings_playback_direction(direction));
|
effect.set_playback_direction(Animations::css_animation_direction_to_bindings_playback_direction(direction));
|
||||||
|
effect.set_composite(composite_operation);
|
||||||
|
|
||||||
if (play_state != effect.last_css_animation_play_state()) {
|
if (play_state != effect.last_css_animation_play_state()) {
|
||||||
if (play_state == CSS::AnimationPlayState::Running && animation.play_state() != Bindings::AnimationPlayState::Running) {
|
if (play_state == CSS::AnimationPlayState::Running && animation.play_state() != Bindings::AnimationPlayState::Running) {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ All properties associated with getComputedStyle(document.body):
|
||||||
"align-content",
|
"align-content",
|
||||||
"align-items",
|
"align-items",
|
||||||
"align-self",
|
"align-self",
|
||||||
|
"animation-composition",
|
||||||
"animation-delay",
|
"animation-delay",
|
||||||
"animation-direction",
|
"animation-direction",
|
||||||
"animation-duration",
|
"animation-duration",
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,8 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'align-self': 'auto'
|
'align-self': 'auto'
|
||||||
'all': ''
|
'all': ''
|
||||||
'animation': 'none'
|
'animation': 'none'
|
||||||
|
'animationComposition': 'replace'
|
||||||
|
'animation-composition': 'replace'
|
||||||
'animationDelay': '0s'
|
'animationDelay': '0s'
|
||||||
'animation-delay': '0s'
|
'animation-delay': '0s'
|
||||||
'animationDirection': 'normal'
|
'animationDirection': 'normal'
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ writing-mode: horizontal-tb
|
||||||
align-content: normal
|
align-content: normal
|
||||||
align-items: normal
|
align-items: normal
|
||||||
align-self: auto
|
align-self: auto
|
||||||
|
animation-composition: replace
|
||||||
animation-delay: 0s
|
animation-delay: 0s
|
||||||
animation-direction: normal
|
animation-direction: normal
|
||||||
animation-duration: 0s
|
animation-duration: 0s
|
||||||
|
|
@ -94,7 +95,7 @@ background-position-x: 0%
|
||||||
background-position-y: 0%
|
background-position-y: 0%
|
||||||
background-repeat: repeat
|
background-repeat: repeat
|
||||||
background-size: auto
|
background-size: auto
|
||||||
block-size: 1440px
|
block-size: 1455px
|
||||||
border-block-end-color: rgb(0, 0, 0)
|
border-block-end-color: rgb(0, 0, 0)
|
||||||
border-block-end-style: none
|
border-block-end-style: none
|
||||||
border-block-end-width: 0px
|
border-block-end-width: 0px
|
||||||
|
|
@ -171,7 +172,7 @@ grid-row-start: auto
|
||||||
grid-template-areas: none
|
grid-template-areas: none
|
||||||
grid-template-columns: none
|
grid-template-columns: none
|
||||||
grid-template-rows: none
|
grid-template-rows: none
|
||||||
height: 2595px
|
height: 2610px
|
||||||
inline-size: 784px
|
inline-size: 784px
|
||||||
inset-block-end: auto
|
inset-block-end: auto
|
||||||
inset-block-start: auto
|
inset-block-start: auto
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ Harness status: OK
|
||||||
|
|
||||||
Found 8 tests
|
Found 8 tests
|
||||||
|
|
||||||
4 Pass
|
5 Pass
|
||||||
4 Fail
|
3 Fail
|
||||||
Fail Setting a null effect on a running animation fires an animationend event
|
Fail Setting a null effect on a running animation fires an animationend event
|
||||||
Pass Replacing an animation's effect with an effect that targets a different property should update both properties
|
Pass Replacing an animation's effect with an effect that targets a different property should update both properties
|
||||||
Pass Replacing an animation's effect with a shorter one that should have already finished, the animation finishes immediately
|
Pass Replacing an animation's effect with a shorter one that should have already finished, the animation finishes immediately
|
||||||
Pass A play-pending animation's effect whose effect is replaced still exits the pending state
|
Pass A play-pending animation's effect whose effect is replaced still exits the pending state
|
||||||
Fail CSS animation events are dispatched at the original element even after setting an effect with a different target element
|
Fail CSS animation events are dispatched at the original element even after setting an effect with a different target element
|
||||||
Pass After replacing a finished animation's effect with a longer one it fires an animationstart event
|
Pass After replacing a finished animation's effect with a longer one it fires an animationstart event
|
||||||
Fail Setting animation-composition sets the composite property on the effect
|
Pass Setting animation-composition sets the composite property on the effect
|
||||||
Fail Replacing the effect of a CSSAnimation causes subsequent changes to corresponding animation-* properties to be ignored
|
Fail Replacing the effect of a CSSAnimation causes subsequent changes to corresponding animation-* properties to be ignored
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 6 tests
|
||||||
|
|
||||||
|
4 Pass
|
||||||
|
2 Fail
|
||||||
|
Pass animation-composition: replace of property filter
|
||||||
|
Fail animation-composition: add of property filter
|
||||||
|
Fail animation-composition: accumulate of property filter
|
||||||
|
Pass animation-composition: replace of property width
|
||||||
|
Pass animation-composition: add of property width
|
||||||
|
Pass animation-composition: accumulate of property width
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 4 tests
|
||||||
|
|
||||||
|
4 Pass
|
||||||
|
Pass e.style['animation-composition'] = "auto" should not set the property value
|
||||||
|
Pass e.style['animation-composition'] = "add replace" should not set the property value
|
||||||
|
Pass e.style['animation-composition'] = "add, initial" should not set the property value
|
||||||
|
Pass e.style['animation-composition'] = "initial, add" should not set the property value
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 4 tests
|
||||||
|
|
||||||
|
3 Pass
|
||||||
|
1 Fail
|
||||||
|
Pass e.style['animation-composition'] = "replace" should set the property value
|
||||||
|
Pass e.style['animation-composition'] = "add" should set the property value
|
||||||
|
Pass e.style['animation-composition'] = "accumulate" should set the property value
|
||||||
|
Fail e.style['animation-composition'] = "replace, add, accumulate" should set the property value
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
Harness status: OK
|
Harness status: OK
|
||||||
|
|
||||||
Found 260 tests
|
Found 261 tests
|
||||||
|
|
||||||
253 Pass
|
254 Pass
|
||||||
7 Fail
|
7 Fail
|
||||||
Pass accent-color
|
Pass accent-color
|
||||||
Pass border-collapse
|
Pass border-collapse
|
||||||
|
|
@ -76,6 +76,7 @@ Pass word-wrap
|
||||||
Pass writing-mode
|
Pass writing-mode
|
||||||
Pass align-items
|
Pass align-items
|
||||||
Pass align-self
|
Pass align-self
|
||||||
|
Pass animation-composition
|
||||||
Pass animation-delay
|
Pass animation-delay
|
||||||
Pass animation-direction
|
Pass animation-direction
|
||||||
Pass animation-duration
|
Pass animation-duration
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>animation-composition test</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#animation-composition">
|
||||||
|
<script src=../../resources/testharness.js></script>
|
||||||
|
<script src=../../resources/testharnessreport.js></script>
|
||||||
|
<script src="support/testcommon.js"></script>
|
||||||
|
<style>
|
||||||
|
@keyframes anim {
|
||||||
|
from {
|
||||||
|
filter: blur(10px);
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
filter: blur(15px);
|
||||||
|
width: 228px;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
filter: blur(20px);
|
||||||
|
width: 1337px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.anim-target {
|
||||||
|
animation: anim 1s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
filter: blur(5px);
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replace {
|
||||||
|
animation-composition: replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
animation-composition: add;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accumulate {
|
||||||
|
animation-composition: accumulate;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="log"></div>
|
||||||
|
<script>
|
||||||
|
function run_test_case(element, property, composite_type, timing_value_map) {
|
||||||
|
element.classList.add(composite_type);
|
||||||
|
const anim = element.getAnimations()[0];
|
||||||
|
for (const [time, value] of Object.entries(timing_value_map)) {
|
||||||
|
anim.currentTime = time;
|
||||||
|
const property_value = getComputedStyle(element).getPropertyValue(property);
|
||||||
|
assert_equals(property_value, value, "at time " + time);
|
||||||
|
}
|
||||||
|
element.classList.remove(composite_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const test_cases = [
|
||||||
|
["filter", {
|
||||||
|
"replace": {
|
||||||
|
0: "blur(10px)",
|
||||||
|
250: "blur(12.5px)",
|
||||||
|
500: "blur(15px)",
|
||||||
|
1000: "blur(20px)"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
0: "blur(5px) blur(10px)",
|
||||||
|
250: "blur(5px) blur(12.5px)",
|
||||||
|
500: "blur(5px) blur(15px)",
|
||||||
|
1000: "blur(5px) blur(20px)"
|
||||||
|
},
|
||||||
|
"accumulate": {
|
||||||
|
0: "blur(15px)",
|
||||||
|
250: "blur(17.5px)",
|
||||||
|
500: "blur(20px)",
|
||||||
|
1000: "blur(25px)"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["width", {
|
||||||
|
"replace": {
|
||||||
|
0: "100px",
|
||||||
|
250: "164px",
|
||||||
|
500: "228px",
|
||||||
|
1000: "1337px"
|
||||||
|
},
|
||||||
|
"add": {
|
||||||
|
0: "150px",
|
||||||
|
250: "214px",
|
||||||
|
500: "278px",
|
||||||
|
1000: "1387px"
|
||||||
|
},
|
||||||
|
"accumulate": {
|
||||||
|
0: "150px",
|
||||||
|
250: "214px",
|
||||||
|
500: "278px",
|
||||||
|
1000: "1387px"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const test_case of test_cases) {
|
||||||
|
const property = test_case[0];
|
||||||
|
const test_data = test_case[1];
|
||||||
|
for (const [composite_type, expected_values] of Object.entries(test_data)) {
|
||||||
|
test(t => {
|
||||||
|
let elem = addDiv(t, {"class": "anim-target"});
|
||||||
|
run_test_case(elem, property, composite_type, expected_values);
|
||||||
|
}, "animation-composition: " + composite_type + " of property " + property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Animations: parsing animation-composition with invalid values</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#propdef-animation-composition">
|
||||||
|
<meta name="assert" content="animation-composition supports only the grammar '<single-animation-composition> #'.">
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../../css/support/parsing-testcommon.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
test_invalid_value("animation-composition", "auto");
|
||||||
|
test_invalid_value("animation-composition", "add replace");
|
||||||
|
|
||||||
|
test_invalid_value("animation-composition", "add, initial");
|
||||||
|
test_invalid_value("animation-composition", "initial, add");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Animations: parsing animation-composition with valid values</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-animations-2/#propdef-animation-composition">
|
||||||
|
<meta name="assert" content="animation-composition supports the full grammar '<single-animation-composition> #'.">
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<script src="../../../css/support/parsing-testcommon.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
test_valid_value("animation-composition", "replace");
|
||||||
|
test_valid_value("animation-composition", "add");
|
||||||
|
test_valid_value("animation-composition", "accumulate");
|
||||||
|
test_valid_value("animation-composition", "replace, add, accumulate");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue