diff options
author | Andreas Kling <kling@serenityos.org> | 2022-07-17 18:46:38 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-07-26 01:53:41 +0200 |
commit | 71a707480c6c580dbf88a88dde8d0c3d7898d930 (patch) | |
tree | ce4300cc2ff3a8db0f3561283aad9fb7f3febb2b /Userland/Libraries | |
parent | 25e6ad8d3e294b231658dbdb47ab156c05982fff (diff) | |
download | serenity-71a707480c6c580dbf88a88dde8d0c3d7898d930.zip |
LibWeb: Move "has-definite-width/height" flags to UsedValues
This state is less static than we originally assumed, and there are
special formatting context-specific rules that say certain sizes are
definite in special circumstances.
To be able to support this, we move the has-definite-size flags from
the layout node to the UsedValues struct instead.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Document.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/FormattingContext.cpp | 12 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/LayoutState.cpp | 47 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/LayoutState.h | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/Node.cpp | 35 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/Node.h | 9 |
8 files changed, 71 insertions, 70 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index d6aa84af5c..d783433cf9 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -622,8 +622,8 @@ void Document::update_layout() auto& icb = static_cast<Layout::InitialContainingBlock&>(*m_layout_root); auto& icb_state = layout_state.get_mutable(icb); - icb.set_has_definite_width(true); - icb.set_has_definite_height(true); + icb_state.set_has_definite_width(true); + icb_state.set_has_definite_height(true); icb_state.set_content_width(viewport_rect.width()); icb_state.set_content_height(viewport_rect.height()); diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 5145357d09..bd5235dae0 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -418,7 +418,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain if (is<ReplacedBox>(box) || is<BlockContainer>(box)) place_block_level_element_in_normal_flow_vertically(box, block_container); - if (box.has_definite_height()) { + if (box_state.has_definite_height()) { compute_height(box, m_state); } @@ -456,10 +456,10 @@ void BlockFormattingContext::run_intrinsic_size_determination(Box const& box) { auto& box_state = m_state.get_mutable(box); - if (box.has_definite_width()) + if (box_state.has_definite_width()) box_state.set_content_width(box.computed_values().width().resolved(box, CSS::Length::make_px(containing_block_width_for(box))).to_px(box)); - if (box.has_definite_height()) + if (box_state.has_definite_height()) box_state.set_content_height(box.computed_values().height().resolved(box, CSS::Length::make_px(containing_block_height_for(box))).to_px(box)); run(box, LayoutMode::IntrinsicSizeDetermination); diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index 6a7b1fba78..d1d0f51095 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -275,7 +275,8 @@ void FlexFormattingContext::generate_anonymous_flex_items() bool FlexFormattingContext::has_definite_main_size(Box const& box) const { - return is_row_layout() ? box.has_definite_width() : box.has_definite_height(); + auto const& used_values = m_state.get(box); + return is_row_layout() ? used_values.has_definite_width() : used_values.has_definite_height(); } float FlexFormattingContext::specified_main_size(Box const& box) const @@ -292,10 +293,6 @@ float FlexFormattingContext::specified_cross_size(Box const& box) const float FlexFormattingContext::resolved_definite_cross_size(Box const& box) const { - if (is_row_layout()) - VERIFY(box.has_definite_height()); - else - VERIFY(box.has_definite_width()); auto const& cross_value = is_row_layout() ? box.computed_values().height() : box.computed_values().width(); if (cross_value.is_length()) return cross_value.length().to_px(box); @@ -304,10 +301,6 @@ float FlexFormattingContext::resolved_definite_cross_size(Box const& box) const float FlexFormattingContext::resolved_definite_main_size(Box const& box) const { - if (is_row_layout()) - VERIFY(box.has_definite_width()); - else - VERIFY(box.has_definite_height()); auto const& cross_value = is_row_layout() ? box.computed_values().width() : box.computed_values().height(); if (cross_value.is_length()) return cross_value.length().to_px(box); @@ -328,7 +321,8 @@ bool FlexFormattingContext::has_cross_min_size(Box const& box) const bool FlexFormattingContext::has_definite_cross_size(Box const& box) const { - return is_row_layout() ? box.has_definite_height() : box.has_definite_width(); + auto const& used_values = m_state.get(box); + return is_row_layout() ? used_values.has_definite_height() : used_values.has_definite_width(); } float FlexFormattingContext::specified_main_size_of_child_box(Box const& child_box) const diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index cfdc57ed22..a8221c1738 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -32,10 +32,10 @@ void FormattingContext::run_intrinsic_size_determination(Box const& box) { auto& box_state = m_state.get_mutable(box); - if (box.has_definite_width()) + if (box_state.has_definite_width()) box_state.set_content_width(box.computed_values().width().resolved(box, CSS::Length::make_px(containing_block_width_for(box))).to_px(box)); - if (box.has_definite_height()) + if (box_state.has_definite_height()) box_state.set_content_height(box.computed_values().height().resolved(box, CSS::Length::make_px(containing_block_height_for(box))).to_px(box)); run(box, LayoutMode::IntrinsicSizeDetermination); @@ -866,7 +866,7 @@ float FormattingContext::calculate_min_content_width(Layout::Box const& box) con auto& containing_block_state = throwaway_state.get_mutable(containing_block); containing_block_state.set_content_width(0); - if (!containing_block.has_definite_height()) + if (!containing_block_state.has_definite_height()) containing_block_state.set_content_height(INFINITY); else if (containing_block.computed_values().height().is_auto()) containing_block_state.set_content_height(containing_block_height_for(containing_block)); @@ -908,7 +908,7 @@ float FormattingContext::calculate_max_content_width(Layout::Box const& box) con auto& containing_block_state = throwaway_state.get_mutable(containing_block); containing_block_state.set_content_width(INFINITY); - if (!containing_block.has_definite_height()) + if (!containing_block_state.has_definite_height()) containing_block_state.set_content_height(INFINITY); else if (containing_block.computed_values().height().is_auto()) containing_block_state.set_content_height(containing_block_height_for(containing_block)); @@ -950,7 +950,7 @@ float FormattingContext::calculate_min_content_height(Layout::Box const& box) co auto& containing_block_state = throwaway_state.get_mutable(containing_block); containing_block_state.set_content_height(0); - if (!containing_block.has_definite_width()) + if (!containing_block_state.has_definite_width()) containing_block_state.set_content_width(INFINITY); else if (containing_block.computed_values().width().is_auto()) containing_block_state.set_content_width(containing_block_width_for(containing_block)); @@ -992,7 +992,7 @@ float FormattingContext::calculate_max_content_height(Layout::Box const& box) co auto& containing_block_state = throwaway_state.get_mutable(containing_block); containing_block_state.set_content_height(INFINITY); - if (!containing_block.has_definite_width()) + if (!containing_block_state.has_definite_width()) containing_block_state.set_content_width(INFINITY); else if (containing_block.computed_values().width().is_auto()) containing_block_state.set_content_width(containing_block_width_for(containing_block)); diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index 7d67780a02..8d153a73c1 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -25,8 +25,10 @@ LayoutState::UsedValues& LayoutState::get_mutable(NodeWithStyleAndBoxModelMetric } } + auto const* containing_block_used_values = box.is_initial_containing_block_box() ? nullptr : &get(*box.containing_block()); + used_values_per_layout_node[serial_id] = adopt_own(*new UsedValues); - used_values_per_layout_node[serial_id]->node = const_cast<NodeWithStyleAndBoxModelMetrics*>(&box); + used_values_per_layout_node[serial_id]->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values); return *used_values_per_layout_node[serial_id]; } @@ -40,8 +42,11 @@ LayoutState::UsedValues const& LayoutState::get(NodeWithStyleAndBoxModelMetrics if (ancestor->used_values_per_layout_node[serial_id]) return *ancestor->used_values_per_layout_node[serial_id]; } + + auto const* containing_block_used_values = box.is_initial_containing_block_box() ? nullptr : &get(*box.containing_block()); + const_cast<LayoutState*>(this)->used_values_per_layout_node[serial_id] = adopt_own(*new UsedValues); - const_cast<LayoutState*>(this)->used_values_per_layout_node[serial_id]->node = const_cast<NodeWithStyleAndBoxModelMetrics*>(&box); + const_cast<LayoutState*>(this)->used_values_per_layout_node[serial_id]->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values); return *used_values_per_layout_node[serial_id]; } @@ -56,7 +61,7 @@ void LayoutState::commit() if (!used_values_ptr) continue; auto& used_values = *used_values_ptr; - auto& node = *used_values.node; + auto& node = const_cast<NodeWithStyleAndBoxModelMetrics&>(used_values.node()); // Transfer box model metrics. node.box_model().inset = { used_values.inset_top, used_values.inset_right, used_values.inset_bottom, used_values.inset_left }; @@ -68,7 +73,7 @@ void LayoutState::commit() // For boxes, transfer all the state needed for painting. if (is<Layout::Box>(node)) { - auto& box = static_cast<Layout::Box&>(node); + auto& box = static_cast<Layout::Box const&>(node); auto& paint_box = const_cast<Painting::PaintableBox&>(*box.paint_box()); paint_box.set_offset(used_values.offset); paint_box.set_content_size(used_values.content_width(), used_values.content_height()); @@ -125,6 +130,40 @@ Gfx::FloatRect absolute_content_rect(Box const& box, LayoutState const& state) return rect; } +void LayoutState::UsedValues::set_node(NodeWithStyleAndBoxModelMetrics& node, UsedValues const* containing_block_used_values) +{ + m_node = &node; + + auto const& computed_values = node.computed_values(); + + auto is_definite_size = [&](CSS::LengthPercentage const& size, bool width) { + // A size that can be determined without performing layout; that is, + // a <length>, + // a measure of text (without consideration of line-wrapping), + // a size of the initial containing block, + // or a <percentage> or other formula (such as the “stretch-fit” sizing of non-replaced blocks [CSS2]) that is resolved solely against definite sizes. + + auto containing_block_has_definite_size = containing_block_used_values ? (width ? containing_block_used_values->has_definite_width() : containing_block_used_values->has_definite_height()) : false; + + if (size.is_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 && node.parent() && !node.parent()->computed_values().display().is_flex_inside()) + return containing_block_has_definite_size; + return false; + } + + if (size.is_length()) + return true; + if (size.is_percentage()) + return containing_block_has_definite_size; + // FIXME: Determine if calc() value is definite. + return false; + }; + + m_has_definite_width = is_definite_size(computed_values.width(), true); + m_has_definite_height = is_definite_size(computed_values.height(), false); +} + void LayoutState::UsedValues::set_content_width(float width) { m_content_width = width; diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.h b/Userland/Libraries/LibWeb/Layout/LayoutState.h index 837845554e..b315068348 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.h +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.h @@ -42,14 +42,19 @@ struct LayoutState { } struct UsedValues { - Layout::NodeWithStyleAndBoxModelMetrics* node { nullptr }; + NodeWithStyleAndBoxModelMetrics const& node() const { return *m_node; } + void set_node(NodeWithStyleAndBoxModelMetrics&, UsedValues const* containing_block_used_values); float content_width() const { return m_content_width; } float content_height() const { return m_content_height; } - void set_content_width(float); void set_content_height(float); + bool has_definite_width() const { return m_has_definite_width && width_constraint == SizeConstraint::None; } + bool has_definite_height() const { return m_has_definite_height && height_constraint == SizeConstraint::None; } + void set_has_definite_width(bool value) { m_has_definite_width = value; } + void set_has_definite_height(bool value) { m_has_definite_height = value; } + Gfx::FloatPoint offset; SizeConstraint width_constraint { SizeConstraint::None }; @@ -105,8 +110,13 @@ struct LayoutState { Optional<LineBoxFragmentCoordinate> containing_line_box_fragment; private: + Layout::NodeWithStyleAndBoxModelMetrics* m_node { nullptr }; + float m_content_width { 0 }; float m_content_height { 0 }; + + bool m_has_definite_width { false }; + bool m_has_definite_height { false }; }; void commit(); diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 78f8d4de52..30d78de036 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -192,41 +192,8 @@ 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) +void NodeWithStyle::did_insert_into_layout_tree(CSS::StyleProperties const&) { - // 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 <length>, - // a measure of text (without consideration of line-wrapping), - // a size of the initial containing block, - // or a <percentage> 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_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& computed_style) diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index 59a8efcdc4..70fbb42150 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -169,12 +169,6 @@ public: NonnullRefPtr<NodeWithStyle> create_anonymous_wrapper() const; - bool has_definite_height() const { return m_has_definite_height; } - bool has_definite_width() const { return m_has_definite_width; } - - 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: @@ -186,9 +180,6 @@ private: RefPtr<Gfx::Font> m_font; float m_line_height { 0 }; RefPtr<CSS::ImageStyleValue> m_list_style_image; - - bool m_has_definite_height { false }; - bool m_has_definite_width { false }; }; class NodeWithStyleAndBoxModelMetrics : public NodeWithStyle { |