LibWeb: Don't extrapolate transition properties for unknown properties
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-22.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-22.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run

If we don't recognize a given transition-property value as a known CSS
property (one that we know about, not necessarily an invalid one),
we should not extrapolate the other transition-foo values for it.

Fixes #1480
This commit is contained in:
Andreas Kling 2024-09-24 20:19:54 +02:00 committed by Andreas Kling
parent de31ea5852
commit 9765a733d0
Notes: github-actions[bot] 2024-09-24 19:54:35 +00:00
3 changed files with 84 additions and 65 deletions

View file

@ -0,0 +1 @@
PASS (didn't crash)

View file

@ -0,0 +1,15 @@
<style>
#foo {
transition-property: filter;
transition-timing-function: linear;
transition-duration:.3s;
}
</style>
<div id="foo"></div>
<script src="../include.js"></script>
<script>
test(() => {
foo.offsetWidth;
println("PASS (didn't crash)");
});
</script>

View file

@ -1220,79 +1220,82 @@ static void compute_transitioned_properties(StyleProperties const& style, DOM::E
// FIXME: Implement transitioning for pseudo-elements
(void)pseudo_element;
if (auto const source_declaration = style.transition_property_source(); source_declaration && element.computed_css_values()) {
if (source_declaration != element.cached_transition_property_source()) {
// Reparse this transition property
element.clear_transitions();
element.set_cached_transition_property_source(*source_declaration);
auto const source_declaration = style.transition_property_source();
if (!source_declaration)
return;
if (!element.computed_css_values())
return;
if (source_declaration == element.cached_transition_property_source())
return;
// Reparse this transition property
element.clear_transitions();
element.set_cached_transition_property_source(*source_declaration);
auto transition_properties_value = style.property(PropertyID::TransitionProperty);
auto transition_properties = transition_properties_value->is_value_list()
? transition_properties_value->as_value_list().values()
: StyleValueVector { transition_properties_value };
auto transition_properties_value = style.property(PropertyID::TransitionProperty);
auto transition_properties = transition_properties_value->is_value_list()
? transition_properties_value->as_value_list().values()
: StyleValueVector { transition_properties_value };
auto normalize_transition_length_list = [&](PropertyID property, auto make_default_value) {
auto style_value = style.maybe_null_property(property);
StyleValueVector list;
Vector<Vector<PropertyID>> properties;
if (!style_value || !style_value->is_value_list() || style_value->as_value_list().size() == 0) {
auto default_value = make_default_value();
for (size_t i = 0; i < transition_properties.size(); i++)
list.append(default_value);
return list;
}
for (size_t i = 0; i < transition_properties.size(); i++) {
auto property_value = transition_properties[i];
Vector<PropertyID> properties_for_this_transition;
auto const& value_list = style_value->as_value_list();
for (size_t i = 0; i < transition_properties.size(); i++)
list.append(value_list.value_at(i, true));
return list;
};
auto delays = normalize_transition_length_list(
PropertyID::TransitionDelay,
[] { return TimeStyleValue::create(Time::make_seconds(0.0)); });
auto durations = normalize_transition_length_list(
PropertyID::TransitionDuration,
[] { return TimeStyleValue::create(Time::make_seconds(0.0)); });
auto timing_functions = normalize_transition_length_list(
PropertyID::TransitionTimingFunction,
[] { return EasingStyleValue::create(EasingStyleValue::CubicBezier::ease()); });
Vector<Vector<PropertyID>> properties;
for (size_t i = 0; i < transition_properties.size(); i++) {
auto property_value = transition_properties[i];
Vector<PropertyID> properties_for_this_transition;
if (property_value->is_keyword()) {
auto keyword = property_value->as_keyword().keyword();
if (keyword == Keyword::None)
continue;
if (keyword == Keyword::All) {
for (auto prop = first_property_id; prop != last_property_id; prop = static_cast<PropertyID>(to_underlying(prop) + 1))
properties_for_this_transition.append(prop);
}
} else {
auto maybe_property = property_id_from_string(property_value->as_custom_ident().custom_ident());
if (!maybe_property.has_value())
continue;
auto transition_property = maybe_property.release_value();
if (property_is_shorthand(transition_property)) {
for (auto const& prop : longhands_for_shorthand(transition_property))
properties_for_this_transition.append(prop);
} else {
properties_for_this_transition.append(transition_property);
}
}
properties.append(move(properties_for_this_transition));
if (property_value->is_keyword()) {
auto keyword = property_value->as_keyword().keyword();
if (keyword == Keyword::None)
continue;
if (keyword == Keyword::All) {
for (auto prop = first_property_id; prop != last_property_id; prop = static_cast<PropertyID>(to_underlying(prop) + 1))
properties_for_this_transition.append(prop);
}
} else {
auto maybe_property = property_id_from_string(property_value->as_custom_ident().custom_ident());
if (!maybe_property.has_value())
continue;
element.add_transitioned_properties(move(properties), move(delays), move(durations), move(timing_functions));
auto transition_property = maybe_property.release_value();
if (property_is_shorthand(transition_property)) {
for (auto const& prop : longhands_for_shorthand(transition_property))
properties_for_this_transition.append(prop);
} else {
properties_for_this_transition.append(transition_property);
}
}
properties.append(move(properties_for_this_transition));
}
auto normalize_transition_length_list = [&properties, &style](PropertyID property, auto make_default_value) {
auto style_value = style.maybe_null_property(property);
StyleValueVector list;
if (!style_value || !style_value->is_value_list() || style_value->as_value_list().size() == 0) {
auto default_value = make_default_value();
for (size_t i = 0; i < properties.size(); i++)
list.append(default_value);
return list;
}
auto const& value_list = style_value->as_value_list();
for (size_t i = 0; i < properties.size(); i++)
list.append(value_list.value_at(i, true));
return list;
};
auto delays = normalize_transition_length_list(
PropertyID::TransitionDelay,
[] { return TimeStyleValue::create(Time::make_seconds(0.0)); });
auto durations = normalize_transition_length_list(
PropertyID::TransitionDuration,
[] { return TimeStyleValue::create(Time::make_seconds(0.0)); });
auto timing_functions = normalize_transition_length_list(
PropertyID::TransitionTimingFunction,
[] { return EasingStyleValue::create(EasingStyleValue::CubicBezier::ease()); });
element.add_transitioned_properties(move(properties), move(delays), move(durations), move(timing_functions));
}
// https://drafts.csswg.org/css-transitions/#starting