Browse Source

LibWeb: Skip cells layout in table box width calculation

There is no need to run full table layout if we are only interested in
calculating its width.

This change reduces compute_table_box_width_inside_table_wrapper()
from ~30% to ~15% in profiles of "File changed" pages on github.
Aliaksandr Kalenik 1 year ago
parent
commit
6fc59039c4

+ 10 - 5
Userland/Libraries/LibWeb/Layout/FormattingContext.cpp

@@ -405,11 +405,6 @@ CSSPixels FormattingContext::compute_table_box_width_inside_table_wrapper(Box co
     // table-wrapper can't have borders or paddings but it might have margin taken from table-root.
     // table-wrapper can't have borders or paddings but it might have margin taken from table-root.
     auto available_width = width_of_containing_block - margin_left.to_px(box) - margin_right.to_px(box);
     auto available_width = width_of_containing_block - margin_left.to_px(box) - margin_right.to_px(box);
 
 
-    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));
-
     Optional<Box const&> table_box;
     Optional<Box const&> table_box;
     box.for_each_in_subtree_of_type<Box>([&](Box const& child_box) {
     box.for_each_in_subtree_of_type<Box>([&](Box const& child_box) {
         if (child_box.display().is_table_inside()) {
         if (child_box.display().is_table_inside()) {
@@ -420,6 +415,16 @@ CSSPixels FormattingContext::compute_table_box_width_inside_table_wrapper(Box co
     });
     });
     VERIFY(table_box.has_value());
     VERIFY(table_box.has_value());
 
 
+    LayoutState throwaway_state(&m_state);
+
+    auto& table_box_state = throwaway_state.get_mutable(*table_box);
+    auto const& table_box_computed_values = table_box->computed_values();
+    table_box_state.border_left = table_box_computed_values.border_left().width;
+    table_box_state.border_right = table_box_computed_values.border_right().width;
+
+    auto context = make<TableFormattingContext>(throwaway_state, *table_box, this);
+    context->run_until_width_calculation(*table_box, m_state.get(*table_box).available_inner_space_or_constraints_from(available_space));
+
     auto table_used_width = throwaway_state.get(*table_box).border_box_width();
     auto table_used_width = throwaway_state.get(*table_box).border_box_width();
     return available_space.width.is_definite() ? min(table_used_width, available_width) : table_used_width;
     return available_space.width.is_definite() ? min(table_used_width, available_width) : table_used_width;
 }
 }

+ 10 - 3
Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp

@@ -1577,12 +1577,10 @@ void TableFormattingContext::finish_grid_initialization(TableGrid const& table_g
     }
     }
 }
 }
 
 
-void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, AvailableSpace const& available_space)
+void TableFormattingContext::run_until_width_calculation(Box const& box, AvailableSpace const& available_space)
 {
 {
     m_available_space = available_space;
     m_available_space = available_space;
 
 
-    auto total_captions_height = run_caption_layout(layout_mode, CSS::CaptionSide::Top);
-
     // Determine the number of rows/columns the table requires.
     // Determine the number of rows/columns the table requires.
     finish_grid_initialization(TableGrid::calculate_row_column_grid(box, m_cells, m_rows));
     finish_grid_initialization(TableGrid::calculate_row_column_grid(box, m_cells, m_rows));
 
 
@@ -1603,6 +1601,15 @@ void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, Availab
 
 
     // Compute the width of the table.
     // Compute the width of the table.
     compute_table_width();
     compute_table_width();
+}
+
+void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, AvailableSpace const& available_space)
+{
+    m_available_space = available_space;
+
+    auto total_captions_height = run_caption_layout(layout_mode, CSS::CaptionSide::Top);
+
+    run_until_width_calculation(box, available_space);
 
 
     if (available_space.width.is_intrinsic_sizing_constraint() && !available_space.height.is_intrinsic_sizing_constraint()) {
     if (available_space.width.is_intrinsic_sizing_constraint() && !available_space.height.is_intrinsic_sizing_constraint()) {
         return;
         return;

+ 3 - 1
Userland/Libraries/LibWeb/Layout/TableFormattingContext.h

@@ -23,6 +23,8 @@ public:
     explicit TableFormattingContext(LayoutState&, Box const&, FormattingContext* parent);
     explicit TableFormattingContext(LayoutState&, Box const&, FormattingContext* parent);
     ~TableFormattingContext();
     ~TableFormattingContext();
 
 
+    void run_until_width_calculation(Box const&, AvailableSpace const& available_space);
+
     virtual void run(Box const&, LayoutMode, AvailableSpace const&) override;
     virtual void run(Box const&, LayoutMode, AvailableSpace const&) override;
     virtual CSSPixels automatic_content_width() const override;
     virtual CSSPixels automatic_content_width() const override;
     virtual CSSPixels automatic_content_height() const override;
     virtual CSSPixels automatic_content_height() const override;
@@ -146,7 +148,7 @@ private:
     static TableFormattingContext::ConflictingEdge const& winning_conflicting_edge(TableFormattingContext::ConflictingEdge const& a, TableFormattingContext::ConflictingEdge const& b);
     static TableFormattingContext::ConflictingEdge const& winning_conflicting_edge(TableFormattingContext::ConflictingEdge const& a, TableFormattingContext::ConflictingEdge const& b);
 
 
     static const CSS::BorderData& border_data_conflicting_edge(ConflictingEdge const& conflicting_edge);
     static const CSS::BorderData& border_data_conflicting_edge(ConflictingEdge const& conflicting_edge);
-    static const Painting::PaintableBox::BorderDataWithElementKind border_data_with_element_kind_from_conflicting_edge(ConflictingEdge const& conflicting_edge);
+    static Painting::PaintableBox::BorderDataWithElementKind const border_data_with_element_kind_from_conflicting_edge(ConflictingEdge const& conflicting_edge);
 
 
     class BorderConflictFinder {
     class BorderConflictFinder {
     public:
     public: