mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb: Serialize animation according to spec
We now: - Serialize longhands in the correct order - Support serializing multiple values - Include default longhands where required (to distinguish animation-name from that longhand).
This commit is contained in:
parent
869442c206
commit
517e3f5f1d
|
|
@ -199,14 +199,14 @@
|
|||
"inherited": false,
|
||||
"initial": "none 0s ease 1 normal running 0s none",
|
||||
"longhands": [
|
||||
"animation-name",
|
||||
"animation-duration",
|
||||
"animation-timing-function",
|
||||
"animation-delay",
|
||||
"animation-iteration-count",
|
||||
"animation-direction",
|
||||
"animation-fill-mode",
|
||||
"animation-play-state",
|
||||
"animation-delay",
|
||||
"animation-fill-mode"
|
||||
"animation-name"
|
||||
]
|
||||
},
|
||||
"animation-composition": {
|
||||
|
|
|
|||
|
|
@ -141,6 +141,79 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const
|
|||
// handled above, thus, if we get to here that mustn't be the case and we should return the empty string.
|
||||
return ""_string;
|
||||
}
|
||||
case PropertyID::Animation: {
|
||||
auto const get_longhand_as_vector = [&](PropertyID longhand_id) -> StyleValueVector {
|
||||
auto value = longhand(longhand_id);
|
||||
|
||||
if (value->is_value_list())
|
||||
return value->as_value_list().values();
|
||||
|
||||
// FIXME: This is required as parse_comma_separated_value_list() returns a single value directly instead of a list if there's only one.
|
||||
return { value.release_nonnull() };
|
||||
};
|
||||
|
||||
// If we don't have the same number of values for each longhand, we can't serialize this shorthand.
|
||||
if (any_of(m_properties.sub_properties, [&](auto longhand_id) { return get_longhand_as_vector(longhand_id).size() != get_longhand_as_vector(m_properties.sub_properties[0]).size(); }))
|
||||
return ""_string;
|
||||
|
||||
StringBuilder builder;
|
||||
for (size_t i = 0; i < get_longhand_as_vector(m_properties.sub_properties[0]).size(); i++) {
|
||||
auto animation_name = get_longhand_as_vector(PropertyID::AnimationName)[i]->to_string(mode);
|
||||
bool first = true;
|
||||
|
||||
for (auto longhand_id : m_properties.sub_properties) {
|
||||
auto longhand_value = get_longhand_as_vector(longhand_id)[i];
|
||||
|
||||
bool should_serialize_longhand = [&]() {
|
||||
if (!longhand_value->equals(property_initial_value(longhand_id)))
|
||||
return true;
|
||||
|
||||
if (longhand_id == PropertyID::AnimationDuration && !get_longhand_as_vector(PropertyID::AnimationDelay)[i]->equals(property_initial_value(PropertyID::AnimationDelay)))
|
||||
return true;
|
||||
|
||||
auto animation_name_keyword = keyword_from_string(animation_name);
|
||||
|
||||
if (!animation_name_keyword.has_value() || animation_name_keyword == Keyword::None)
|
||||
return false;
|
||||
|
||||
// https://drafts.csswg.org/css-animations-1/#animation
|
||||
// Furthermore, when serializing, default values of other properties must be output in at least the
|
||||
// cases necessary to distinguish an animation-name that could be a value of another property
|
||||
if (longhand_id == PropertyID::AnimationTimingFunction && animation_name.bytes_as_string_view().is_one_of_ignoring_ascii_case("linear"sv, "ease"sv, "ease-in"sv, "ease-out"sv, "ease-in-out"sv, "step-start"sv, "step-end"sv))
|
||||
return true;
|
||||
|
||||
if (longhand_id == PropertyID::AnimationDirection && keyword_to_animation_direction(animation_name_keyword.value()).has_value())
|
||||
return true;
|
||||
|
||||
if (longhand_id == PropertyID::AnimationFillMode && keyword_to_animation_fill_mode(animation_name_keyword.value()).has_value())
|
||||
return true;
|
||||
|
||||
if (longhand_id == PropertyID::AnimationPlayState && keyword_to_animation_play_state(animation_name_keyword.value()).has_value())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (!should_serialize_longhand)
|
||||
continue;
|
||||
|
||||
if (!builder.is_empty() && !first)
|
||||
builder.append(' ');
|
||||
|
||||
builder.append(longhand_value->to_string(mode));
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
builder.append("none"sv);
|
||||
}
|
||||
|
||||
if (i != get_longhand_as_vector(m_properties.sub_properties[0]).size() - 1)
|
||||
builder.append(", "sv);
|
||||
}
|
||||
|
||||
return builder.to_string_without_validation();
|
||||
}
|
||||
case PropertyID::Background: {
|
||||
auto color = longhand(PropertyID::BackgroundColor);
|
||||
auto image = longhand(PropertyID::BackgroundImage);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#timing-function { animation: ease eAsE-In-OuT; }
|
||||
#direction { animation: normal rEvErSe; }
|
||||
#fill-mode { animation: none fOrWaRdS; }
|
||||
#running-state { animation: running pAuSeD; }
|
||||
|
|
@ -2,8 +2,7 @@ Harness status: OK
|
|||
|
||||
Found 15 tests
|
||||
|
||||
11 Pass
|
||||
4 Fail
|
||||
15 Pass
|
||||
Pass Default animation value
|
||||
Pass Property animation value '1s'
|
||||
Pass Property animation value 'cubic-bezier(0, -2, 1, 3)'
|
||||
|
|
@ -15,7 +14,7 @@ Pass Property animation value 'both'
|
|||
Pass Property animation value 'paused'
|
||||
Pass Property animation value 'none'
|
||||
Pass Property animation value 'anim'
|
||||
Fail Property animation value 'anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)'
|
||||
Fail Property animation value 'anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)'
|
||||
Fail Property animation value 'none, none'
|
||||
Fail Animation with a delay but no duration
|
||||
Pass Property animation value 'anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)'
|
||||
Pass Property animation value 'anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)'
|
||||
Pass Property animation value 'none, none'
|
||||
Pass Animation with a delay but no duration
|
||||
|
|
@ -2,8 +2,7 @@ Harness status: OK
|
|||
|
||||
Found 12 tests
|
||||
|
||||
10 Pass
|
||||
2 Fail
|
||||
12 Pass
|
||||
Pass e.style['animation'] = "1s" should set the property value
|
||||
Pass e.style['animation'] = "cubic-bezier(0, -2, 1, 3)" should set the property value
|
||||
Pass e.style['animation'] = "cubic-bezier( 0, -2, 1, 3 )" should set the property value
|
||||
|
|
@ -14,5 +13,5 @@ Pass e.style['animation'] = "both" should set the property value
|
|||
Pass e.style['animation'] = "paused" should set the property value
|
||||
Pass e.style['animation'] = "none" should set the property value
|
||||
Pass e.style['animation'] = "anim" should set the property value
|
||||
Fail e.style['animation'] = "anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)" should set the property value
|
||||
Fail e.style['animation'] = "anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)" should set the property value
|
||||
Pass e.style['animation'] = "anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)" should set the property value
|
||||
Pass e.style['animation'] = "anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)" should set the property value
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<style>
|
||||
#timing-function {
|
||||
animation: none;
|
||||
animation-name: eAsE-In-OuT;
|
||||
}
|
||||
#direction {
|
||||
animation: none;
|
||||
animation-name: rEvErSe;
|
||||
}
|
||||
#fill-mode {
|
||||
animation: none;
|
||||
animation-name: fOrWaRdS;
|
||||
}
|
||||
#running-state {
|
||||
animation: none;
|
||||
animation-name: pAuSeD;
|
||||
}
|
||||
</style>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
for (const rule of document.styleSheets[0].cssRules) {
|
||||
println(rule.cssText);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user