diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index efc1a802ff..4afc3bacea 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -179,6 +179,43 @@ NodeWithStyle::NodeWithStyle(DOM::Document& document, DOM::Node* node, CSS::Comp m_font = Gfx::FontDatabase::default_font(); } +void NodeWithStyle::did_insert_into_layout_tree(CSS::StyleProperties const& style) +{ + // https://drafts.csswg.org/css-sizing-3/#definite + auto is_definite_size = [&](CSS::PropertyID property_id, bool width) { + // A size that can be determined without performing layout; that is, + // a , + // a measure of text (without consideration of line-wrapping), + // a size of the initial containing block, + // or a or other formula (such as the “stretch-fit” sizing of non-replaced blocks [CSS2]) that is resolved solely against definite sizes. + auto maybe_value = style.property(property_id); + + auto const* containing_block = this->containing_block(); + auto containing_block_has_definite_size = containing_block && (width ? containing_block->m_has_definite_width : containing_block->m_has_definite_height); + + if (!maybe_value.has_value() || maybe_value.value()->has_auto()) { + // NOTE: The width of a non-flex-item block is considered definite if it's auto and the containing block has definite width. + if (width && is_block_container() && parent() && !parent()->computed_values().display().is_flex_inside()) + return containing_block_has_definite_size; + return false; + } + + auto maybe_length_percentage = style.length_percentage(property_id); + if (!maybe_length_percentage.has_value()) + return false; + auto length_percentage = maybe_length_percentage.release_value(); + if (length_percentage.is_length()) + return true; + if (length_percentage.is_percentage()) + return containing_block_has_definite_size; + // FIXME: Determine if calc() value is definite. + return false; + }; + + m_has_definite_width = is_definite_size(CSS::PropertyID::Width, true); + m_has_definite_height = is_definite_size(CSS::PropertyID::Height, false); +} + void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) { auto& computed_values = static_cast(m_computed_values); @@ -436,27 +473,6 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) if (computed_values.opacity() == 0) m_visible = false; - auto is_definite_size = [&](CSS::PropertyID property_id, bool width) { - auto maybe_value = specified_style.property(property_id); - if (!maybe_value.has_value() || maybe_value.value()->has_auto()) - return false; - auto maybe_length_percentage = specified_style.length_percentage(property_id); - if (!maybe_length_percentage.has_value()) - return false; - auto length_percentage = maybe_length_percentage.release_value(); - if (length_percentage.is_length()) - return true; - if (length_percentage.is_percentage()) { - auto* containing_block = this->containing_block(); - return containing_block && (width ? containing_block->m_has_definite_width : containing_block->m_has_definite_height); - } - // FIXME: Determine if calc() value is definite. - return false; - }; - - m_has_definite_width = is_definite_size(CSS::PropertyID::Width, true); - m_has_definite_height = is_definite_size(CSS::PropertyID::Height, false); - 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()) diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index 35429c2d8b..f65f263142 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -164,6 +164,8 @@ public: void set_has_definite_height(bool b) { m_has_definite_height = b; } void set_has_definite_width(bool b) { m_has_definite_width = b; } + void did_insert_into_layout_tree(CSS::StyleProperties const&); + protected: NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr); NodeWithStyle(DOM::Document&, DOM::Node*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index bb453a7e43..5da3fc93cd 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -96,18 +96,19 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& auto& document = dom_node.document(); auto& style_computer = document.style_computer(); RefPtr layout_node; + RefPtr style; if (is(dom_node)) { auto& element = static_cast(dom_node); element.clear_pseudo_element_nodes({}); - auto style = style_computer.compute_style(element); + style = style_computer.compute_style(element); if (style->display().is_none()) return; element.set_specified_css_values(style); - layout_node = element.create_layout_node(move(style)); + layout_node = element.create_layout_node(*style); } else if (is(dom_node)) { - auto style = style_computer.create_document_style(); - layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast(dom_node), move(style))); + style = style_computer.create_document_style(); + layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast(dom_node), *style)); } else if (is(dom_node)) { layout_node = adopt_ref(*new Layout::TextNode(document, static_cast(dom_node))); } else if (is(dom_node)) { @@ -150,6 +151,9 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& insert_node_into_inline_or_block_ancestor(layout_node); } + if (layout_node->has_style() && style) + static_cast(*layout_node).did_insert_into_layout_tree(*style); + auto* shadow_root = is(dom_node) ? verify_cast(dom_node).shadow_root() : nullptr; if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children()) {