blob: 538d97bd3c73f6cd2bfa742331640985f7eaa020 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_LAYOUT_NG_TABLE_COLUMN_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_LAYOUT_NG_TABLE_COLUMN_VISITOR_H_
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h"
namespace blink {
// Rules for computed spans of COLGROUP/COL elements are complicated.
// 1) Spans cannot protrude outside of table boundary.
// 2) Colgroup span is
// a) sum of children COL spans if it has children.
// b) span attribute if it has no children.
//
// This function implements a Visitor pattern for LayoutNGTableColumn
// traversal, and computes correct spans.
//
// class Visitor {
// void VisitCol(const NGBlockNode& column,
// wtf_size_t start_column_index,
// wtf_size_t span);
// void EnterColgroup(const NGBlockNode& colgroup,
// wtf_size_t start_column_index);
// void LeaveColgroup(const NGBlockNode& colgroup,
// wtf_size_t start_column_index,
// wtf_size_t span,
// bool has_children);
// }
template <typename Visitor>
void VisitLayoutNGTableColumn(const Vector<NGBlockNode>& columns,
wtf_size_t table_column_count,
Visitor* visitor) {
wtf_size_t current_column_index = 0;
auto VisitCol = [&](const NGBlockNode& col) {
wtf_size_t span = col.TableColumnSpan();
span = std::min(span, table_column_count - current_column_index);
visitor->VisitCol(col, current_column_index, span);
current_column_index += span;
return span;
};
for (const NGBlockNode& table_column : columns) {
// Col spans can cause columns to extend beyond table's edge.
// These columns are ignored.
if (current_column_index >= table_column_count)
break;
if (table_column.IsTableCol()) { // COL element.
VisitCol(table_column);
continue;
}
DCHECK(table_column.IsTableColgroup());
// Visit COLGROUP element.
visitor->EnterColgroup(table_column, current_column_index);
NGBlockNode col_child = To<NGBlockNode>(table_column.FirstChild());
wtf_size_t colgroup_start_index = current_column_index;
wtf_size_t colgroup_span = 0;
bool has_children = bool(col_child);
if (col_child) {
while (col_child) {
colgroup_span += VisitCol(col_child);
if (current_column_index >= table_column_count)
break;
col_child = To<NGBlockNode>(col_child.NextSibling());
}
} else {
// If COLGROUP has no children, its span is defined by the COLGROUP.
colgroup_span = std::min(table_column.TableColumnSpan(),
table_column_count - current_column_index);
current_column_index += colgroup_span;
}
visitor->LeaveColgroup(table_column, colgroup_start_index, colgroup_span,
has_children);
}
}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_LAYOUT_NG_TABLE_COLUMN_VISITOR_H_