1 /*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 * (C) 1997 Torben Weis (weis@kde.org)
4 * (C) 1998 Waldo Bastian (bastian@kde.org)
5 * (C) 1999 Lars Knoll (knoll@kde.org)
6 * (C) 1999 Antti Koivisto (koivisto@kde.org)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010 Apple Inc.
8 * All rights reserved.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TABLE_H_
27 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TABLE_H_
28
29 #include <memory>
30 #include "third_party/blink/renderer/core/core_export.h"
31 #include "third_party/blink/renderer/core/css/css_property_names.h"
32 #include "third_party/blink/renderer/core/layout/layout_block.h"
33 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_interface.h"
34 #include "third_party/blink/renderer/platform/graphics/overlay_scrollbar_clip_behavior.h"
35 #include "third_party/blink/renderer/platform/wtf/vector.h"
36
37 namespace blink {
38
39 class LayoutNGTableSectionInterface;
40 class LayoutTableCol;
41 class LayoutTableCaption;
42 class LayoutTableCell;
43 class LayoutTableSection;
44 class TableLayoutAlgorithm;
45
46 enum TableHeightChangingValue { kTableHeightNotChanging, kTableHeightChanging };
47
48 // LayoutTable is the LayoutObject associated with
49 // display: table or inline-table.
50 //
51 // LayoutTable is the coordinator for determining the overall table structure.
52 // The reason is that LayoutTableSection children have a local view over what
53 // their structure is but don't account for other LayoutTableSection. Thus
54 // LayoutTable helps keep consistency across LayoutTableSection. See e.g.
55 // |m_effectiveColumns| below.
56 //
57 // LayoutTable expects only 3 types of children:
58 // - zero or more LayoutTableCol
59 // - zero or more LayoutTableCaption
60 // - zero or more LayoutTableSection
61 // This is aligned with what HTML5 expects:
62 // https://html.spec.whatwg.org/C/#the-table-element
63 // with one difference: we allow more than one caption as we follow what
64 // CSS expects (https://bugs.webkit.org/show_bug.cgi?id=69773).
65 // Those expectations are enforced by LayoutTable::addChild, that wraps unknown
66 // children into an anonymous LayoutTableSection. This is what the "generate
67 // missing child wrapper" step in CSS mandates in
68 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes.
69 //
70 // LayoutTable assumes a pretty strict structure that is mandated by CSS:
71 // (note that this structure in HTML is enforced by the HTML5 Parser).
72 //
73 // LayoutTable
74 // | |
75 // LayoutTableSection LayoutTableCaption
76 // |
77 // LayoutTableRow
78 // |
79 // LayoutTableCell
80 //
81 // This means that we have to generate some anonymous table wrappers in order to
82 // satisfy the structure. See again
83 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes.
84 // The anonymous table wrappers are inserted in LayoutTable::addChild,
85 // LayoutTableSection::addChild, LayoutTableRow::addChild and
86 // LayoutObject::addChild.
87 //
88 // Note that this yields to interesting issues in the insertion code. The DOM
89 // code is unaware of the anonymous LayoutObjects and thus can insert
90 // LayoutObjects into a different part of the layout tree. An example is:
91 //
92 // <!DOCTYPE html>
93 // <style>
94 // tablerow { display: table-row; }
95 // tablecell { display: table-cell; border: 5px solid purple; }
96 // </style>
97 // <tablerow id="firstRow">
98 // <tablecell>Short first row.</tablecell>
99 // </tablerow>
100 // <tablecell id="cell">Long second row, shows the table structure.</tablecell>
101 //
102 // The page generates a single anonymous table (LayoutTable) and table row group
103 // (LayoutTableSection) to wrap the <tablerow> (#firstRow) and an anonymous
104 // table row (LayoutTableRow) for the second <tablecell>.
105 // It is possible for JavaScript to insert a new element between these 2
106 // <tablecell> (using Node.insertBefore), requiring us to split the anonymous
107 // table (or the anonymous table row group) in 2. Also note that even
108 // though the second <tablecell> and <tablerow> are siblings in the DOM tree,
109 // they are not in the layout tree.
110 //
111 //
112 // Note about absolute column index vs effective column index:
113 //
114 // To save memory at the expense of massive code complexity, the code tries
115 // to coalesce columns. This means that we try to the wider column grouping
116 // seen over the LayoutTableSections.
117 //
118 // Note that this is also a defensive pattern as <td colspan="6666666666">
119 // only allocates a single entry in this Vector. This argument is weak
120 // though as we cap colspans in HTMLTableCellElement.
121 //
122 // The following example would have 2 entries [ 3, 2 ] in effectiveColumns():
123 // <table>
124 // <tr>
125 // <td colspan="3"></td>
126 // <td colspan="2"></td>
127 // </tr>
128 // </table>
129 //
130 // Columns can be split if we add a row with a different colspan structure.
131 // See splitEffectiveColumn() and appendEffectiveColumn() for operations
132 // over effectiveColumns() and effectiveColumnPositions().
133 //
134 // See absoluteColumnToEffectiveColumn() for converting an absolute column
135 // index into an index into effectiveColumns() and effectiveColumnPositions().
136
137 class CORE_EXPORT LayoutTable final : public LayoutBlock,
138 public LayoutNGTableInterface {
139 public:
140 explicit LayoutTable(Element*);
141 ~LayoutTable() override;
142
143 // Per CSS 3 writing-mode: "The first and second values of the
144 // 'border-spacing' property represent spacing between columns and rows
145 // respectively, not necessarily the horizontal and vertical spacing
146 // respectively".
HBorderSpacing()147 int16_t HBorderSpacing() const final {
148 NOT_DESTROYED();
149 return h_spacing_;
150 }
VBorderSpacing()151 int16_t VBorderSpacing() const final {
152 NOT_DESTROYED();
153 return v_spacing_;
154 }
155
ShouldCollapseBorders()156 bool ShouldCollapseBorders() const final {
157 NOT_DESTROYED();
158 return StyleRef().BorderCollapse() == EBorderCollapse::kCollapse;
159 }
160
161 LayoutUnit BorderLeft() const override;
162 LayoutUnit BorderRight() const override;
163 LayoutUnit BorderTop() const override;
164 LayoutUnit BorderBottom() const override;
165
166 void AddChild(LayoutObject* child,
167 LayoutObject* before_child = nullptr) override;
168
169 struct ColumnStruct {
170 DISALLOW_NEW();
spanColumnStruct171 explicit ColumnStruct(unsigned initial_span = 1) : span(initial_span) {}
172
173 unsigned span;
174 };
175
ForceSectionsRecalc()176 void ForceSectionsRecalc() final {
177 NOT_DESTROYED();
178 SetNeedsSectionRecalc();
179 RecalcSections();
180 }
181
EffectiveColumns()182 const Vector<ColumnStruct>& EffectiveColumns() const {
183 NOT_DESTROYED();
184 return effective_columns_;
185 }
EffectiveColumnPositions()186 const Vector<int>& EffectiveColumnPositions() const {
187 NOT_DESTROYED();
188 return effective_column_positions_;
189 }
SetEffectiveColumnPosition(unsigned index,int position)190 void SetEffectiveColumnPosition(unsigned index, int position) {
191 NOT_DESTROYED();
192 // Note that if our horizontal border-spacing changed, our position will
193 // change but not our column's width. In practice, horizontal border-spacing
194 // won't change often.
195 column_logical_width_changed_ |=
196 effective_column_positions_[index] != position;
197 effective_column_positions_[index] = position;
198 }
199
Header()200 LayoutTableSection* Header() const {
201 NOT_DESTROYED();
202 DCHECK(!NeedsSectionRecalc());
203 return head_;
204 }
Footer()205 LayoutTableSection* Footer() const {
206 NOT_DESTROYED();
207 DCHECK(!NeedsSectionRecalc());
208 return foot_;
209 }
FirstBody()210 LayoutTableSection* FirstBody() const {
211 NOT_DESTROYED();
212 DCHECK(!NeedsSectionRecalc());
213 return first_body_;
214 }
215
SetRowOffsetFromRepeatingHeader(LayoutUnit offset)216 void SetRowOffsetFromRepeatingHeader(LayoutUnit offset) {
217 NOT_DESTROYED();
218 row_offset_from_repeating_header_ = offset;
219 }
RowOffsetFromRepeatingHeader()220 LayoutUnit RowOffsetFromRepeatingHeader() const final {
221 NOT_DESTROYED();
222 return row_offset_from_repeating_header_;
223 }
224
SetRowOffsetFromRepeatingFooter(LayoutUnit offset)225 void SetRowOffsetFromRepeatingFooter(LayoutUnit offset) {
226 NOT_DESTROYED();
227 row_offset_from_repeating_footer_ = offset;
228 }
RowOffsetFromRepeatingFooter()229 LayoutUnit RowOffsetFromRepeatingFooter() const final {
230 NOT_DESTROYED();
231 return row_offset_from_repeating_footer_;
232 }
233
234 // These functions return nullptr if the table has no sections.
235 LayoutTableSection* TopSection() const;
236 LayoutTableSection* BottomSection() const;
237
238 // These functions return nullptr if the table has no non-empty sections.
239 LayoutTableSection* TopNonEmptySection() const;
240 LayoutTableSection* BottomNonEmptySection() const;
241
LastEffectiveColumnIndex()242 unsigned LastEffectiveColumnIndex() const {
243 NOT_DESTROYED();
244 return NumEffectiveColumns() - 1;
245 }
246
247 void SplitEffectiveColumn(unsigned index, unsigned first_span);
248 void AppendEffectiveColumn(unsigned span);
NumEffectiveColumns()249 unsigned NumEffectiveColumns() const {
250 NOT_DESTROYED();
251 return effective_columns_.size();
252 }
SpanOfEffectiveColumn(unsigned effective_column_index)253 unsigned SpanOfEffectiveColumn(unsigned effective_column_index) const {
254 NOT_DESTROYED();
255 return effective_columns_[effective_column_index].span;
256 }
257
AbsoluteColumnToEffectiveColumn(unsigned absolute_column_index)258 unsigned AbsoluteColumnToEffectiveColumn(
259 unsigned absolute_column_index) const final {
260 NOT_DESTROYED();
261 if (absolute_column_index < no_cell_colspan_at_least_)
262 return absolute_column_index;
263
264 unsigned effective_column = no_cell_colspan_at_least_;
265 unsigned num_columns = NumEffectiveColumns();
266 for (unsigned c = no_cell_colspan_at_least_;
267 effective_column < num_columns &&
268 c + effective_columns_[effective_column].span - 1 <
269 absolute_column_index;
270 ++effective_column)
271 c += effective_columns_[effective_column].span;
272 return effective_column;
273 }
274
EffectiveColumnToAbsoluteColumn(unsigned effective_column_index)275 unsigned EffectiveColumnToAbsoluteColumn(
276 unsigned effective_column_index) const {
277 NOT_DESTROYED();
278 if (effective_column_index < no_cell_colspan_at_least_)
279 return effective_column_index;
280
281 unsigned c = no_cell_colspan_at_least_;
282 for (unsigned i = no_cell_colspan_at_least_; i < effective_column_index;
283 i++)
284 c += effective_columns_[i].span;
285 return c;
286 }
287
BorderSpacingInRowDirection()288 LayoutUnit BorderSpacingInRowDirection() const {
289 NOT_DESTROYED();
290 if (unsigned effective_column_count = NumEffectiveColumns())
291 return static_cast<LayoutUnit>(effective_column_count + 1) *
292 HBorderSpacing();
293
294 return LayoutUnit();
295 }
296
297 // The collapsing border model dissallows paddings on table, which is why we
298 // override those functions.
299 // See http://www.w3.org/TR/CSS2/tables.html#collapsing-borders.
300 LayoutUnit PaddingTop() const override;
301 LayoutUnit PaddingBottom() const override;
302 LayoutUnit PaddingLeft() const override;
303 LayoutUnit PaddingRight() const override;
304
BordersPaddingAndSpacingInRowDirection()305 LayoutUnit BordersPaddingAndSpacingInRowDirection() const {
306 NOT_DESTROYED();
307 // 'border-spacing' only applies to separate borders (see 17.6.1 The
308 // separated borders model).
309 return BorderStart() + BorderEnd() +
310 (ShouldCollapseBorders() ? LayoutUnit()
311 : (PaddingStart() + PaddingEnd() +
312 BorderSpacingInRowDirection()));
313 }
314
315 // Return the first column or column-group.
316 LayoutTableCol* FirstColumn() const;
317
318 struct ColAndColGroup {
ColAndColGroupColAndColGroup319 ColAndColGroup()
320 : col(nullptr),
321 colgroup(nullptr),
322 adjoins_start_border_of_col_group(false),
323 adjoins_end_border_of_col_group(false) {}
324 LayoutTableCol* col;
325 LayoutTableCol* colgroup;
326 bool adjoins_start_border_of_col_group;
327 bool adjoins_end_border_of_col_group;
InnermostColOrColGroupColAndColGroup328 LayoutTableCol* InnermostColOrColGroup() { return col ? col : colgroup; }
329 };
ColElementAtAbsoluteColumn(unsigned absolute_column_index)330 ColAndColGroup ColElementAtAbsoluteColumn(
331 unsigned absolute_column_index) const {
332 NOT_DESTROYED();
333 // The common case is to not have col/colgroup elements, make that case
334 // fast.
335 if (!has_col_elements_)
336 return ColAndColGroup();
337 return SlowColElementAtAbsoluteColumn(absolute_column_index);
338 }
HasColElements()339 bool HasColElements() const final {
340 NOT_DESTROYED();
341 return has_col_elements_;
342 }
343
NeedsSectionRecalc()344 bool NeedsSectionRecalc() const {
345 NOT_DESTROYED();
346 return needs_section_recalc_;
347 }
SetNeedsSectionRecalc()348 void SetNeedsSectionRecalc() {
349 NOT_DESTROYED();
350 if (DocumentBeingDestroyed())
351 return;
352 // For all we know, sections may have been deleted at this point. Don't
353 // keep pointers dangling around.
354 head_ = nullptr;
355 foot_ = nullptr;
356 first_body_ = nullptr;
357
358 needs_section_recalc_ = true;
359 SetNeedsLayoutAndFullPaintInvalidation(
360 layout_invalidation_reason::kTableChanged);
361
362 // Grid structure affects cell adjacence relationships which affect
363 // conflict resolution of collapsed borders.
364 InvalidateCollapsedBorders();
365 }
366
367 LayoutTableSection* SectionAbove(
368 const LayoutTableSection*,
369 SkipEmptySectionsValue = kDoNotSkipEmptySections) const;
370 LayoutTableSection* SectionBelow(
371 const LayoutTableSection*,
372 SkipEmptySectionsValue = kDoNotSkipEmptySections) const;
373
374 // Returns the adjacent cell to the logical top, logical bottom, logical left
375 // and logical right, respectively, of the given cell, in the table's
376 // direction. If there are multiple adjacent cells in the direction due to row
377 // or col spans, returns the primary LayoutTableCell of the first (in DOM
378 // order) adjacent TableGridCell in the direction. Returns nullptr if there
379 // are no adjacent cells in the direction.
380 LayoutTableCell* CellAbove(const LayoutTableCell&) const;
381 LayoutTableCell* CellBelow(const LayoutTableCell&) const;
382 LayoutTableCell* CellPreceding(const LayoutTableCell&) const;
383 LayoutTableCell* CellFollowing(const LayoutTableCell&) const;
384
385 void InvalidateCollapsedBorders();
386 void InvalidateCollapsedBordersForAllCellsIfNeeded();
387
HasCollapsedBorders()388 bool HasCollapsedBorders() const final {
389 NOT_DESTROYED();
390 DCHECK(collapsed_borders_valid_);
391 return has_collapsed_borders_;
392 }
NeedsAdjustCollapsedBorderJoints()393 bool NeedsAdjustCollapsedBorderJoints() const {
394 NOT_DESTROYED();
395 DCHECK(collapsed_borders_valid_);
396 return needs_adjust_collapsed_border_joints_;
397 }
398
HasSections()399 bool HasSections() const {
400 NOT_DESTROYED();
401 return Header() || Footer() || FirstBody();
402 }
403
RecalcSectionsIfNeeded()404 void RecalcSectionsIfNeeded() const final {
405 NOT_DESTROYED();
406 if (needs_section_recalc_)
407 RecalcSections();
408 }
409
410 LayoutBox* CreateAnonymousBoxWithSameTypeAs(
411 const LayoutObject* parent) const override;
412
413 void AddCaption(const LayoutTableCaption*);
414 void RemoveCaption(const LayoutTableCaption*);
415 void AddColumn(const LayoutTableCol*);
416 void RemoveColumn(const LayoutTableCol*);
417
418 void PaintBoxDecorationBackground(
419 const PaintInfo&,
420 const PhysicalOffset& paint_offset) const final;
421
422 void PaintMask(const PaintInfo&,
423 const PhysicalOffset& paint_offset) const final;
424
425 void SubtractCaptionRect(PhysicalRect&) const;
426
427 bool IsLogicalWidthAuto() const;
428
GetName()429 const char* GetName() const override {
430 NOT_DESTROYED();
431 return "LayoutTable";
432 }
433
434 // Whether a table has opaque foreground depends on many factors, e.g. border
435 // spacing, missing cells, etc. For simplicity, just conservatively assume
436 // foreground of all tables are not opaque.
ForegroundIsKnownToBeOpaqueInRect(const PhysicalRect &,unsigned)437 bool ForegroundIsKnownToBeOpaqueInRect(const PhysicalRect&,
438 unsigned) const override {
439 NOT_DESTROYED();
440 return false;
441 }
442
443 enum WhatToMarkAllCells { kMarkDirtyOnly, kMarkDirtyAndNeedsLayout };
444 void MarkAllCellsWidthsDirtyAndOrNeedsLayout(WhatToMarkAllCells);
445
446 bool IsAbsoluteColumnCollapsed(unsigned absolute_column_index) const;
447
IsAnyColumnEverCollapsed()448 bool IsAnyColumnEverCollapsed() const {
449 NOT_DESTROYED();
450 return is_any_column_ever_collapsed_;
451 }
452
453 void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
454 void SimplifiedNormalFlowLayout() override;
455
456 RecalcLayoutOverflowResult RecalcLayoutOverflow() final;
457 void RecalcVisualOverflow() final;
458
459 void EnsureIsReadyForPaintInvalidation() override;
460 void InvalidatePaint(const PaintInvalidatorContext&) const override;
461 void ColumnStructureChanged();
462
463 // LayoutNGTableInterface methods start.
464
ToLayoutNGTableInterface()465 const LayoutNGTableInterface* ToLayoutNGTableInterface() const final {
466 NOT_DESTROYED();
467 return this;
468 }
ToLayoutObject()469 const LayoutObject* ToLayoutObject() const final {
470 NOT_DESTROYED();
471 return this;
472 }
ToMutableLayoutObject()473 LayoutObject* ToMutableLayoutObject() final {
474 NOT_DESTROYED();
475 return this;
476 }
IsFixedTableLayout()477 bool IsFixedTableLayout() const final {
478 NOT_DESTROYED();
479 return StyleRef().IsFixedTableLayout();
480 }
481 LayoutNGTableSectionInterface* FirstBodyInterface() const final;
482 LayoutNGTableSectionInterface* TopSectionInterface() const final;
483 LayoutNGTableSectionInterface* TopNonEmptySectionInterface() const final;
484 LayoutNGTableSectionInterface* BottomSectionInterface() const final;
485 LayoutNGTableSectionInterface* BottomNonEmptySectionInterface() const final;
486 LayoutNGTableSectionInterface* SectionBelowInterface(
487 const LayoutNGTableSectionInterface*,
488 SkipEmptySectionsValue) const final;
489 bool IsFirstCell(const LayoutNGTableCellInterface&) const final;
490
491 // LayoutNGTableInterface methods end.
492
493 private:
IsOfType(LayoutObjectType type)494 bool IsOfType(LayoutObjectType type) const override {
495 NOT_DESTROYED();
496 return type == kLayoutObjectTable || LayoutBlock::IsOfType(type);
497 }
498
499 void PaintObject(const PaintInfo&,
500 const PhysicalOffset& paint_offset) const override;
501 void UpdateLayout() override;
502 MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
503 MinMaxSizes PreferredLogicalWidths() const override;
504 bool NodeAtPoint(HitTestResult&,
505 const HitTestLocation&,
506 const PhysicalOffset& accumulated_offset,
507 HitTestAction) override;
508
509 LayoutUnit BaselinePosition(
510 FontBaseline,
511 bool first_line,
512 LineDirectionMode,
513 LinePositionMode = kPositionOnContainingLine) const override;
514 LayoutUnit FirstLineBoxBaseline() const override;
515 LayoutUnit InlineBlockBaseline(LineDirectionMode) const override;
516
517 ColAndColGroup SlowColElementAtAbsoluteColumn(unsigned col) const;
518
519 void UpdateColumnCache() const;
520 void InvalidateCachedColumns();
521
522 void UpdateLogicalWidth() override;
523
524 LayoutUnit ConvertStyleLogicalWidthToComputedWidth(
525 const Length& style_logical_width,
526 LayoutUnit available_width) const;
527 LayoutUnit ConvertStyleLogicalHeightToComputedHeight(
528 const Length& style_logical_height) const;
529
530 PhysicalRect OverflowClipRect(const PhysicalOffset& location,
531 OverlayScrollbarClipBehavior =
532 kIgnoreOverlayScrollbarSize) const override;
533
534 void ComputeVisualOverflow(bool recompute_floats) final;
535
536 void AddVisualOverflowFromChildren();
537 void AddLayoutOverflowFromChildren() override;
538
539 void RecalcSections() const;
540
541 void UpdateCollapsedOuterBorders() const;
542
543 void LayoutCaption(LayoutTableCaption&, SubtreeLayoutScope&);
544 void LayoutSection(LayoutTableSection&,
545 SubtreeLayoutScope&,
546 LayoutUnit logical_left,
547 TableHeightChangingValue);
548
549 // If any columns are collapsed, populates given vector with how much width is
550 // collapsed in each column. If no columns are collapsed, given vector remains
551 // empty. Logical width of table is adjusted.
552 void AdjustWidthsForCollapsedColumns(Vector<int>&);
553
554 // Return the logical height based on the height, min-height and max-height
555 // properties from CSS. Will return 0 if auto.
556 LayoutUnit LogicalHeightFromStyle() const;
557
558 void DistributeExtraLogicalHeight(int extra_logical_height);
559
SetIsAnyColumnEverCollapsed()560 void SetIsAnyColumnEverCollapsed() {
561 NOT_DESTROYED();
562 is_any_column_ever_collapsed_ = true;
563 }
564
565 // TODO(layout-dev): All mutables in this class are lazily updated by
566 // recalcSections() which is called by various getter methods (e.g.
567 // borderBefore(), borderAfter()).
568 // They allow dirty layout even after DocumentLifecycle::LayoutClean which
569 // seems not proper. crbug.com/538236.
570
571 // Holds spans (number of absolute columns) of effective columns.
572 // See "absolute column index vs effective column index" in comments of
573 // LayoutTable.
574 mutable Vector<ColumnStruct> effective_columns_;
575
576 // Holds the logical layout positions of effective columns, and the last item
577 // (whose index is numEffectiveColumns()) holds the position of the imaginary
578 // column after the last column.
579 // Because of the last item, m_effectiveColumnPositions.size() is always
580 // numEffectiveColumns() + 1.
581 mutable Vector<int> effective_column_positions_;
582
583 // The captions associated with this object.
584 mutable Vector<LayoutTableCaption*> captions_;
585
586 // Holds pointers to LayoutTableCol objects for <col>s and <colgroup>s under
587 // this table.
588 // There is no direct relationship between the size of and index into this
589 // vector and those of m_effectiveColumns because they hold different things.
590 mutable Vector<LayoutTableCol*> column_layout_objects_;
591
592 mutable LayoutTableSection* head_;
593 mutable LayoutTableSection* foot_;
594 mutable LayoutTableSection* first_body_;
595
596 // The layout algorithm used by this table.
597 //
598 // CSS 2.1 defines 2 types of table layouts toggled with 'table-layout':
599 // fixed (TableLayoutAlgorithmFixed) and auto (TableLayoutAlgorithmAuto).
600 // See http://www.w3.org/TR/CSS21/tables.html#width-layout.
601 //
602 // The layout algorithm is delegated to TableLayoutAlgorithm. This enables
603 // changing 'table-layout' without having to reattach the <table>.
604 //
605 // As the algorithm is dependent on the style, this field is nullptr before
606 // the first style is applied in styleDidChange().
607 std::unique_ptr<TableLayoutAlgorithm> table_layout_;
608
609 // Collapsed borders are SUPER EXPENSIVE to compute. The reason is that we
610 // need to compare a cells border against all the adjoining cells, rows,
611 // row groups, column, column groups and table. Thus we cache the values in
612 // LayoutTableCells and some status here.
613 bool collapsed_borders_valid_ : 1;
614 bool has_collapsed_borders_ : 1;
615 bool needs_adjust_collapsed_border_joints_ : 1;
616 bool needs_invalidate_collapsed_borders_for_all_cells_ : 1;
617 mutable bool collapsed_outer_borders_valid_ : 1;
618
619 // Whether any column in the table section is or has been collapsed.
620 bool is_any_column_ever_collapsed_ : 1;
621
622 mutable bool has_col_elements_ : 1;
623 mutable bool needs_section_recalc_ : 1;
624
625 bool column_logical_width_changed_ : 1;
626 // This flag indicates whether any columns (with or without fixed widths) have
627 // been added or removed since the last layout. If they have, then the true
628 // size of the cell contents needs to be determined with a full layout before
629 // the layout cache is updated. The layout cache can be invalid when layout is
630 // valid (e.g. if the table is being painted for the first time).
631 mutable bool column_structure_changed_ : 1;
632 mutable bool column_layout_objects_valid_ : 1;
633 mutable unsigned no_cell_colspan_at_least_;
CalcNoCellColspanAtLeast()634 unsigned CalcNoCellColspanAtLeast() const {
635 NOT_DESTROYED();
636 for (unsigned c = 0; c < NumEffectiveColumns(); c++) {
637 if (effective_columns_[c].span > 1)
638 return c;
639 }
640 return NumEffectiveColumns();
641 }
642
LogicalCollapsedOuterBorderToPhysical()643 LogicalToPhysical<unsigned> LogicalCollapsedOuterBorderToPhysical() const {
644 NOT_DESTROYED();
645 return LogicalToPhysical<unsigned>(
646 StyleRef().GetWritingDirection(), collapsed_outer_border_start_,
647 collapsed_outer_border_end_, collapsed_outer_border_before_,
648 collapsed_outer_border_after_);
649 }
650
651 int16_t h_spacing_;
652 int16_t v_spacing_;
653
654 // See UpdateCollapsedOuterBorders().
655 mutable unsigned collapsed_outer_border_start_;
656 mutable unsigned collapsed_outer_border_end_;
657 mutable unsigned collapsed_outer_border_before_;
658 mutable unsigned collapsed_outer_border_after_;
659 mutable unsigned collapsed_outer_border_start_overflow_;
660 mutable unsigned collapsed_outer_border_end_overflow_;
661
662 LayoutUnit row_offset_from_repeating_header_;
663 LayoutUnit row_offset_from_repeating_footer_;
664 LayoutUnit old_available_logical_height_;
665 };
666
TopSection()667 inline LayoutTableSection* LayoutTable::TopSection() const {
668 DCHECK(!NeedsSectionRecalc());
669 if (head_)
670 return head_;
671 if (first_body_)
672 return first_body_;
673 return foot_;
674 }
675
676 // To<LayoutTable>() helper.
677 template <>
678 struct DowncastTraits<LayoutTable> {
679 static bool AllowFrom(const LayoutObject& object) { return object.IsTable(); }
680 };
681
682 } // namespace blink
683
684 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TABLE_H_
685