LibWeb: Make LengthBox hold LengthPercentageOrAuto

Not every user of this requires an `auto` state, but most do.

This has quite a big diff but most of that is mechanical:
LengthPercentageOrAuto has `resolved_or_auto()` instead of `resolved()`,
and `to_px_or_zero()` instead of `to_px()`, to make their output
clearer.
This commit is contained in:
Sam Atkins 2025-09-01 12:51:52 +01:00
commit dd122e2f74
Notes: github-actions[bot] 2025-09-04 12:32:43 +00:00
17 changed files with 199 additions and 215 deletions

View file

@ -330,6 +330,17 @@ static NonnullRefPtr<StyleValue const> style_value_for_length_percentage(LengthP
return length_percentage.calculated(); return length_percentage.calculated();
} }
static NonnullRefPtr<StyleValue const> style_value_for_length_percentage_or_auto(LengthPercentageOrAuto const& length_percentage)
{
if (length_percentage.is_auto())
return KeywordStyleValue::create(Keyword::Auto);
if (length_percentage.is_percentage())
return PercentageStyleValue::create(length_percentage.percentage());
if (length_percentage.is_length())
return LengthStyleValue::create(length_percentage.length());
return length_percentage.calculated();
}
static NonnullRefPtr<StyleValue const> style_value_for_size(Size const& size) static NonnullRefPtr<StyleValue const> style_value_for_size(Size const& size)
{ {
if (size.is_none()) if (size.is_none())
@ -517,7 +528,7 @@ RefPtr<StyleValue const> CSSStyleProperties::style_value_for_computed_property(L
auto& element = owner_node()->element(); auto& element = owner_node()->element();
auto pseudo_element = owner_node()->pseudo_element(); auto pseudo_element = owner_node()->pseudo_element();
auto used_value_for_inset = [&layout_node, used_value_for_property](LengthPercentage const& start_side, LengthPercentage const& end_side, Function<CSSPixels(Painting::PaintableBox const&)>&& used_value_getter) -> Optional<CSSPixels> { auto used_value_for_inset = [&layout_node, used_value_for_property](LengthPercentageOrAuto const& start_side, LengthPercentageOrAuto const& end_side, Function<CSSPixels(Painting::PaintableBox const&)>&& used_value_getter) -> Optional<CSSPixels> {
if (!layout_node.is_positioned()) if (!layout_node.is_positioned())
return {}; return {};
@ -630,35 +641,35 @@ RefPtr<StyleValue const> CSSStyleProperties::style_value_for_computed_property(L
case PropertyID::MarginBottom: case PropertyID::MarginBottom:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.bottom; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.bottom; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().margin().bottom()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().margin().bottom());
case PropertyID::MarginLeft: case PropertyID::MarginLeft:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.left; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.left; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().margin().left()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().margin().left());
case PropertyID::MarginRight: case PropertyID::MarginRight:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.right; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.right; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().margin().right()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().margin().right());
case PropertyID::MarginTop: case PropertyID::MarginTop:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.top; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().margin.top; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().margin().top()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().margin().top());
case PropertyID::PaddingBottom: case PropertyID::PaddingBottom:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.bottom; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.bottom; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().padding().bottom()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().padding().bottom());
case PropertyID::PaddingLeft: case PropertyID::PaddingLeft:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.left; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.left; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().padding().left()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().padding().left());
case PropertyID::PaddingRight: case PropertyID::PaddingRight:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.right; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.right; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().padding().right()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().padding().right());
case PropertyID::PaddingTop: case PropertyID::PaddingTop:
if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.top; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_property([](auto const& paintable_box) { return paintable_box.box_model().padding.top; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(layout_node.computed_values().padding().top()); return style_value_for_length_percentage_or_auto(layout_node.computed_values().padding().top());
case PropertyID::Width: { case PropertyID::Width: {
auto maybe_used_width = used_value_for_property([](auto const& paintable_box) { return paintable_box.content_width(); }); auto maybe_used_width = used_value_for_property([](auto const& paintable_box) { return paintable_box.content_width(); });
if (maybe_used_width.has_value()) if (maybe_used_width.has_value())
@ -683,27 +694,27 @@ RefPtr<StyleValue const> CSSStyleProperties::style_value_for_computed_property(L
if (auto maybe_used_value = used_value_for_inset(inset.bottom(), inset.top(), [](auto const& paintable_box) { return paintable_box.box_model().inset.bottom; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_inset(inset.bottom(), inset.top(), [](auto const& paintable_box) { return paintable_box.box_model().inset.bottom; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(inset.bottom()); return style_value_for_length_percentage_or_auto(inset.bottom());
} }
case PropertyID::Left: { case PropertyID::Left: {
auto& inset = layout_node.computed_values().inset(); auto& inset = layout_node.computed_values().inset();
if (auto maybe_used_value = used_value_for_inset(inset.left(), inset.right(), [](auto const& paintable_box) { return paintable_box.box_model().inset.left; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_inset(inset.left(), inset.right(), [](auto const& paintable_box) { return paintable_box.box_model().inset.left; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(inset.left()); return style_value_for_length_percentage_or_auto(inset.left());
} }
case PropertyID::Right: { case PropertyID::Right: {
auto& inset = layout_node.computed_values().inset(); auto& inset = layout_node.computed_values().inset();
if (auto maybe_used_value = used_value_for_inset(inset.right(), inset.left(), [](auto const& paintable_box) { return paintable_box.box_model().inset.right; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_inset(inset.right(), inset.left(), [](auto const& paintable_box) { return paintable_box.box_model().inset.right; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(inset.right()); return style_value_for_length_percentage_or_auto(inset.right());
} }
case PropertyID::Top: { case PropertyID::Top: {
auto& inset = layout_node.computed_values().inset(); auto& inset = layout_node.computed_values().inset();
if (auto maybe_used_value = used_value_for_inset(inset.top(), inset.bottom(), [](auto const& paintable_box) { return paintable_box.box_model().inset.top; }); maybe_used_value.has_value()) if (auto maybe_used_value = used_value_for_inset(inset.top(), inset.bottom(), [](auto const& paintable_box) { return paintable_box.box_model().inset.top; }); maybe_used_value.has_value())
return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value())); return LengthStyleValue::create(Length::make_px(maybe_used_value.release_value()));
return style_value_for_length_percentage(inset.top()); return style_value_for_length_percentage_or_auto(inset.top());
} }
// -> A resolved value special case property defined in another specification // -> A resolved value special case property defined in another specification

View file

@ -261,9 +261,9 @@ Length ComputedProperties::length(PropertyID property_id) const
return property(property_id).as_length().length(); return property(property_id).as_length().length();
} }
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 ComputedProperties::length_box(PropertyID left_id, PropertyID top_id, PropertyID right_id, PropertyID bottom_id, Layout::NodeWithStyle const& layout_node, ClampNegativeLengths disallow_negative_lengths, LengthPercentageOrAuto const& default_value) const
{ {
auto length_box_side = [&](PropertyID id) -> LengthPercentage { auto length_box_side = [&](PropertyID id) -> LengthPercentageOrAuto {
auto const& value = property(id); auto const& value = property(id);
if (value.is_calculated()) if (value.is_calculated())
@ -292,7 +292,7 @@ LengthBox ComputedProperties::length_box(PropertyID left_id, PropertyID top_id,
} }
if (value.has_auto()) if (value.has_auto())
return LengthPercentage { Length::make_auto() }; return LengthPercentageOrAuto::make_auto();
return default_value; return default_value;
}; };

View file

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

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org> * Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022, Ben Wiederhake <BenWiederhake.GitHub@gmx.de> * Copyright (c) 2022, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -10,18 +11,18 @@
namespace Web::CSS { namespace Web::CSS {
LengthBox::LengthBox() LengthBox::LengthBox()
: m_top(Length::make_auto()) : m_top(LengthPercentageOrAuto::make_auto())
, m_right(Length::make_auto()) , m_right(LengthPercentageOrAuto::make_auto())
, m_bottom(Length::make_auto()) , m_bottom(LengthPercentageOrAuto::make_auto())
, m_left(Length::make_auto()) , m_left(LengthPercentageOrAuto::make_auto())
{ {
} }
LengthBox::LengthBox(LengthPercentage top, LengthPercentage right, LengthPercentage bottom, LengthPercentage left) LengthBox::LengthBox(LengthPercentageOrAuto top, LengthPercentageOrAuto right, LengthPercentageOrAuto bottom, LengthPercentageOrAuto left)
: m_top(top) : m_top(move(top))
, m_right(right) , m_right(move(right))
, m_bottom(bottom) , m_bottom(move(bottom))
, m_left(left) , m_left(move(left))
{ {
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org> * Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -13,27 +14,25 @@ namespace Web::CSS {
class LengthBox { class LengthBox {
public: public:
LengthBox(); LengthBox();
LengthBox(LengthPercentage top, LengthPercentage right, LengthPercentage bottom, LengthPercentage left); LengthBox(LengthPercentageOrAuto top, LengthPercentageOrAuto right, LengthPercentageOrAuto bottom, LengthPercentageOrAuto left);
~LengthBox(); ~LengthBox();
// Length (and thus LengthPercentage) includes a RefPtr<CalculatedStyleValue const> member, but we can't include the header StyleValue.h as it includes LengthPercentageOrAuto& top() { return m_top; }
// this file already. To break the cyclic dependency, we must initialize these members in the constructor. LengthPercentageOrAuto& right() { return m_right; }
LengthPercentage& top() { return m_top; } LengthPercentageOrAuto& bottom() { return m_bottom; }
LengthPercentage& right() { return m_right; } LengthPercentageOrAuto& left() { return m_left; }
LengthPercentage& bottom() { return m_bottom; } LengthPercentageOrAuto const& top() const { return m_top; }
LengthPercentage& left() { return m_left; } LengthPercentageOrAuto const& right() const { return m_right; }
LengthPercentage const& top() const { return m_top; } LengthPercentageOrAuto const& bottom() const { return m_bottom; }
LengthPercentage const& right() const { return m_right; } LengthPercentageOrAuto const& left() const { return m_left; }
LengthPercentage const& bottom() const { return m_bottom; }
LengthPercentage const& left() const { return m_left; }
bool operator==(LengthBox const&) const = default; bool operator==(LengthBox const&) const = default;
private: private:
LengthPercentage m_top; LengthPercentageOrAuto m_top;
LengthPercentage m_right; LengthPercentageOrAuto m_right;
LengthPercentage m_bottom; LengthPercentageOrAuto m_bottom;
LengthPercentage m_left; LengthPercentageOrAuto m_left;
}; };
} }

View file

@ -3310,15 +3310,13 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
// FIXME: Parse the border-radius. // FIXME: Parse the border-radius.
auto arguments_tokens = TokenStream { component_value.function().value }; auto arguments_tokens = TokenStream { component_value.function().value };
auto parse_length_percentage_or_auto = [this](TokenStream<ComponentValue>& tokens) -> Optional<LengthPercentage> { auto parse_length_percentage_or_auto = [this](TokenStream<ComponentValue>& tokens) -> Optional<LengthPercentageOrAuto> {
tokens.discard_whitespace(); tokens.discard_whitespace();
auto value = parse_length_percentage(tokens); if (auto value = parse_length_percentage(tokens); value.has_value())
if (!value.has_value()) { return value.release_value();
if (tokens.consume_a_token().is_ident("auto"sv)) { if (tokens.consume_a_token().is_ident("auto"sv))
value = Length::make_auto(); return LengthPercentageOrAuto::make_auto();
} return {};
}
return value;
}; };
auto top = parse_length_percentage_or_auto(arguments_tokens); auto top = parse_length_percentage_or_auto(arguments_tokens);

View file

@ -29,10 +29,10 @@ Gfx::Path Inset::to_path(CSSPixelRect reference_box, Layout::Node const& node) c
// (such as left and right insets of 75% apiece) use the CSS Backgrounds 3 §4.5 Overlapping Curves rules // (such as left and right insets of 75% apiece) use the CSS Backgrounds 3 §4.5 Overlapping Curves rules
// to proportionally reduce the inset effect to 100%. // to proportionally reduce the inset effect to 100%.
auto top = inset_box.top().to_px(node, reference_box.height()).to_float(); auto top = inset_box.top().to_px_or_zero(node, reference_box.height()).to_float();
auto right = reference_box.width().to_float() - inset_box.right().to_px(node, reference_box.width()).to_float(); auto right = reference_box.width().to_float() - inset_box.right().to_px_or_zero(node, reference_box.width()).to_float();
auto bottom = reference_box.height().to_float() - inset_box.bottom().to_px(node, reference_box.height()).to_float(); auto bottom = reference_box.height().to_float() - inset_box.bottom().to_px_or_zero(node, reference_box.height()).to_float();
auto left = inset_box.left().to_px(node, reference_box.width()).to_float(); auto left = inset_box.left().to_px_or_zero(node, reference_box.width()).to_float();
return path_from_resolved_rect(top, right, bottom, left); return path_from_resolved_rect(top, right, bottom, left);
} }
@ -62,10 +62,10 @@ Gfx::Path Rect::to_path(CSSPixelRect reference_box, Layout::Node const& node) co
// An auto value makes the edge of the box coincide with the corresponding edge of the reference box: // An auto value makes the edge of the box coincide with the corresponding edge of the reference box:
// its equivalent to 0% as the first (top) or fourth (left) value, and equivalent to 100% as the second (right) or third (bottom) value. // its equivalent to 0% as the first (top) or fourth (left) value, and equivalent to 100% as the second (right) or third (bottom) value.
auto top = box.top().is_auto() ? 0 : box.top().to_px(node, reference_box.height()).to_float(); auto top = box.top().is_auto() ? 0 : box.top().to_px_or_zero(node, reference_box.height()).to_float();
auto right = box.right().is_auto() ? reference_box.width().to_float() : box.right().to_px(node, reference_box.width()).to_float(); auto right = box.right().is_auto() ? reference_box.width().to_float() : box.right().to_px_or_zero(node, reference_box.width()).to_float();
auto bottom = box.bottom().is_auto() ? reference_box.height().to_float() : box.bottom().to_px(node, reference_box.height()).to_float(); auto bottom = box.bottom().is_auto() ? reference_box.height().to_float() : box.bottom().to_px_or_zero(node, reference_box.height()).to_float();
auto left = box.left().is_auto() ? 0 : box.left().to_px(node, reference_box.width()).to_float(); auto left = box.left().is_auto() ? 0 : box.left().to_px_or_zero(node, reference_box.width()).to_float();
// The second (right) and third (bottom) values are floored by the fourth (left) and second (top) values, respectively. // The second (right) and third (bottom) values are floored by the fourth (left) and second (top) values, respectively.
return path_from_resolved_rect(top, max(right, left), max(bottom, top), left); return path_from_resolved_rect(top, max(right, left), max(bottom, top), left);

View file

@ -208,18 +208,18 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
auto const& computed_values = box.computed_values(); auto const& computed_values = box.computed_values();
auto available_width_px = available_space.width.to_px_or_zero(); auto available_width_px = available_space.width.to_px_or_zero();
auto margin_left = computed_values.margin().left().resolved(box, available_width_px); auto margin_left = computed_values.margin().left().resolved_or_auto(box, available_width_px);
auto margin_right = computed_values.margin().right().resolved(box, available_width_px); auto margin_right = computed_values.margin().right().resolved_or_auto(box, available_width_px);
auto const padding_left = computed_values.padding().left().resolved(box, available_width_px); auto const padding_left = computed_values.padding().left().resolved_or_auto(box, available_width_px);
auto const padding_right = computed_values.padding().right().resolved(box, available_width_px); auto const padding_right = computed_values.padding().right().resolved_or_auto(box, available_width_px);
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
box_state.margin_left = margin_left.to_px(box); box_state.margin_left = margin_left.to_px_or_zero(box);
box_state.margin_right = margin_right.to_px(box); box_state.margin_right = margin_right.to_px_or_zero(box);
box_state.border_left = computed_values.border_left().width; box_state.border_left = computed_values.border_left().width;
box_state.border_right = computed_values.border_right().width; box_state.border_right = computed_values.border_right().width;
box_state.padding_left = padding_left.to_px(box); box_state.padding_left = padding_left.to_px_or_zero(box);
box_state.padding_right = padding_right.to_px(box); box_state.padding_right = padding_right.to_px_or_zero(box);
// https://html.spec.whatwg.org/multipage/rendering.html#button-layout // https://html.spec.whatwg.org/multipage/rendering.html#button-layout
// If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size. // If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size.
@ -240,8 +240,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
auto try_compute_width = [&](CSS::LengthOrAuto const& a_width) { auto try_compute_width = [&](CSS::LengthOrAuto const& a_width) {
auto width = a_width; auto width = a_width;
margin_left = computed_values.margin().left().resolved(box, available_space.width.to_px_or_zero()); margin_left = computed_values.margin().left().resolved_or_auto(box, available_space.width.to_px_or_zero());
margin_right = computed_values.margin().right().resolved(box, available_space.width.to_px_or_zero()); margin_right = computed_values.margin().right().resolved_or_auto(box, available_space.width.to_px_or_zero());
CSSPixels total_px = computed_values.border_left().width + computed_values.border_right().width; CSSPixels total_px = computed_values.border_left().width + computed_values.border_right().width;
for (auto& value : { CSS::LengthOrAuto(margin_left), CSS::LengthOrAuto(padding_left), width, CSS::LengthOrAuto(padding_right), CSS::LengthOrAuto(margin_right) }) for (auto& value : { CSS::LengthOrAuto(margin_left), CSS::LengthOrAuto(padding_left), width, CSS::LengthOrAuto(padding_right), CSS::LengthOrAuto(margin_right) })
total_px += value.to_px_or_zero(box); total_px += value.to_px_or_zero(box);
@ -285,7 +285,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
} }
} else { } else {
if (!margin_left.is_auto() && !margin_right.is_auto()) { if (!margin_left.is_auto() && !margin_right.is_auto()) {
margin_right = CSS::Length::make_px(margin_right.to_px(box) + underflow_px); margin_right = CSS::Length::make_px(margin_right.to_px_or_zero(box) + underflow_px);
} else if (!margin_left.is_auto() && margin_right.is_auto()) { } else if (!margin_left.is_auto() && margin_right.is_auto()) {
margin_right = CSS::Length::make_px(underflow_px); margin_right = CSS::Length::make_px(underflow_px);
} else if (margin_left.is_auto() && !margin_right.is_auto()) { } else if (margin_left.is_auto() && !margin_right.is_auto()) {
@ -337,8 +337,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
if (!box_is_sized_as_replaced_element(box, available_space) && !used_width.is_auto()) if (!box_is_sized_as_replaced_element(box, available_space) && !used_width.is_auto())
box_state.set_content_width(used_width.to_px_or_zero(box)); box_state.set_content_width(used_width.to_px_or_zero(box));
box_state.margin_left = margin_left.to_px(box); box_state.margin_left = margin_left.to_px_or_zero(box);
box_state.margin_right = margin_right.to_px(box); box_state.margin_right = margin_right.to_px_or_zero(box);
} }
void BlockFormattingContext::avoid_float_intrusions(Box const& box, AvailableSpace const& available_space) void BlockFormattingContext::avoid_float_intrusions(Box const& box, AvailableSpace const& available_space)
@ -388,20 +388,15 @@ void BlockFormattingContext::compute_width_for_floating_box(Box const& box, Avai
auto zero_value = CSS::Length::make_px(0); auto zero_value = CSS::Length::make_px(0);
auto width_of_containing_block = available_space.width.to_px_or_zero(); auto width_of_containing_block = available_space.width.to_px_or_zero();
auto margin_left = computed_values.margin().left().resolved(box, width_of_containing_block);
auto margin_right = computed_values.margin().right().resolved(box, width_of_containing_block);
// If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'. // If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'.
if (margin_left.is_auto()) auto margin_left = computed_values.margin().left().to_px_or_zero(box, width_of_containing_block);
margin_left = zero_value; auto margin_right = computed_values.margin().right().to_px_or_zero(box, width_of_containing_block);
if (margin_right.is_auto())
margin_right = zero_value;
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
box_state.padding_left = computed_values.padding().left().resolved(box, width_of_containing_block).to_px(box); box_state.padding_left = computed_values.padding().left().to_px_or_zero(box, width_of_containing_block);
box_state.padding_right = computed_values.padding().right().resolved(box, width_of_containing_block).to_px(box); box_state.padding_right = computed_values.padding().right().to_px_or_zero(box, width_of_containing_block);
box_state.margin_left = margin_left.to_px(box); box_state.margin_left = margin_left;
box_state.margin_right = margin_right.to_px(box); box_state.margin_right = margin_right;
box_state.border_left = computed_values.border_left().width; box_state.border_left = computed_values.border_left().width;
box_state.border_right = computed_values.border_right().width; box_state.border_right = computed_values.border_right().width;
@ -415,8 +410,8 @@ void BlockFormattingContext::compute_width_for_floating_box(Box const& box, Avai
// block minus the used values of 'margin-left', 'border-left-width', 'padding-left', // block minus the used values of 'margin-left', 'border-left-width', 'padding-left',
// 'padding-right', 'border-right-width', 'margin-right', and the widths of any relevant scroll bars. // 'padding-right', 'border-right-width', 'margin-right', and the widths of any relevant scroll bars.
auto available_width = available_space.width.to_px_or_zero() auto available_width = available_space.width.to_px_or_zero()
- margin_left.to_px(box) - computed_values.border_left().width - box_state.padding_left - margin_left - computed_values.border_left().width - box_state.padding_left
- box_state.padding_right - computed_values.border_right().width - margin_right.to_px(box); - box_state.padding_right - computed_values.border_right().width - margin_right;
// Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width). // Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).
width = CSS::Length::make_px(min(max(result.preferred_minimum_width, available_width), result.preferred_width)); width = CSS::Length::make_px(min(max(result.preferred_minimum_width, available_width), result.preferred_width));
} else if (available_space.width.is_indefinite() || available_space.width.is_max_content()) { } else if (available_space.width.is_indefinite() || available_space.width.is_max_content()) {
@ -464,27 +459,21 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n
// 10.3.6 Floating, replaced elements // 10.3.6 Floating, replaced elements
auto& computed_values = box.computed_values(); auto& computed_values = box.computed_values();
auto zero_value = CSS::Length::make_px(0);
auto width_of_containing_block = available_space.width.to_px_or_zero(); auto width_of_containing_block = available_space.width.to_px_or_zero();
// 10.3.4 Block-level, replaced elements in normal flow // 10.3.4 Block-level, replaced elements in normal flow
// The used value of 'width' is determined as for inline replaced elements. Then the rules for // The used value of 'width' is determined as for inline replaced elements. Then the rules for
// non-replaced block-level elements are applied to determine the margins. // non-replaced block-level elements are applied to determine the margins.
auto margin_left = computed_values.margin().left().resolved(box, width_of_containing_block);
auto margin_right = computed_values.margin().right().resolved(box, width_of_containing_block);
auto const padding_left = computed_values.padding().left().resolved(box, width_of_containing_block).to_px(box);
auto const padding_right = computed_values.padding().right().resolved(box, width_of_containing_block).to_px(box);
// If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'. // If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'.
if (margin_left.is_auto()) auto margin_left = computed_values.margin().left().to_px_or_zero(box, width_of_containing_block);
margin_left = zero_value; auto margin_right = computed_values.margin().right().to_px_or_zero(box, width_of_containing_block);
if (margin_right.is_auto()) auto const padding_left = computed_values.padding().left().to_px_or_zero(box, width_of_containing_block);
margin_right = zero_value; auto const padding_right = computed_values.padding().right().to_px_or_zero(box, width_of_containing_block);
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
auto width = compute_width_for_replaced_element(box, available_space); auto width = compute_width_for_replaced_element(box, available_space);
box_state.margin_left = margin_left.to_px(box); box_state.margin_left = margin_left;
box_state.margin_right = margin_right.to_px(box); box_state.margin_right = margin_right;
box_state.border_left = computed_values.border_left().width; box_state.border_left = computed_values.border_left().width;
box_state.border_right = computed_values.border_right().width; box_state.border_right = computed_values.border_right().width;
box_state.padding_left = padding_left; box_state.padding_left = padding_left;
@ -936,12 +925,12 @@ void BlockFormattingContext::resolve_vertical_box_model_metrics(Box const& box,
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
auto const& computed_values = box.computed_values(); auto const& computed_values = box.computed_values();
box_state.margin_top = computed_values.margin().top().to_px(box, width_of_containing_block); box_state.margin_top = computed_values.margin().top().to_px_or_zero(box, width_of_containing_block);
box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block); box_state.margin_bottom = computed_values.margin().bottom().to_px_or_zero(box, width_of_containing_block);
box_state.border_top = computed_values.border_top().width; box_state.border_top = computed_values.border_top().width;
box_state.border_bottom = computed_values.border_bottom().width; box_state.border_bottom = computed_values.border_bottom().width;
box_state.padding_top = computed_values.padding().top().to_px(box, width_of_containing_block); box_state.padding_top = computed_values.padding().top().to_px_or_zero(box, width_of_containing_block);
box_state.padding_bottom = computed_values.padding().bottom().to_px(box, width_of_containing_block); box_state.padding_bottom = computed_values.padding().bottom().to_px_or_zero(box, width_of_containing_block);
} }
CSSPixels BlockFormattingContext::BlockMarginState::current_collapsed_margin() const CSSPixels BlockFormattingContext::BlockMarginState::current_collapsed_margin() const

View file

@ -243,10 +243,10 @@ void FlexFormattingContext::populate_specified_margins(FlexItem& item, CSS::Flex
{ {
auto width_of_containing_block = m_flex_container_state.content_width(); auto width_of_containing_block = m_flex_container_state.content_width();
item.used_values.padding_left = item.box->computed_values().padding().left().to_px(item.box, width_of_containing_block); item.used_values.padding_left = item.box->computed_values().padding().left().to_px_or_zero(item.box, width_of_containing_block);
item.used_values.padding_right = item.box->computed_values().padding().right().to_px(item.box, width_of_containing_block); item.used_values.padding_right = item.box->computed_values().padding().right().to_px_or_zero(item.box, width_of_containing_block);
item.used_values.padding_top = item.box->computed_values().padding().top().to_px(item.box, width_of_containing_block); item.used_values.padding_top = item.box->computed_values().padding().top().to_px_or_zero(item.box, width_of_containing_block);
item.used_values.padding_bottom = item.box->computed_values().padding().bottom().to_px(item.box, width_of_containing_block); item.used_values.padding_bottom = item.box->computed_values().padding().bottom().to_px_or_zero(item.box, width_of_containing_block);
// FIXME: This should also take reverse-ness into account // FIXME: This should also take reverse-ness into account
if (flex_direction == CSS::FlexDirection::Row || flex_direction == CSS::FlexDirection::RowReverse) { if (flex_direction == CSS::FlexDirection::Row || flex_direction == CSS::FlexDirection::RowReverse) {
@ -255,15 +255,15 @@ void FlexFormattingContext::populate_specified_margins(FlexItem& item, CSS::Flex
item.borders.cross_before = item.box->computed_values().border_top().width; item.borders.cross_before = item.box->computed_values().border_top().width;
item.borders.cross_after = item.box->computed_values().border_bottom().width; item.borders.cross_after = item.box->computed_values().border_bottom().width;
item.padding.main_before = item.box->computed_values().padding().left().to_px(item.box, width_of_containing_block); item.padding.main_before = item.box->computed_values().padding().left().to_px_or_zero(item.box, width_of_containing_block);
item.padding.main_after = item.box->computed_values().padding().right().to_px(item.box, width_of_containing_block); item.padding.main_after = item.box->computed_values().padding().right().to_px_or_zero(item.box, width_of_containing_block);
item.padding.cross_before = item.box->computed_values().padding().top().to_px(item.box, width_of_containing_block); item.padding.cross_before = item.box->computed_values().padding().top().to_px_or_zero(item.box, width_of_containing_block);
item.padding.cross_after = item.box->computed_values().padding().bottom().to_px(item.box, width_of_containing_block); item.padding.cross_after = item.box->computed_values().padding().bottom().to_px_or_zero(item.box, width_of_containing_block);
item.margins.main_before = item.box->computed_values().margin().left().to_px(item.box, width_of_containing_block); item.margins.main_before = item.box->computed_values().margin().left().to_px_or_zero(item.box, width_of_containing_block);
item.margins.main_after = item.box->computed_values().margin().right().to_px(item.box, width_of_containing_block); item.margins.main_after = item.box->computed_values().margin().right().to_px_or_zero(item.box, width_of_containing_block);
item.margins.cross_before = item.box->computed_values().margin().top().to_px(item.box, width_of_containing_block); item.margins.cross_before = item.box->computed_values().margin().top().to_px_or_zero(item.box, width_of_containing_block);
item.margins.cross_after = item.box->computed_values().margin().bottom().to_px(item.box, width_of_containing_block); item.margins.cross_after = item.box->computed_values().margin().bottom().to_px_or_zero(item.box, width_of_containing_block);
item.margins.main_before_is_auto = item.box->computed_values().margin().left().is_auto(); item.margins.main_before_is_auto = item.box->computed_values().margin().left().is_auto();
item.margins.main_after_is_auto = item.box->computed_values().margin().right().is_auto(); item.margins.main_after_is_auto = item.box->computed_values().margin().right().is_auto();
@ -280,10 +280,10 @@ void FlexFormattingContext::populate_specified_margins(FlexItem& item, CSS::Flex
item.padding.cross_before = item.used_values.padding_left; item.padding.cross_before = item.used_values.padding_left;
item.padding.cross_after = item.used_values.padding_right; item.padding.cross_after = item.used_values.padding_right;
item.margins.main_before = item.box->computed_values().margin().top().to_px(item.box, width_of_containing_block); item.margins.main_before = item.box->computed_values().margin().top().to_px_or_zero(item.box, width_of_containing_block);
item.margins.main_after = item.box->computed_values().margin().bottom().to_px(item.box, width_of_containing_block); item.margins.main_after = item.box->computed_values().margin().bottom().to_px_or_zero(item.box, width_of_containing_block);
item.margins.cross_before = item.box->computed_values().margin().left().to_px(item.box, width_of_containing_block); item.margins.cross_before = item.box->computed_values().margin().left().to_px_or_zero(item.box, width_of_containing_block);
item.margins.cross_after = item.box->computed_values().margin().right().to_px(item.box, width_of_containing_block); item.margins.cross_after = item.box->computed_values().margin().right().to_px_or_zero(item.box, width_of_containing_block);
item.margins.main_before_is_auto = item.box->computed_values().margin().top().is_auto(); item.margins.main_before_is_auto = item.box->computed_values().margin().top().is_auto();
item.margins.main_after_is_auto = item.box->computed_values().margin().bottom().is_auto(); item.margins.main_after_is_auto = item.box->computed_values().margin().bottom().is_auto();
@ -1693,10 +1693,10 @@ void FlexFormattingContext::copy_dimensions_from_flex_items_to_boxes()
for (auto& item : m_flex_items) { for (auto& item : m_flex_items) {
auto const& box = item.box; auto const& box = item.box;
item.used_values.margin_left = box->computed_values().margin().left().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_left = box->computed_values().margin().left().to_px_or_zero(box, m_flex_container_state.content_width());
item.used_values.margin_right = box->computed_values().margin().right().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_right = box->computed_values().margin().right().to_px_or_zero(box, m_flex_container_state.content_width());
item.used_values.margin_top = box->computed_values().margin().top().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_top = box->computed_values().margin().top().to_px_or_zero(box, m_flex_container_state.content_width());
item.used_values.margin_bottom = box->computed_values().margin().bottom().to_px(box, m_flex_container_state.content_width()); item.used_values.margin_bottom = box->computed_values().margin().bottom().to_px_or_zero(box, m_flex_container_state.content_width());
item.used_values.border_left = box->computed_values().border_left().width; item.used_values.border_left = box->computed_values().border_left().width;
item.used_values.border_right = box->computed_values().border_right().width; item.used_values.border_right = box->computed_values().border_right().width;

View file

@ -416,17 +416,12 @@ CSSPixels FormattingContext::compute_table_box_width_inside_table_wrapper(Box co
auto zero_value = CSS::Length::make_px(0); auto zero_value = CSS::Length::make_px(0);
auto margin_left = computed_values.margin().left().resolved(box, width_of_containing_block);
auto margin_right = computed_values.margin().right().resolved(box, width_of_containing_block);
// If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'. // If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'.
if (margin_left.is_auto()) auto margin_left = computed_values.margin().left().to_px_or_zero(box, width_of_containing_block);
margin_left = zero_value; auto margin_right = computed_values.margin().right().to_px_or_zero(box, width_of_containing_block);
if (margin_right.is_auto())
margin_right = zero_value;
// table-wrapper can't have borders or paddings but it might have margin taken from table-root. // table-wrapper can't have borders or paddings but it might have margin taken from table-root.
auto available_width = width_of_containing_block - margin_left.to_px(box) - margin_right.to_px(box); auto available_width = width_of_containing_block - margin_left - margin_right;
Optional<Box const&> table_box; Optional<Box const&> table_box;
box.for_each_in_subtree_of_type<Box>([&](Box const& child_box) { box.for_each_in_subtree_of_type<Box>([&](Box const& child_box) {
@ -463,19 +458,12 @@ CSSPixels FormattingContext::compute_table_box_height_inside_table_wrapper(Box c
auto width_of_containing_block = available_space.width.to_px_or_zero(); auto width_of_containing_block = available_space.width.to_px_or_zero();
auto height_of_containing_block = available_space.height.to_px_or_zero(); auto height_of_containing_block = available_space.height.to_px_or_zero();
auto zero_value = CSS::Length::make_px(0); // If 'margin-top', or 'margin-bottom' are computed as 'auto', their used value is '0'.
auto margin_top = computed_values.margin().top().resolved_or_auto(box, width_of_containing_block).to_px_or_zero(box);
auto margin_top = computed_values.margin().top().resolved(box, width_of_containing_block); auto margin_bottom = computed_values.margin().bottom().resolved_or_auto(box, width_of_containing_block).to_px_or_zero(box);
auto margin_bottom = computed_values.margin().bottom().resolved(box, width_of_containing_block);
// If 'margin-top', or 'margin-top' are computed as 'auto', their used value is '0'.
if (margin_top.is_auto())
margin_top = zero_value;
if (margin_bottom.is_auto())
margin_bottom = zero_value;
// table-wrapper can't have borders or paddings but it might have margin taken from table-root. // table-wrapper can't have borders or paddings but it might have margin taken from table-root.
auto available_height = height_of_containing_block - margin_top.to_px(box) - margin_bottom.to_px(box); auto available_height = height_of_containing_block - margin_top - margin_bottom;
LayoutState throwaway_state; LayoutState throwaway_state;
@ -699,12 +687,12 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
auto computed_left = computed_values.inset().left(); auto computed_left = computed_values.inset().left();
auto computed_right = computed_values.inset().right(); auto computed_right = computed_values.inset().right();
auto left = computed_values.inset().left().to_px(box, width_of_containing_block); auto left = computed_values.inset().left().to_px_or_zero(box, width_of_containing_block);
auto right = computed_values.inset().right().to_px(box, width_of_containing_block); auto right = computed_values.inset().right().to_px_or_zero(box, width_of_containing_block);
auto try_compute_width = [&](CSS::LengthOrAuto const& a_width) { auto try_compute_width = [&](CSS::LengthOrAuto const& a_width) {
margin_left = computed_values.margin().left().resolved(box, width_of_containing_block); margin_left = computed_values.margin().left().resolved_or_auto(box, width_of_containing_block);
margin_right = computed_values.margin().right().resolved(box, width_of_containing_block); margin_right = computed_values.margin().right().resolved_or_auto(box, width_of_containing_block);
auto width = a_width; auto width = a_width;
@ -886,8 +874,8 @@ void FormattingContext::compute_width_for_absolutely_positioned_replaced_element
auto margin_right = computed_values.margin().right(); auto margin_right = computed_values.margin().right();
auto static_position = m_state.get(box).static_position(); auto static_position = m_state.get(box).static_position();
auto to_px = [&](CSS::LengthPercentage const& l) { auto to_px = [&](CSS::LengthPercentageOrAuto const& l) {
return l.to_px(box, width_of_containing_block); return l.to_px_or_zero(box, width_of_containing_block);
}; };
// If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below. // If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below.
@ -993,15 +981,15 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
auto try_compute_height = [&](CSS::LengthOrAuto height) -> CSS::LengthOrAuto { auto try_compute_height = [&](CSS::LengthOrAuto height) -> CSS::LengthOrAuto {
auto solve_for = [&](CSS::LengthOrAuto const& length_or_auto, ClampToZero clamp_to_zero = ClampToZero::No) { auto solve_for = [&](CSS::LengthOrAuto const& length_or_auto, ClampToZero clamp_to_zero = ClampToZero::No) {
auto unclamped_value = height_of_containing_block auto unclamped_value = height_of_containing_block
- top.to_px(box, height_of_containing_block) - top.to_px_or_zero(box, height_of_containing_block)
- margin_top.to_px(box, width_of_containing_block) - margin_top.to_px_or_zero(box, width_of_containing_block)
- box.computed_values().border_top().width - box.computed_values().border_top().width
- state.padding_top - state.padding_top
- apply_min_max_height_constraints(height).to_px_or_zero(box) - apply_min_max_height_constraints(height).to_px_or_zero(box)
- state.padding_bottom - state.padding_bottom
- box.computed_values().border_bottom().width - box.computed_values().border_bottom().width
- margin_bottom.to_px(box, width_of_containing_block) - margin_bottom.to_px_or_zero(box, width_of_containing_block)
- bottom.to_px(box, height_of_containing_block) - bottom.to_px_or_zero(box, height_of_containing_block)
+ length_or_auto.to_px_or_zero(box); + length_or_auto.to_px_or_zero(box);
if (clamp_to_zero == ClampToZero::Yes) if (clamp_to_zero == ClampToZero::Yes)
return CSS::Length::make_px(max(CSSPixels(0), unclamped_value)); return CSS::Length::make_px(max(CSSPixels(0), unclamped_value));
@ -1009,11 +997,11 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
}; };
auto solve_for_top = [&] { auto solve_for_top = [&] {
top = solve_for(top.resolved(box, height_of_containing_block)); top = solve_for(top.resolved_or_auto(box, height_of_containing_block));
}; };
auto solve_for_bottom = [&] { auto solve_for_bottom = [&] {
bottom = solve_for(bottom.resolved(box, height_of_containing_block)); bottom = solve_for(bottom.resolved_or_auto(box, height_of_containing_block));
}; };
auto solve_for_height = [&] { auto solve_for_height = [&] {
@ -1021,15 +1009,15 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
}; };
auto solve_for_margin_top = [&] { auto solve_for_margin_top = [&] {
margin_top = solve_for(margin_top.resolved(box, width_of_containing_block)); margin_top = solve_for(margin_top.resolved_or_auto(box, width_of_containing_block));
}; };
auto solve_for_margin_bottom = [&] { auto solve_for_margin_bottom = [&] {
margin_bottom = solve_for(margin_bottom.resolved(box, width_of_containing_block)); margin_bottom = solve_for(margin_bottom.resolved_or_auto(box, width_of_containing_block));
}; };
auto solve_for_margin_top_and_margin_bottom = [&] { auto solve_for_margin_top_and_margin_bottom = [&] {
auto remainder = solve_for(CSS::Length::make_px(margin_top.to_px(box, width_of_containing_block) + margin_bottom.to_px(box, width_of_containing_block))).to_px(box); auto remainder = solve_for(CSS::Length::make_px(margin_top.to_px_or_zero(box, width_of_containing_block) + margin_bottom.to_px_or_zero(box, width_of_containing_block))).to_px(box);
margin_top = CSS::Length::make_px(remainder / 2); margin_top = CSS::Length::make_px(remainder / 2);
margin_bottom = CSS::Length::make_px(remainder / 2); margin_bottom = CSS::Length::make_px(remainder / 2);
}; };
@ -1173,10 +1161,10 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
if (box.computed_values().height().is_auto() && before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before) if (box.computed_values().height().is_auto() && before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return; return;
box_state.set_has_definite_height(true); box_state.set_has_definite_height(true);
box_state.inset_top = top.to_px(box, height_of_containing_block); box_state.inset_top = top.to_px_or_zero(box, height_of_containing_block);
box_state.inset_bottom = bottom.to_px(box, height_of_containing_block); box_state.inset_bottom = bottom.to_px_or_zero(box, height_of_containing_block);
box_state.margin_top = margin_top.to_px(box, width_of_containing_block); box_state.margin_top = margin_top.to_px_or_zero(box, width_of_containing_block);
box_state.margin_bottom = margin_bottom.to_px(box, width_of_containing_block); box_state.margin_bottom = margin_bottom.to_px_or_zero(box, width_of_containing_block);
} }
CSSPixelRect FormattingContext::content_box_rect_in_static_position_ancestor_coordinate_space(Box const& box, Box const& ancestor_box) const CSSPixelRect FormattingContext::content_box_rect_in_static_position_ancestor_coordinate_space(Box const& box, Box const& ancestor_box) const
@ -1217,10 +1205,10 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
box_state.border_bottom = box.computed_values().border_bottom().width; box_state.border_bottom = box.computed_values().border_bottom().width;
auto const containing_block_width = available_space.width.to_px_or_zero(); auto const containing_block_width = available_space.width.to_px_or_zero();
box_state.padding_left = box.computed_values().padding().left().to_px(box, containing_block_width); box_state.padding_left = box.computed_values().padding().left().to_px_or_zero(box, containing_block_width);
box_state.padding_right = box.computed_values().padding().right().to_px(box, containing_block_width); box_state.padding_right = box.computed_values().padding().right().to_px_or_zero(box, containing_block_width);
box_state.padding_top = box.computed_values().padding().top().to_px(box, containing_block_width); box_state.padding_top = box.computed_values().padding().top().to_px_or_zero(box, containing_block_width);
box_state.padding_bottom = box.computed_values().padding().bottom().to_px(box, containing_block_width); box_state.padding_bottom = box.computed_values().padding().bottom().to_px_or_zero(box, containing_block_width);
compute_width_for_absolutely_positioned_element(box, available_space); compute_width_for_absolutely_positioned_element(box, available_space);
@ -1305,8 +1293,8 @@ void FormattingContext::compute_height_for_absolutely_positioned_replaced_elemen
auto margin_bottom = computed_values.margin().bottom(); auto margin_bottom = computed_values.margin().bottom();
auto static_position = m_state.get(box).static_position(); auto static_position = m_state.get(box).static_position();
auto to_px = [&](CSS::LengthPercentage const& l) { auto to_px = [&](CSS::LengthPercentageOrAuto const& l) {
return l.to_px(box, height_of_containing_block); return l.to_px_or_zero(box, height_of_containing_block);
}; };
// If 'margin-top' or 'margin-bottom' is specified as 'auto' its used value is determined by the rules below. // If 'margin-top' or 'margin-bottom' is specified as 'auto' its used value is determined by the rules below.
@ -1366,9 +1354,9 @@ void FormattingContext::compute_inset(NodeWithStyleAndBoxModelMetrics const& box
if (box.computed_values().position() != CSS::Positioning::Relative) if (box.computed_values().position() != CSS::Positioning::Relative)
return; return;
auto resolve_two_opposing_insets = [&](CSS::LengthPercentage const& computed_first, CSS::LengthPercentage const& computed_second, CSSPixels& used_start, CSSPixels& used_end, CSSPixels reference_for_percentage) { auto resolve_two_opposing_insets = [&](CSS::LengthPercentageOrAuto const& computed_first, CSS::LengthPercentageOrAuto const& computed_second, CSSPixels& used_start, CSSPixels& used_end, CSSPixels reference_for_percentage) {
auto resolved_first = computed_first.to_px(box, reference_for_percentage); auto resolved_first = computed_first.to_px_or_zero(box, reference_for_percentage);
auto resolved_second = computed_second.to_px(box, reference_for_percentage); auto resolved_second = computed_second.to_px_or_zero(box, reference_for_percentage);
if (computed_first.is_auto() && computed_second.is_auto()) { if (computed_first.is_auto() && computed_second.is_auto()) {
// If opposing inset properties in an axis both compute to auto (their initial values), // If opposing inset properties in an axis both compute to auto (their initial values),

View file

@ -1819,20 +1819,20 @@ void GridFormattingContext::resolve_items_box_metrics(GridDimension dimension)
CSSPixels containing_block_width = containing_block_size_for_item(item, GridDimension::Column); CSSPixels containing_block_width = containing_block_size_for_item(item, GridDimension::Column);
if (dimension == GridDimension::Column) { if (dimension == GridDimension::Column) {
item.used_values.padding_right = computed_values.padding().right().to_px(grid_container(), containing_block_width); item.used_values.padding_right = computed_values.padding().right().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.padding_left = computed_values.padding().left().to_px(grid_container(), containing_block_width); item.used_values.padding_left = computed_values.padding().left().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.margin_right = computed_values.margin().right().to_px(grid_container(), containing_block_width); item.used_values.margin_right = computed_values.margin().right().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.margin_left = computed_values.margin().left().to_px(grid_container(), containing_block_width); item.used_values.margin_left = computed_values.margin().left().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.border_right = computed_values.border_right().width; item.used_values.border_right = computed_values.border_right().width;
item.used_values.border_left = computed_values.border_left().width; item.used_values.border_left = computed_values.border_left().width;
} else { } else {
item.used_values.padding_top = computed_values.padding().top().to_px(grid_container(), containing_block_width); item.used_values.padding_top = computed_values.padding().top().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.padding_bottom = computed_values.padding().bottom().to_px(grid_container(), containing_block_width); item.used_values.padding_bottom = computed_values.padding().bottom().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.margin_top = computed_values.margin().top().to_px(grid_container(), containing_block_width); item.used_values.margin_top = computed_values.margin().top().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.margin_bottom = computed_values.margin().bottom().to_px(grid_container(), containing_block_width); item.used_values.margin_bottom = computed_values.margin().bottom().to_px_or_zero(grid_container(), containing_block_width);
item.used_values.border_top = computed_values.border_top().width; item.used_values.border_top = computed_values.border_top().width;
item.used_values.border_bottom = computed_values.border_bottom().width; item.used_values.border_bottom = computed_values.border_bottom().width;
@ -2179,10 +2179,10 @@ void GridFormattingContext::layout_absolutely_positioned_element(Box const& box)
box_state.border_right = box.computed_values().border_right().width; box_state.border_right = box.computed_values().border_right().width;
box_state.border_top = box.computed_values().border_top().width; box_state.border_top = box.computed_values().border_top().width;
box_state.border_bottom = box.computed_values().border_bottom().width; box_state.border_bottom = box.computed_values().border_bottom().width;
box_state.padding_left = box.computed_values().padding().left().to_px(grid_container(), grid_area_rect.width()); box_state.padding_left = box.computed_values().padding().left().to_px_or_zero(grid_container(), grid_area_rect.width());
box_state.padding_right = box.computed_values().padding().right().to_px(grid_container(), grid_area_rect.width()); box_state.padding_right = box.computed_values().padding().right().to_px_or_zero(grid_container(), grid_area_rect.width());
box_state.padding_top = box.computed_values().padding().top().to_px(grid_container(), grid_area_rect.width()); box_state.padding_top = box.computed_values().padding().top().to_px_or_zero(grid_container(), grid_area_rect.width());
box_state.padding_bottom = box.computed_values().padding().bottom().to_px(grid_container(), grid_area_rect.width()); box_state.padding_bottom = box.computed_values().padding().bottom().to_px_or_zero(grid_container(), grid_area_rect.width());
compute_width_for_absolutely_positioned_element(box, available_space); compute_width_for_absolutely_positioned_element(box, available_space);

View file

@ -94,12 +94,12 @@ struct GridItem {
return dimension == GridDimension::Column ? computed_values().width() : computed_values().height(); return dimension == GridDimension::Column ? computed_values().width() : computed_values().height();
} }
CSS::LengthPercentage const& margin_start(GridDimension dimension) const CSS::LengthPercentageOrAuto const& margin_start(GridDimension dimension) const
{ {
return dimension == GridDimension::Column ? computed_values().margin().left() : computed_values().margin().top(); return dimension == GridDimension::Column ? computed_values().margin().left() : computed_values().margin().top();
} }
CSS::LengthPercentage const& margin_end(GridDimension dimension) const CSS::LengthPercentageOrAuto const& margin_end(GridDimension dimension) const
{ {
return dimension == GridDimension::Column ? computed_values().margin().right() : computed_values().margin().bottom(); return dimension == GridDimension::Column ? computed_values().margin().right() : computed_values().margin().bottom();
} }

View file

@ -103,21 +103,21 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
auto const& computed_values = box.computed_values(); auto const& computed_values = box.computed_values();
box_state.margin_left = computed_values.margin().left().to_px(box, width_of_containing_block); box_state.margin_left = computed_values.margin().left().to_px_or_zero(box, width_of_containing_block);
box_state.border_left = computed_values.border_left().width; box_state.border_left = computed_values.border_left().width;
box_state.padding_left = computed_values.padding().left().to_px(box, width_of_containing_block); box_state.padding_left = computed_values.padding().left().to_px_or_zero(box, width_of_containing_block);
box_state.margin_right = computed_values.margin().right().to_px(box, width_of_containing_block); box_state.margin_right = computed_values.margin().right().to_px_or_zero(box, width_of_containing_block);
box_state.border_right = computed_values.border_right().width; box_state.border_right = computed_values.border_right().width;
box_state.padding_right = computed_values.padding().right().to_px(box, width_of_containing_block); box_state.padding_right = computed_values.padding().right().to_px_or_zero(box, width_of_containing_block);
box_state.margin_top = computed_values.margin().top().to_px(box, width_of_containing_block); box_state.margin_top = computed_values.margin().top().to_px_or_zero(box, width_of_containing_block);
box_state.border_top = computed_values.border_top().width; box_state.border_top = computed_values.border_top().width;
box_state.padding_top = computed_values.padding().top().to_px(box, width_of_containing_block); box_state.padding_top = computed_values.padding().top().to_px_or_zero(box, width_of_containing_block);
box_state.padding_bottom = computed_values.padding().bottom().to_px(box, width_of_containing_block); box_state.padding_bottom = computed_values.padding().bottom().to_px_or_zero(box, width_of_containing_block);
box_state.border_bottom = computed_values.border_bottom().width; box_state.border_bottom = computed_values.border_bottom().width;
box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block); box_state.margin_bottom = computed_values.margin().bottom().to_px_or_zero(box, width_of_containing_block);
if (box_is_sized_as_replaced_element(box, *m_available_space)) { if (box_is_sized_as_replaced_element(box, *m_available_space)) {
box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space)); box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space));

View file

@ -35,21 +35,21 @@ void InlineLevelIterator::enter_node_with_box_model_metrics(Layout::NodeWithStyl
auto& used_values = m_layout_state.get_mutable(node); auto& used_values = m_layout_state.get_mutable(node);
auto const& computed_values = node.computed_values(); auto const& computed_values = node.computed_values();
used_values.margin_top = computed_values.margin().top().to_px(node, m_containing_block_used_values.content_width()); used_values.margin_top = computed_values.margin().top().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.margin_bottom = computed_values.margin().bottom().to_px(node, m_containing_block_used_values.content_width()); used_values.margin_bottom = computed_values.margin().bottom().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.margin_left = computed_values.margin().left().to_px(node, m_containing_block_used_values.content_width()); used_values.margin_left = computed_values.margin().left().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.border_left = computed_values.border_left().width; used_values.border_left = computed_values.border_left().width;
used_values.padding_left = computed_values.padding().left().to_px(node, m_containing_block_used_values.content_width()); used_values.padding_left = computed_values.padding().left().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.margin_right = computed_values.margin().right().to_px(node, m_containing_block_used_values.content_width()); used_values.margin_right = computed_values.margin().right().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.border_right = computed_values.border_right().width; used_values.border_right = computed_values.border_right().width;
used_values.padding_right = computed_values.padding().right().to_px(node, m_containing_block_used_values.content_width()); used_values.padding_right = computed_values.padding().right().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.border_top = computed_values.border_top().width; used_values.border_top = computed_values.border_top().width;
used_values.border_bottom = computed_values.border_bottom().width; used_values.border_bottom = computed_values.border_bottom().width;
used_values.padding_bottom = computed_values.padding().bottom().to_px(node, m_containing_block_used_values.content_width()); used_values.padding_bottom = computed_values.padding().bottom().to_px_or_zero(node, m_containing_block_used_values.content_width());
used_values.padding_top = computed_values.padding().top().to_px(node, m_containing_block_used_values.content_width()); used_values.padding_top = computed_values.padding().top().to_px_or_zero(node, m_containing_block_used_values.content_width());
m_extra_leading_metrics->margin += used_values.margin_left; m_extra_leading_metrics->margin += used_values.margin_left;
m_extra_leading_metrics->border += used_values.border_left; m_extra_leading_metrics->border += used_values.border_left;

View file

@ -458,14 +458,13 @@ void LayoutState::commit(Box& root)
scrollport_size = nearest_scrollable_ancestor->absolute_rect().size(); scrollport_size = nearest_scrollable_ancestor->absolute_rect().size();
if (!inset.top().is_auto()) if (!inset.top().is_auto())
sticky_insets->top = inset.top().to_px(node, scrollport_size.height()); sticky_insets->top = inset.top().to_px_or_zero(node, scrollport_size.height());
if (!inset.right().is_auto()) if (!inset.right().is_auto())
sticky_insets->right = inset.right().to_px(node, scrollport_size.width()); sticky_insets->right = inset.right().to_px_or_zero(node, scrollport_size.width());
if (!inset.bottom().is_auto()) if (!inset.bottom().is_auto())
sticky_insets->bottom = inset.bottom().to_px(node, scrollport_size.height()); sticky_insets->bottom = inset.bottom().to_px_or_zero(node, scrollport_size.height());
if (!inset.left().is_auto()) if (!inset.left().is_auto())
sticky_insets->left = inset.left().to_px(node, scrollport_size.width()); sticky_insets->left = inset.left().to_px_or_zero(node, scrollport_size.width());
paintable_box->set_sticky_insets(move(sticky_insets)); paintable_box->set_sticky_insets(move(sticky_insets));
} }
} }
@ -498,14 +497,14 @@ void LayoutState::UsedValues::set_node(NodeWithStyle const& node, UsedValues con
if (width) { if (width) {
border_and_padding = computed_values.border_left().width border_and_padding = computed_values.border_left().width
+ computed_values.padding().left().to_px(*m_node, containing_block_used_values->content_width()) + computed_values.padding().left().to_px_or_zero(*m_node, containing_block_used_values->content_width())
+ computed_values.border_right().width + computed_values.border_right().width
+ computed_values.padding().right().to_px(*m_node, containing_block_used_values->content_width()); + computed_values.padding().right().to_px_or_zero(*m_node, containing_block_used_values->content_width());
} else { } else {
border_and_padding = computed_values.border_top().width border_and_padding = computed_values.border_top().width
+ computed_values.padding().top().to_px(*m_node, containing_block_used_values->content_width()) + computed_values.padding().top().to_px_or_zero(*m_node, containing_block_used_values->content_width())
+ computed_values.border_bottom().width + computed_values.border_bottom().width
+ computed_values.padding().bottom().to_px(*m_node, containing_block_used_values->content_width()); + computed_values.padding().bottom().to_px_or_zero(*m_node, containing_block_used_values->content_width());
} }
return unadjusted_pixels - border_and_padding; return unadjusted_pixels - border_and_padding;

View file

@ -672,7 +672,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_min_height(computed_style.size_value(CSS::PropertyID::MinHeight)); 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_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, *this, CSS::ComputedProperties::ClampNegativeLengths::No, CSS::Length::make_auto())); 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::LengthPercentageOrAuto::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_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_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)));

View file

@ -108,10 +108,10 @@ void TableFormattingContext::compute_cell_measures()
for (auto& cell : m_cells) { for (auto& cell : m_cells) {
auto const& computed_values = cell.box->computed_values(); auto const& computed_values = cell.box->computed_values();
CSSPixels padding_top = computed_values.padding().top().to_px(cell.box, containing_block.content_height()); CSSPixels padding_top = computed_values.padding().top().to_px_or_zero(cell.box, containing_block.content_height());
CSSPixels padding_bottom = computed_values.padding().bottom().to_px(cell.box, containing_block.content_height()); CSSPixels padding_bottom = computed_values.padding().bottom().to_px_or_zero(cell.box, containing_block.content_height());
CSSPixels padding_left = computed_values.padding().left().to_px(cell.box, containing_block.content_width()); CSSPixels padding_left = computed_values.padding().left().to_px_or_zero(cell.box, containing_block.content_width());
CSSPixels padding_right = computed_values.padding().right().to_px(cell.box, containing_block.content_width()); CSSPixels padding_right = computed_values.padding().right().to_px_or_zero(cell.box, containing_block.content_width());
auto const& cell_state = m_state.get(cell.box); auto const& cell_state = m_state.get(cell.box);
auto use_collapsing_borders_model = cell_state.override_borders_data().has_value(); auto use_collapsing_borders_model = cell_state.override_borders_data().has_value();
@ -861,10 +861,10 @@ void TableFormattingContext::compute_table_height()
auto width_of_containing_block = cell_state.containing_block_used_values()->content_width(); auto width_of_containing_block = cell_state.containing_block_used_values()->content_width();
auto height_of_containing_block = cell_state.containing_block_used_values()->content_height(); auto height_of_containing_block = cell_state.containing_block_used_values()->content_height();
cell_state.padding_top = cell.box->computed_values().padding().top().to_px(cell.box, width_of_containing_block); cell_state.padding_top = cell.box->computed_values().padding().top().to_px_or_zero(cell.box, width_of_containing_block);
cell_state.padding_bottom = cell.box->computed_values().padding().bottom().to_px(cell.box, width_of_containing_block); cell_state.padding_bottom = cell.box->computed_values().padding().bottom().to_px_or_zero(cell.box, width_of_containing_block);
cell_state.padding_left = cell.box->computed_values().padding().left().to_px(cell.box, width_of_containing_block); cell_state.padding_left = cell.box->computed_values().padding().left().to_px_or_zero(cell.box, width_of_containing_block);
cell_state.padding_right = cell.box->computed_values().padding().right().to_px(cell.box, width_of_containing_block); cell_state.padding_right = cell.box->computed_values().padding().right().to_px_or_zero(cell.box, width_of_containing_block);
if (table_box().computed_values().border_collapse() == CSS::BorderCollapse::Separate) { if (table_box().computed_values().border_collapse() == CSS::BorderCollapse::Separate) {
cell_state.border_top = cell.box->computed_values().border_top().width; cell_state.border_top = cell.box->computed_values().border_top().width;