Skip to content

Commit

Permalink
Store more information on table break tokens.
Browse files Browse the repository at this point in the history
This way we avoid O(n^m) performance complexity [1] in subsequent
fragments. When performing the initial table layout measure pass for
non-first fragments, we are pretty much guaranteed to miss the measure
cache, because of CL:3967751. This is something we cannot afford when
nested tables are involved. The whole ComputeRows() design depends on
cache hits, or we'd descend all the way to the innermost table for each
table we attempt to lay out.

[1] O(n^m): 'n' is the "amount of content" inside the tables, 'm' is the
number of tables nested.

This makes perf_tests/layout/multicol/deeply-nested-tables-2.html
about 700 times faster.

(cherry picked from commit 2c12f88)

Bug: 1400918
Change-Id: Ib7fafe2b13f6f7ba35f74b3f49937d4d621178ad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4151250
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1090986}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4158032
Auto-Submit: Morten Stenshorne <mstensho@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5481@{#249}
Cr-Branched-From: 130f3e4-refs/heads/main@{#1084008}
  • Loading branch information
mstensho authored and Chromium LUCI CQ committed Jan 12, 2023
1 parent 8c6ce10 commit efce398
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,34 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_NG_TABLE_BREAK_TOKEN_DATA_H_

#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token_data.h"
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_types.h"

namespace blink {

struct NGTableBreakTokenData final : NGBlockBreakTokenData {
NGTableBreakTokenData(const NGBlockBreakTokenData* break_token_data,
LayoutUnit consumed_table_box_block_size,
bool has_entered_table_box,
bool is_past_table_box)
NGTableBreakTokenData(
const NGBlockBreakTokenData* break_token_data,
const NGTableTypes::Rows& rows,
const NGTableTypes::CellBlockConstraints& cell_block_constraints,
const NGTableTypes::Sections& sections,
LayoutUnit total_table_min_block_size,
LayoutUnit consumed_table_box_block_size,
bool has_entered_table_box,
bool is_past_table_box)
: NGBlockBreakTokenData(kTableBreakTokenData, break_token_data),
rows(rows),
cell_block_constraints(cell_block_constraints),
sections(sections),
total_table_min_block_size(total_table_min_block_size),
consumed_table_box_block_size(consumed_table_box_block_size),
has_entered_table_box(has_entered_table_box),
is_past_table_box(is_past_table_box) {}
// Table layout information that will be the same for all fragments to be
// generated (but potentially very expensive to calculate).
NGTableTypes::Rows rows;
NGTableTypes::CellBlockConstraints cell_block_constraints;
NGTableTypes::Sections sections;
LayoutUnit total_table_min_block_size;

// Similar to |consumed_block_size|, but it only counts space consumed by the
// table box itself, i.e. excluding any captions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,23 +754,31 @@ void NGTableLayoutAlgorithm::ComputeRows(
DCHECK_EQ(rows->size(), 0u);
DCHECK_EQ(cell_block_constraints->size(), 0u);

// If this isn't the first fragment, avoid side-effects. We need to leave the
// NGLayoutResult vector in LayoutBox objects alone, since we're in the middle
// of building those.
absl::optional<NGDisableSideEffectsScope> disable_side_effects;
if (IsBreakInside(BreakToken()))
disable_side_effects.emplace();

const bool is_table_block_size_specified = !Style().LogicalHeight().IsAuto();
LayoutUnit total_table_block_size;
wtf_size_t section_index = 0;
for (auto it = grouped_children.begin(); it != grouped_children.end(); ++it) {
NGTableAlgorithmUtils::ComputeSectionMinimumRowBlockSizes(
*it, table_grid_inline_size, is_table_block_size_specified,
column_locations, table_borders, border_spacing.block_size,
section_index++, it.TreatAsTBody(), sections, rows,
cell_block_constraints);
total_table_block_size += sections->back().block_size;
const NGTableBreakTokenData* table_break_data = nullptr;
if (BreakToken()) {
table_break_data =
DynamicTo<NGTableBreakTokenData>(BreakToken()->TokenData());
}
if (table_break_data) {
DCHECK(IsBreakInside(BreakToken()));
*rows = table_break_data->rows;
*cell_block_constraints = table_break_data->cell_block_constraints;
*sections = table_break_data->sections;
total_table_min_block_size_ = table_break_data->total_table_min_block_size;
} else {
DCHECK_EQ(total_table_min_block_size_, LayoutUnit());
const bool is_table_block_size_specified =
!Style().LogicalHeight().IsAuto();
wtf_size_t section_index = 0;
for (auto it = grouped_children.begin(); it != grouped_children.end();
++it) {
NGTableAlgorithmUtils::ComputeSectionMinimumRowBlockSizes(
*it, table_grid_inline_size, is_table_block_size_specified,
column_locations, table_borders, border_spacing.block_size,
section_index++, it.TreatAsTBody(), sections, rows,
cell_block_constraints);
total_table_min_block_size_ += sections->back().block_size;
}
}

LayoutUnit css_table_block_size;
Expand Down Expand Up @@ -809,7 +817,7 @@ void NGTableLayoutAlgorithm::ComputeRows(
*minimal_table_grid_block_size = css_table_block_size;
LayoutUnit distributable_block_size = std::max(
LayoutUnit(), css_table_block_size - table_border_padding.BlockSum());
if (distributable_block_size > total_table_block_size) {
if (distributable_block_size > total_table_min_block_size_) {
NGTableAlgorithmHelpers::DistributeTableBlockSizeToSections(
border_spacing.block_size, distributable_block_size, sections, rows);
}
Expand Down Expand Up @@ -1597,7 +1605,8 @@ const NGLayoutResult* NGTableLayoutAlgorithm::GenerateFragment(

container_builder_.SetBreakTokenData(
MakeGarbageCollected<NGTableBreakTokenData>(
container_builder_.GetBreakTokenData(),
container_builder_.GetBreakTokenData(), rows,
cell_block_constraints, sections, total_table_min_block_size_,
consumed_table_box_block_size, has_entered_table_box,
is_past_table_box));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class CORE_EXPORT NGTableLayoutAlgorithm
const NGTableBorders& table_borders,
const LogicalSize& border_spacing);

LayoutUnit total_table_min_block_size_;

// Set to true when we're re-laying out without repeating table headers and
// footers.
bool is_known_to_be_last_table_box_ = false;
Expand Down

0 comments on commit efce398

Please sign in to comment.