From 5b2482a9396dc5f7044647f9132f55785fabffdd Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 18 Feb 2022 15:10:11 +0000 Subject: [PATCH] LibWeb: Use Optional instead of undefined-lengths for widths/heights --- .../Libraries/LibWeb/CSS/ComputedValues.h | 24 ++++----- .../CSS/ResolvedCSSStyleDeclaration.cpp | 20 +++---- .../Libraries/LibWeb/CSS/StyleProperties.cpp | 9 +++- .../Libraries/LibWeb/CSS/StyleProperties.h | 1 + .../LibWeb/Layout/BlockFormattingContext.cpp | 30 ++++++----- .../LibWeb/Layout/FlexFormattingContext.cpp | 53 ++++++++++++------- .../LibWeb/Layout/FormattingContext.cpp | 43 +++++++-------- .../LibWeb/Layout/InlineFormattingContext.cpp | 10 ++-- Userland/Libraries/LibWeb/Layout/Node.cpp | 20 ++++--- .../LibWeb/Layout/TableFormattingContext.cpp | 8 +-- 10 files changed, 126 insertions(+), 92 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index f9444e8758..b82d66099c 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -108,12 +108,12 @@ public: CSS::JustifyContent justify_content() const { return m_noninherited.justify_content; } Vector const& box_shadow() const { return m_noninherited.box_shadow; } CSS::BoxSizing box_sizing() const { return m_noninherited.box_sizing; } - CSS::LengthPercentage const& width() const { return m_noninherited.width; } - CSS::LengthPercentage const& min_width() const { return m_noninherited.min_width; } - CSS::LengthPercentage const& max_width() const { return m_noninherited.max_width; } - CSS::LengthPercentage const& height() const { return m_noninherited.height; } - CSS::LengthPercentage const& min_height() const { return m_noninherited.min_height; } - CSS::LengthPercentage const& max_height() const { return m_noninherited.max_height; } + Optional const& width() const { return m_noninherited.width; } + Optional const& min_width() const { return m_noninherited.min_width; } + Optional const& max_width() const { return m_noninherited.max_width; } + Optional const& height() const { return m_noninherited.height; } + Optional const& min_height() const { return m_noninherited.min_height; } + Optional const& max_height() const { return m_noninherited.max_height; } const CSS::LengthBox& offset() const { return m_noninherited.offset; } const CSS::LengthBox& margin() const { return m_noninherited.margin; } @@ -174,12 +174,12 @@ protected: CSS::TextDecorationLine text_decoration_line { InitialValues::text_decoration_line() }; CSS::TextDecorationStyle text_decoration_style { InitialValues::text_decoration_style() }; CSS::Position position { InitialValues::position() }; - CSS::LengthPercentage width { Length::make_auto() }; - CSS::LengthPercentage min_width { Length::make_auto() }; - CSS::LengthPercentage max_width { Length::make_auto() }; - CSS::LengthPercentage height { Length::make_auto() }; - CSS::LengthPercentage min_height { Length::make_auto() }; - CSS::LengthPercentage max_height { Length::make_auto() }; + Optional width; + Optional min_width; + Optional max_width; + Optional height; + Optional min_height; + Optional max_height; CSS::LengthBox offset; CSS::LengthBox margin; CSS::LengthBox padding; diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index 1338b5d160..752c637665 100644 --- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -536,25 +536,25 @@ RefPtr ResolvedCSSStyleDeclaration::style_value_for_property(Layout: return StyleValueList::create(move(box_shadow), StyleValueList::Separator::Comma); } case CSS::PropertyID::Width: - return style_value_for_length_percentage(layout_node.computed_values().width()); + return style_value_for_length_percentage(layout_node.computed_values().width().value_or(Length::make_auto())); case CSS::PropertyID::MinWidth: - if (layout_node.computed_values().min_width().is_length() && layout_node.computed_values().min_width().length().is_undefined_or_auto()) + if (!layout_node.computed_values().min_width().has_value()) return IdentifierStyleValue::create(CSS::ValueID::Auto); - return style_value_for_length_percentage(layout_node.computed_values().min_width()); + return style_value_for_length_percentage(layout_node.computed_values().min_width().value()); case CSS::PropertyID::MaxWidth: - if (layout_node.computed_values().max_width().is_length() && layout_node.computed_values().max_width().length().is_undefined()) + if (!layout_node.computed_values().max_width().has_value()) return IdentifierStyleValue::create(CSS::ValueID::None); - return style_value_for_length_percentage(layout_node.computed_values().max_width()); + return style_value_for_length_percentage(layout_node.computed_values().max_width().value()); case CSS::PropertyID::Height: - return style_value_for_length_percentage(layout_node.computed_values().height()); + return style_value_for_length_percentage(layout_node.computed_values().height().value_or(Length::make_auto())); case CSS::PropertyID::MinHeight: - if (layout_node.computed_values().min_height().is_length() && layout_node.computed_values().min_height().length().is_undefined_or_auto()) + if (!layout_node.computed_values().min_height().has_value()) return IdentifierStyleValue::create(CSS::ValueID::Auto); - return style_value_for_length_percentage(layout_node.computed_values().min_height()); + return style_value_for_length_percentage(layout_node.computed_values().min_height().value()); case CSS::PropertyID::MaxHeight: - if (layout_node.computed_values().max_height().is_length() && layout_node.computed_values().max_height().length().is_undefined()) + if (!layout_node.computed_values().max_height().has_value()) return IdentifierStyleValue::create(CSS::ValueID::None); - return style_value_for_length_percentage(layout_node.computed_values().max_height()); + return style_value_for_length_percentage(layout_node.computed_values().max_height().value()); case CSS::PropertyID::Margin: { auto margin = layout_node.computed_values().margin(); auto values = NonnullRefPtrVector {}; diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 3673aa6639..086db9e3e0 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -64,10 +64,15 @@ Length StyleProperties::length_or_fallback(CSS::PropertyID id, Length const& fal } LengthPercentage StyleProperties::length_percentage_or_fallback(CSS::PropertyID id, LengthPercentage const& fallback) const +{ + return length_percentage(id).value_or(fallback); +} + +Optional StyleProperties::length_percentage(CSS::PropertyID id) const { auto maybe_value = property(id); if (!maybe_value.has_value()) - return fallback; + return {}; auto& value = maybe_value.value(); if (value->is_calculated()) @@ -79,7 +84,7 @@ LengthPercentage StyleProperties::length_percentage_or_fallback(CSS::PropertyID if (value->has_length()) return value->to_length(); - return fallback; + return {}; } LengthBox StyleProperties::length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 4c86749b7a..09263ce1ba 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -41,6 +41,7 @@ public: Length length_or_fallback(CSS::PropertyID, Length const& fallback) const; LengthPercentage length_percentage_or_fallback(CSS::PropertyID, LengthPercentage const& fallback) const; + Optional length_percentage(CSS::PropertyID) const; LengthBox length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const; Color color_or_fallback(CSS::PropertyID, Layout::NodeWithStyle const&, Color fallback) const; Optional text_align() const; diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 64cf2ddc3e..b2a16757e3 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -195,14 +195,14 @@ void BlockFormattingContext::compute_width(Box& box) return width; }; - auto specified_width = computed_values.width().resolved(box, width_of_containing_block_as_length).resolved_or_auto(box); + auto specified_width = computed_values.width().has_value() ? computed_values.width()->resolved(box, width_of_containing_block_as_length).resolved_or_auto(box) : CSS::Length::make_auto(); // 1. The tentative used width is calculated (without 'min-width' and 'max-width') auto used_width = try_compute_width(specified_width); // 2. The tentative used width is greater than 'max-width', the rules above are applied again, // but this time using the computed value of 'max-width' as the computed value for 'width'. - auto specified_max_width = computed_values.max_width().resolved(box, width_of_containing_block_as_length).resolved_or_auto(box); + auto specified_max_width = computed_values.max_width().has_value() ? computed_values.max_width()->resolved(box, width_of_containing_block_as_length).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_max_width.is_auto()) { if (used_width.to_px(box) > specified_max_width.to_px(box)) { used_width = try_compute_width(specified_max_width); @@ -211,7 +211,7 @@ void BlockFormattingContext::compute_width(Box& box) // 3. If the resulting width is smaller than 'min-width', the rules above are applied again, // but this time using the value of 'min-width' as the computed value for 'width'. - auto specified_min_width = computed_values.min_width().resolved(box, width_of_containing_block_as_length).resolved_or_auto(box); + auto specified_min_width = computed_values.min_width().has_value() ? computed_values.min_width()->resolved(box, width_of_containing_block_as_length).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_min_width.is_auto()) { if (used_width.to_px(box) < specified_min_width.to_px(box)) { used_width = try_compute_width(specified_min_width); @@ -246,7 +246,7 @@ void BlockFormattingContext::compute_width_for_floating_box(Box& box) if (margin_right.is_auto()) margin_right = zero_value; - auto width = computed_values.width().resolved(box, width_of_containing_block_as_length).resolved_or_auto(box); + auto width = computed_values.width().has_value() ? computed_values.width()->resolved(box, width_of_containing_block_as_length).resolved_or_auto(box) : CSS::Length::make_auto(); // If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width. if (width.is_auto()) { @@ -285,8 +285,8 @@ float BlockFormattingContext::compute_theoretical_height(Box const& box) auto& containing_block = *box.containing_block(); auto containing_block_height = CSS::Length::make_px(containing_block.content_height()); - auto is_absolute = [](CSS::LengthPercentage const& length_percentage) { - return length_percentage.is_length() && length_percentage.length().is_absolute(); + auto is_absolute = [](Optional const& length_percentage) { + return length_percentage.has_value() && length_percentage->is_length() && length_percentage->length().is_absolute(); }; // Then work out what the height is, based on box type and CSS properties. @@ -294,21 +294,22 @@ float BlockFormattingContext::compute_theoretical_height(Box const& box) if (is(box)) { height = compute_height_for_replaced_element(verify_cast(box)); } else { - if ((box.computed_values().height().is_length() && box.computed_values().height().length().is_undefined_or_auto()) - || (computed_values.height().is_percentage() && !is_absolute(containing_block.computed_values().height()))) { + if (!box.computed_values().height().has_value() + || (box.computed_values().height()->is_length() && box.computed_values().height()->length().is_undefined_or_auto()) + || (computed_values.height().has_value() && computed_values.height()->is_percentage() && !is_absolute(containing_block.computed_values().height()))) { height = compute_auto_height_for_block_level_element(box, ConsiderFloats::No); } else { - height = computed_values.height().resolved(box, containing_block_height).resolved_or_auto(box).to_px(box); + height = computed_values.height().has_value() ? computed_values.height()->resolved(box, containing_block_height).resolved_or_auto(box).to_px(box) : 0; } } - auto specified_max_height = computed_values.max_height().resolved(box, containing_block_height).resolved_or_auto(box); + auto specified_max_height = computed_values.max_height().has_value() ? computed_values.max_height()->resolved(box, containing_block_height).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_max_height.is_auto() - && !(computed_values.max_height().is_percentage() && !is_absolute(containing_block.computed_values().height()))) + && !(computed_values.max_height().has_value() && computed_values.max_height()->is_percentage() && !is_absolute(containing_block.computed_values().height()))) height = min(height, specified_max_height.to_px(box)); - auto specified_min_height = computed_values.min_height().resolved(box, containing_block_height).resolved_or_auto(box); + auto specified_min_height = computed_values.min_height().has_value() ? computed_values.min_height()->resolved(box, containing_block_height).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_min_height.is_auto() - && !(computed_values.min_height().is_percentage() && !is_absolute(containing_block.computed_values().height()))) + && !(computed_values.min_height().has_value() && computed_values.min_height()->is_percentage() && !is_absolute(containing_block.computed_values().height()))) height = max(height, specified_min_height.to_px(box)); return height; } @@ -439,7 +440,8 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer& block_c }); if (layout_mode != LayoutMode::Default) { - if (block_container.computed_values().width().is_length() && block_container.computed_values().width().length().is_undefined_or_auto()) + auto& width = block_container.computed_values().width(); + if (!width.has_value() || (width->is_length() && width->length().is_undefined_or_auto())) block_container.set_content_width(content_width); } } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index 80eac81c35..eba2536701 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -17,17 +17,19 @@ namespace Web::Layout { -static float get_pixel_size(Box const& box, CSS::LengthPercentage const& length_percentage) +static float get_pixel_size(Box const& box, Optional const& length_percentage) { + if (!length_percentage.has_value()) + return 0; auto inner_main_size = CSS::Length::make_px(box.containing_block()->content_width()); - return length_percentage.resolved(box, inner_main_size) - .resolved(CSS::Length::make_px(0), box) - .to_px(box); + return length_percentage->resolved(box, inner_main_size).resolved(CSS::Length::make_px(0), box).to_px(box); } -static bool is_undefined_or_auto(CSS::LengthPercentage const& length_percentage) +static bool is_undefined_or_auto(Optional const& length_percentage) { - return length_percentage.is_length() && length_percentage.length().is_undefined_or_auto(); + if (!length_percentage.has_value()) + return true; + return length_percentage->is_length() && length_percentage->length().is_undefined_or_auto(); } FlexFormattingContext::FlexFormattingContext(Box& flex_container, FormattingContext* parent) @@ -143,16 +145,27 @@ void FlexFormattingContext::generate_anonymous_flex_items() flex_container().set_content_width(flex_container().containing_block()->content_width()); } else { auto container_width = flex_container().containing_block()->content_width(); - auto width = flex_container().computed_values().width().resolved(flex_container(), CSS::Length::make_px(container_width)).resolved_or_zero(flex_container()).to_px(flex_container()); - flex_container().set_content_width(width); + + auto& maybe_width = flex_container().computed_values().width(); + if (maybe_width.has_value()) { + auto width = maybe_width->resolved(flex_container(), CSS::Length::make_px(container_width)).resolved_or_zero(flex_container()).to_px(flex_container()); + flex_container().set_content_width(width); + } else { + flex_container().set_content_width(0); + } } if (!flex_container().has_definite_height()) { flex_container().set_content_height(flex_container().containing_block()->content_height()); } else { auto container_height = flex_container().containing_block()->content_height(); - auto height = flex_container().computed_values().height().resolved(flex_container(), CSS::Length::make_px(container_height)).resolved_or_zero(flex_container()).to_px(flex_container()); - flex_container().set_content_height(height); + auto& maybe_height = flex_container().computed_values().height(); + if (maybe_height.has_value()) { + auto height = maybe_height->resolved(flex_container(), CSS::Length::make_px(container_height)).resolved_or_zero(flex_container()).to_px(flex_container()); + flex_container().set_content_height(height); + } else { + flex_container().set_content_height(0); + } } flex_container().for_each_child_of_type([&](Box& child_box) { @@ -219,8 +232,11 @@ bool FlexFormattingContext::cross_size_is_absolute_or_resolved_nicely(NodeWithSt { auto length_percentage = is_row_layout() ? box.computed_values().height() : box.computed_values().width(); - if (length_percentage.is_length()) { - auto& length = length_percentage.length(); + if (!length_percentage.has_value()) + return false; + + if (length_percentage->is_length()) { + auto& length = length_percentage->length(); if (length.is_absolute() || length.is_relative()) return true; if (length.is_undefined_or_auto()) @@ -229,7 +245,7 @@ bool FlexFormattingContext::cross_size_is_absolute_or_resolved_nicely(NodeWithSt if (!box.parent()) return false; - if (length_percentage.is_percentage() && cross_size_is_absolute_or_resolved_nicely(*box.parent())) + if (length_percentage->is_percentage() && cross_size_is_absolute_or_resolved_nicely(*box.parent())) return true; return false; } @@ -237,8 +253,10 @@ bool FlexFormattingContext::cross_size_is_absolute_or_resolved_nicely(NodeWithSt float FlexFormattingContext::specified_main_size_of_child_box(Box const& child_box) const { auto main_size_of_parent = specified_main_size(flex_container()); - auto value = is_row_layout() ? child_box.computed_values().width() : child_box.computed_values().height(); - return value.resolved(child_box, CSS::Length::make_px(main_size_of_parent)).resolved_or_zero(child_box).to_px(child_box); + auto& value = is_row_layout() ? child_box.computed_values().width() : child_box.computed_values().height(); + if (!value.has_value()) + return 0; + return value->resolved(child_box, CSS::Length::make_px(main_size_of_parent)).resolved_or_zero(child_box).to_px(child_box); } float FlexFormattingContext::specified_main_min_size(Box const& box) const @@ -290,9 +308,8 @@ float FlexFormattingContext::calculated_main_size(Box const& box) const bool FlexFormattingContext::is_cross_auto(Box const& box) const { - if (is_row_layout()) - return box.computed_values().height().is_length() && box.computed_values().height().length().is_auto(); - return box.computed_values().width().is_length() && box.computed_values().width().length().is_auto(); + auto& cross_length = is_row_layout() ? box.computed_values().height() : box.computed_values().width(); + return cross_length.has_value() && cross_length->length().is_auto(); } bool FlexFormattingContext::is_main_axis_margin_first_auto(Box const& box) const diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index 7077952ddc..d3fd918a16 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -157,10 +157,10 @@ static Gfx::FloatSize solve_replaced_size_constraint(float w, float h, const Rep auto width_of_containing_block = CSS::Length::make_px(containing_block.content_width()); auto height_of_containing_block = CSS::Length::make_px(containing_block.content_height()); - auto specified_min_width = box.computed_values().min_width().resolved(box, width_of_containing_block).resolved_or_zero(box).to_px(box); - auto specified_max_width = box.computed_values().max_width().resolved(box, width_of_containing_block).resolved(CSS::Length::make_px(w), box).to_px(box); - auto specified_min_height = box.computed_values().min_height().resolved(box, height_of_containing_block).resolved_or_auto(box).to_px(box); - auto specified_max_height = box.computed_values().max_height().resolved(box, height_of_containing_block).resolved(CSS::Length::make_px(h), box).to_px(box); + auto specified_min_width = box.computed_values().min_width().has_value() ? box.computed_values().min_width()->resolved(box, width_of_containing_block).resolved_or_zero(box).to_px(box) : 0; + auto specified_max_width = box.computed_values().max_width().has_value() ? box.computed_values().max_width()->resolved(box, width_of_containing_block).resolved(CSS::Length::make_px(w), box).to_px(box) : w; + auto specified_min_height = box.computed_values().min_height().has_value() ? box.computed_values().min_height()->resolved(box, height_of_containing_block).resolved_or_auto(box).to_px(box) : 0; + auto specified_max_height = box.computed_values().max_height().has_value() ? box.computed_values().max_height()->resolved(box, height_of_containing_block).resolved(CSS::Length::make_px(h), box).to_px(box) : h; auto min_width = min(specified_min_width, specified_max_width); auto max_width = max(specified_min_width, specified_max_width); @@ -252,7 +252,7 @@ float FormattingContext::tentative_width_for_replaced_element(ReplacedBox const& { auto& containing_block = *box.containing_block(); auto height_of_containing_block = CSS::Length::make_px(containing_block.content_height()); - auto computed_height = box.computed_values().height().resolved(box, height_of_containing_block).resolved_or_auto(box); + auto computed_height = box.computed_values().height().has_value() ? box.computed_values().height()->resolved(box, height_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); float used_width = computed_width.to_px(box); @@ -323,14 +323,14 @@ float FormattingContext::compute_width_for_replaced_element(const ReplacedBox& b if (margin_right.is_auto()) margin_right = zero_value; - auto specified_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); // 1. The tentative used width is calculated (without 'min-width' and 'max-width') auto used_width = tentative_width_for_replaced_element(box, specified_width); // 2. The tentative used width is greater than 'max-width', the rules above are applied again, // but this time using the computed value of 'max-width' as the computed value for 'width'. - auto specified_max_width = box.computed_values().max_width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_max_width = box.computed_values().max_width().has_value() ? box.computed_values().max_width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_max_width.is_auto()) { if (used_width > specified_max_width.to_px(box)) { used_width = tentative_width_for_replaced_element(box, specified_max_width); @@ -339,7 +339,7 @@ float FormattingContext::compute_width_for_replaced_element(const ReplacedBox& b // 3. If the resulting width is smaller than 'min-width', the rules above are applied again, // but this time using the value of 'min-width' as the computed value for 'width'. - auto specified_min_width = box.computed_values().min_width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_min_width = box.computed_values().min_width().has_value() ? box.computed_values().min_width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_min_width.is_auto()) { if (used_width < specified_min_width.to_px(box)) { used_width = tentative_width_for_replaced_element(box, specified_min_width); @@ -355,7 +355,7 @@ float FormattingContext::tentative_height_for_replaced_element(ReplacedBox const { auto& containing_block = *box.containing_block(); auto width_of_containing_block = CSS::Length::make_px(containing_block.content_width()); - auto computed_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto computed_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); // If 'height' and 'width' both have computed values of 'auto' and the element also has // an intrinsic height, then that intrinsic height is the used value of 'height'. @@ -389,8 +389,8 @@ float FormattingContext::compute_height_for_replaced_element(const ReplacedBox& auto& containing_block = *box.containing_block(); auto width_of_containing_block = CSS::Length::make_px(containing_block.content_width()); auto height_of_containing_block = CSS::Length::make_px(containing_block.content_height()); - auto specified_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box); - auto specified_height = box.computed_values().height().resolved(box, height_of_containing_block).resolved_or_auto(box); + auto specified_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); + auto specified_height = box.computed_values().height().has_value() ? box.computed_values().height()->resolved(box, height_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); float used_height = tentative_height_for_replaced_element(box, specified_height); @@ -511,14 +511,14 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele return width; }; - auto specified_width = computed_values.width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_width = computed_values.width().has_value() ? computed_values.width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); // 1. The tentative used width is calculated (without 'min-width' and 'max-width') auto used_width = try_compute_width(specified_width); // 2. The tentative used width is greater than 'max-width', the rules above are applied again, // but this time using the computed value of 'max-width' as the computed value for 'width'. - auto specified_max_width = computed_values.max_width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_max_width = computed_values.max_width().has_value() ? computed_values.max_width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_max_width.is_auto()) { if (used_width.to_px(box) > specified_max_width.to_px(box)) { used_width = try_compute_width(specified_max_width); @@ -527,7 +527,7 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele // 3. If the resulting width is smaller than 'min-width', the rules above are applied again, // but this time using the value of 'min-width' as the computed value for 'width'. - auto specified_min_width = computed_values.min_width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_min_width = computed_values.min_width().has_value() ? computed_values.min_width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); if (!specified_min_width.is_auto()) { if (used_width.to_px(box) < specified_min_width.to_px(box)) { used_width = try_compute_width(specified_min_width); @@ -561,16 +561,17 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el CSS::Length specified_top = computed_values.offset().top.resolved(box, height_of_containing_block).resolved_or_auto(box); CSS::Length specified_bottom = computed_values.offset().bottom.resolved(box, height_of_containing_block).resolved_or_auto(box); - CSS::Length specified_height; + CSS::Length specified_height = CSS::Length::make_auto(); - if (computed_values.height().is_percentage() && !(containing_block.computed_values().height().is_length() && containing_block.computed_values().height().length().is_absolute())) { - specified_height = CSS::Length::make_auto(); + if (computed_values.height().has_value() && computed_values.height()->is_percentage() + && !(containing_block.computed_values().height().has_value() && containing_block.computed_values().height()->is_length() && containing_block.computed_values().height()->length().is_absolute())) { + // specified_height is already auto } else { - specified_height = computed_values.height().resolved(box, height_of_containing_block).resolved_or_auto(box); + specified_height = computed_values.height().has_value() ? computed_values.height()->resolved(box, height_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); } - auto specified_max_height = computed_values.max_height().resolved(box, height_of_containing_block).resolved_or_auto(box); - auto specified_min_height = computed_values.min_height().resolved(box, height_of_containing_block).resolved_or_auto(box); + auto specified_max_height = computed_values.max_height().has_value() ? computed_values.max_height()->resolved(box, height_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); + auto specified_min_height = computed_values.min_height().has_value() ? computed_values.min_height()->resolved(box, height_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); box.box_model().margin.top = computed_values.margin().top.resolved(box, width_of_containing_block).resolved_or_zero(box).to_px(box); box.box_model().margin.bottom = computed_values.margin().bottom.resolved(box, width_of_containing_block).resolved_or_zero(box).to_px(box); @@ -613,7 +614,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box& box) auto height_of_containing_block = CSS::Length::make_px(containing_block.content_height()); auto& box_model = box.box_model(); - auto specified_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box); + auto specified_width = box.computed_values().width().has_value() ? box.computed_values().width()->resolved(box, width_of_containing_block).resolved_or_auto(box) : CSS::Length::make_auto(); compute_width_for_absolutely_positioned_element(box); auto independent_formatting_context = layout_inside(box, LayoutMode::Default); diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 8b65caf3cd..fe6f778a07 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -125,7 +125,8 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ if (box.is_inline_block()) { auto& inline_block = const_cast(verify_cast(box)); - if (inline_block.computed_values().width().is_length() && inline_block.computed_values().width().length().is_undefined_or_auto()) { + auto& width_value = inline_block.computed_values().width(); + if (!width_value.has_value() || (width_value->is_length() && width_value->length().is_undefined_or_auto())) { auto result = calculate_shrink_to_fit_widths(inline_block); auto available_width = containing_block().content_width() @@ -140,16 +141,17 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ inline_block.set_content_width(width); } else { auto container_width = CSS::Length::make_px(containing_block().content_width()); - inline_block.set_content_width(inline_block.computed_values().width().resolved(box, container_width).resolved_or_zero(inline_block).to_px(inline_block)); + inline_block.set_content_width(width_value->resolved(box, container_width).resolved_or_zero(inline_block).to_px(inline_block)); } auto independent_formatting_context = layout_inside(inline_block, layout_mode); - if (inline_block.computed_values().height().is_length() && inline_block.computed_values().height().length().is_undefined_or_auto()) { + auto& height_value = inline_block.computed_values().height(); + if (!height_value.has_value() || (height_value->is_length() && height_value->length().is_undefined_or_auto())) { // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. BlockFormattingContext::compute_height(inline_block); } else { auto container_height = CSS::Length::make_px(containing_block().content_height()); - inline_block.set_content_height(inline_block.computed_values().height().resolved(box, container_height).resolved_or_zero(inline_block).to_px(inline_block)); + inline_block.set_content_height(height_value->resolved(box, container_height).resolved_or_zero(inline_block).to_px(inline_block)); } independent_formatting_context->parent_context_did_dimension_child_root_box(); diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 185ede5c06..7562f87e36 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -430,15 +430,21 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) if (auto width = specified_style.property(CSS::PropertyID::Width); width.has_value() && !width.value()->has_auto()) m_has_definite_width = true; - computed_values.set_width(specified_style.length_percentage_or_fallback(CSS::PropertyID::Width, CSS::Length {})); - computed_values.set_min_width(specified_style.length_percentage_or_fallback(CSS::PropertyID::MinWidth, CSS::Length {})); - computed_values.set_max_width(specified_style.length_percentage_or_fallback(CSS::PropertyID::MaxWidth, CSS::Length {})); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::Width); maybe_length_percentage.has_value()) + computed_values.set_width(maybe_length_percentage.release_value()); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::MinWidth); maybe_length_percentage.has_value()) + computed_values.set_min_width(maybe_length_percentage.release_value()); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::MaxWidth); maybe_length_percentage.has_value()) + computed_values.set_max_width(maybe_length_percentage.release_value()); if (auto height = specified_style.property(CSS::PropertyID::Height); height.has_value() && !height.value()->has_auto()) m_has_definite_height = true; - computed_values.set_height(specified_style.length_percentage_or_fallback(CSS::PropertyID::Height, CSS::Length {})); - computed_values.set_min_height(specified_style.length_percentage_or_fallback(CSS::PropertyID::MinHeight, CSS::Length {})); - computed_values.set_max_height(specified_style.length_percentage_or_fallback(CSS::PropertyID::MaxHeight, CSS::Length {})); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::Height); maybe_length_percentage.has_value()) + computed_values.set_height(maybe_length_percentage.release_value()); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::MinHeight); maybe_length_percentage.has_value()) + computed_values.set_min_height(maybe_length_percentage.release_value()); + if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::MaxHeight); maybe_length_percentage.has_value()) + computed_values.set_max_height(maybe_length_percentage.release_value()); computed_values.set_offset(specified_style.length_box(CSS::PropertyID::Left, CSS::PropertyID::Top, CSS::PropertyID::Right, CSS::PropertyID::Bottom, CSS::Length::make_auto())); computed_values.set_margin(specified_style.length_box(CSS::PropertyID::MarginLeft, CSS::PropertyID::MarginTop, CSS::PropertyID::MarginRight, CSS::PropertyID::MarginBottom, CSS::Length::make_px(0))); @@ -457,7 +463,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) if (border.line_style == CSS::LineStyle::None) border.width = 0; else - border.width = specified_style.length_or_fallback(width_property, {}).resolved_or_zero(*this).to_px(*this); + border.width = specified_style.length_or_fallback(width_property, CSS::Length::make_px(0)).resolved_or_zero(*this).to_px(*this); }; do_border_style(computed_values.border_left(), CSS::PropertyID::BorderLeftWidth, CSS::PropertyID::BorderLeftColor, CSS::PropertyID::BorderLeftStyle); diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp index d460ea6b68..9683e798b8 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp @@ -52,7 +52,7 @@ void TableFormattingContext::run(Box& box, LayoutMode) content_height += row.content_height(); }); - if (row_group_box.computed_values().width().is_length() && row_group_box.computed_values().width().length().is_auto()) + if (row_group_box.computed_values().width().has_value() && row_group_box.computed_values().width()->is_length() && row_group_box.computed_values().width()->length().is_auto()) row_group_box.set_content_width(content_width); row_group_box.set_content_height(content_height); @@ -61,7 +61,7 @@ void TableFormattingContext::run(Box& box, LayoutMode) total_content_width = max(total_content_width, row_group_box.content_width()); }); - if (box.computed_values().width().is_length() && box.computed_values().width().length().is_auto()) + if (box.computed_values().width().has_value() && box.computed_values().width()->is_length() && box.computed_values().width()->length().is_auto()) box.set_content_width(total_content_width); // FIXME: This is a total hack, we should respect the 'height' property. @@ -72,7 +72,7 @@ void TableFormattingContext::calculate_column_widths(Box& row, Vector& co { size_t column_index = 0; auto* table = row.first_ancestor_of_type(); - bool use_auto_layout = !table || (table->computed_values().width().is_length() && table->computed_values().width().length().is_undefined_or_auto()); + bool use_auto_layout = !table || (!table->computed_values().width().has_value() || (table->computed_values().width()->is_length() && table->computed_values().width()->length().is_undefined_or_auto())); row.for_each_child_of_type([&](auto& cell) { compute_width(cell); if (use_auto_layout) { @@ -91,7 +91,7 @@ void TableFormattingContext::layout_row(Box& row, Vector& column_widths) float tallest_cell_height = 0; float content_width = 0; auto* table = row.first_ancestor_of_type(); - bool use_auto_layout = !table || (table->computed_values().width().is_length() && table->computed_values().width().length().is_undefined_or_auto()); + bool use_auto_layout = !table || (!table->computed_values().width().has_value() || (table->computed_values().width()->is_length() && table->computed_values().width()->length().is_undefined_or_auto())); row.for_each_child_of_type([&](auto& cell) { cell.set_offset(row.effective_offset().translated(content_width, 0));