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, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
8 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
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.
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.
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.
27 #include "core/layout/LayoutTable.h"
29 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/frame/FrameView.h"
32 #include "core/html/HTMLTableElement.h"
33 #include "core/layout/HitTestResult.h"
34 #include "core/layout/LayoutAnalyzer.h"
35 #include "core/layout/LayoutTableCaption.h"
36 #include "core/layout/LayoutTableCell.h"
37 #include "core/layout/LayoutTableCol.h"
38 #include "core/layout/LayoutTableSection.h"
39 #include "core/layout/LayoutView.h"
40 #include "core/layout/SubtreeLayoutScope.h"
41 #include "core/layout/TableLayoutAlgorithmAuto.h"
42 #include "core/layout/TableLayoutAlgorithmFixed.h"
43 #include "core/layout/TextAutosizer.h"
44 #include "core/paint/BoxPainter.h"
45 #include "core/paint/DeprecatedPaintLayer.h"
46 #include "core/paint/TablePainter.h"
47 #include "core/style/StyleInheritedData.h"
51 using namespace HTMLNames
;
53 LayoutTable::LayoutTable(Element
* element
)
54 : LayoutBlock(element
)
57 , m_firstBody(nullptr)
58 , m_currentBorder(nullptr)
59 , m_collapsedBordersValid(false)
60 , m_hasColElements(false)
61 , m_needsSectionRecalc(false)
62 , m_columnLogicalWidthChanged(false)
63 , m_columnLayoutObjectsValid(false)
64 , m_hasCellColspanThatDeterminesTableWidth(false)
70 ASSERT(!childrenInline());
71 m_columnPos
.fill(0, 1);
74 LayoutTable::~LayoutTable()
78 void LayoutTable::styleDidChange(StyleDifference diff
, const ComputedStyle
* oldStyle
)
80 LayoutBlock::styleDidChange(diff
, oldStyle
);
81 propagateStyleToAnonymousChildren();
83 bool oldFixedTableLayout
= oldStyle
? oldStyle
->isFixedTableLayout() : false;
85 // In the collapsed border model, there is no cell spacing.
86 m_hSpacing
= collapseBorders() ? 0 : style()->horizontalBorderSpacing();
87 m_vSpacing
= collapseBorders() ? 0 : style()->verticalBorderSpacing();
88 m_columnPos
[0] = m_hSpacing
;
90 if (!m_tableLayout
|| style()->isFixedTableLayout() != oldFixedTableLayout
) {
92 m_tableLayout
->willChangeTableLayout();
94 // According to the CSS2 spec, you only use fixed table layout if an
95 // explicit width is specified on the table. Auto width implies auto table layout.
96 if (style()->isFixedTableLayout())
97 m_tableLayout
= adoptPtr(new TableLayoutAlgorithmFixed(this));
99 m_tableLayout
= adoptPtr(new TableLayoutAlgorithmAuto(this));
102 // If border was changed, invalidate collapsed borders cache.
103 if (!needsLayout() && oldStyle
&& oldStyle
->border() != style()->border())
104 invalidateCollapsedBorders();
107 static inline void resetSectionPointerIfNotBefore(LayoutTableSection
*& ptr
, LayoutObject
* before
)
111 LayoutObject
* o
= before
->previousSibling();
112 while (o
&& o
!= ptr
)
113 o
= o
->previousSibling();
118 static inline bool needsTableSection(LayoutObject
* object
)
120 // Return true if 'object' can't exist in an anonymous table without being
121 // wrapped in a table section box.
122 EDisplay display
= object
->style()->display();
123 return display
!= TABLE_CAPTION
&& display
!= TABLE_COLUMN_GROUP
&& display
!= TABLE_COLUMN
;
126 void LayoutTable::addChild(LayoutObject
* child
, LayoutObject
* beforeChild
)
128 bool wrapInAnonymousSection
= !child
->isOutOfFlowPositioned();
130 if (child
->isTableCaption()) {
131 wrapInAnonymousSection
= false;
132 } else if (child
->isLayoutTableCol()) {
133 m_hasColElements
= true;
134 wrapInAnonymousSection
= false;
135 } else if (child
->isTableSection()) {
136 switch (child
->style()->display()) {
137 case TABLE_HEADER_GROUP
:
138 resetSectionPointerIfNotBefore(m_head
, beforeChild
);
140 m_head
= toLayoutTableSection(child
);
142 resetSectionPointerIfNotBefore(m_firstBody
, beforeChild
);
144 m_firstBody
= toLayoutTableSection(child
);
146 wrapInAnonymousSection
= false;
148 case TABLE_FOOTER_GROUP
:
149 resetSectionPointerIfNotBefore(m_foot
, beforeChild
);
151 m_foot
= toLayoutTableSection(child
);
152 wrapInAnonymousSection
= false;
156 case TABLE_ROW_GROUP
:
157 resetSectionPointerIfNotBefore(m_firstBody
, beforeChild
);
159 m_firstBody
= toLayoutTableSection(child
);
160 wrapInAnonymousSection
= false;
163 ASSERT_NOT_REACHED();
166 wrapInAnonymousSection
= true;
169 if (child
->isTableSection())
170 setNeedsSectionRecalc();
172 if (!wrapInAnonymousSection
) {
173 if (beforeChild
&& beforeChild
->parent() != this)
174 beforeChild
= splitAnonymousBoxesAroundChild(beforeChild
);
176 LayoutBox::addChild(child
, beforeChild
);
180 if (!beforeChild
&& lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
181 lastChild()->addChild(child
);
185 if (beforeChild
&& !beforeChild
->isAnonymous() && beforeChild
->parent() == this) {
186 LayoutObject
* section
= beforeChild
->previousSibling();
187 if (section
&& section
->isTableSection() && section
->isAnonymous()) {
188 section
->addChild(child
);
193 LayoutObject
* lastBox
= beforeChild
;
194 while (lastBox
&& lastBox
->parent()->isAnonymous() && !lastBox
->isTableSection() && needsTableSection(lastBox
))
195 lastBox
= lastBox
->parent();
196 if (lastBox
&& lastBox
->isAnonymous() && !isAfterContent(lastBox
)) {
197 if (beforeChild
== lastBox
)
198 beforeChild
= lastBox
->slowFirstChild();
199 lastBox
->addChild(child
, beforeChild
);
203 if (beforeChild
&& !beforeChild
->isTableSection() && needsTableSection(beforeChild
))
206 LayoutTableSection
* section
= LayoutTableSection::createAnonymousWithParent(this);
207 addChild(section
, beforeChild
);
208 section
->addChild(child
);
211 void LayoutTable::addChildIgnoringContinuation(LayoutObject
* newChild
, LayoutObject
* beforeChild
)
213 // We need to bypass the LayoutBlock implementation and instead do a normal addChild() (or we
214 // won't get there at all), so that any missing anonymous table part layoutObjects are
215 // inserted. Otherwise we might end up with an insane layout tree with inlines or blocks as
216 // direct children of a table, which will break assumptions made all over the code, which may
217 // lead to crashers and security issues.
218 addChild(newChild
, beforeChild
);
221 void LayoutTable::addCaption(const LayoutTableCaption
* caption
)
223 ASSERT(m_captions
.find(caption
) == kNotFound
);
224 m_captions
.append(const_cast<LayoutTableCaption
*>(caption
));
227 void LayoutTable::removeCaption(const LayoutTableCaption
* oldCaption
)
229 size_t index
= m_captions
.find(oldCaption
);
230 ASSERT(index
!= kNotFound
);
231 if (index
== kNotFound
)
234 m_captions
.remove(index
);
237 void LayoutTable::invalidateCachedColumns()
239 m_columnLayoutObjectsValid
= false;
240 m_columnLayoutObjects
.resize(0);
243 void LayoutTable::addColumn(const LayoutTableCol
*)
245 invalidateCachedColumns();
248 void LayoutTable::removeColumn(const LayoutTableCol
*)
250 invalidateCachedColumns();
251 // We don't really need to recompute our sections, but we need to update our
252 // column count and whether we have a column. Currently, we only have one
253 // size-fit-all flag but we may have to consider splitting it.
254 setNeedsSectionRecalc();
257 void LayoutTable::updateLogicalWidth()
259 recalcSectionsIfNeeded();
261 if (isOutOfFlowPositioned()) {
262 LogicalExtentComputedValues computedValues
;
263 computePositionedLogicalWidth(computedValues
);
264 setLogicalWidth(computedValues
.m_extent
);
265 setLogicalLeft(computedValues
.m_position
);
266 setMarginStart(computedValues
.m_margins
.m_start
);
267 setMarginEnd(computedValues
.m_margins
.m_end
);
270 LayoutBlock
* cb
= containingBlock();
272 LayoutUnit availableLogicalWidth
= containingBlockLogicalWidthForContent() + (isOutOfFlowPositioned() ? cb
->paddingLogicalWidth() : LayoutUnit());
273 bool hasPerpendicularContainingBlock
= cb
->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
274 LayoutUnit containerWidthInInlineDirection
= hasPerpendicularContainingBlock
? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth
;
276 Length styleLogicalWidth
= style()->logicalWidth();
277 if ((styleLogicalWidth
.isSpecified() && styleLogicalWidth
.isPositive()) || styleLogicalWidth
.isIntrinsic()) {
278 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth
, containerWidthInInlineDirection
));
280 // Subtract out any fixed margins from our available width for auto width tables.
281 LayoutUnit marginStart
= minimumValueForLength(style()->marginStart(), availableLogicalWidth
);
282 LayoutUnit marginEnd
= minimumValueForLength(style()->marginEnd(), availableLogicalWidth
);
283 LayoutUnit marginTotal
= marginStart
+ marginEnd
;
285 // Subtract out our margins to get the available content width.
286 LayoutUnit availableContentLogicalWidth
= std::max
<LayoutUnit
>(0, containerWidthInInlineDirection
- marginTotal
);
287 if (shrinkToAvoidFloats() && cb
->isLayoutBlockFlow() && toLayoutBlockFlow(cb
)->containsFloats() && !hasPerpendicularContainingBlock
)
288 availableContentLogicalWidth
= shrinkLogicalWidthToAvoidFloats(marginStart
, marginEnd
, toLayoutBlockFlow(cb
));
290 // Ensure we aren't bigger than our available width.
291 setLogicalWidth(std::min
<int>(availableContentLogicalWidth
, maxPreferredLogicalWidth()));
294 // Ensure we aren't bigger than our max-width style.
295 Length styleMaxLogicalWidth
= style()->logicalMaxWidth();
296 if ((styleMaxLogicalWidth
.isSpecified() && !styleMaxLogicalWidth
.isNegative()) || styleMaxLogicalWidth
.isIntrinsic()) {
297 LayoutUnit computedMaxLogicalWidth
= convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth
, availableLogicalWidth
);
298 setLogicalWidth(std::min
<int>(logicalWidth(), computedMaxLogicalWidth
));
301 // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as
302 // we ignore it if it means we wouldn't accomodate our content.
303 setLogicalWidth(std::max
<int>(logicalWidth(), minPreferredLogicalWidth()));
305 // Ensure we aren't smaller than our min-width style.
306 Length styleMinLogicalWidth
= style()->logicalMinWidth();
307 if ((styleMinLogicalWidth
.isSpecified() && !styleMinLogicalWidth
.isNegative()) || styleMinLogicalWidth
.isIntrinsic()) {
308 LayoutUnit computedMinLogicalWidth
= convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth
, availableLogicalWidth
);
309 setLogicalWidth(std::max
<int>(logicalWidth(), computedMinLogicalWidth
));
312 // Finally, with our true width determined, compute our margins for real.
313 ComputedMarginValues marginValues
;
314 computeMarginsForDirection(InlineDirection
, cb
, availableLogicalWidth
, logicalWidth(), marginValues
.m_start
, marginValues
.m_end
, style()->marginStart(), style()->marginEnd());
315 setMarginStart(marginValues
.m_start
);
316 setMarginEnd(marginValues
.m_end
);
318 // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
319 // its own content which doesn't match CSS nor what authors expect.
320 // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
321 // https://code.google.com/p/chromium/issues/detail?id=241198
322 ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt());
325 // This method takes a ComputedStyle's logical width, min-width, or max-width length and computes its actual value.
326 LayoutUnit
LayoutTable::convertStyleLogicalWidthToComputedWidth(const Length
& styleLogicalWidth
, LayoutUnit availableWidth
)
328 if (styleLogicalWidth
.isIntrinsic())
329 return computeIntrinsicLogicalWidthUsing(styleLogicalWidth
, availableWidth
, bordersPaddingAndSpacingInRowDirection());
331 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
332 LayoutUnit borders
= 0;
333 bool isCSSTable
= !isHTMLTableElement(node());
334 if (isCSSTable
&& styleLogicalWidth
.isSpecified() && styleLogicalWidth
.isPositive() && style()->boxSizing() == CONTENT_BOX
)
335 borders
= borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
337 return minimumValueForLength(styleLogicalWidth
, availableWidth
) + borders
;
340 LayoutUnit
LayoutTable::convertStyleLogicalHeightToComputedHeight(const Length
& styleLogicalHeight
)
342 LayoutUnit borderAndPaddingBefore
= borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
343 LayoutUnit borderAndPaddingAfter
= borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
344 LayoutUnit borderAndPadding
= borderAndPaddingBefore
+ borderAndPaddingAfter
;
345 LayoutUnit computedLogicalHeight
= 0;
346 if (styleLogicalHeight
.isFixed()) {
347 // HTML tables size as though CSS height includes border/padding, CSS tables do not.
348 LayoutUnit borders
= LayoutUnit();
349 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
350 if (isHTMLTableElement(node()) || style()->boxSizing() == BORDER_BOX
) {
351 borders
= borderAndPadding
;
353 computedLogicalHeight
= styleLogicalHeight
.value() - borders
;
354 } else if (styleLogicalHeight
.hasPercent()) {
355 computedLogicalHeight
= computePercentageLogicalHeight(styleLogicalHeight
);
356 } else if (styleLogicalHeight
.isIntrinsic()) {
357 computedLogicalHeight
= computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight
, logicalHeight() - borderAndPadding
, borderAndPadding
);
359 ASSERT_NOT_REACHED();
361 return std::max
<LayoutUnit
>(0, computedLogicalHeight
);
364 void LayoutTable::layoutCaption(LayoutTableCaption
& caption
)
366 if (caption
.needsLayout()) {
367 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
368 // so that it does not mistakenly think any floats in the previous caption intrude into it.
369 caption
.setLogicalLocation(LayoutPoint(caption
.marginStart(), collapsedMarginBeforeForChild(caption
) + logicalHeight()));
370 // If LayoutTableCaption ever gets a layout() function, use it here.
371 caption
.layoutIfNeeded();
373 // Apply the margins to the location now that they are definitely available from layout
374 LayoutUnit captionLogicalTop
= collapsedMarginBeforeForChild(caption
) + logicalHeight();
375 if (view()->layoutState()->isPaginated()) {
376 captionLogicalTop
+= caption
.paginationStrut();
377 caption
.setPaginationStrut(0);
379 caption
.setLogicalLocation(LayoutPoint(caption
.marginStart(), captionLogicalTop
));
381 if (!selfNeedsLayout())
382 caption
.setMayNeedPaintInvalidation();
384 setLogicalHeight(logicalHeight() + caption
.logicalHeight() + collapsedMarginBeforeForChild(caption
) + collapsedMarginAfterForChild(caption
));
387 void LayoutTable::distributeExtraLogicalHeight(int extraLogicalHeight
)
389 if (extraLogicalHeight
<= 0)
392 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
393 if (LayoutTableSection
* section
= firstBody())
394 extraLogicalHeight
-= section
->distributeExtraLogicalHeightToRows(extraLogicalHeight
);
396 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
397 // However our current distribution algorithm does not round properly and thus we can have some remaining height.
398 // ASSERT(!topSection() || !extraLogicalHeight);
401 void LayoutTable::simplifiedNormalFlowLayout()
403 // FIXME: We should walk through the items in the tree in tree order to do the layout here
404 // instead of walking through individual parts of the tree. crbug.com/442737
405 for (auto& caption
: m_captions
)
406 caption
->layoutIfNeeded();
408 for (LayoutTableSection
* section
= topSection(); section
; section
= sectionBelow(section
)) {
409 section
->layoutIfNeeded();
410 section
->layoutRows();
411 section
->computeOverflowFromCells();
412 section
->updateLayerTransformAfterLayout();
413 section
->addVisualEffectOverflow();
417 void LayoutTable::layout()
419 ASSERT(needsLayout());
420 LayoutAnalyzer::Scope
analyzer(*this);
422 if (simplifiedLayout())
425 // Note: LayoutTable is handled differently than other LayoutBlocks and the LayoutScope
426 // must be created before the table begins laying out.
427 TextAutosizer::LayoutScope
textAutosizerLayoutScope(this);
429 recalcSectionsIfNeeded();
430 // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
431 // to call this before we call borderStart/borderEnd to avoid getting a stale value.
432 recalcBordersInRowDirection();
434 SubtreeLayoutScope
layouter(*this);
436 // If any table section moved vertically, we will just issue paint invalidations for everything from that
437 // section down (it is quite unlikely that any of the following sections
439 bool sectionMoved
= false;
441 LayoutState
state(*this, locationOffset());
442 LayoutUnit oldLogicalWidth
= logicalWidth();
443 LayoutUnit oldLogicalHeight
= logicalHeight();
446 updateLogicalWidth();
448 if (logicalWidth() != oldLogicalWidth
) {
449 for (unsigned i
= 0; i
< m_captions
.size(); i
++)
450 layouter
.setNeedsLayout(m_captions
[i
], LayoutInvalidationReason::TableChanged
);
452 // FIXME: The optimisation below doesn't work since the internal table
453 // layout could have changed. We need to add a flag to the table
454 // layout that tells us if something has changed in the min max
455 // calculations to do it correctly.
456 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
457 m_tableLayout
->layout();
459 LayoutUnit totalSectionLogicalHeight
= 0;
460 LayoutUnit oldTableLogicalTop
= 0;
461 for (unsigned i
= 0; i
< m_captions
.size(); i
++)
462 oldTableLogicalTop
+= m_captions
[i
]->logicalHeight() + m_captions
[i
]->marginBefore() + m_captions
[i
]->marginAfter();
464 bool collapsing
= collapseBorders();
466 for (LayoutObject
* child
= firstChild(); child
; child
= child
->nextSibling()) {
467 if (!child
->needsLayout() && child
->isBox())
468 toLayoutBox(child
)->markForPaginationRelayoutIfNeeded(layouter
);
469 if (child
->isTableSection()) {
470 LayoutTableSection
* section
= toLayoutTableSection(child
);
471 if (m_columnLogicalWidthChanged
)
472 layouter
.setChildNeedsLayout(section
);
473 section
->layoutIfNeeded();
474 totalSectionLogicalHeight
+= section
->calcRowLogicalHeight();
476 section
->recalcOuterBorder();
477 ASSERT(!section
->needsLayout());
478 } else if (child
->isLayoutTableCol()) {
479 child
->layoutIfNeeded();
480 ASSERT(!child
->needsLayout());
482 // FIXME: We should never have other type of children (they should be wrapped in an
483 // anonymous table section) but our code is too crazy and this can happen in practice.
484 // Until this is fixed, let's make sure we don't leave non laid out children in the tree.
485 child
->layoutIfNeeded();
489 // FIXME: Collapse caption margin.
490 if (!m_captions
.isEmpty()) {
491 for (unsigned i
= 0; i
< m_captions
.size(); i
++) {
492 if (m_captions
[i
]->style()->captionSide() == CAPBOTTOM
)
494 layoutCaption(*m_captions
[i
]);
496 sectionMoved
= logicalHeight() != oldTableLogicalTop
;
499 LayoutUnit borderAndPaddingBefore
= borderBefore() + (collapsing
? LayoutUnit() : paddingBefore());
500 LayoutUnit borderAndPaddingAfter
= borderAfter() + (collapsing
? LayoutUnit() : paddingAfter());
502 setLogicalHeight(logicalHeight() + borderAndPaddingBefore
);
504 LayoutUnit computedLogicalHeight
= 0;
506 Length logicalHeightLength
= style()->logicalHeight();
507 if (logicalHeightLength
.isIntrinsic() || (logicalHeightLength
.isSpecified() && logicalHeightLength
.isPositive()))
508 computedLogicalHeight
= convertStyleLogicalHeightToComputedHeight(logicalHeightLength
);
510 Length logicalMaxHeightLength
= style()->logicalMaxHeight();
511 if (logicalMaxHeightLength
.isIntrinsic() || (logicalMaxHeightLength
.isSpecified() && !logicalMaxHeightLength
.isNegative())) {
512 LayoutUnit computedMaxLogicalHeight
= convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength
);
513 computedLogicalHeight
= std::min(computedLogicalHeight
, computedMaxLogicalHeight
);
516 Length logicalMinHeightLength
= style()->logicalMinHeight();
517 if (logicalMinHeightLength
.isIntrinsic() || (logicalMinHeightLength
.isSpecified() && !logicalMinHeightLength
.isNegative())) {
518 LayoutUnit computedMinLogicalHeight
= convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength
);
519 computedLogicalHeight
= std::max(computedLogicalHeight
, computedMinLogicalHeight
);
522 distributeExtraLogicalHeight(floorToInt(computedLogicalHeight
- totalSectionLogicalHeight
));
524 for (LayoutTableSection
* section
= topSection(); section
; section
= sectionBelow(section
))
525 section
->layoutRows();
527 if (!topSection() && computedLogicalHeight
> totalSectionLogicalHeight
&& !document().inQuirksMode()) {
528 // Completely empty tables (with no sections or anything) should at least honor specified height
530 setLogicalHeight(logicalHeight() + computedLogicalHeight
);
533 LayoutUnit sectionLogicalLeft
= style()->isLeftToRightDirection() ? borderStart() : borderEnd();
535 sectionLogicalLeft
+= style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
537 // position the table sections
538 LayoutTableSection
* section
= topSection();
540 if (!sectionMoved
&& section
->logicalTop() != logicalHeight())
542 section
->setLogicalLocation(LayoutPoint(sectionLogicalLeft
, logicalHeight()));
544 // As we may skip invalidation on the table, we need to ensure that sections are invalidated when they moved.
545 if (sectionMoved
&& !section
->selfNeedsLayout())
546 section
->setMayNeedPaintInvalidation();
548 setLogicalHeight(logicalHeight() + section
->logicalHeight());
550 section
->updateLayerTransformAfterLayout();
551 section
->addVisualEffectOverflow();
553 section
= sectionBelow(section
);
556 setLogicalHeight(logicalHeight() + borderAndPaddingAfter
);
558 for (unsigned i
= 0; i
< m_captions
.size(); i
++) {
559 if (m_captions
[i
]->style()->captionSide() != CAPBOTTOM
)
561 layoutCaption(*m_captions
[i
]);
564 updateLogicalHeight();
566 // table can be containing block of positioned elements.
567 bool dimensionChanged
= oldLogicalWidth
!= logicalWidth() || oldLogicalHeight
!= logicalHeight();
568 layoutPositionedObjects(dimensionChanged
);
570 updateLayerTransformAfterLayout();
572 // Layout was changed, so probably borders too.
573 invalidateCollapsedBorders();
575 computeOverflow(clientLogicalBottom());
576 updateScrollInfoAfterLayout();
579 // FIXME: This value isn't the intrinsic content logical height, but we need
580 // to update the value as its used by flexbox layout. crbug.com/367324
581 setIntrinsicContentLogicalHeight(contentLogicalHeight());
583 if (view()->layoutState()->pageLogicalHeight())
584 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
586 m_columnLogicalWidthChanged
= false;
590 void LayoutTable::invalidateCollapsedBorders()
592 m_collapsedBorders
.clear();
593 if (!collapseBorders())
596 m_collapsedBordersValid
= false;
597 setMayNeedPaintInvalidation();
600 // Collect all the unique border values that we want to paint in a sorted list.
601 // During the collection, each cell saves its recalculated borders into the cache
602 // of its containing section, and invalidates itself if any border changes.
603 // This method doesn't affect layout.
604 void LayoutTable::recalcCollapsedBordersIfNeeded()
606 if (m_collapsedBordersValid
|| !collapseBorders())
608 m_collapsedBordersValid
= true;
609 m_collapsedBorders
.clear();
610 for (LayoutObject
* section
= firstChild(); section
; section
= section
->nextSibling()) {
611 if (!section
->isTableSection())
613 for (LayoutTableRow
* row
= toLayoutTableSection(section
)->firstRow(); row
; row
= row
->nextRow()) {
614 for (LayoutTableCell
* cell
= row
->firstCell(); cell
; cell
= cell
->nextCell()) {
615 ASSERT(cell
->table() == this);
616 cell
->collectBorderValues(m_collapsedBorders
);
620 LayoutTableCell::sortBorderValues(m_collapsedBorders
);
623 void LayoutTable::addOverflowFromChildren()
625 // Add overflow from borders.
626 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
627 // descendant objects, but since tables don't support overflow:auto, this works out fine.
628 if (collapseBorders()) {
629 int rightBorderOverflow
= size().width() + outerBorderRight() - borderRight();
630 int leftBorderOverflow
= borderLeft() - outerBorderLeft();
631 int bottomBorderOverflow
= size().height() + outerBorderBottom() - borderBottom();
632 int topBorderOverflow
= borderTop() - outerBorderTop();
633 IntRect
borderOverflowRect(leftBorderOverflow
, topBorderOverflow
, rightBorderOverflow
- leftBorderOverflow
, bottomBorderOverflow
- topBorderOverflow
);
634 if (borderOverflowRect
!= pixelSnappedBorderBoxRect()) {
635 LayoutRect
borderLayoutRect(borderOverflowRect
);
636 addLayoutOverflow(borderLayoutRect
);
637 addVisualOverflow(borderLayoutRect
);
641 // Add overflow from our caption.
642 for (unsigned i
= 0; i
< m_captions
.size(); i
++)
643 addOverflowFromChild(m_captions
[i
]);
645 // Add overflow from our sections.
646 for (LayoutTableSection
* section
= topSection(); section
; section
= sectionBelow(section
))
647 addOverflowFromChild(section
);
650 void LayoutTable::paintObject(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
652 TablePainter(*this).paintObject(paintInfo
, paintOffset
);
655 void LayoutTable::subtractCaptionRect(LayoutRect
& rect
) const
657 for (unsigned i
= 0; i
< m_captions
.size(); i
++) {
658 LayoutUnit captionLogicalHeight
= m_captions
[i
]->logicalHeight() + m_captions
[i
]->marginBefore() + m_captions
[i
]->marginAfter();
659 bool captionIsBefore
= (m_captions
[i
]->style()->captionSide() != CAPBOTTOM
) ^ style()->isFlippedBlocksWritingMode();
660 if (style()->isHorizontalWritingMode()) {
661 rect
.setHeight(rect
.height() - captionLogicalHeight
);
663 rect
.move(0, captionLogicalHeight
);
665 rect
.setWidth(rect
.width() - captionLogicalHeight
);
667 rect
.move(captionLogicalHeight
, 0);
672 void LayoutTable::paintBoxDecorationBackground(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
674 TablePainter(*this).paintBoxDecorationBackground(paintInfo
, paintOffset
);
677 void LayoutTable::paintMask(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
679 TablePainter(*this).paintMask(paintInfo
, paintOffset
);
682 void LayoutTable::computeIntrinsicLogicalWidths(LayoutUnit
& minWidth
, LayoutUnit
& maxWidth
) const
684 recalcSectionsIfNeeded();
685 // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
686 // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
687 // of reading out stale values.
688 const_cast<LayoutTable
*>(this)->recalcBordersInRowDirection();
689 // FIXME: Restructure the table layout code so that we can make this method const.
690 const_cast<LayoutTable
*>(this)->m_tableLayout
->computeIntrinsicLogicalWidths(minWidth
, maxWidth
);
692 // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
695 void LayoutTable::computePreferredLogicalWidths()
697 ASSERT(preferredLogicalWidthsDirty());
699 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth
, m_maxPreferredLogicalWidth
);
701 int bordersPaddingAndSpacing
= bordersPaddingAndSpacingInRowDirection();
702 m_minPreferredLogicalWidth
+= bordersPaddingAndSpacing
;
703 m_maxPreferredLogicalWidth
+= bordersPaddingAndSpacing
;
705 m_tableLayout
->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth
, m_maxPreferredLogicalWidth
);
707 for (unsigned i
= 0; i
< m_captions
.size(); i
++)
708 m_minPreferredLogicalWidth
= std::max(m_minPreferredLogicalWidth
, m_captions
[i
]->minPreferredLogicalWidth());
710 const ComputedStyle
& styleToUse
= styleRef();
711 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width.
712 if (styleToUse
.logicalMinWidth().isFixed() && styleToUse
.logicalMinWidth().value() > 0) {
713 m_maxPreferredLogicalWidth
= std::max(m_maxPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.logicalMinWidth().value()));
714 m_minPreferredLogicalWidth
= std::max(m_minPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.logicalMinWidth().value()));
717 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth.
718 if (styleToUse
.logicalMaxWidth().isFixed()) {
719 // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'.
720 m_maxPreferredLogicalWidth
= std::min(m_maxPreferredLogicalWidth
, adjustContentBoxLogicalWidthForBoxSizing(styleToUse
.logicalMaxWidth().value()));
721 m_maxPreferredLogicalWidth
= std::max(m_minPreferredLogicalWidth
, m_maxPreferredLogicalWidth
);
724 // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
725 // so a bunch of tests break doing this naively.
726 clearPreferredLogicalWidthsDirty();
729 LayoutTableSection
* LayoutTable::topNonEmptySection() const
731 LayoutTableSection
* section
= topSection();
732 if (section
&& !section
->numRows())
733 section
= sectionBelow(section
, SkipEmptySections
);
737 void LayoutTable::splitColumn(unsigned position
, unsigned firstSpan
)
739 // We split the column at "position", taking "firstSpan" cells from the span.
740 ASSERT(m_columns
[position
].span
> firstSpan
);
741 m_columns
.insert(position
, ColumnStruct(firstSpan
));
742 m_columns
[position
+ 1].span
-= firstSpan
;
744 // Propagate the change in our columns representation to the sections that don't need
745 // cell recalc. If they do, they will be synced up directly with m_columns later.
746 for (LayoutObject
* child
= firstChild(); child
; child
= child
->nextSibling()) {
747 if (!child
->isTableSection())
750 LayoutTableSection
* section
= toLayoutTableSection(child
);
751 if (section
->needsCellRecalc())
754 section
->splitColumn(position
, firstSpan
);
757 m_columnPos
.grow(numEffCols() + 1);
760 void LayoutTable::appendColumn(unsigned span
)
762 unsigned newColumnIndex
= m_columns
.size();
763 m_columns
.append(ColumnStruct(span
));
765 // Unless the table has cell(s) with colspan that exceed the number of columns afforded
766 // by the other rows in the table we can use the fast path when mapping columns to effective columns.
767 m_hasCellColspanThatDeterminesTableWidth
= m_hasCellColspanThatDeterminesTableWidth
|| span
> 1;
769 // Propagate the change in our columns representation to the sections that don't need
770 // cell recalc. If they do, they will be synced up directly with m_columns later.
771 for (LayoutObject
* child
= firstChild(); child
; child
= child
->nextSibling()) {
772 if (!child
->isTableSection())
775 LayoutTableSection
* section
= toLayoutTableSection(child
);
776 if (section
->needsCellRecalc())
779 section
->appendColumn(newColumnIndex
);
782 m_columnPos
.grow(numEffCols() + 1);
785 LayoutTableCol
* LayoutTable::firstColumn() const
787 for (LayoutObject
* child
= firstChild(); child
; child
= child
->nextSibling()) {
788 if (child
->isLayoutTableCol())
789 return toLayoutTableCol(child
);
795 void LayoutTable::updateColumnCache() const
797 ASSERT(m_hasColElements
);
798 ASSERT(m_columnLayoutObjects
.isEmpty());
799 ASSERT(!m_columnLayoutObjectsValid
);
801 for (LayoutTableCol
* columnLayoutObject
= firstColumn(); columnLayoutObject
; columnLayoutObject
= columnLayoutObject
->nextColumn()) {
802 if (columnLayoutObject
->isTableColumnGroupWithColumnChildren())
804 m_columnLayoutObjects
.append(columnLayoutObject
);
806 m_columnLayoutObjectsValid
= true;
809 LayoutTableCol
* LayoutTable::slowColElement(unsigned col
, bool* startEdge
, bool* endEdge
) const
811 ASSERT(m_hasColElements
);
813 if (!m_columnLayoutObjectsValid
)
816 unsigned columnCount
= 0;
817 for (unsigned i
= 0; i
< m_columnLayoutObjects
.size(); i
++) {
818 LayoutTableCol
* columnLayoutObject
= m_columnLayoutObjects
[i
];
819 unsigned span
= columnLayoutObject
->span();
820 unsigned startCol
= columnCount
;
822 unsigned endCol
= columnCount
+ span
- 1;
824 if (columnCount
> col
) {
826 *startEdge
= startCol
== col
;
828 *endEdge
= endCol
== col
;
829 return columnLayoutObject
;
835 void LayoutTable::recalcSections() const
837 ASSERT(m_needsSectionRecalc
);
841 m_firstBody
= nullptr;
842 m_hasColElements
= false;
843 m_hasCellColspanThatDeterminesTableWidth
= hasCellColspanThatDeterminesTableWidth();
845 // We need to get valid pointers to caption, head, foot and first body again
846 LayoutObject
* nextSibling
;
847 for (LayoutObject
* child
= firstChild(); child
; child
= nextSibling
) {
848 nextSibling
= child
->nextSibling();
849 switch (child
->style()->display()) {
851 case TABLE_COLUMN_GROUP
:
852 m_hasColElements
= true;
854 case TABLE_HEADER_GROUP
:
855 if (child
->isTableSection()) {
856 LayoutTableSection
* section
= toLayoutTableSection(child
);
859 else if (!m_firstBody
)
860 m_firstBody
= section
;
861 section
->recalcCellsIfNeeded();
864 case TABLE_FOOTER_GROUP
:
865 if (child
->isTableSection()) {
866 LayoutTableSection
* section
= toLayoutTableSection(child
);
869 else if (!m_firstBody
)
870 m_firstBody
= section
;
871 section
->recalcCellsIfNeeded();
874 case TABLE_ROW_GROUP
:
875 if (child
->isTableSection()) {
876 LayoutTableSection
* section
= toLayoutTableSection(child
);
878 m_firstBody
= section
;
879 section
->recalcCellsIfNeeded();
887 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
888 unsigned maxCols
= 0;
889 for (LayoutObject
* child
= firstChild(); child
; child
= child
->nextSibling()) {
890 if (child
->isTableSection()) {
891 LayoutTableSection
* section
= toLayoutTableSection(child
);
892 unsigned sectionCols
= section
->numColumns();
893 if (sectionCols
> maxCols
)
894 maxCols
= sectionCols
;
898 m_columns
.resize(maxCols
);
899 m_columnPos
.resize(maxCols
+ 1);
901 ASSERT(selfNeedsLayout());
903 m_needsSectionRecalc
= false;
906 int LayoutTable::calcBorderStart() const
908 if (!collapseBorders())
909 return LayoutBlock::borderStart();
911 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
917 const BorderValue
& tableStartBorder
= style()->borderStart();
918 if (tableStartBorder
.style() == BHIDDEN
)
920 if (tableStartBorder
.style() > BHIDDEN
)
921 borderWidth
= tableStartBorder
.width();
923 if (LayoutTableCol
* column
= colElement(0)) {
924 // FIXME: We don't account for direction on columns and column groups.
925 const BorderValue
& columnAdjoiningBorder
= column
->style()->borderStart();
926 if (columnAdjoiningBorder
.style() == BHIDDEN
)
928 if (columnAdjoiningBorder
.style() > BHIDDEN
)
929 borderWidth
= std::max(borderWidth
, columnAdjoiningBorder
.width());
930 // FIXME: This logic doesn't properly account for the first column in the first column-group case.
933 if (const LayoutTableSection
* topNonEmptySection
= this->topNonEmptySection()) {
934 const BorderValue
& sectionAdjoiningBorder
= topNonEmptySection
->borderAdjoiningTableStart();
935 if (sectionAdjoiningBorder
.style() == BHIDDEN
)
938 if (sectionAdjoiningBorder
.style() > BHIDDEN
)
939 borderWidth
= std::max(borderWidth
, sectionAdjoiningBorder
.width());
941 if (const LayoutTableCell
* adjoiningStartCell
= topNonEmptySection
->firstRowCellAdjoiningTableStart()) {
942 // FIXME: Make this work with perpendicular and flipped cells.
943 const BorderValue
& startCellAdjoiningBorder
= adjoiningStartCell
->borderAdjoiningTableStart();
944 if (startCellAdjoiningBorder
.style() == BHIDDEN
)
947 const BorderValue
& firstRowAdjoiningBorder
= adjoiningStartCell
->row()->borderAdjoiningTableStart();
948 if (firstRowAdjoiningBorder
.style() == BHIDDEN
)
951 if (startCellAdjoiningBorder
.style() > BHIDDEN
)
952 borderWidth
= std::max(borderWidth
, startCellAdjoiningBorder
.width());
953 if (firstRowAdjoiningBorder
.style() > BHIDDEN
)
954 borderWidth
= std::max(borderWidth
, firstRowAdjoiningBorder
.width());
957 return (borderWidth
+ (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
960 int LayoutTable::calcBorderEnd() const
962 if (!collapseBorders())
963 return LayoutBlock::borderEnd();
965 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
971 const BorderValue
& tableEndBorder
= style()->borderEnd();
972 if (tableEndBorder
.style() == BHIDDEN
)
974 if (tableEndBorder
.style() > BHIDDEN
)
975 borderWidth
= tableEndBorder
.width();
977 unsigned endColumn
= numEffCols() - 1;
978 if (LayoutTableCol
* column
= colElement(endColumn
)) {
979 // FIXME: We don't account for direction on columns and column groups.
980 const BorderValue
& columnAdjoiningBorder
= column
->style()->borderEnd();
981 if (columnAdjoiningBorder
.style() == BHIDDEN
)
983 if (columnAdjoiningBorder
.style() > BHIDDEN
)
984 borderWidth
= std::max(borderWidth
, columnAdjoiningBorder
.width());
985 // FIXME: This logic doesn't properly account for the last column in the last column-group case.
988 if (const LayoutTableSection
* topNonEmptySection
= this->topNonEmptySection()) {
989 const BorderValue
& sectionAdjoiningBorder
= topNonEmptySection
->borderAdjoiningTableEnd();
990 if (sectionAdjoiningBorder
.style() == BHIDDEN
)
993 if (sectionAdjoiningBorder
.style() > BHIDDEN
)
994 borderWidth
= std::max(borderWidth
, sectionAdjoiningBorder
.width());
996 if (const LayoutTableCell
* adjoiningEndCell
= topNonEmptySection
->firstRowCellAdjoiningTableEnd()) {
997 // FIXME: Make this work with perpendicular and flipped cells.
998 const BorderValue
& endCellAdjoiningBorder
= adjoiningEndCell
->borderAdjoiningTableEnd();
999 if (endCellAdjoiningBorder
.style() == BHIDDEN
)
1002 const BorderValue
& firstRowAdjoiningBorder
= adjoiningEndCell
->row()->borderAdjoiningTableEnd();
1003 if (firstRowAdjoiningBorder
.style() == BHIDDEN
)
1006 if (endCellAdjoiningBorder
.style() > BHIDDEN
)
1007 borderWidth
= std::max(borderWidth
, endCellAdjoiningBorder
.width());
1008 if (firstRowAdjoiningBorder
.style() > BHIDDEN
)
1009 borderWidth
= std::max(borderWidth
, firstRowAdjoiningBorder
.width());
1012 return (borderWidth
+ (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1015 void LayoutTable::recalcBordersInRowDirection()
1017 // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1018 m_borderStart
= calcBorderStart();
1019 m_borderEnd
= calcBorderEnd();
1022 int LayoutTable::borderBefore() const
1024 if (collapseBorders()) {
1025 recalcSectionsIfNeeded();
1026 return outerBorderBefore();
1028 return LayoutBlock::borderBefore();
1031 int LayoutTable::borderAfter() const
1033 if (collapseBorders()) {
1034 recalcSectionsIfNeeded();
1035 return outerBorderAfter();
1037 return LayoutBlock::borderAfter();
1040 int LayoutTable::outerBorderBefore() const
1042 if (!collapseBorders())
1044 int borderWidth
= 0;
1045 if (LayoutTableSection
* topSection
= this->topSection()) {
1046 borderWidth
= topSection
->outerBorderBefore();
1047 if (borderWidth
< 0)
1048 return 0; // Overridden by hidden
1050 const BorderValue
& tb
= style()->borderBefore();
1051 if (tb
.style() == BHIDDEN
)
1053 if (tb
.style() > BHIDDEN
)
1054 borderWidth
= std::max
<int>(borderWidth
, tb
.width() / 2);
1058 int LayoutTable::outerBorderAfter() const
1060 if (!collapseBorders())
1062 int borderWidth
= 0;
1064 if (LayoutTableSection
* section
= bottomSection()) {
1065 borderWidth
= section
->outerBorderAfter();
1066 if (borderWidth
< 0)
1067 return 0; // Overridden by hidden
1069 const BorderValue
& tb
= style()->borderAfter();
1070 if (tb
.style() == BHIDDEN
)
1072 if (tb
.style() > BHIDDEN
)
1073 borderWidth
= std::max
<int>(borderWidth
, (tb
.width() + 1) / 2);
1077 int LayoutTable::outerBorderStart() const
1079 if (!collapseBorders())
1082 int borderWidth
= 0;
1084 const BorderValue
& tb
= style()->borderStart();
1085 if (tb
.style() == BHIDDEN
)
1087 if (tb
.style() > BHIDDEN
)
1088 borderWidth
= (tb
.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1090 bool allHidden
= true;
1091 for (LayoutTableSection
* section
= topSection(); section
; section
= sectionBelow(section
)) {
1092 int sw
= section
->outerBorderStart();
1096 borderWidth
= std::max(borderWidth
, sw
);
1104 int LayoutTable::outerBorderEnd() const
1106 if (!collapseBorders())
1109 int borderWidth
= 0;
1111 const BorderValue
& tb
= style()->borderEnd();
1112 if (tb
.style() == BHIDDEN
)
1114 if (tb
.style() > BHIDDEN
)
1115 borderWidth
= (tb
.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1117 bool allHidden
= true;
1118 for (LayoutTableSection
* section
= topSection(); section
; section
= sectionBelow(section
)) {
1119 int sw
= section
->outerBorderEnd();
1123 borderWidth
= std::max(borderWidth
, sw
);
1131 LayoutTableSection
* LayoutTable::sectionAbove(const LayoutTableSection
* section
, SkipEmptySectionsValue skipEmptySections
) const
1133 recalcSectionsIfNeeded();
1135 if (section
== m_head
)
1138 LayoutObject
* prevSection
= section
== m_foot
? lastChild() : section
->previousSibling();
1139 while (prevSection
) {
1140 if (prevSection
->isTableSection() && prevSection
!= m_head
&& prevSection
!= m_foot
&& (skipEmptySections
== DoNotSkipEmptySections
|| toLayoutTableSection(prevSection
)->numRows()))
1142 prevSection
= prevSection
->previousSibling();
1144 if (!prevSection
&& m_head
&& (skipEmptySections
== DoNotSkipEmptySections
|| m_head
->numRows()))
1145 prevSection
= m_head
;
1146 return toLayoutTableSection(prevSection
);
1149 LayoutTableSection
* LayoutTable::sectionBelow(const LayoutTableSection
* section
, SkipEmptySectionsValue skipEmptySections
) const
1151 recalcSectionsIfNeeded();
1153 if (section
== m_foot
)
1156 LayoutObject
* nextSection
= section
== m_head
? firstChild() : section
->nextSibling();
1157 while (nextSection
) {
1158 if (nextSection
->isTableSection() && nextSection
!= m_head
&& nextSection
!= m_foot
&& (skipEmptySections
== DoNotSkipEmptySections
|| toLayoutTableSection(nextSection
)->numRows()))
1160 nextSection
= nextSection
->nextSibling();
1162 if (!nextSection
&& m_foot
&& (skipEmptySections
== DoNotSkipEmptySections
|| m_foot
->numRows()))
1163 nextSection
= m_foot
;
1164 return toLayoutTableSection(nextSection
);
1167 LayoutTableSection
* LayoutTable::bottomSection() const
1169 recalcSectionsIfNeeded();
1174 for (LayoutObject
* child
= lastChild(); child
; child
= child
->previousSibling()) {
1175 if (child
->isTableSection())
1176 return toLayoutTableSection(child
);
1182 LayoutTableCell
* LayoutTable::cellAbove(const LayoutTableCell
* cell
) const
1184 recalcSectionsIfNeeded();
1186 // Find the section and row to look in
1187 unsigned r
= cell
->rowIndex();
1188 LayoutTableSection
* section
= nullptr;
1189 unsigned rAbove
= 0;
1191 // cell is not in the first row, so use the above row in its own section
1192 section
= cell
->section();
1195 section
= sectionAbove(cell
->section(), SkipEmptySections
);
1197 ASSERT(section
->numRows());
1198 rAbove
= section
->numRows() - 1;
1202 // Look up the cell in the section's grid, which requires effective col index
1204 unsigned effCol
= colToEffCol(cell
->col());
1205 LayoutTableSection::CellStruct
& aboveCell
= section
->cellAt(rAbove
, effCol
);
1206 return aboveCell
.primaryCell();
1211 LayoutTableCell
* LayoutTable::cellBelow(const LayoutTableCell
* cell
) const
1213 recalcSectionsIfNeeded();
1215 // Find the section and row to look in
1216 unsigned r
= cell
->rowIndex() + cell
->rowSpan() - 1;
1217 LayoutTableSection
* section
= nullptr;
1218 unsigned rBelow
= 0;
1219 if (r
< cell
->section()->numRows() - 1) {
1220 // The cell is not in the last row, so use the next row in the section.
1221 section
= cell
->section();
1224 section
= sectionBelow(cell
->section(), SkipEmptySections
);
1229 // Look up the cell in the section's grid, which requires effective col index
1231 unsigned effCol
= colToEffCol(cell
->col());
1232 LayoutTableSection::CellStruct
& belowCell
= section
->cellAt(rBelow
, effCol
);
1233 return belowCell
.primaryCell();
1238 LayoutTableCell
* LayoutTable::cellBefore(const LayoutTableCell
* cell
) const
1240 recalcSectionsIfNeeded();
1242 LayoutTableSection
* section
= cell
->section();
1243 unsigned effCol
= colToEffCol(cell
->col());
1247 // If we hit a colspan back up to a real cell.
1248 LayoutTableSection::CellStruct
& prevCell
= section
->cellAt(cell
->rowIndex(), effCol
- 1);
1249 return prevCell
.primaryCell();
1252 LayoutTableCell
* LayoutTable::cellAfter(const LayoutTableCell
* cell
) const
1254 recalcSectionsIfNeeded();
1256 unsigned effCol
= colToEffCol(cell
->col() + cell
->colSpan());
1257 if (effCol
>= numEffCols())
1259 return cell
->section()->primaryCellAt(cell
->rowIndex(), effCol
);
1262 int LayoutTable::baselinePosition(FontBaseline baselineType
, bool firstLine
, LineDirectionMode direction
, LinePositionMode linePositionMode
) const
1264 ASSERT(linePositionMode
== PositionOnContainingLine
);
1265 int baseline
= firstLineBoxBaseline();
1266 if (baseline
!= -1) {
1268 return beforeMarginInLineDirection(direction
) + baseline
;
1272 return LayoutBox::baselinePosition(baselineType
, firstLine
, direction
, linePositionMode
);
1275 int LayoutTable::inlineBlockBaseline(LineDirectionMode
) const
1277 // Tables are skipped when computing an inline-block's baseline.
1281 int LayoutTable::firstLineBoxBaseline() const
1283 // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1284 // doesn't define the baseline of a 'table' only an 'inline-table').
1285 // This is also needed to properly determine the baseline of a cell if it has a table child.
1287 if (isWritingModeRoot())
1290 recalcSectionsIfNeeded();
1292 const LayoutTableSection
* topNonEmptySection
= this->topNonEmptySection();
1293 if (!topNonEmptySection
)
1296 int baseline
= topNonEmptySection
->firstLineBoxBaseline();
1298 return topNonEmptySection
->logicalTop() + baseline
;
1300 // FF, Presto and IE use the top of the section as the baseline if its first row is empty of cells or content.
1301 // The baseline of an empty row isn't specified by CSS 2.1.
1302 if (topNonEmptySection
->firstRow() && !topNonEmptySection
->firstRow()->firstCell())
1303 return topNonEmptySection
->logicalTop();
1308 LayoutRect
LayoutTable::overflowClipRect(const LayoutPoint
& location
, OverlayScrollbarSizeRelevancy relevancy
) const
1310 LayoutRect rect
= LayoutBlock::overflowClipRect(location
, relevancy
);
1312 // If we have a caption, expand the clip to include the caption.
1313 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1314 // for real until captions have been re-written.
1315 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1316 // supported. When we actually support left/right and stop mapping them to top/bottom,
1317 // we might have to hack this code first (depending on what order we do these bug fixes in).
1318 if (!m_captions
.isEmpty()) {
1319 if (style()->isHorizontalWritingMode()) {
1320 rect
.setHeight(size().height());
1321 rect
.setY(location
.y());
1323 rect
.setWidth(size().width());
1324 rect
.setX(location
.x());
1331 bool LayoutTable::nodeAtPoint(HitTestResult
& result
, const HitTestLocation
& locationInContainer
, const LayoutPoint
& accumulatedOffset
, HitTestAction action
)
1333 LayoutPoint adjustedLocation
= accumulatedOffset
+ location();
1335 // Check kids first.
1336 if (!hasOverflowClip() || locationInContainer
.intersects(overflowClipRect(adjustedLocation
))) {
1337 for (LayoutObject
* child
= lastChild(); child
; child
= child
->previousSibling()) {
1338 if (child
->isBox() && !toLayoutBox(child
)->hasSelfPaintingLayer() && (child
->isTableSection() || child
->isTableCaption())) {
1339 LayoutPoint childPoint
= flipForWritingModeForChild(toLayoutBox(child
), adjustedLocation
);
1340 if (child
->nodeAtPoint(result
, locationInContainer
, childPoint
, action
)) {
1341 updateHitTestResult(result
, toLayoutPoint(locationInContainer
.point() - childPoint
));
1348 // Check our bounds next.
1349 LayoutRect
boundsRect(adjustedLocation
, size());
1350 if (visibleToHitTestRequest(result
.hitTestRequest()) && (action
== HitTestBlockBackground
|| action
== HitTestChildBlockBackground
) && locationInContainer
.intersects(boundsRect
)) {
1351 updateHitTestResult(result
, flipForWritingMode(locationInContainer
.point() - toLayoutSize(adjustedLocation
)));
1352 if (!result
.addNodeToListBasedTestResult(node(), locationInContainer
, boundsRect
))
1359 LayoutTable
* LayoutTable::createAnonymousWithParent(const LayoutObject
* parent
)
1361 RefPtr
<ComputedStyle
> newStyle
= ComputedStyle::createAnonymousStyleWithDisplay(parent
->styleRef(), TABLE
);
1362 LayoutTable
* newTable
= new LayoutTable(nullptr);
1363 newTable
->setDocumentForAnonymous(&parent
->document());
1364 newTable
->setStyle(newStyle
.release());
1368 const BorderValue
& LayoutTable::tableStartBorderAdjoiningCell(const LayoutTableCell
* cell
) const
1370 ASSERT(cell
->isFirstOrLastCellInRow());
1371 if (hasSameDirectionAs(cell
->row()))
1372 return style()->borderStart();
1374 return style()->borderEnd();
1377 const BorderValue
& LayoutTable::tableEndBorderAdjoiningCell(const LayoutTableCell
* cell
) const
1379 ASSERT(cell
->isFirstOrLastCellInRow());
1380 if (hasSameDirectionAs(cell
->row()))
1381 return style()->borderEnd();
1383 return style()->borderStart();
1386 PaintInvalidationReason
LayoutTable::invalidatePaintIfNeeded(PaintInvalidationState
& paintInvalidationState
, const LayoutBoxModelObject
& paintInvalidationContainer
)
1388 // Information of collapsed borders doesn't affect layout and are for painting only.
1389 // Do it now instead of during painting to invalidate table cells if needed.
1390 recalcCollapsedBordersIfNeeded();
1391 return LayoutBlock::invalidatePaintIfNeeded(paintInvalidationState
, paintInvalidationContainer
);
1394 void LayoutTable::invalidatePaintOfSubtreesIfNeeded(PaintInvalidationState
& childPaintInvalidationState
)
1396 // Table cells paint background from the containing column group, column, section and row.
1397 // If background of any of them changed, we need to invalidate all affected cells.
1398 // Here use shouldDoFullPaintInvalidation() as a broader condition of background change.
1399 for (LayoutObject
* section
= firstChild(); section
; section
= section
->nextSibling()) {
1400 if (!section
->isTableSection())
1402 for (LayoutTableRow
* row
= toLayoutTableSection(section
)->firstRow(); row
; row
= row
->nextRow()) {
1403 for (LayoutTableCell
* cell
= row
->firstCell(); cell
; cell
= cell
->nextCell()) {
1404 LayoutTableCol
* column
= colElement(cell
->col());
1405 LayoutTableCol
* columnGroup
= column
? column
->enclosingColumnGroup() : 0;
1406 if ((columnGroup
&& columnGroup
->shouldDoFullPaintInvalidation())
1407 || (column
&& column
->shouldDoFullPaintInvalidation())
1408 || section
->shouldDoFullPaintInvalidation()
1409 || row
->shouldDoFullPaintInvalidation())
1410 cell
->invalidateDisplayItemClient(*cell
);
1415 LayoutBlock::invalidatePaintOfSubtreesIfNeeded(childPaintInvalidationState
);