summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderTable.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/RenderTable.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/RenderTable.cpp')
-rw-r--r--Source/WebCore/rendering/RenderTable.cpp579
1 files changed, 372 insertions, 207 deletions
diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp
index 20bbe4c46..386b52780 100644
--- a/Source/WebCore/rendering/RenderTable.cpp
+++ b/Source/WebCore/rendering/RenderTable.cpp
@@ -4,7 +4,7 @@
* (C) 1998 Waldo Bastian (bastian@kde.org)
* (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
* This library is free software; you can redistribute it and/or
@@ -35,8 +35,10 @@
#include "HTMLNames.h"
#include "HTMLTableElement.h"
#include "LayoutRepainter.h"
+#include "RenderChildIterator.h"
#include "RenderIterator.h"
#include "RenderLayer.h"
+#include "RenderNamedFlowFragment.h"
#include "RenderTableCaption.h"
#include "RenderTableCell.h"
#include "RenderTableCol.h"
@@ -49,39 +51,41 @@ namespace WebCore {
using namespace HTMLNames;
-RenderTable::RenderTable(Element& element, PassRef<RenderStyle> style)
- : RenderBlock(element, std::move(style), 0)
+RenderTable::RenderTable(Element& element, RenderStyle&& style)
+ : RenderBlock(element, WTFMove(style), 0)
, m_head(nullptr)
, m_foot(nullptr)
, m_firstBody(nullptr)
, m_currentBorder(nullptr)
, m_collapsedBordersValid(false)
+ , m_collapsedEmptyBorderIsPresent(false)
, m_hasColElements(false)
, m_needsSectionRecalc(false)
, m_columnLogicalWidthChanged(false)
, m_columnRenderersValid(false)
- , m_hSpacing(0)
- , m_vSpacing(0)
+ , m_hasCellColspanThatDeterminesTableWidth(false)
, m_borderStart(0)
, m_borderEnd(0)
+ , m_columnOffsetTop(-1)
+ , m_columnOffsetHeight(-1)
{
setChildrenInline(false);
m_columnPos.fill(0, 1);
}
-RenderTable::RenderTable(Document& document, PassRef<RenderStyle> style)
- : RenderBlock(document, std::move(style), 0)
+RenderTable::RenderTable(Document& document, RenderStyle&& style)
+ : RenderBlock(document, WTFMove(style), 0)
, m_head(nullptr)
, m_foot(nullptr)
, m_firstBody(nullptr)
, m_currentBorder(nullptr)
, m_collapsedBordersValid(false)
+ , m_collapsedEmptyBorderIsPresent(false)
, m_hasColElements(false)
, m_needsSectionRecalc(false)
, m_columnLogicalWidthChanged(false)
, m_columnRenderersValid(false)
- , m_hSpacing(0)
- , m_vSpacing(0)
+ , m_hasCellColspanThatDeterminesTableWidth(false)
, m_borderStart(0)
, m_borderEnd(0)
{
@@ -109,13 +113,13 @@ void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
// According to the CSS2 spec, you only use fixed table layout if an
// explicit width is specified on the table. Auto width implies auto table layout.
if (style().tableLayout() == TFIXED && !style().logicalWidth().isAuto())
- m_tableLayout = adoptPtr(new FixedTableLayout(this));
+ m_tableLayout = std::make_unique<FixedTableLayout>(this);
else
- m_tableLayout = adoptPtr(new AutoTableLayout(this));
+ m_tableLayout = std::make_unique<AutoTableLayout>(this);
}
// If border was changed, invalidate collapsed borders cache.
- if (!needsLayout() && oldStyle && oldStyle->border() != style().border())
+ if (oldStyle && oldStyle->border() != style().border())
invalidateCollapsedBorders();
}
@@ -134,28 +138,28 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
{
bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
- if (child->isTableCaption())
+ if (is<RenderTableCaption>(*child))
wrapInAnonymousSection = false;
- else if (child->isRenderTableCol()) {
+ else if (is<RenderTableCol>(*child)) {
m_hasColElements = true;
wrapInAnonymousSection = false;
- } else if (child->isTableSection()) {
+ } else if (is<RenderTableSection>(*child)) {
switch (child->style().display()) {
case TABLE_HEADER_GROUP:
resetSectionPointerIfNotBefore(m_head, beforeChild);
if (!m_head) {
- m_head = toRenderTableSection(child);
+ m_head = downcast<RenderTableSection>(child);
} else {
resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
if (!m_firstBody)
- m_firstBody = toRenderTableSection(child);
+ m_firstBody = downcast<RenderTableSection>(child);
}
wrapInAnonymousSection = false;
break;
case TABLE_FOOTER_GROUP:
resetSectionPointerIfNotBefore(m_foot, beforeChild);
if (!m_foot) {
- m_foot = toRenderTableSection(child);
+ m_foot = downcast<RenderTableSection>(child);
wrapInAnonymousSection = false;
break;
}
@@ -163,18 +167,18 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
case TABLE_ROW_GROUP:
resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
if (!m_firstBody)
- m_firstBody = toRenderTableSection(child);
+ m_firstBody = downcast<RenderTableSection>(child);
wrapInAnonymousSection = false;
break;
default:
ASSERT_NOT_REACHED();
}
- } else if (child->isTableCell() || child->isTableRow())
+ } else if (is<RenderTableCell>(*child) || is<RenderTableRow>(*child))
wrapInAnonymousSection = true;
else
wrapInAnonymousSection = true;
- if (child->isTableSection())
+ if (is<RenderTableSection>(*child))
setNeedsSectionRecalc();
if (!wrapInAnonymousSection) {
@@ -185,34 +189,34 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
return;
}
- if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
- toRenderTableSection(lastChild())->addChild(child);
+ if (!beforeChild && is<RenderTableSection>(lastChild()) && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
+ downcast<RenderTableSection>(*lastChild()).addChild(child);
return;
}
if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
RenderObject* section = beforeChild->previousSibling();
- if (section && section->isTableSection() && section->isAnonymous()) {
- toRenderTableSection(section)->addChild(child);
+ if (is<RenderTableSection>(section) && section->isAnonymous()) {
+ downcast<RenderTableSection>(*section).addChild(child);
return;
}
}
RenderObject* lastBox = beforeChild;
- while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style().display() != TABLE_CAPTION && lastBox->style().display() != TABLE_COLUMN_GROUP)
+ while (lastBox && lastBox->parent()->isAnonymous() && !is<RenderTableSection>(*lastBox) && lastBox->style().display() != TABLE_CAPTION && lastBox->style().display() != TABLE_COLUMN_GROUP)
lastBox = lastBox->parent();
if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox) && lastBox->isTableSection()) {
- RenderTableSection* section = toRenderTableSection(lastBox);
- if (beforeChild == section)
- beforeChild = section->firstRow();
- section->addChild(child, beforeChild);
+ RenderTableSection& section = downcast<RenderTableSection>(*lastBox);
+ if (beforeChild == &section)
+ beforeChild = section.firstRow();
+ section.addChild(child, beforeChild);
return;
}
- if (beforeChild && !beforeChild->isTableSection() && beforeChild->style().display() != TABLE_CAPTION && beforeChild->style().display() != TABLE_COLUMN_GROUP)
- beforeChild = 0;
+ if (beforeChild && !is<RenderTableSection>(*beforeChild) && beforeChild->style().display() != TABLE_CAPTION && beforeChild->style().display() != TABLE_COLUMN_GROUP)
+ beforeChild = nullptr;
- RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
+ auto section = RenderTableSection::createAnonymousWithParentRenderer(*this).release();
addChild(section, beforeChild);
section->addChild(child);
}
@@ -225,18 +229,21 @@ void RenderTable::addCaption(const RenderTableCaption* caption)
void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
{
- size_t index = m_captions.find(oldCaption);
- ASSERT(index != notFound);
- if (index == notFound)
- return;
-
- m_captions.remove(index);
+ bool removed = m_captions.removeFirst(oldCaption);
+ ASSERT_UNUSED(removed, removed);
}
void RenderTable::invalidateCachedColumns()
{
m_columnRenderersValid = false;
m_columnRenderers.resize(0);
+ m_effectiveColumnIndexMap.clear();
+}
+
+void RenderTable::invalidateCachedColumnOffsets()
+{
+ m_columnOffsetTop = -1;
+ m_columnOffsetHeight = -1;
}
void RenderTable::addColumn(const RenderTableCol*)
@@ -266,10 +273,10 @@ void RenderTable::updateLogicalWidth()
setMarginEnd(computedValues.m_margins.m_end);
}
- RenderBlock* cb = containingBlock();
+ RenderBlock& cb = *containingBlock();
LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
- bool hasPerpendicularContainingBlock = cb->style().isHorizontalWritingMode() != style().isHorizontalWritingMode();
+ bool hasPerpendicularContainingBlock = cb.style().isHorizontalWritingMode() != style().isHorizontalWritingMode();
LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
Length styleLogicalWidth = style().logicalWidth();
@@ -283,31 +290,38 @@ void RenderTable::updateLogicalWidth()
// Subtract out our margins to get the available content width.
LayoutUnit availableContentLogicalWidth = std::max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
- if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
+ if (shrinkToAvoidFloats() && cb.containsFloats() && !hasPerpendicularContainingBlock) {
// FIXME: Work with regions someday.
availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, 0);
}
// Ensure we aren't bigger than our available width.
- setLogicalWidth(std::min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
+ setLogicalWidth(std::min(availableContentLogicalWidth, maxPreferredLogicalWidth()));
+ LayoutUnit maxWidth = maxPreferredLogicalWidth();
+ // scaledWidthFromPercentColumns depends on m_layoutStruct in TableLayoutAlgorithmAuto, which
+ // maxPreferredLogicalWidth fills in. So scaledWidthFromPercentColumns has to be called after
+ // maxPreferredLogicalWidth.
+ LayoutUnit scaledWidth = m_tableLayout->scaledWidthFromPercentColumns() + bordersPaddingAndSpacingInRowDirection();
+ maxWidth = std::max(scaledWidth, maxWidth);
+ setLogicalWidth(std::min(availableContentLogicalWidth, maxWidth));
}
// Ensure we aren't smaller than our min preferred width.
- setLogicalWidth(std::max<int>(logicalWidth(), minPreferredLogicalWidth()));
+ setLogicalWidth(std::max(logicalWidth(), minPreferredLogicalWidth()));
// Ensure we aren't bigger than our max-width style.
Length styleMaxLogicalWidth = style().logicalMaxWidth();
if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
- setLogicalWidth(std::min<int>(logicalWidth(), computedMaxLogicalWidth));
+ setLogicalWidth(std::min(logicalWidth(), computedMaxLogicalWidth));
}
// Ensure we aren't smaller than our min-width style.
Length styleMinLogicalWidth = style().logicalMinWidth();
if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
- setLogicalWidth(std::max<int>(logicalWidth(), computedMinLogicalWidth));
+ setLogicalWidth(std::max(logicalWidth(), computedMinLogicalWidth));
}
// Finally, with our true width determined, compute our margins for real.
@@ -315,10 +329,10 @@ void RenderTable::updateLogicalWidth()
setMarginEnd(0);
if (!hasPerpendicularContainingBlock) {
LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
- if (avoidsFloats() && cb->containsFloats())
+ if (avoidsFloats() && cb.containsFloats())
containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday.
ComputedMarginValues marginValues;
- bool hasInvertedDirection = cb->style().isLeftToRightDirection() == style().isLeftToRightDirection();
+ bool hasInvertedDirection = cb.style().isLeftToRightDirection() == style().isLeftToRightDirection();
computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(),
hasInvertedDirection ? marginValues.m_start : marginValues.m_end,
hasInvertedDirection ? marginValues.m_end : marginValues.m_start);
@@ -338,7 +352,7 @@ LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& st
// HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
LayoutUnit borders = 0;
- bool isCSSTable = !element() || !isHTMLTableElement(element());
+ bool isCSSTable = !is<HTMLTableElement>(element());
if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style().boxSizing() == CONTENT_BOX)
borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
@@ -347,47 +361,60 @@ LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& st
LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
{
- LayoutUnit computedLogicalHeight = 0;
+ LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
+ LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
+ LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter;
if (styleLogicalHeight.isFixed()) {
// HTML tables size as though CSS height includes border/padding, CSS tables do not.
LayoutUnit borders = LayoutUnit();
// FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
- if ((element() && isHTMLTableElement(element())) || style().boxSizing() == BORDER_BOX) {
- LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
- LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
- borders = borderAndPaddingBefore + borderAndPaddingAfter;
+ if (is<HTMLTableElement>(element()) || style().boxSizing() == BORDER_BOX) {
+ borders = borderAndPadding;
}
- computedLogicalHeight = styleLogicalHeight.value() - borders;
- } else if (styleLogicalHeight.isPercent())
- computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
- else if (styleLogicalHeight.isViewportPercentage())
- computedLogicalHeight = minimumValueForLength(styleLogicalHeight, 0);
+ return styleLogicalHeight.value() - borders;
+ } else if (styleLogicalHeight.isPercentOrCalculated())
+ return computePercentageLogicalHeight(styleLogicalHeight).value_or(0);
+ else if (styleLogicalHeight.isIntrinsic())
+ return computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding).value_or(0);
else
ASSERT_NOT_REACHED();
- return std::max<LayoutUnit>(0, computedLogicalHeight);
+ return LayoutUnit();
}
-void RenderTable::layoutCaption(RenderTableCaption* caption)
+void RenderTable::layoutCaption(RenderTableCaption& caption)
{
- LayoutRect captionRect(caption->frameRect());
+ LayoutRect captionRect(caption.frameRect());
- if (caption->needsLayout()) {
+ if (caption.needsLayout()) {
// The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
// so that it does not mistakenly think any floats in the previous caption intrude into it.
- caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
+ caption.setLogicalLocation(LayoutPoint(caption.marginStart(), caption.marginBefore() + logicalHeight()));
// If RenderTableCaption ever gets a layout() function, use it here.
- caption->layoutIfNeeded();
+ caption.layoutIfNeeded();
}
// Apply the margins to the location now that they are definitely available from layout
- caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
+ caption.setLogicalLocation(LayoutPoint(caption.marginStart(), caption.marginBefore() + logicalHeight()));
- if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
- caption->repaintDuringLayoutIfMoved(captionRect);
+ if (!selfNeedsLayout() && caption.checkForRepaintDuringLayout())
+ caption.repaintDuringLayoutIfMoved(captionRect);
- setLogicalHeight(logicalHeight() + caption->logicalHeight() + caption->marginBefore() + caption->marginAfter());
+ setLogicalHeight(logicalHeight() + caption.logicalHeight() + caption.marginBefore() + caption.marginAfter());
+}
+
+void RenderTable::layoutCaptions(BottomCaptionLayoutPhase bottomCaptionLayoutPhase)
+{
+ if (m_captions.isEmpty())
+ return;
+ // FIXME: Collapse caption margin.
+ for (unsigned i = 0; i < m_captions.size(); ++i) {
+ if ((bottomCaptionLayoutPhase == BottomCaptionLayoutPhase::Yes && m_captions[i]->style().captionSide() != CAPBOTTOM)
+ || (bottomCaptionLayoutPhase == BottomCaptionLayoutPhase::No && m_captions[i]->style().captionSide() == CAPBOTTOM))
+ continue;
+ layoutCaption(*m_captions[i]);
+ }
}
-void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
+void RenderTable::distributeExtraLogicalHeight(LayoutUnit extraLogicalHeight)
{
if (extraLogicalHeight <= 0)
return;
@@ -403,10 +430,12 @@ void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
void RenderTable::simplifiedNormalFlowLayout()
{
+ layoutCaptions();
for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
section->layoutIfNeeded();
section->computeOverflowFromCells();
}
+ layoutCaptions(BottomCaptionLayoutPhase::Yes);
}
void RenderTable::layout()
@@ -421,13 +450,13 @@ void RenderTable::layout()
// FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
// to call this before we call borderStart/borderEnd to avoid getting a stale value.
recalcBordersInRowDirection();
-
+
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
- setLogicalHeight(0);
-
LayoutUnit oldLogicalWidth = logicalWidth();
+ LayoutUnit oldLogicalHeight = logicalHeight();
+ setLogicalHeight(0);
updateLogicalWidth();
if (logicalWidth() != oldLogicalWidth) {
@@ -449,8 +478,8 @@ void RenderTable::layout()
bool collapsing = collapseBorders();
for (auto& child : childrenOfType<RenderElement>(*this)) {
- if (child.isTableSection()) {
- RenderTableSection& section = toRenderTableSection(child);
+ if (is<RenderTableSection>(child)) {
+ RenderTableSection& section = downcast<RenderTableSection>(child);
if (m_columnLogicalWidthChanged)
section.setChildNeedsLayout(MarkOnlyThis);
section.layoutIfNeeded();
@@ -458,8 +487,8 @@ void RenderTable::layout()
if (collapsing)
section.recalcOuterBorder();
ASSERT(!section.needsLayout());
- } else if (child.isRenderTableCol()) {
- toRenderTableCol(child).layoutIfNeeded();
+ } else if (is<RenderTableCol>(child)) {
+ downcast<RenderTableCol>(child).layoutIfNeeded();
ASSERT(!child.needsLayout());
}
}
@@ -470,17 +499,10 @@ void RenderTable::layout()
bool sectionMoved = false;
LayoutUnit movedSectionLogicalTop = 0;
- // FIXME: Collapse caption margin.
- if (!m_captions.isEmpty()) {
- for (unsigned i = 0; i < m_captions.size(); i++) {
- if (m_captions[i]->style().captionSide() == CAPBOTTOM)
- continue;
- layoutCaption(m_captions[i]);
- }
- if (logicalHeight() != oldTableLogicalTop) {
- sectionMoved = true;
- movedSectionLogicalTop = std::min(logicalHeight(), oldTableLogicalTop);
- }
+ layoutCaptions();
+ if (!m_captions.isEmpty() && logicalHeight() != oldTableLogicalTop) {
+ sectionMoved = true;
+ movedSectionLogicalTop = std::min(logicalHeight(), oldTableLogicalTop);
}
LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore());
@@ -494,22 +516,22 @@ void RenderTable::layout()
LayoutUnit computedLogicalHeight = 0;
Length logicalHeightLength = style().logicalHeight();
- if (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive())
+ if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive()))
computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength);
Length logicalMaxHeightLength = style().logicalMaxHeight();
- if (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative()) {
+ if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) {
LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength);
computedLogicalHeight = std::min(computedLogicalHeight, computedMaxLogicalHeight);
}
Length logicalMinHeightLength = style().logicalMinHeight();
- if (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative()) {
+ if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) {
LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength);
computedLogicalHeight = std::max(computedLogicalHeight, computedMinLogicalHeight);
}
- distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
+ distributeExtraLogicalHeight(computedLogicalHeight - totalSectionLogicalHeight);
for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
section->layoutRows();
@@ -539,24 +561,23 @@ void RenderTable::layout()
setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
- for (unsigned i = 0; i < m_captions.size(); i++) {
- if (m_captions[i]->style().captionSide() != CAPBOTTOM)
- continue;
- layoutCaption(m_captions[i]);
- }
+ layoutCaptions(BottomCaptionLayoutPhase::Yes);
if (isOutOfFlowPositioned())
updateLogicalHeight();
// table can be containing block of positioned elements.
- // FIXME: Only pass true if width or height changed.
- layoutPositionedObjects(true);
+ bool dimensionChanged = oldLogicalWidth != logicalWidth() || oldLogicalHeight != logicalHeight();
+ layoutPositionedObjects(dimensionChanged);
updateLayerTransform();
// Layout was changed, so probably borders too.
invalidateCollapsedBorders();
+ // The location or height of one or more sections may have changed.
+ invalidateCachedColumnOffsets();
+
computeOverflow(clientLogicalBottom());
statePusher.pop();
@@ -577,14 +598,48 @@ void RenderTable::layout()
clearNeedsLayout();
}
+void RenderTable::invalidateCollapsedBorders(RenderTableCell* cellWithStyleChange)
+{
+ m_collapsedBordersValid = false;
+ m_collapsedBorders.clear();
+
+ for (auto& section : childrenOfType<RenderTableSection>(*this))
+ section.clearCachedCollapsedBorders();
+
+ if (!m_collapsedEmptyBorderIsPresent)
+ return;
+
+ if (cellWithStyleChange) {
+ // It is enough to invalidate just the surrounding cells when cell border style changes.
+ cellWithStyleChange->invalidateHasEmptyCollapsedBorders();
+ if (auto* below = cellBelow(cellWithStyleChange))
+ below->invalidateHasEmptyCollapsedBorders();
+ if (auto* above = cellAbove(cellWithStyleChange))
+ above->invalidateHasEmptyCollapsedBorders();
+ if (auto* before = cellBefore(cellWithStyleChange))
+ before->invalidateHasEmptyCollapsedBorders();
+ if (auto* after = cellAfter(cellWithStyleChange))
+ after->invalidateHasEmptyCollapsedBorders();
+ return;
+ }
+
+ for (auto& section : childrenOfType<RenderTableSection>(*this)) {
+ for (auto* row = section.firstRow(); row; row = row->nextRow()) {
+ for (auto* cell = row->firstCell(); cell; cell = cell->nextCell()) {
+ ASSERT(cell->table() == this);
+ cell->invalidateHasEmptyCollapsedBorders();
+ }
+ }
+ }
+ m_collapsedEmptyBorderIsPresent = false;
+}
+
// Collect all the unique border values that we want to paint in a sorted list.
void RenderTable::recalcCollapsedBorders()
{
if (m_collapsedBordersValid)
return;
- m_collapsedBordersValid = true;
m_collapsedBorders.clear();
-
for (auto& section : childrenOfType<RenderTableSection>(*this)) {
for (RenderTableRow* row = section.firstRow(); row; row = row->nextRow()) {
for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) {
@@ -594,21 +649,21 @@ void RenderTable::recalcCollapsedBorders()
}
}
RenderTableCell::sortBorderValues(m_collapsedBorders);
+ m_collapsedBordersValid = true;
}
-
void RenderTable::addOverflowFromChildren()
{
// Add overflow from borders.
// Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
// descendant objects, but since tables don't support overflow:auto, this works out fine.
if (collapseBorders()) {
- int rightBorderOverflow = width() + outerBorderRight() - borderRight();
- int leftBorderOverflow = borderLeft() - outerBorderLeft();
- int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
- int topBorderOverflow = borderTop() - outerBorderTop();
- IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
- if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
+ LayoutUnit rightBorderOverflow = width() + outerBorderRight() - borderRight();
+ LayoutUnit leftBorderOverflow = borderLeft() - outerBorderLeft();
+ LayoutUnit bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
+ LayoutUnit topBorderOverflow = borderTop() - outerBorderTop();
+ LayoutRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
+ if (borderOverflowRect != borderBoxRect()) {
addLayoutOverflow(borderOverflowRect);
addVisualOverflow(borderOverflowRect);
}
@@ -629,10 +684,9 @@ void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
PaintPhase paintPhase = paintInfo.phase;
- if (!isRoot()) {
+ if (!isDocumentElementRenderer()) {
LayoutRect overflowBox = visualOverflowRect();
flipForWritingMode(overflowBox);
- overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
overflowBox.moveBy(adjustedPaintOffset);
if (!overflowBox.intersects(paintInfo.rect))
return;
@@ -647,7 +701,7 @@ void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
PaintPhase paintPhase = paintInfo.phase;
- if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style().visibility() == VISIBLE)
+ if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasVisibleBoxDecorations() && style().visibility() == VISIBLE)
paintBoxDecorations(paintInfo, paintOffset);
if (paintPhase == PaintPhaseMask) {
@@ -720,14 +774,14 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& p
LayoutRect rect(paintOffset, size());
subtractCaptionRect(rect);
- BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
- if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
- paintBoxShadow(paintInfo, rect, &style(), Normal);
+ BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context());
+ if (!boxShadowShouldBeAppliedToBackground(rect.location(), bleedAvoidance))
+ paintBoxShadow(paintInfo, rect, style(), Normal);
paintBackground(paintInfo, rect, bleedAvoidance);
- paintBoxShadow(paintInfo, rect, &style(), Inset);
+ paintBoxShadow(paintInfo, rect, style(), Inset);
- if (style().hasBorder() && !collapseBorders())
- paintBorder(paintInfo, rect, &style());
+ if (style().hasVisibleBorderDecoration() && !collapseBorders())
+ paintBorder(paintInfo, rect, style());
}
void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
@@ -760,7 +814,7 @@ void RenderTable::computePreferredLogicalWidths()
computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
- int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
+ LayoutUnit bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
@@ -769,14 +823,14 @@ void RenderTable::computePreferredLogicalWidths()
for (unsigned i = 0; i < m_captions.size(); i++)
m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
- RenderStyle& styleToUse = style();
- // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
+ auto& styleToUse = style();
+ // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width.
if (styleToUse.logicalMinWidth().isFixed() && styleToUse.logicalMinWidth().value() > 0) {
m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
}
- // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
+ // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth.
if (styleToUse.logicalMaxWidth().isFixed()) {
m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
@@ -819,6 +873,10 @@ void RenderTable::appendColumn(unsigned span)
unsigned newColumnIndex = m_columns.size();
m_columns.append(ColumnStruct(span));
+ // Unless the table has cell(s) with colspan that exceed the number of columns afforded
+ // by the other rows in the table we can use the fast path when mapping columns to effective columns.
+ m_hasCellColspanThatDeterminesTableWidth = m_hasCellColspanThatDeterminesTableWidth || span > 1;
+
// Propagate the change in our columns representation to the sections that don't need
// cell recalc. If they do, they will be synced up directly with m_columns later.
for (auto& section : childrenOfType<RenderTableSection>(*this)) {
@@ -833,32 +891,117 @@ void RenderTable::appendColumn(unsigned span)
RenderTableCol* RenderTable::firstColumn() const
{
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isRenderTableCol())
- return toRenderTableCol(child);
+ for (auto& child : childrenOfType<RenderObject>(*this)) {
+ if (is<RenderTableCol>(child))
+ return &const_cast<RenderTableCol&>(downcast<RenderTableCol>(child));
// We allow only table-captions before columns or column-groups.
- if (!child->isTableCaption())
- return 0;
+ if (!is<RenderTableCaption>(child))
+ return nullptr;
}
- return 0;
+ return nullptr;
}
void RenderTable::updateColumnCache() const
{
ASSERT(m_hasColElements);
ASSERT(m_columnRenderers.isEmpty());
+ ASSERT(m_effectiveColumnIndexMap.isEmpty());
ASSERT(!m_columnRenderersValid);
+ unsigned columnIndex = 0;
for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
if (columnRenderer->isTableColumnGroupWithColumnChildren())
continue;
m_columnRenderers.append(columnRenderer);
+ // FIXME: We should look to compute the effective column index successively from previous values instead of
+ // calling colToEffCol(), which is in O(numEffCols()). Although it's unlikely that this is a hot function.
+ m_effectiveColumnIndexMap.add(columnRenderer, colToEffCol(columnIndex));
+ columnIndex += columnRenderer->span();
}
m_columnRenderersValid = true;
}
+unsigned RenderTable::effectiveIndexOfColumn(const RenderTableCol& column) const
+{
+ if (!m_columnRenderersValid)
+ updateColumnCache();
+ const RenderTableCol* columnToUse = &column;
+ if (columnToUse->isTableColumnGroupWithColumnChildren())
+ columnToUse = columnToUse->nextColumn(); // First column in column-group
+ auto it = m_effectiveColumnIndexMap.find(columnToUse);
+ ASSERT(it != m_effectiveColumnIndexMap.end());
+ if (it == m_effectiveColumnIndexMap.end())
+ return std::numeric_limits<unsigned>::max();
+ return it->value;
+}
+
+LayoutUnit RenderTable::offsetTopForColumn(const RenderTableCol& column) const
+{
+ if (effectiveIndexOfColumn(column) >= numEffCols())
+ return 0;
+ if (m_columnOffsetTop >= 0) {
+ ASSERT(!needsLayout());
+ return m_columnOffsetTop;
+ }
+ RenderTableSection* section = topNonEmptySection();
+ return m_columnOffsetTop = section ? section->offsetTop() : LayoutUnit(0);
+}
+
+LayoutUnit RenderTable::offsetLeftForColumn(const RenderTableCol& column) const
+{
+ unsigned columnIndex = effectiveIndexOfColumn(column);
+ if (columnIndex >= numEffCols())
+ return 0;
+ return m_columnPos[columnIndex] + m_hSpacing + borderLeft();
+}
+
+LayoutUnit RenderTable::offsetWidthForColumn(const RenderTableCol& column) const
+{
+ const RenderTableCol* currentColumn = &column;
+ bool hasColumnChildren;
+ if ((hasColumnChildren = currentColumn->isTableColumnGroupWithColumnChildren()))
+ currentColumn = currentColumn->nextColumn(); // First column in column-group
+ unsigned numberOfEffectiveColumns = numEffCols();
+ ASSERT_WITH_SECURITY_IMPLICATION(m_columnPos.size() >= numberOfEffectiveColumns + 1);
+ LayoutUnit width = 0;
+ LayoutUnit spacing = m_hSpacing;
+ while (currentColumn) {
+ unsigned columnIndex = effectiveIndexOfColumn(*currentColumn);
+ unsigned span = currentColumn->span();
+ while (span && columnIndex < numberOfEffectiveColumns) {
+ width += m_columnPos[columnIndex + 1] - m_columnPos[columnIndex] - spacing;
+ span -= m_columns[columnIndex].span;
+ ++columnIndex;
+ if (span)
+ width += spacing;
+ }
+ if (!hasColumnChildren)
+ break;
+ currentColumn = currentColumn->nextColumn();
+ if (!currentColumn || currentColumn->isTableColumnGroup())
+ break;
+ width += spacing;
+ }
+ return width;
+}
+
+LayoutUnit RenderTable::offsetHeightForColumn(const RenderTableCol& column) const
+{
+ if (effectiveIndexOfColumn(column) >= numEffCols())
+ return 0;
+ if (m_columnOffsetHeight >= 0) {
+ ASSERT(!needsLayout());
+ return m_columnOffsetHeight;
+ }
+ LayoutUnit height = 0;
+ for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
+ height += section->offsetHeight();
+ m_columnOffsetHeight = height;
+ return m_columnOffsetHeight;
+}
+
RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
{
ASSERT(m_hasColElements);
@@ -893,6 +1036,7 @@ void RenderTable::recalcSections() const
m_foot = 0;
m_firstBody = 0;
m_hasColElements = false;
+ m_hasCellColspanThatDeterminesTableWidth = hasCellColspanThatDeterminesTableWidth();
// We need to get valid pointers to caption, head, foot and first body again
RenderObject* nextSibling;
@@ -904,31 +1048,31 @@ void RenderTable::recalcSections() const
m_hasColElements = true;
break;
case TABLE_HEADER_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = toRenderTableSection(child);
+ if (is<RenderTableSection>(*child)) {
+ RenderTableSection& section = downcast<RenderTableSection>(*child);
if (!m_head)
- m_head = section;
+ m_head = &section;
else if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
+ m_firstBody = &section;
+ section.recalcCellsIfNeeded();
}
break;
case TABLE_FOOTER_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = toRenderTableSection(child);
+ if (is<RenderTableSection>(*child)) {
+ RenderTableSection& section = downcast<RenderTableSection>(*child);
if (!m_foot)
- m_foot = section;
+ m_foot = &section;
else if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
+ m_firstBody = &section;
+ section.recalcCellsIfNeeded();
}
break;
case TABLE_ROW_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = toRenderTableSection(child);
+ if (is<RenderTableSection>(*child)) {
+ RenderTableSection& section = downcast<RenderTableSection>(*child);
if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
+ m_firstBody = &section;
+ section.recalcCellsIfNeeded();
}
break;
default:
@@ -952,7 +1096,7 @@ void RenderTable::recalcSections() const
m_needsSectionRecalc = false;
}
-int RenderTable::calcBorderStart() const
+LayoutUnit RenderTable::calcBorderStart() const
{
if (!collapseBorders())
return RenderBlock::borderStart();
@@ -961,7 +1105,7 @@ int RenderTable::calcBorderStart() const
if (!numEffCols())
return 0;
- unsigned borderWidth = 0;
+ float borderWidth = 0;
const BorderValue& tableStartBorder = style().borderStart();
if (tableStartBorder.style() == BHIDDEN)
@@ -1003,10 +1147,10 @@ int RenderTable::calcBorderStart() const
borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width());
}
}
- return (borderWidth + (style().isLeftToRightDirection() ? 0 : 1)) / 2;
+ return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), !style().isLeftToRightDirection());
}
-int RenderTable::calcBorderEnd() const
+LayoutUnit RenderTable::calcBorderEnd() const
{
if (!collapseBorders())
return RenderBlock::borderEnd();
@@ -1015,7 +1159,7 @@ int RenderTable::calcBorderEnd() const
if (!numEffCols())
return 0;
- unsigned borderWidth = 0;
+ float borderWidth = 0;
const BorderValue& tableEndBorder = style().borderEnd();
if (tableEndBorder.style() == BHIDDEN)
@@ -1058,7 +1202,7 @@ int RenderTable::calcBorderEnd() const
borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width());
}
}
- return (borderWidth + (style().isLeftToRightDirection() ? 1 : 0)) / 2;
+ return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), style().isLeftToRightDirection());
}
void RenderTable::recalcBordersInRowDirection()
@@ -1068,7 +1212,7 @@ void RenderTable::recalcBordersInRowDirection()
m_borderEnd = calcBorderEnd();
}
-int RenderTable::borderBefore() const
+LayoutUnit RenderTable::borderBefore() const
{
if (collapseBorders()) {
recalcSectionsIfNeeded();
@@ -1077,7 +1221,7 @@ int RenderTable::borderBefore() const
return RenderBlock::borderBefore();
}
-int RenderTable::borderAfter() const
+LayoutUnit RenderTable::borderAfter() const
{
if (collapseBorders()) {
recalcSectionsIfNeeded();
@@ -1086,11 +1230,11 @@ int RenderTable::borderAfter() const
return RenderBlock::borderAfter();
}
-int RenderTable::outerBorderBefore() const
+LayoutUnit RenderTable::outerBorderBefore() const
{
if (!collapseBorders())
return 0;
- int borderWidth = 0;
+ LayoutUnit borderWidth = 0;
if (RenderTableSection* topSection = this->topSection()) {
borderWidth = topSection->outerBorderBefore();
if (borderWidth < 0)
@@ -1099,16 +1243,18 @@ int RenderTable::outerBorderBefore() const
const BorderValue& tb = style().borderBefore();
if (tb.style() == BHIDDEN)
return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = std::max<int>(borderWidth, tb.width() / 2);
+ if (tb.style() > BHIDDEN) {
+ LayoutUnit collapsedBorderWidth = std::max<LayoutUnit>(borderWidth, tb.width() / 2);
+ borderWidth = floorToDevicePixel(collapsedBorderWidth, document().deviceScaleFactor());
+ }
return borderWidth;
}
-int RenderTable::outerBorderAfter() const
+LayoutUnit RenderTable::outerBorderAfter() const
{
if (!collapseBorders())
return 0;
- int borderWidth = 0;
+ LayoutUnit borderWidth = 0;
if (RenderTableSection* section = bottomSection()) {
borderWidth = section->outerBorderAfter();
@@ -1118,27 +1264,30 @@ int RenderTable::outerBorderAfter() const
const BorderValue& tb = style().borderAfter();
if (tb.style() == BHIDDEN)
return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = std::max<int>(borderWidth, (tb.width() + 1) / 2);
+ if (tb.style() > BHIDDEN) {
+ float deviceScaleFactor = document().deviceScaleFactor();
+ LayoutUnit collapsedBorderWidth = std::max<LayoutUnit>(borderWidth, (tb.width() + (1 / deviceScaleFactor)) / 2);
+ borderWidth = floorToDevicePixel(collapsedBorderWidth, deviceScaleFactor);
+ }
return borderWidth;
}
-int RenderTable::outerBorderStart() const
+LayoutUnit RenderTable::outerBorderStart() const
{
if (!collapseBorders())
return 0;
- int borderWidth = 0;
+ LayoutUnit borderWidth = 0;
const BorderValue& tb = style().borderStart();
if (tb.style() == BHIDDEN)
return 0;
if (tb.style() > BHIDDEN)
- borderWidth = (tb.width() + (style().isLeftToRightDirection() ? 0 : 1)) / 2;
+ return CollapsedBorderValue::adjustedCollapsedBorderWidth(tb.width(), document().deviceScaleFactor(), !style().isLeftToRightDirection());
bool allHidden = true;
for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
- int sw = section->outerBorderStart();
+ LayoutUnit sw = section->outerBorderStart();
if (sw < 0)
continue;
allHidden = false;
@@ -1150,22 +1299,22 @@ int RenderTable::outerBorderStart() const
return borderWidth;
}
-int RenderTable::outerBorderEnd() const
+LayoutUnit RenderTable::outerBorderEnd() const
{
if (!collapseBorders())
return 0;
- int borderWidth = 0;
+ LayoutUnit borderWidth = 0;
const BorderValue& tb = style().borderEnd();
if (tb.style() == BHIDDEN)
return 0;
if (tb.style() > BHIDDEN)
- borderWidth = (tb.width() + (style().isLeftToRightDirection() ? 1 : 0)) / 2;
+ return CollapsedBorderValue::adjustedCollapsedBorderWidth(tb.width(), document().deviceScaleFactor(), style().isLeftToRightDirection());
bool allHidden = true;
for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
- int sw = section->outerBorderEnd();
+ LayoutUnit sw = section->outerBorderEnd();
if (sw < 0)
continue;
allHidden = false;
@@ -1182,17 +1331,17 @@ RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section,
recalcSectionsIfNeeded();
if (section == m_head)
- return 0;
+ return nullptr;
RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
while (prevSection) {
- if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
+ if (is<RenderTableSection>(*prevSection) && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || downcast<RenderTableSection>(*prevSection).numRows()))
break;
prevSection = prevSection->previousSibling();
}
if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
prevSection = m_head;
- return toRenderTableSection(prevSection);
+ return downcast<RenderTableSection>(prevSection);
}
RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
@@ -1200,17 +1349,17 @@ RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section,
recalcSectionsIfNeeded();
if (section == m_foot)
- return 0;
+ return nullptr;
RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
while (nextSection) {
- if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
+ if (is<RenderTableSection>(*nextSection) && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || downcast<RenderTableSection>(*nextSection).numRows()))
break;
nextSection = nextSection->nextSibling();
}
if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
nextSection = m_foot;
- return toRenderTableSection(nextSection);
+ return downcast<RenderTableSection>(nextSection);
}
RenderTableSection* RenderTable::bottomSection() const
@@ -1221,11 +1370,11 @@ RenderTableSection* RenderTable::bottomSection() const
return m_foot;
for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
- if (child->isTableSection())
- return toRenderTableSection(child);
+ if (is<RenderTableSection>(*child))
+ return downcast<RenderTableSection>(child);
}
- return 0;
+ return nullptr;
}
RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
@@ -1234,7 +1383,7 @@ RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
// Find the section and row to look in
unsigned r = cell->rowIndex();
- RenderTableSection* section = 0;
+ RenderTableSection* section = nullptr;
unsigned rAbove = 0;
if (r > 0) {
// cell is not in the first row, so use the above row in its own section
@@ -1254,7 +1403,7 @@ RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
return aboveCell.primaryCell();
} else
- return 0;
+ return nullptr;
}
RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
@@ -1263,7 +1412,7 @@ RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
// Find the section and row to look in
unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
- RenderTableSection* section = 0;
+ RenderTableSection* section = nullptr;
unsigned rBelow = 0;
if (r < cell->section()->numRows() - 1) {
// The cell is not in the last row, so use the next row in the section.
@@ -1281,7 +1430,7 @@ RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
return belowCell.primaryCell();
} else
- return 0;
+ return nullptr;
}
RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
@@ -1291,7 +1440,7 @@ RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
RenderTableSection* section = cell->section();
unsigned effCol = colToEffCol(cell->col());
if (!effCol)
- return 0;
+ return nullptr;
// If we hit a colspan back up to a real cell.
RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
@@ -1304,55 +1453,52 @@ RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
if (effCol >= numEffCols())
- return 0;
+ return nullptr;
return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
}
RenderBlock* RenderTable::firstLineBlock() const
{
- return 0;
+ return nullptr;
}
-void RenderTable::updateFirstLetter()
+void RenderTable::updateFirstLetter(RenderTreeMutationIsAllowed)
{
}
int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
- LayoutUnit baseline = firstLineBaseline();
- if (baseline != -1)
- return baseline;
-
- return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
+ return valueOrCompute(firstLineBaseline(), [&] {
+ return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
+ });
}
-int RenderTable::inlineBlockBaseline(LineDirectionMode) const
+std::optional<int> RenderTable::inlineBlockBaseline(LineDirectionMode) const
{
// Tables are skipped when computing an inline-block's baseline.
- return -1;
+ return std::optional<int>();
}
-int RenderTable::firstLineBaseline() const
+std::optional<int> RenderTable::firstLineBaseline() const
{
// The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
// doesn't define the baseline of a 'table' only an 'inline-table').
// This is also needed to properly determine the baseline of a cell if it has a table child.
if (isWritingModeRoot())
- return -1;
+ return std::optional<int>();
recalcSectionsIfNeeded();
const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
if (!topNonEmptySection)
- return -1;
+ return std::optional<int>();
- int baseline = topNonEmptySection->firstLineBaseline();
- if (baseline > 0)
- return topNonEmptySection->logicalTop() + baseline;
+ if (std::optional<int> baseline = topNonEmptySection->firstLineBaseline())
+ return std::optional<int>(topNonEmptySection->logicalTop() + baseline.value());
// FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
- return -1;
+ return std::optional<int>();
}
LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase phase)
@@ -1390,10 +1536,10 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
LayoutPoint adjustedLocation = accumulatedOffset + location();
// Check kids first.
- if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) {
+ if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, currentRenderNamedFlowFragment()))) {
for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
- if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
- LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
+ if (is<RenderBox>(*child) && !downcast<RenderBox>(*child).hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
+ LayoutPoint childPoint = flipForWritingModeForChild(downcast<RenderBox>(child), adjustedLocation);
if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
return true;
@@ -1413,29 +1559,48 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
return false;
}
-RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
+std::unique_ptr<RenderTable> RenderTable::createTableWithStyle(Document& document, const RenderStyle& style)
{
- auto table = new RenderTable(parent->document(), RenderStyle::createAnonymousStyleWithDisplay(&parent->style(), TABLE));
+ auto table = std::make_unique<RenderTable>(document, RenderStyle::createAnonymousStyleWithDisplay(style, style.display() == INLINE ? INLINE_TABLE : TABLE));
table->initializeStyle();
return table;
}
-const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
+std::unique_ptr<RenderTable> RenderTable::createAnonymousWithParentRenderer(const RenderElement& parent)
+{
+ return RenderTable::createTableWithStyle(parent.document(), parent.style());
+}
+
+const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell& cell) const
{
- ASSERT(cell->isFirstOrLastCellInRow());
- if (hasSameDirectionAs(cell->row()))
+ ASSERT(cell.isFirstOrLastCellInRow());
+ if (isDirectionSame(this, cell.row()))
return style().borderStart();
return style().borderEnd();
}
-const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
+const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell& cell) const
{
- ASSERT(cell->isFirstOrLastCellInRow());
- if (hasSameDirectionAs(cell->row()))
+ ASSERT(cell.isFirstOrLastCellInRow());
+ if (isDirectionSame(this, cell.row()))
return style().borderEnd();
return style().borderStart();
}
+void RenderTable::markForPaginationRelayoutIfNeeded()
+{
+ if (!view().layoutState()->isPaginated() || (!view().layoutState()->pageLogicalHeightChanged() && (!view().layoutState()->pageLogicalHeight() || view().layoutState()->pageLogicalOffset(this, logicalTop()) == pageLogicalOffset())))
+ return;
+
+ // When a table moves, we have to dirty all of the sections too.
+ if (!needsLayout())
+ setChildNeedsLayout(MarkOnlyThis);
+ for (auto& child : childrenOfType<RenderTableSection>(*this)) {
+ if (!child.needsLayout())
+ child.setChildNeedsLayout(MarkOnlyThis);
+ }
+}
+
}