LibWeb: Clamp negative computed values for padding-* properties

Interpolation can leave `padding-*` values as negative - this should be
handled by interpolation clamping it to the allowed range of values
but we don't yet do that. As a stop gap we can clamp this before setting
it in ComputedValues.

This fixes 3 crashes and gains us 11 passes in the imported WPT tests
This commit is contained in:
Callum Law 2025-08-22 03:41:19 +12:00 committed by Sam Atkins
commit 6fcaceedd9
Notes: github-actions[bot] 2025-09-01 11:30:30 +00:00
10 changed files with 490 additions and 28 deletions

View file

@ -222,23 +222,39 @@ Size ComputedProperties::size_value(PropertyID id) const
return Size::make_auto();
}
LengthPercentage ComputedProperties::length_percentage_or_fallback(PropertyID id, LengthPercentage const& fallback) const
LengthPercentage ComputedProperties::length_percentage_or_fallback(PropertyID id, Layout::NodeWithStyle const& layout_node, ClampNegativeLengths disallow_negative_lengths, LengthPercentage const& fallback) const
{
return length_percentage(id).value_or(fallback);
return length_percentage(id, layout_node, disallow_negative_lengths).value_or(fallback);
}
Optional<LengthPercentage> ComputedProperties::length_percentage(PropertyID id) const
Optional<LengthPercentage> ComputedProperties::length_percentage(PropertyID id, Layout::NodeWithStyle const& layout_node, ClampNegativeLengths disallow_negative_lengths) const
{
auto const& value = property(id);
if (value.is_calculated())
return LengthPercentage { value.as_calculated() };
if (value.is_percentage())
return value.as_percentage().percentage();
if (value.is_percentage()) {
auto percentage = value.as_percentage().percentage();
if (value.is_length())
return value.as_length().length();
// FIXME: This value can be negative as interpolation does not yet clamp values to allowed ranges - remove this
// once we do that.
if (disallow_negative_lengths == ClampNegativeLengths::Yes && percentage.as_fraction() < 0)
return {};
return percentage;
}
if (value.is_length()) {
auto length = value.as_length().length();
// FIXME: This value can be negative as interpolation does not yet clamp values to allowed ranges - remove this
// once we do that.
if (disallow_negative_lengths == ClampNegativeLengths::Yes && length.to_px(layout_node) < 0)
return {};
return length;
}
if (value.has_auto())
return LengthPercentage { Length::make_auto() };
@ -251,13 +267,13 @@ Length ComputedProperties::length(PropertyID property_id) const
return property(property_id).as_length().length();
}
LengthBox ComputedProperties::length_box(PropertyID left_id, PropertyID top_id, PropertyID right_id, PropertyID bottom_id, Length const& default_value) const
LengthBox ComputedProperties::length_box(PropertyID left_id, PropertyID top_id, PropertyID right_id, PropertyID bottom_id, Layout::NodeWithStyle const& layout_node, ClampNegativeLengths disallow_negative_lengths, Length const& default_value) const
{
LengthBox box;
box.left() = length_percentage_or_fallback(left_id, default_value);
box.top() = length_percentage_or_fallback(top_id, default_value);
box.right() = length_percentage_or_fallback(right_id, default_value);
box.bottom() = length_percentage_or_fallback(bottom_id, default_value);
box.left() = length_percentage_or_fallback(left_id, layout_node, disallow_negative_lengths, default_value);
box.top() = length_percentage_or_fallback(top_id, layout_node, disallow_negative_lengths, default_value);
box.right() = length_percentage_or_fallback(right_id, layout_node, disallow_negative_lengths, default_value);
box.bottom() = length_percentage_or_fallback(bottom_id, layout_node, disallow_negative_lengths, default_value);
return box;
}

View file

@ -76,10 +76,15 @@ public:
Size size_value(PropertyID) const;
[[nodiscard]] Variant<LengthPercentage, NormalGap> gap_value(PropertyID) const;
LengthPercentage length_percentage_or_fallback(PropertyID, LengthPercentage const& fallback) const;
Optional<LengthPercentage> length_percentage(PropertyID) const;
Length length(PropertyID) const;
LengthBox length_box(PropertyID left_id, PropertyID top_id, PropertyID right_id, PropertyID bottom_id, Length const& default_value) const;
enum class ClampNegativeLengths {
No,
Yes,
};
LengthPercentage length_percentage_or_fallback(PropertyID, Layout::NodeWithStyle const&, ClampNegativeLengths, LengthPercentage const& fallback) const;
Optional<LengthPercentage> length_percentage(PropertyID, Layout::NodeWithStyle const&, ClampNegativeLengths) const;
LengthBox length_box(PropertyID left_id, PropertyID top_id, PropertyID right_id, PropertyID bottom_id, Layout::NodeWithStyle const&, ClampNegativeLengths, Length const& default_value) const;
Color color_or_fallback(PropertyID, ColorResolutionContext, Color fallback) const;
ColorInterpolation color_interpolation() const;
PreferredColorScheme color_scheme(PreferredColorScheme, Optional<Vector<String> const&> document_supported_schemes) const;

View file

@ -609,7 +609,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_text_overflow(computed_style.text_overflow());
computed_values.set_text_rendering(computed_style.text_rendering());
if (auto text_indent = computed_style.length_percentage(CSS::PropertyID::TextIndent); text_indent.has_value())
if (auto text_indent = computed_style.length_percentage(CSS::PropertyID::TextIndent, *this, CSS::ComputedProperties::ClampNegativeLengths::No); text_indent.has_value())
computed_values.set_text_indent(text_indent.release_value());
computed_values.set_text_wrap_mode(computed_style.text_wrap_mode());
@ -653,7 +653,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
// we just manually grab the value from `color`. This makes it dependent on `color` being
// specified first, so it's far from ideal.
computed_values.set_text_decoration_color(computed_style.color_or_fallback(CSS::PropertyID::TextDecorationColor, CSS::ColorResolutionContext::for_layout_node_with_style(*this), computed_values.color()));
if (auto maybe_text_decoration_thickness = computed_style.length_percentage(CSS::PropertyID::TextDecorationThickness); maybe_text_decoration_thickness.has_value())
if (auto maybe_text_decoration_thickness = computed_style.length_percentage(CSS::PropertyID::TextDecorationThickness, *this, CSS::ComputedProperties::ClampNegativeLengths::No); maybe_text_decoration_thickness.has_value())
computed_values.set_text_decoration_thickness(maybe_text_decoration_thickness.release_value());
computed_values.set_webkit_text_fill_color(computed_style.color_or_fallback(CSS::PropertyID::WebkitTextFillColor, CSS::ColorResolutionContext::for_layout_node_with_style(*this), computed_values.color()));
@ -673,9 +673,9 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_min_height(computed_style.size_value(CSS::PropertyID::MinHeight));
computed_values.set_max_height(computed_style.size_value(CSS::PropertyID::MaxHeight));
computed_values.set_inset(computed_style.length_box(CSS::PropertyID::Left, CSS::PropertyID::Top, CSS::PropertyID::Right, CSS::PropertyID::Bottom, CSS::Length::make_auto()));
computed_values.set_margin(computed_style.length_box(CSS::PropertyID::MarginLeft, CSS::PropertyID::MarginTop, CSS::PropertyID::MarginRight, CSS::PropertyID::MarginBottom, CSS::Length::make_px(0)));
computed_values.set_padding(computed_style.length_box(CSS::PropertyID::PaddingLeft, CSS::PropertyID::PaddingTop, CSS::PropertyID::PaddingRight, CSS::PropertyID::PaddingBottom, CSS::Length::make_px(0)));
computed_values.set_inset(computed_style.length_box(CSS::PropertyID::Left, CSS::PropertyID::Top, CSS::PropertyID::Right, CSS::PropertyID::Bottom, *this, CSS::ComputedProperties::ClampNegativeLengths::No, CSS::Length::make_auto()));
computed_values.set_margin(computed_style.length_box(CSS::PropertyID::MarginLeft, CSS::PropertyID::MarginTop, CSS::PropertyID::MarginRight, CSS::PropertyID::MarginBottom, *this, CSS::ComputedProperties::ClampNegativeLengths::No, CSS::Length::make_px(0)));
computed_values.set_padding(computed_style.length_box(CSS::PropertyID::PaddingLeft, CSS::PropertyID::PaddingTop, CSS::PropertyID::PaddingRight, CSS::PropertyID::PaddingBottom, *this, CSS::ComputedProperties::ClampNegativeLengths::Yes, CSS::Length::make_px(0)));
computed_values.set_box_shadow(computed_style.box_shadow(*this));
@ -737,19 +737,19 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_grid_template_areas(computed_style.grid_template_areas());
computed_values.set_grid_auto_flow(computed_style.grid_auto_flow());
if (auto cx_value = computed_style.length_percentage(CSS::PropertyID::Cx); cx_value.has_value())
if (auto cx_value = computed_style.length_percentage(CSS::PropertyID::Cx, *this, CSS::ComputedProperties::ClampNegativeLengths::No); cx_value.has_value())
computed_values.set_cx(*cx_value);
if (auto cy_value = computed_style.length_percentage(CSS::PropertyID::Cy); cy_value.has_value())
if (auto cy_value = computed_style.length_percentage(CSS::PropertyID::Cy, *this, CSS::ComputedProperties::ClampNegativeLengths::No); cy_value.has_value())
computed_values.set_cy(*cy_value);
if (auto r_value = computed_style.length_percentage(CSS::PropertyID::R); r_value.has_value())
if (auto r_value = computed_style.length_percentage(CSS::PropertyID::R, *this, CSS::ComputedProperties::ClampNegativeLengths::No); r_value.has_value())
computed_values.set_r(*r_value);
if (auto rx_value = computed_style.length_percentage(CSS::PropertyID::Rx); rx_value.has_value())
if (auto rx_value = computed_style.length_percentage(CSS::PropertyID::Rx, *this, CSS::ComputedProperties::ClampNegativeLengths::No); rx_value.has_value())
computed_values.set_rx(*rx_value);
if (auto ry_value = computed_style.length_percentage(CSS::PropertyID::Ry); ry_value.has_value())
if (auto ry_value = computed_style.length_percentage(CSS::PropertyID::Ry, *this, CSS::ComputedProperties::ClampNegativeLengths::No); ry_value.has_value())
computed_values.set_ry(*ry_value);
if (auto x_value = computed_style.length_percentage(CSS::PropertyID::X); x_value.has_value())
if (auto x_value = computed_style.length_percentage(CSS::PropertyID::X, *this, CSS::ComputedProperties::ClampNegativeLengths::No); x_value.has_value())
computed_values.set_x(*x_value);
if (auto y_value = computed_style.length_percentage(CSS::PropertyID::Y); y_value.has_value())
if (auto y_value = computed_style.length_percentage(CSS::PropertyID::Y, *this, CSS::ComputedProperties::ClampNegativeLengths::No); y_value.has_value())
computed_values.set_y(*y_value);
auto const& fill = computed_style.property(CSS::PropertyID::Fill);

View file

@ -313,8 +313,10 @@ GC::Ref<SVGAnimatedLength> SVGElement::svg_animated_length_for_property(CSS::Pro
// FIXME: Create a proper animated value when animations are supported.
auto make_length = [&](SVGLength::ReadOnly read_only) {
if (auto const computed_properties = this->computed_properties()) {
if (auto length = computed_properties->length_percentage(property); length.has_value())
return SVGLength::from_length_percentage(realm(), *length, read_only);
if (auto layout_node = this->layout_node()) {
if (auto length = computed_properties->length_percentage(property, *layout_node, CSS::ComputedProperties::ClampNegativeLengths::Yes); length.has_value())
return SVGLength::from_length_percentage(realm(), *length, read_only);
}
}
return SVGLength::create(realm(), 0, 0, read_only);
};

View file

@ -0,0 +1,26 @@
Harness status: OK
Found 20 tests
1 Pass
19 Fail
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to add [200px] at (-0.3) should be [120px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to add [200px] at (0) should be [150px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to add [200px] at (0.5) should be [200px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to add [200px] at (1) should be [250px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to add [200px] at (1.5) should be [300px]
Fail Compositing: property <padding-bottom> underlying [100px] from add [10px] to add [2px] at (-0.5) should be [114px]
Fail Compositing: property <padding-bottom> underlying [100px] from add [10px] to add [2px] at (0) should be [110px]
Fail Compositing: property <padding-bottom> underlying [100px] from add [10px] to add [2px] at (0.5) should be [106px]
Fail Compositing: property <padding-bottom> underlying [100px] from add [10px] to add [2px] at (1) should be [102px]
Fail Compositing: property <padding-bottom> underlying [100px] from add [10px] to add [2px] at (1.5) should be [98px]
Fail Compositing: property <padding-bottom> underlying [10%] from add [100px] to add [20%] at (-0.3) should be [calc(130px + 4%)]
Fail Compositing: property <padding-bottom> underlying [10%] from add [100px] to add [20%] at (0) should be [calc(100px + 10%)]
Fail Compositing: property <padding-bottom> underlying [10%] from add [100px] to add [20%] at (0.5) should be [calc(50px + 20%)]
Fail Compositing: property <padding-bottom> underlying [10%] from add [100px] to add [20%] at (1) should be [30%]
Fail Compositing: property <padding-bottom> underlying [10%] from add [100px] to add [20%] at (1.5) should be [calc(-50px + 40%)]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to replace [200px] at (-0.3) should be [135px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to replace [200px] at (0) should be [150px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to replace [200px] at (0.5) should be [175px]
Pass Compositing: property <padding-bottom> underlying [50px] from add [100px] to replace [200px] at (1) should be [200px]
Fail Compositing: property <padding-bottom> underlying [50px] from add [100px] to replace [200px] at (1.5) should be [225px]

View file

@ -0,0 +1,149 @@
Harness status: OK
Found 144 tests
144 Pass
Pass CSS Transitions: property <padding> from neutral to [20px] at (-0.3) should be [7px]
Pass CSS Transitions: property <padding> from neutral to [20px] at (0) should be [10px]
Pass CSS Transitions: property <padding> from neutral to [20px] at (0.3) should be [13px]
Pass CSS Transitions: property <padding> from neutral to [20px] at (0.6) should be [16px]
Pass CSS Transitions: property <padding> from neutral to [20px] at (1) should be [20px]
Pass CSS Transitions: property <padding> from neutral to [20px] at (1.5) should be [25px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (-0.3) should be [7px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (0) should be [10px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (0.3) should be [13px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (0.6) should be [16px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (1) should be [20px]
Pass CSS Transitions with transition: all: property <padding> from neutral to [20px] at (1.5) should be [25px]
Pass CSS Animations: property <padding> from neutral to [20px] at (-0.3) should be [7px]
Pass CSS Animations: property <padding> from neutral to [20px] at (0) should be [10px]
Pass CSS Animations: property <padding> from neutral to [20px] at (0.3) should be [13px]
Pass CSS Animations: property <padding> from neutral to [20px] at (0.6) should be [16px]
Pass CSS Animations: property <padding> from neutral to [20px] at (1) should be [20px]
Pass CSS Animations: property <padding> from neutral to [20px] at (1.5) should be [25px]
Pass Web Animations: property <padding> from neutral to [20px] at (-0.3) should be [7px]
Pass Web Animations: property <padding> from neutral to [20px] at (0) should be [10px]
Pass Web Animations: property <padding> from neutral to [20px] at (0.3) should be [13px]
Pass Web Animations: property <padding> from neutral to [20px] at (0.6) should be [16px]
Pass Web Animations: property <padding> from neutral to [20px] at (1) should be [20px]
Pass Web Animations: property <padding> from neutral to [20px] at (1.5) should be [25px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (-0.3) should be [0px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (0) should be [0px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (0.3) should be [6px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (0.6) should be [12px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (1) should be [20px]
Pass CSS Transitions: property <padding> from [initial] to [20px] at (1.5) should be [30px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (-0.3) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (0) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (0.3) should be [6px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (0.6) should be [12px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (1) should be [20px]
Pass CSS Transitions with transition: all: property <padding> from [initial] to [20px] at (1.5) should be [30px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (-0.3) should be [0px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (0) should be [0px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (0.3) should be [6px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (0.6) should be [12px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (1) should be [20px]
Pass CSS Animations: property <padding> from [initial] to [20px] at (1.5) should be [30px]
Pass Web Animations: property <padding> from [initial] to [20px] at (-0.3) should be [0px]
Pass Web Animations: property <padding> from [initial] to [20px] at (0) should be [0px]
Pass Web Animations: property <padding> from [initial] to [20px] at (0.3) should be [6px]
Pass Web Animations: property <padding> from [initial] to [20px] at (0.6) should be [12px]
Pass Web Animations: property <padding> from [initial] to [20px] at (1) should be [20px]
Pass Web Animations: property <padding> from [initial] to [20px] at (1.5) should be [30px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (-0.3) should be [33px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (0) should be [30px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (0.3) should be [27px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (0.6) should be [24px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (1) should be [20px]
Pass CSS Transitions: property <padding> from [inherit] to [20px] at (1.5) should be [15px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (-0.3) should be [33px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (0) should be [30px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (0.3) should be [27px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (0.6) should be [24px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (1) should be [20px]
Pass CSS Transitions with transition: all: property <padding> from [inherit] to [20px] at (1.5) should be [15px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (-0.3) should be [33px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (0) should be [30px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (0.3) should be [27px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (0.6) should be [24px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (1) should be [20px]
Pass CSS Animations: property <padding> from [inherit] to [20px] at (1.5) should be [15px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (-0.3) should be [33px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (0) should be [30px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (0.3) should be [27px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (0.6) should be [24px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (1) should be [20px]
Pass Web Animations: property <padding> from [inherit] to [20px] at (1.5) should be [15px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (-0.3) should be [0px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (0) should be [0px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (0.3) should be [6px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (0.6) should be [12px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (1) should be [20px]
Pass CSS Transitions: property <padding> from [unset] to [20px] at (1.5) should be [30px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (-0.3) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (0) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (0.3) should be [6px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (0.6) should be [12px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (1) should be [20px]
Pass CSS Transitions with transition: all: property <padding> from [unset] to [20px] at (1.5) should be [30px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (-0.3) should be [0px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (0) should be [0px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (0.3) should be [6px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (0.6) should be [12px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (1) should be [20px]
Pass CSS Animations: property <padding> from [unset] to [20px] at (1.5) should be [30px]
Pass Web Animations: property <padding> from [unset] to [20px] at (-0.3) should be [0px]
Pass Web Animations: property <padding> from [unset] to [20px] at (0) should be [0px]
Pass Web Animations: property <padding> from [unset] to [20px] at (0.3) should be [6px]
Pass Web Animations: property <padding> from [unset] to [20px] at (0.6) should be [12px]
Pass Web Animations: property <padding> from [unset] to [20px] at (1) should be [20px]
Pass Web Animations: property <padding> from [unset] to [20px] at (1.5) should be [30px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (-0.3) should be [0px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (0) should be [0px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (0.3) should be [3px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (0.6) should be [6px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (1) should be [10px]
Pass CSS Transitions: property <padding> from [0px] to [10px] at (1.5) should be [15px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (-0.3) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (0) should be [0px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (0.3) should be [3px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (0.6) should be [6px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (1) should be [10px]
Pass CSS Transitions with transition: all: property <padding> from [0px] to [10px] at (1.5) should be [15px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (-0.3) should be [0px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (0) should be [0px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (0.3) should be [3px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (0.6) should be [6px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (1) should be [10px]
Pass CSS Animations: property <padding> from [0px] to [10px] at (1.5) should be [15px]
Pass Web Animations: property <padding> from [0px] to [10px] at (-0.3) should be [0px]
Pass Web Animations: property <padding> from [0px] to [10px] at (0) should be [0px]
Pass Web Animations: property <padding> from [0px] to [10px] at (0.3) should be [3px]
Pass Web Animations: property <padding> from [0px] to [10px] at (0.6) should be [6px]
Pass Web Animations: property <padding> from [0px] to [10px] at (1) should be [10px]
Pass Web Animations: property <padding> from [0px] to [10px] at (1.5) should be [15px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (-0.3) should be [17px 37px 57px 77px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0) should be [20px 40px 60px 80px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.3) should be [23px 43px 63px 83px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.6) should be [26px 46px 66px 86px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1) should be [30px 50px 70px 90px]
Pass CSS Transitions: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1.5) should be [35px 55px 75px 95px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (-0.3) should be [17px 37px 57px 77px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0) should be [20px 40px 60px 80px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.3) should be [23px 43px 63px 83px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.6) should be [26px 46px 66px 86px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1) should be [30px 50px 70px 90px]
Pass CSS Transitions with transition: all: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1.5) should be [35px 55px 75px 95px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (-0.3) should be [17px 37px 57px 77px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0) should be [20px 40px 60px 80px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.3) should be [23px 43px 63px 83px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.6) should be [26px 46px 66px 86px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1) should be [30px 50px 70px 90px]
Pass CSS Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1.5) should be [35px 55px 75px 95px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (-0.3) should be [17px 37px 57px 77px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0) should be [20px 40px 60px 80px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.3) should be [23px 43px 63px 83px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (0.6) should be [26px 46px 66px 86px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1) should be [30px 50px 70px 90px]
Pass Web Animations: property <padding> from [20px 40px 60px 80px] to [30px 50px 70px 90px] at (1.5) should be [35px 55px 75px 95px]

View file

@ -0,0 +1,26 @@
Harness status: OK
Found 20 tests
1 Pass
19 Fail
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to add [200px] at (-0.3) should be [120px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to add [200px] at (0) should be [150px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to add [200px] at (0.5) should be [200px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to add [200px] at (1) should be [250px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to add [200px] at (1.5) should be [300px]
Fail Compositing: property <padding-top> underlying [100px] from add [10px] to add [2px] at (-0.5) should be [114px]
Fail Compositing: property <padding-top> underlying [100px] from add [10px] to add [2px] at (0) should be [110px]
Fail Compositing: property <padding-top> underlying [100px] from add [10px] to add [2px] at (0.5) should be [106px]
Fail Compositing: property <padding-top> underlying [100px] from add [10px] to add [2px] at (1) should be [102px]
Fail Compositing: property <padding-top> underlying [100px] from add [10px] to add [2px] at (1.5) should be [98px]
Fail Compositing: property <padding-top> underlying [10%] from add [100px] to add [20%] at (-0.3) should be [calc(130px + 4%)]
Fail Compositing: property <padding-top> underlying [10%] from add [100px] to add [20%] at (0) should be [calc(100px + 10%)]
Fail Compositing: property <padding-top> underlying [10%] from add [100px] to add [20%] at (0.5) should be [calc(50px + 20%)]
Fail Compositing: property <padding-top> underlying [10%] from add [100px] to add [20%] at (1) should be [30%]
Fail Compositing: property <padding-top> underlying [10%] from add [100px] to add [20%] at (1.5) should be [calc(-50px + 40%)]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to replace [200px] at (-0.3) should be [135px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to replace [200px] at (0) should be [150px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to replace [200px] at (0.5) should be [175px]
Pass Compositing: property <padding-top> underlying [50px] from add [100px] to replace [200px] at (1) should be [200px]
Fail Compositing: property <padding-top> underlying [50px] from add [100px] to replace [200px] at (1.5) should be [225px]

View file

@ -0,0 +1,65 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>padding-bottom composition</title>
<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-shorthand">
<meta name="assert" content="padding-bottom supports animation as a list of lengths">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/interpolation-testcommon.js"></script>
<body>
<script>
test_composition({
property: 'padding-bottom',
underlying: '50px',
addFrom: '100px',
addTo: '200px',
}, [
{at: -0.3, expect: '120px'},
{at: 0, expect: '150px'},
{at: 0.5, expect: '200px'},
{at: 1, expect: '250px'},
{at: 1.5, expect: '300px'},
]);
test_composition({
property: 'padding-bottom',
underlying: '100px',
addFrom: '10px',
addTo: '2px',
}, [
{at: -0.5, expect: '114px'},
{at: 0, expect: '110px'},
{at: 0.5, expect: '106px'},
{at: 1, expect: '102px'},
{at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
]);
test_composition({
property: 'padding-bottom',
underlying: '10%',
addFrom: '100px',
addTo: '20%',
}, [
{at: -0.3, expect: 'calc(130px + 4%)'},
{at: 0, expect: 'calc(100px + 10%)'},
{at: 0.5, expect: 'calc(50px + 20%)'},
{at: 1, expect: '30%'},
{at: 1.5, expect: 'calc(-50px + 40%)'},
]);
test_composition({
property: 'padding-bottom',
underlying: '50px',
addFrom: '100px',
replaceTo: '200px',
}, [
{at: -0.3, expect: '135px'},
{at: 0, expect: '150px'},
{at: 0.5, expect: '175px'},
{at: 1, expect: '200px'},
{at: 1.5, expect: '225px'},
]);
</script>
</body>

View file

@ -0,0 +1,108 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>padding interpolation</title>
<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-shorthand">
<meta name="assert" content="padding supports animation as a list of lengths">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/interpolation-testcommon.js"></script>
<style>
.parent {
padding: 30px;
}
.target {
width: 1px;
height: 1px;
background-color: black;
display: inline-block;
padding: 10px;
}
.expected {
background-color: green;
margin-right: 10px;
}
</style>
<body></body>
<script>
test_interpolation({
property: 'padding',
from: neutralKeyframe,
to: '20px',
}, [
{at: -0.3, expect: '7px'},
{at: 0, expect: '10px'},
{at: 0.3, expect: '13px'},
{at: 0.6, expect: '16px'},
{at: 1, expect: '20px'},
{at: 1.5, expect: '25px'},
]);
test_interpolation({
property: 'padding',
from: 'initial',
to: '20px',
}, [
{at: -0.3, expect: '0px'},
{at: 0, expect: '0px'},
{at: 0.3, expect: '6px'},
{at: 0.6, expect: '12px'},
{at: 1, expect: '20px'},
{at: 1.5, expect: '30px'},
]);
test_interpolation({
property: 'padding',
from: 'inherit',
to: '20px',
}, [
{at: -0.3, expect: '33px'},
{at: 0, expect: '30px'},
{at: 0.3, expect: '27px'},
{at: 0.6, expect: '24px'},
{at: 1, expect: '20px'},
{at: 1.5, expect: '15px'},
]);
test_interpolation({
property: 'padding',
from: 'unset',
to: '20px',
}, [
{at: -0.3, expect: '0px'},
{at: 0, expect: '0px'},
{at: 0.3, expect: '6px'},
{at: 0.6, expect: '12px'},
{at: 1, expect: '20px'},
{at: 1.5, expect: '30px'},
]);
test_interpolation({
property: 'padding',
from: '0px',
to: '10px'
}, [
{at: -0.3, expect: '0px'}, // CSS padding can't be negative.
{at: 0, expect: '0px'},
{at: 0.3, expect: '3px'},
{at: 0.6, expect: '6px'},
{at: 1, expect: '10px'},
{at: 1.5, expect: '15px'}
]);
test_interpolation({
property: 'padding',
from: '20px 40px 60px 80px',
to: '30px 50px 70px 90px'
}, [
{at: -0.3, expect: '17px 37px 57px 77px'},
{at: 0, expect: '20px 40px 60px 80px'},
{at: 0.3, expect: '23px 43px 63px 83px'},
{at: 0.6, expect: '26px 46px 66px 86px'},
{at: 1, expect: '30px 50px 70px 90px'},
{at: 1.5, expect: '35px 55px 75px 95px'}
]);
</script>

View file

@ -0,0 +1,65 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>padding-top composition</title>
<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-shorthand">
<meta name="assert" content="padding-top supports animation as a list of lengths">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/interpolation-testcommon.js"></script>
<body>
<script>
test_composition({
property: 'padding-top',
underlying: '50px',
addFrom: '100px',
addTo: '200px',
}, [
{at: -0.3, expect: '120px'},
{at: 0, expect: '150px'},
{at: 0.5, expect: '200px'},
{at: 1, expect: '250px'},
{at: 1.5, expect: '300px'},
]);
test_composition({
property: 'padding-top',
underlying: '100px',
addFrom: '10px',
addTo: '2px',
}, [
{at: -0.5, expect: '114px'},
{at: 0, expect: '110px'},
{at: 0.5, expect: '106px'},
{at: 1, expect: '102px'},
{at: 1.5, expect: '98px'}, // Value clamping should happen after composition.
]);
test_composition({
property: 'padding-top',
underlying: '10%',
addFrom: '100px',
addTo: '20%',
}, [
{at: -0.3, expect: 'calc(130px + 4%)'},
{at: 0, expect: 'calc(100px + 10%)'},
{at: 0.5, expect: 'calc(50px + 20%)'},
{at: 1, expect: '30%'},
{at: 1.5, expect: 'calc(-50px + 40%)'},
]);
test_composition({
property: 'padding-top',
underlying: '50px',
addFrom: '100px',
replaceTo: '200px',
}, [
{at: -0.3, expect: '135px'},
{at: 0, expect: '150px'},
{at: 0.5, expect: '175px'},
{at: 1, expect: '200px'},
{at: 1.5, expect: '225px'},
]);
</script>
</body>