diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 3ce472d49c..2d99ab0709 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -347,6 +347,7 @@ set(SOURCES Layout/TableFormattingContext.cpp Layout/TableRowBox.cpp Layout/TableRowGroupBox.cpp + Layout/TableWrapper.cpp Layout/TextNode.cpp Layout/TreeBuilder.cpp Loader/ContentFilter.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 74f2c1fb5e..43eb94910c 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -454,6 +454,7 @@ class NodeWithStyle; class NodeWithStyleAndBoxModelMetrics; class RadioButton; class ReplacedBox; +class TableWrapper; class TextNode; } diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index ced4e0f27a..cdd95cf793 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include namespace Web::Layout { @@ -193,6 +195,8 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const& }; auto input_width = [&] { + if (is(box)) + return CSS::Length::make_px(compute_width_for_table_wrapper(box, available_space)); if (should_treat_width_as_auto(box, available_space)) return CSS::Length::make_auto(); return calculate_inner_width(box, available_space.width, computed_values.width()); @@ -312,6 +316,18 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n m_state.get_mutable(box).set_content_width(compute_width_for_replaced_element(m_state, box, available_space)); } +CSSPixels BlockFormattingContext::compute_width_for_table_wrapper(Box const& box, AvailableSpace const& available_space) +{ + // 17.5.2 + // Table wrapper width should be equal to width of table box it contains + LayoutState throwaway_state(&m_state); + auto context = create_independent_formatting_context_if_needed(throwaway_state, box); + VERIFY(context); + context->run(box, LayoutMode::IntrinsicSizing, m_state.get(box).available_inner_space_or_constraints_from(available_space)); + auto const* table_box = box.first_child_of_type(); + return throwaway_state.get(*table_box).content_width(); +} + void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const& available_space) { auto const& computed_values = box.computed_values(); diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 22a97da3df..0c27aeaf0d 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -59,6 +59,8 @@ private: void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox const&, AvailableSpace const&); + CSSPixels compute_width_for_table_wrapper(Box const&, AvailableSpace const&); + void layout_initial_containing_block(LayoutMode, AvailableSpace const&); void layout_block_level_children(BlockContainer const&, LayoutMode, AvailableSpace const&); diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index 4a0c51d42d..109ab80587 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -90,6 +90,7 @@ public: virtual bool is_label() const { return false; } virtual bool is_replaced_box() const { return false; } virtual bool is_list_item_marker_box() const { return false; } + virtual bool is_table_wrapper() const { return false; } template bool fast_is() const = delete; diff --git a/Userland/Libraries/LibWeb/Layout/TableWrapper.cpp b/Userland/Libraries/LibWeb/Layout/TableWrapper.cpp new file mode 100644 index 0000000000..7baa516308 --- /dev/null +++ b/Userland/Libraries/LibWeb/Layout/TableWrapper.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Web::Layout { + +TableWrapper::TableWrapper(DOM::Document& document, DOM::Node* node, NonnullRefPtr style) + : BlockContainer(document, node, move(style)) +{ +} + +TableWrapper::TableWrapper(DOM::Document& document, DOM::Node* node, CSS::ComputedValues computed_values) + : BlockContainer(document, node, move(computed_values)) +{ +} + +TableWrapper::~TableWrapper() = default; + +} diff --git a/Userland/Libraries/LibWeb/Layout/TableWrapper.h b/Userland/Libraries/LibWeb/Layout/TableWrapper.h new file mode 100644 index 0000000000..de707bb783 --- /dev/null +++ b/Userland/Libraries/LibWeb/Layout/TableWrapper.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::Layout { + +class TableWrapper : public BlockContainer { + JS_CELL(TableWrapper, BlockContainer); + +public: + TableWrapper(DOM::Document&, DOM::Node*, NonnullRefPtr); + TableWrapper(DOM::Document&, DOM::Node*, CSS::ComputedValues); + virtual ~TableWrapper() override; + +private: + virtual bool is_table_wrapper() const final { return true; } +}; + +template<> +inline bool Node::fast_is() const { return is_table_wrapper(); } + +} diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index e675830491..bb581bbcd3 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -598,7 +599,7 @@ void TreeBuilder::generate_missing_parents(NodeWithStyle& root) mutable_wrapper_computed_values.set_margin(table_box->computed_values().margin()); table_box->reset_table_box_computed_values_used_by_wrapper_to_init_values(); - auto wrapper = parent.heap().allocate_without_realm(parent.document(), nullptr, move(wrapper_computed_values)); + auto wrapper = parent.heap().allocate_without_realm(parent.document(), nullptr, move(wrapper_computed_values)); parent.remove_child(*table_box); wrapper->append_child(*table_box);