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/rendering/RenderTable.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/rendering/AutoTableLayout.h"
34 #include "core/rendering/FixedTableLayout.h"
35 #include "core/rendering/GraphicsContextAnnotator.h"
36 #include "core/rendering/HitTestResult.h"
37 #include "core/rendering/RenderLayer.h"
38 #include "core/rendering/RenderTableCaption.h"
39 #include "core/rendering/RenderTableCell.h"
40 #include "core/rendering/RenderTableCol.h"
41 #include "core/rendering/RenderTableSection.h"
42 #include "core/rendering/RenderView.h"
43 #include "core/rendering/SubtreeLayoutScope.h"
44 #include "core/rendering/TextAutosizer.h"
45 #include "core/rendering/style/StyleInheritedData.h"
46 #include "platform/graphics/GraphicsContextStateSaver.h"
50 using namespace HTMLNames;
52 RenderTable::RenderTable(Element* element)
53 : RenderBlock(element)
58 , m_collapsedBordersValid(false)
59 , m_hasColElements(false)
60 , m_needsSectionRecalc(false)
61 , m_columnLogicalWidthChanged(false)
62 , m_columnRenderersValid(false)
63 , m_hasCellColspanThatDeterminesTableWidth(false)
69 ASSERT(!childrenInline());
70 m_columnPos.fill(0, 1);
73 RenderTable::~RenderTable()
77 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
79 RenderBlock::styleDidChange(diff, oldStyle);
80 propagateStyleToAnonymousChildren();
82 bool oldFixedTableLayout = oldStyle ? oldStyle->isFixedTableLayout() : false;
84 // In the collapsed border model, there is no cell spacing.
85 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
86 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
87 m_columnPos[0] = m_hSpacing;
89 if (!m_tableLayout || style()->isFixedTableLayout() != oldFixedTableLayout) {
91 m_tableLayout->willChangeTableLayout();
93 // According to the CSS2 spec, you only use fixed table layout if an
94 // explicit width is specified on the table. Auto width implies auto table layout.
95 if (style()->isFixedTableLayout())
96 m_tableLayout = adoptPtr(new FixedTableLayout(this));
98 m_tableLayout = adoptPtr(new AutoTableLayout(this));
101 // If border was changed, invalidate collapsed borders cache.
102 if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
103 invalidateCollapsedBorders();
106 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
110 RenderObject* o = before->previousSibling();
111 while (o && o != ptr)
112 o = o->previousSibling();
117 static inline bool needsTableSection(RenderObject* object)
119 // Return true if 'object' can't exist in an anonymous table without being
120 // wrapped in a table section box.
121 EDisplay display = object->style()->display();
122 return display != TABLE_CAPTION && display != TABLE_COLUMN_GROUP && display != TABLE_COLUMN;
125 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
127 bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
129 if (child->isTableCaption())
130 wrapInAnonymousSection = false;
131 else if (child->isRenderTableCol()) {
132 m_hasColElements = true;
133 wrapInAnonymousSection = false;
134 } else if (child->isTableSection()) {
135 switch (child->style()->display()) {
136 case TABLE_HEADER_GROUP:
137 resetSectionPointerIfNotBefore(m_head, beforeChild);
139 m_head = toRenderTableSection(child);
141 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
143 m_firstBody = toRenderTableSection(child);
145 wrapInAnonymousSection = false;
147 case TABLE_FOOTER_GROUP:
148 resetSectionPointerIfNotBefore(m_foot, beforeChild);
150 m_foot = toRenderTableSection(child);
151 wrapInAnonymousSection = false;
155 case TABLE_ROW_GROUP:
156 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
158 m_firstBody = toRenderTableSection(child);
159 wrapInAnonymousSection = false;
162 ASSERT_NOT_REACHED();
165 wrapInAnonymousSection = true;
167 if (child->isTableSection())
168 setNeedsSectionRecalc();
170 if (!wrapInAnonymousSection) {
171 if (beforeChild && beforeChild->parent() != this)
172 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
174 RenderBox::addChild(child, beforeChild);
178 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
179 lastChild()->addChild(child);
183 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
184 RenderObject* section = beforeChild->previousSibling();
185 if (section && section->isTableSection() && section->isAnonymous()) {
186 section->addChild(child);
191 RenderObject* lastBox = beforeChild;
192 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && needsTableSection(lastBox))
193 lastBox = lastBox->parent();
194 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
195 if (beforeChild == lastBox)
196 beforeChild = lastBox->slowFirstChild();
197 lastBox->addChild(child, beforeChild);
201 if (beforeChild && !beforeChild->isTableSection() && needsTableSection(beforeChild))
204 RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
205 addChild(section, beforeChild);
206 section->addChild(child);
209 void RenderTable::addCaption(const RenderTableCaption* caption)
211 ASSERT(m_captions.find(caption) == kNotFound);
212 m_captions.append(const_cast<RenderTableCaption*>(caption));
215 void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
217 size_t index = m_captions.find(oldCaption);
218 ASSERT(index != kNotFound);
219 if (index == kNotFound)
222 m_captions.remove(index);
225 void RenderTable::invalidateCachedColumns()
227 m_columnRenderersValid = false;
228 m_columnRenderers.resize(0);
231 void RenderTable::addColumn(const RenderTableCol*)
233 invalidateCachedColumns();
236 void RenderTable::removeColumn(const RenderTableCol*)
238 invalidateCachedColumns();
239 // We don't really need to recompute our sections, but we need to update our
240 // column count and whether we have a column. Currently, we only have one
241 // size-fit-all flag but we may have to consider splitting it.
242 setNeedsSectionRecalc();
245 void RenderTable::updateLogicalWidth()
247 recalcSectionsIfNeeded();
249 if (isOutOfFlowPositioned()) {
250 LogicalExtentComputedValues computedValues;
251 computePositionedLogicalWidth(computedValues);
252 setLogicalWidth(computedValues.m_extent);
253 setLogicalLeft(computedValues.m_position);
254 setMarginStart(computedValues.m_margins.m_start);
255 setMarginEnd(computedValues.m_margins.m_end);
258 RenderBlock* cb = containingBlock();
260 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent() + (isOutOfFlowPositioned() ? cb->paddingLogicalWidth() : LayoutUnit(0));
261 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
262 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
264 Length styleLogicalWidth = style()->logicalWidth();
265 if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
266 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
268 // Subtract out any fixed margins from our available width for auto width tables.
269 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
270 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
271 LayoutUnit marginTotal = marginStart + marginEnd;
273 // Subtract out our margins to get the available content width.
274 LayoutUnit availableContentLogicalWidth = std::max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
275 if (shrinkToAvoidFloats() && cb->isRenderBlockFlow() && toRenderBlockFlow(cb)->containsFloats() && !hasPerpendicularContainingBlock)
276 availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb));
278 // Ensure we aren't bigger than our available width.
279 setLogicalWidth(std::min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
282 // Ensure we aren't bigger than our max-width style.
283 Length styleMaxLogicalWidth = style()->logicalMaxWidth();
284 if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
285 LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
286 setLogicalWidth(std::min<int>(logicalWidth(), computedMaxLogicalWidth));
289 // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as
290 // we ignore it if it means we wouldn't accomodate our content.
291 setLogicalWidth(std::max<int>(logicalWidth(), minPreferredLogicalWidth()));
293 // Ensure we aren't smaller than our min-width style.
294 Length styleMinLogicalWidth = style()->logicalMinWidth();
295 if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
296 LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
297 setLogicalWidth(std::max<int>(logicalWidth(), computedMinLogicalWidth));
300 // Finally, with our true width determined, compute our margins for real.
301 ComputedMarginValues marginValues;
302 computeMarginsForDirection(InlineDirection, cb, availableLogicalWidth, logicalWidth(), marginValues.m_start, marginValues.m_end, style()->marginStart(), style()->marginEnd());
303 setMarginStart(marginValues.m_start);
304 setMarginEnd(marginValues.m_end);
306 // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
307 // its own content which doesn't match CSS nor what authors expect.
308 // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
309 // https://code.google.com/p/chromium/issues/detail?id=241198
310 ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt());
313 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
314 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
316 if (styleLogicalWidth.isIntrinsic())
317 return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
319 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
320 LayoutUnit borders = 0;
321 bool isCSSTable = !isHTMLTableElement(node());
322 if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
323 borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
325 return minimumValueForLength(styleLogicalWidth, availableWidth) + borders;
328 LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
330 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
331 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
332 LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter;
333 LayoutUnit computedLogicalHeight = 0;
334 if (styleLogicalHeight.isFixed()) {
335 // HTML tables size as though CSS height includes border/padding, CSS tables do not.
336 LayoutUnit borders = LayoutUnit();
337 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
338 if (isHTMLTableElement(node()) || style()->boxSizing() == BORDER_BOX) {
339 borders = borderAndPadding;
341 computedLogicalHeight = styleLogicalHeight.value() - borders;
342 } else if (styleLogicalHeight.isPercent())
343 computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
344 else if (styleLogicalHeight.isIntrinsic())
345 computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding);
347 ASSERT_NOT_REACHED();
348 return std::max<LayoutUnit>(0, computedLogicalHeight);
351 void RenderTable::layoutCaption(RenderTableCaption* caption)
353 if (caption->needsLayout()) {
354 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
355 // so that it does not mistakenly think any floats in the previous caption intrude into it.
356 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight()));
357 // If RenderTableCaption ever gets a layout() function, use it here.
358 caption->layoutIfNeeded();
360 // Apply the margins to the location now that they are definitely available from layout
361 LayoutUnit captionLogicalTop = collapsedMarginBeforeForChild(caption) + logicalHeight();
362 if (view()->layoutState()->isPaginated()) {
363 captionLogicalTop += caption->paginationStrut();
364 caption->setPaginationStrut(0);
366 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), captionLogicalTop));
368 if (!selfNeedsLayout())
369 caption->setMayNeedPaintInvalidation(true);
371 setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption));
374 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
376 if (extraLogicalHeight <= 0)
379 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
380 if (RenderTableSection* section = firstBody())
381 extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
383 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
384 // However our current distribution algorithm does not round properly and thus we can have some remaining height.
385 // ASSERT(!topSection() || !extraLogicalHeight);
388 void RenderTable::simplifiedNormalFlowLayout()
390 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
391 section->layoutIfNeeded();
392 section->computeOverflowFromCells();
396 void RenderTable::layout()
398 ASSERT(needsLayout());
400 if (simplifiedLayout())
403 // Note: RenderTable is handled differently than other RenderBlocks and the LayoutScope
404 // must be created before the table begins laying out.
405 TextAutosizer::LayoutScope textAutosizerLayoutScope(this);
407 recalcSectionsIfNeeded();
408 // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
409 // to call this before we call borderStart/borderEnd to avoid getting a stale value.
410 recalcBordersInRowDirection();
412 SubtreeLayoutScope layouter(*this);
414 // If any table section moved vertically, we will just repaint everything from that
415 // section down (it is quite unlikely that any of the following sections
417 bool sectionMoved = false;
418 LayoutUnit movedSectionLogicalTop = 0;
420 LayoutState state(*this, locationOffset());
424 LayoutUnit oldLogicalWidth = logicalWidth();
425 updateLogicalWidth();
427 if (logicalWidth() != oldLogicalWidth) {
428 for (unsigned i = 0; i < m_captions.size(); i++)
429 layouter.setNeedsLayout(m_captions[i]);
431 // FIXME: The optimisation below doesn't work since the internal table
432 // layout could have changed. We need to add a flag to the table
433 // layout that tells us if something has changed in the min max
434 // calculations to do it correctly.
435 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
436 m_tableLayout->layout();
438 LayoutUnit totalSectionLogicalHeight = 0;
439 LayoutUnit oldTableLogicalTop = 0;
440 for (unsigned i = 0; i < m_captions.size(); i++)
441 oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
443 bool collapsing = collapseBorders();
445 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
446 if (child->isTableSection()) {
447 RenderTableSection* section = toRenderTableSection(child);
448 if (m_columnLogicalWidthChanged)
449 layouter.setChildNeedsLayout(section);
450 section->layoutIfNeeded();
451 totalSectionLogicalHeight += section->calcRowLogicalHeight();
453 section->recalcOuterBorder();
454 ASSERT(!section->needsLayout());
455 } else if (child->isRenderTableCol()) {
456 child->layoutIfNeeded();
457 ASSERT(!child->needsLayout());
459 // FIXME: We should never have other type of children (they should be wrapped in an
460 // anonymous table section) but our code is too crazy and this can happen in practice.
461 // Until this is fixed, let's make sure we don't leave non laid out children in the tree.
462 child->layoutIfNeeded();
466 // FIXME: Collapse caption margin.
467 if (!m_captions.isEmpty()) {
468 for (unsigned i = 0; i < m_captions.size(); i++) {
469 if (m_captions[i]->style()->captionSide() == CAPBOTTOM)
471 layoutCaption(m_captions[i]);
473 if (logicalHeight() != oldTableLogicalTop) {
475 movedSectionLogicalTop = std::min(logicalHeight(), oldTableLogicalTop);
479 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore());
480 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter());
482 setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
484 LayoutUnit computedLogicalHeight = 0;
486 Length logicalHeightLength = style()->logicalHeight();
487 if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive()))
488 computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength);
490 Length logicalMaxHeightLength = style()->logicalMaxHeight();
491 if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) {
492 LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength);
493 computedLogicalHeight = std::min(computedLogicalHeight, computedMaxLogicalHeight);
496 Length logicalMinHeightLength = style()->logicalMinHeight();
497 if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) {
498 LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength);
499 computedLogicalHeight = std::max(computedLogicalHeight, computedMinLogicalHeight);
502 distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
504 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
505 section->layoutRows();
507 if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) {
508 // Completely empty tables (with no sections or anything) should at least honor specified height
510 setLogicalHeight(logicalHeight() + computedLogicalHeight);
513 LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
515 sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
517 // position the table sections
518 RenderTableSection* section = topSection();
520 if (!sectionMoved && section->logicalTop() != logicalHeight()) {
522 movedSectionLogicalTop = std::min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x());
524 section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
526 // As we may skip invalidation on the table, we need to ensure that sections are invalidated when they moved.
527 if (sectionMoved && !section->selfNeedsLayout())
528 section->setMayNeedPaintInvalidation(true);
530 setLogicalHeight(logicalHeight() + section->logicalHeight());
532 section = sectionBelow(section);
535 setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
537 for (unsigned i = 0; i < m_captions.size(); i++) {
538 if (m_captions[i]->style()->captionSide() != CAPBOTTOM)
540 layoutCaption(m_captions[i]);
543 updateLogicalHeight();
545 // table can be containing block of positioned elements.
546 // FIXME: Only pass true if width or height changed.
547 layoutPositionedObjects(true);
549 updateLayerTransformAfterLayout();
551 // Layout was changed, so probably borders too.
552 invalidateCollapsedBorders();
554 computeOverflow(clientLogicalBottom());
557 // FIXME: This value isn't the intrinsic content logical height, but we need
558 // to update the value as its used by flexbox layout. crbug.com/367324
559 updateIntrinsicContentLogicalHeight(contentLogicalHeight());
561 if (view()->layoutState()->pageLogicalHeight())
562 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
564 m_columnLogicalWidthChanged = false;
568 // Collect all the unique border values that we want to paint in a sorted list.
569 void RenderTable::recalcCollapsedBorders()
571 if (m_collapsedBordersValid)
573 m_collapsedBordersValid = true;
574 m_collapsedBorders.clear();
575 for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
576 if (!section->isTableSection())
578 for (RenderTableRow* row = toRenderTableSection(section)->firstRow(); row; row = row->nextRow()) {
579 for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) {
580 ASSERT(cell->table() == this);
581 cell->collectBorderValues(m_collapsedBorders);
585 RenderTableCell::sortBorderValues(m_collapsedBorders);
589 void RenderTable::addOverflowFromChildren()
591 // Add overflow from borders.
592 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
593 // descendant objects, but since tables don't support overflow:auto, this works out fine.
594 if (collapseBorders()) {
595 int rightBorderOverflow = width() + outerBorderRight() - borderRight();
596 int leftBorderOverflow = borderLeft() - outerBorderLeft();
597 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
598 int topBorderOverflow = borderTop() - outerBorderTop();
599 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
600 if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
601 addLayoutOverflow(borderOverflowRect);
602 addVisualOverflow(borderOverflowRect);
606 // Add overflow from our caption.
607 for (unsigned i = 0; i < m_captions.size(); i++)
608 addOverflowFromChild(m_captions[i]);
610 // Add overflow from our sections.
611 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
612 addOverflowFromChild(section);
615 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
617 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
619 LayoutPoint adjustedPaintOffset = paintOffset + location();
621 PaintPhase paintPhase = paintInfo.phase;
623 if (!isDocumentElement()) {
624 LayoutRect overflowBox = visualOverflowRect();
625 flipForWritingMode(overflowBox);
626 overflowBox.moveBy(adjustedPaintOffset);
627 if (!overflowBox.intersects(paintInfo.rect))
631 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
632 paintObject(paintInfo, adjustedPaintOffset);
634 popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
637 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
639 PaintPhase paintPhase = paintInfo.phase;
640 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorationBackground() && style()->visibility() == VISIBLE)
641 paintBoxDecorationBackground(paintInfo, paintOffset);
643 if (paintPhase == PaintPhaseMask) {
644 paintMask(paintInfo, paintOffset);
648 // We're done. We don't bother painting any children.
649 if (paintPhase == PaintPhaseBlockBackground)
652 // We don't paint our own background, but we do let the kids paint their backgrounds.
653 if (paintPhase == PaintPhaseChildBlockBackgrounds)
654 paintPhase = PaintPhaseChildBlockBackground;
656 PaintInfo info(paintInfo);
657 info.phase = paintPhase;
658 info.updatePaintingRootForChildren(this);
660 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
661 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
662 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
663 child->paint(info, childPoint);
667 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
668 recalcCollapsedBorders();
669 // Using our cached sorted styles, we then do individual passes,
670 // painting each style of border from lowest precedence to highest precedence.
671 info.phase = PaintPhaseCollapsedTableBorders;
672 size_t count = m_collapsedBorders.size();
673 for (size_t i = 0; i < count; ++i) {
674 m_currentBorder = &m_collapsedBorders[i];
675 for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
676 LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
677 section->paint(info, childPoint);
684 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
685 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
688 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
690 for (unsigned i = 0; i < m_captions.size(); i++) {
691 LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
692 bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
693 if (style()->isHorizontalWritingMode()) {
694 rect.setHeight(rect.height() - captionLogicalHeight);
696 rect.move(0, captionLogicalHeight);
698 rect.setWidth(rect.width() - captionLogicalHeight);
700 rect.move(captionLogicalHeight, 0);
705 void RenderTable::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
707 if (!paintInfo.shouldPaintWithinRoot(this))
710 LayoutRect rect(paintOffset, size());
711 subtractCaptionRect(rect);
712 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, rect);
715 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
717 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
720 LayoutRect rect(paintOffset, size());
721 subtractCaptionRect(rect);
723 paintMaskImages(paintInfo, rect);
726 void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
728 recalcSectionsIfNeeded();
729 // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
730 // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
731 // of reading out stale values.
732 const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
733 // FIXME: Restructure the table layout code so that we can make this method const.
734 const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
736 // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
739 void RenderTable::computePreferredLogicalWidths()
741 ASSERT(preferredLogicalWidthsDirty());
743 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
745 int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
746 m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
747 m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
749 m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
751 for (unsigned i = 0; i < m_captions.size(); i++)
752 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
754 RenderStyle* styleToUse = style();
755 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width.
756 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
757 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
758 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
761 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth.
762 if (styleToUse->logicalMaxWidth().isFixed()) {
763 // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'.
764 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
765 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
768 // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
769 // so a bunch of tests break doing this naively.
770 clearPreferredLogicalWidthsDirty();
773 RenderTableSection* RenderTable::topNonEmptySection() const
775 RenderTableSection* section = topSection();
776 if (section && !section->numRows())
777 section = sectionBelow(section, SkipEmptySections);
781 void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
783 // We split the column at "position", taking "firstSpan" cells from the span.
784 ASSERT(m_columns[position].span > firstSpan);
785 m_columns.insert(position, ColumnStruct(firstSpan));
786 m_columns[position + 1].span -= firstSpan;
788 // Propagate the change in our columns representation to the sections that don't need
789 // cell recalc. If they do, they will be synced up directly with m_columns later.
790 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
791 if (!child->isTableSection())
794 RenderTableSection* section = toRenderTableSection(child);
795 if (section->needsCellRecalc())
798 section->splitColumn(position, firstSpan);
801 m_columnPos.grow(numEffCols() + 1);
804 void RenderTable::appendColumn(unsigned span)
806 unsigned newColumnIndex = m_columns.size();
807 m_columns.append(ColumnStruct(span));
809 // Unless the table has cell(s) with colspan that exceed the number of columns afforded
810 // by the other rows in the table we can use the fast path when mapping columns to effective columns.
811 m_hasCellColspanThatDeterminesTableWidth = m_hasCellColspanThatDeterminesTableWidth || span > 1;
813 // Propagate the change in our columns representation to the sections that don't need
814 // cell recalc. If they do, they will be synced up directly with m_columns later.
815 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
816 if (!child->isTableSection())
819 RenderTableSection* section = toRenderTableSection(child);
820 if (section->needsCellRecalc())
823 section->appendColumn(newColumnIndex);
826 m_columnPos.grow(numEffCols() + 1);
829 RenderTableCol* RenderTable::firstColumn() const
831 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
832 if (child->isRenderTableCol())
833 return toRenderTableCol(child);
839 void RenderTable::updateColumnCache() const
841 ASSERT(m_hasColElements);
842 ASSERT(m_columnRenderers.isEmpty());
843 ASSERT(!m_columnRenderersValid);
845 for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
846 if (columnRenderer->isTableColumnGroupWithColumnChildren())
848 m_columnRenderers.append(columnRenderer);
850 m_columnRenderersValid = true;
853 RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
855 ASSERT(m_hasColElements);
857 if (!m_columnRenderersValid)
860 unsigned columnCount = 0;
861 for (unsigned i = 0; i < m_columnRenderers.size(); i++) {
862 RenderTableCol* columnRenderer = m_columnRenderers[i];
863 unsigned span = columnRenderer->span();
864 unsigned startCol = columnCount;
866 unsigned endCol = columnCount + span - 1;
868 if (columnCount > col) {
870 *startEdge = startCol == col;
872 *endEdge = endCol == col;
873 return columnRenderer;
879 void RenderTable::recalcSections() const
881 ASSERT(m_needsSectionRecalc);
886 m_hasColElements = false;
887 m_hasCellColspanThatDeterminesTableWidth = hasCellColspanThatDeterminesTableWidth();
889 // We need to get valid pointers to caption, head, foot and first body again
890 RenderObject* nextSibling;
891 for (RenderObject* child = firstChild(); child; child = nextSibling) {
892 nextSibling = child->nextSibling();
893 switch (child->style()->display()) {
895 case TABLE_COLUMN_GROUP:
896 m_hasColElements = true;
898 case TABLE_HEADER_GROUP:
899 if (child->isTableSection()) {
900 RenderTableSection* section = toRenderTableSection(child);
903 else if (!m_firstBody)
904 m_firstBody = section;
905 section->recalcCellsIfNeeded();
908 case TABLE_FOOTER_GROUP:
909 if (child->isTableSection()) {
910 RenderTableSection* section = toRenderTableSection(child);
913 else if (!m_firstBody)
914 m_firstBody = section;
915 section->recalcCellsIfNeeded();
918 case TABLE_ROW_GROUP:
919 if (child->isTableSection()) {
920 RenderTableSection* section = toRenderTableSection(child);
922 m_firstBody = section;
923 section->recalcCellsIfNeeded();
931 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
932 unsigned maxCols = 0;
933 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
934 if (child->isTableSection()) {
935 RenderTableSection* section = toRenderTableSection(child);
936 unsigned sectionCols = section->numColumns();
937 if (sectionCols > maxCols)
938 maxCols = sectionCols;
942 m_columns.resize(maxCols);
943 m_columnPos.resize(maxCols + 1);
945 ASSERT(selfNeedsLayout());
947 m_needsSectionRecalc = false;
950 int RenderTable::calcBorderStart() const
952 if (!collapseBorders())
953 return RenderBlock::borderStart();
955 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
959 unsigned borderWidth = 0;
961 const BorderValue& tableStartBorder = style()->borderStart();
962 if (tableStartBorder.style() == BHIDDEN)
964 if (tableStartBorder.style() > BHIDDEN)
965 borderWidth = tableStartBorder.width();
967 if (RenderTableCol* column = colElement(0)) {
968 // FIXME: We don't account for direction on columns and column groups.
969 const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
970 if (columnAdjoiningBorder.style() == BHIDDEN)
972 if (columnAdjoiningBorder.style() > BHIDDEN)
973 borderWidth = std::max(borderWidth, columnAdjoiningBorder.width());
974 // FIXME: This logic doesn't properly account for the first column in the first column-group case.
977 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
978 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
979 if (sectionAdjoiningBorder.style() == BHIDDEN)
982 if (sectionAdjoiningBorder.style() > BHIDDEN)
983 borderWidth = std::max(borderWidth, sectionAdjoiningBorder.width());
985 if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
986 // FIXME: Make this work with perpendicular and flipped cells.
987 const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
988 if (startCellAdjoiningBorder.style() == BHIDDEN)
991 const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
992 if (firstRowAdjoiningBorder.style() == BHIDDEN)
995 if (startCellAdjoiningBorder.style() > BHIDDEN)
996 borderWidth = std::max(borderWidth, startCellAdjoiningBorder.width());
997 if (firstRowAdjoiningBorder.style() > BHIDDEN)
998 borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width());
1001 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1004 int RenderTable::calcBorderEnd() const
1006 if (!collapseBorders())
1007 return RenderBlock::borderEnd();
1009 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
1013 unsigned borderWidth = 0;
1015 const BorderValue& tableEndBorder = style()->borderEnd();
1016 if (tableEndBorder.style() == BHIDDEN)
1018 if (tableEndBorder.style() > BHIDDEN)
1019 borderWidth = tableEndBorder.width();
1021 unsigned endColumn = numEffCols() - 1;
1022 if (RenderTableCol* column = colElement(endColumn)) {
1023 // FIXME: We don't account for direction on columns and column groups.
1024 const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
1025 if (columnAdjoiningBorder.style() == BHIDDEN)
1027 if (columnAdjoiningBorder.style() > BHIDDEN)
1028 borderWidth = std::max(borderWidth, columnAdjoiningBorder.width());
1029 // FIXME: This logic doesn't properly account for the last column in the last column-group case.
1032 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1033 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
1034 if (sectionAdjoiningBorder.style() == BHIDDEN)
1037 if (sectionAdjoiningBorder.style() > BHIDDEN)
1038 borderWidth = std::max(borderWidth, sectionAdjoiningBorder.width());
1040 if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
1041 // FIXME: Make this work with perpendicular and flipped cells.
1042 const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
1043 if (endCellAdjoiningBorder.style() == BHIDDEN)
1046 const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
1047 if (firstRowAdjoiningBorder.style() == BHIDDEN)
1050 if (endCellAdjoiningBorder.style() > BHIDDEN)
1051 borderWidth = std::max(borderWidth, endCellAdjoiningBorder.width());
1052 if (firstRowAdjoiningBorder.style() > BHIDDEN)
1053 borderWidth = std::max(borderWidth, firstRowAdjoiningBorder.width());
1056 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1059 void RenderTable::recalcBordersInRowDirection()
1061 // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1062 m_borderStart = calcBorderStart();
1063 m_borderEnd = calcBorderEnd();
1066 int RenderTable::borderBefore() const
1068 if (collapseBorders()) {
1069 recalcSectionsIfNeeded();
1070 return outerBorderBefore();
1072 return RenderBlock::borderBefore();
1075 int RenderTable::borderAfter() const
1077 if (collapseBorders()) {
1078 recalcSectionsIfNeeded();
1079 return outerBorderAfter();
1081 return RenderBlock::borderAfter();
1084 int RenderTable::outerBorderBefore() const
1086 if (!collapseBorders())
1088 int borderWidth = 0;
1089 if (RenderTableSection* topSection = this->topSection()) {
1090 borderWidth = topSection->outerBorderBefore();
1091 if (borderWidth < 0)
1092 return 0; // Overridden by hidden
1094 const BorderValue& tb = style()->borderBefore();
1095 if (tb.style() == BHIDDEN)
1097 if (tb.style() > BHIDDEN)
1098 borderWidth = std::max<int>(borderWidth, tb.width() / 2);
1102 int RenderTable::outerBorderAfter() const
1104 if (!collapseBorders())
1106 int borderWidth = 0;
1108 if (RenderTableSection* section = bottomSection()) {
1109 borderWidth = section->outerBorderAfter();
1110 if (borderWidth < 0)
1111 return 0; // Overridden by hidden
1113 const BorderValue& tb = style()->borderAfter();
1114 if (tb.style() == BHIDDEN)
1116 if (tb.style() > BHIDDEN)
1117 borderWidth = std::max<int>(borderWidth, (tb.width() + 1) / 2);
1121 int RenderTable::outerBorderStart() const
1123 if (!collapseBorders())
1126 int borderWidth = 0;
1128 const BorderValue& tb = style()->borderStart();
1129 if (tb.style() == BHIDDEN)
1131 if (tb.style() > BHIDDEN)
1132 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1134 bool allHidden = true;
1135 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1136 int sw = section->outerBorderStart();
1140 borderWidth = std::max(borderWidth, sw);
1148 int RenderTable::outerBorderEnd() const
1150 if (!collapseBorders())
1153 int borderWidth = 0;
1155 const BorderValue& tb = style()->borderEnd();
1156 if (tb.style() == BHIDDEN)
1158 if (tb.style() > BHIDDEN)
1159 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1161 bool allHidden = true;
1162 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1163 int sw = section->outerBorderEnd();
1167 borderWidth = std::max(borderWidth, sw);
1175 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1177 recalcSectionsIfNeeded();
1179 if (section == m_head)
1182 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1183 while (prevSection) {
1184 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1186 prevSection = prevSection->previousSibling();
1188 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1189 prevSection = m_head;
1190 return toRenderTableSection(prevSection);
1193 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1195 recalcSectionsIfNeeded();
1197 if (section == m_foot)
1200 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1201 while (nextSection) {
1202 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1204 nextSection = nextSection->nextSibling();
1206 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1207 nextSection = m_foot;
1208 return toRenderTableSection(nextSection);
1211 RenderTableSection* RenderTable::bottomSection() const
1213 recalcSectionsIfNeeded();
1218 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1219 if (child->isTableSection())
1220 return toRenderTableSection(child);
1226 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1228 recalcSectionsIfNeeded();
1230 // Find the section and row to look in
1231 unsigned r = cell->rowIndex();
1232 RenderTableSection* section = 0;
1233 unsigned rAbove = 0;
1235 // cell is not in the first row, so use the above row in its own section
1236 section = cell->section();
1239 section = sectionAbove(cell->section(), SkipEmptySections);
1241 ASSERT(section->numRows());
1242 rAbove = section->numRows() - 1;
1246 // Look up the cell in the section's grid, which requires effective col index
1248 unsigned effCol = colToEffCol(cell->col());
1249 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1250 return aboveCell.primaryCell();
1255 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1257 recalcSectionsIfNeeded();
1259 // Find the section and row to look in
1260 unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1261 RenderTableSection* section = 0;
1262 unsigned rBelow = 0;
1263 if (r < cell->section()->numRows() - 1) {
1264 // The cell is not in the last row, so use the next row in the section.
1265 section = cell->section();
1268 section = sectionBelow(cell->section(), SkipEmptySections);
1273 // Look up the cell in the section's grid, which requires effective col index
1275 unsigned effCol = colToEffCol(cell->col());
1276 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1277 return belowCell.primaryCell();
1282 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1284 recalcSectionsIfNeeded();
1286 RenderTableSection* section = cell->section();
1287 unsigned effCol = colToEffCol(cell->col());
1291 // If we hit a colspan back up to a real cell.
1292 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1293 return prevCell.primaryCell();
1296 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1298 recalcSectionsIfNeeded();
1300 unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1301 if (effCol >= numEffCols())
1303 return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1306 int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1308 ASSERT(linePositionMode == PositionOnContainingLine);
1309 int baseline = firstLineBoxBaseline();
1310 if (baseline != -1) {
1312 return beforeMarginInLineDirection(direction) + baseline;
1316 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
1319 int RenderTable::inlineBlockBaseline(LineDirectionMode) const
1321 // Tables are skipped when computing an inline-block's baseline.
1325 int RenderTable::firstLineBoxBaseline() const
1327 // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1328 // doesn't define the baseline of a 'table' only an 'inline-table').
1329 // This is also needed to properly determine the baseline of a cell if it has a table child.
1331 if (isWritingModeRoot())
1334 recalcSectionsIfNeeded();
1336 const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1337 if (!topNonEmptySection)
1340 int baseline = topNonEmptySection->firstLineBoxBaseline();
1342 return topNonEmptySection->logicalTop() + baseline;
1344 // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
1348 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy)
1350 LayoutRect rect = RenderBlock::overflowClipRect(location, relevancy);
1352 // If we have a caption, expand the clip to include the caption.
1353 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1354 // for real until captions have been re-written.
1355 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1356 // supported. When we actually support left/right and stop mapping them to top/bottom,
1357 // we might have to hack this code first (depending on what order we do these bug fixes in).
1358 if (!m_captions.isEmpty()) {
1359 if (style()->isHorizontalWritingMode()) {
1360 rect.setHeight(height());
1361 rect.setY(location.y());
1363 rect.setWidth(width());
1364 rect.setX(location.x());
1371 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1373 LayoutPoint adjustedLocation = accumulatedOffset + location();
1375 // Check kids first.
1376 if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation))) {
1377 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1378 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1379 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1380 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1381 updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1388 // Check our bounds next.
1389 LayoutRect boundsRect(adjustedLocation, size());
1390 if (visibleToHitTestRequest(request) && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) {
1391 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation)));
1392 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1399 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1401 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1402 RenderTable* newTable = new RenderTable(0);
1403 newTable->setDocumentForAnonymous(&parent->document());
1404 newTable->setStyle(newStyle.release());
1408 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1410 ASSERT(cell->isFirstOrLastCellInRow());
1411 if (hasSameDirectionAs(cell->row()))
1412 return style()->borderStart();
1414 return style()->borderEnd();
1417 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1419 ASSERT(cell->isFirstOrLastCellInRow());
1420 if (hasSameDirectionAs(cell->row()))
1421 return style()->borderEnd();
1423 return style()->borderStart();