From 709fe01f523aca754f8e23fc40c53299d0982a94 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sat, 14 Jan 2023 14:48:20 +0100 Subject: [PATCH] LibWeb: Override width calculation for table wrappers Introduce `TableWrapper` type so table wrappers could be distinguished from block containers and override width calculation for table wrappers (CSS 2.2 spec, section 17.5.2) inside BFCs in the way that their width should be equal to width of table box they wrap. --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + Userland/Libraries/LibWeb/Forward.h | 1 + .../LibWeb/Layout/BlockFormattingContext.cpp | 16 +++++++++++ .../LibWeb/Layout/BlockFormattingContext.h | 2 ++ Userland/Libraries/LibWeb/Layout/Node.h | 1 + .../Libraries/LibWeb/Layout/TableWrapper.cpp | 23 +++++++++++++++ .../Libraries/LibWeb/Layout/TableWrapper.h | 28 +++++++++++++++++++ .../Libraries/LibWeb/Layout/TreeBuilder.cpp | 3 +- 8 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/Layout/TableWrapper.cpp create mode 100644 Userland/Libraries/LibWeb/Layout/TableWrapper.h 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);