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 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 "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/FastTextAutosizer.h"
35 #include "core/rendering/FixedTableLayout.h"
36 #include "core/rendering/GraphicsContextAnnotator.h"
37 #include "core/rendering/HitTestResult.h"
38 #include "core/rendering/LayoutRepainter.h"
39 #include "core/rendering/RenderLayer.h"
40 #include "core/rendering/RenderTableCaption.h"
41 #include "core/rendering/RenderTableCell.h"
42 #include "core/rendering/RenderTableCol.h"
43 #include "core/rendering/RenderTableSection.h"
44 #include "core/rendering/RenderView.h"
45 #include "core/rendering/SubtreeLayoutScope.h"
46 #include "core/rendering/style/StyleInheritedData.h"
47 #include "platform/graphics/GraphicsContextStateSaver.h"
53 using namespace HTMLNames;
55 RenderTable::RenderTable(Element* element)
56 : RenderBlock(element)
61 , m_collapsedBordersValid(false)
62 , m_hasColElements(false)
63 , m_needsSectionRecalc(false)
64 , m_columnLogicalWidthChanged(false)
65 , m_columnRenderersValid(false)
66 , m_hasCellColspanThatDeterminesTableWidth(false)
72 setChildrenInline(false);
73 m_columnPos.fill(0, 1);
77 RenderTable::~RenderTable()
81 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
83 RenderBlock::styleDidChange(diff, oldStyle);
84 propagateStyleToAnonymousChildren();
86 bool oldFixedTableLayout = oldStyle ? oldStyle->isFixedTableLayout() : false;
88 // In the collapsed border model, there is no cell spacing.
89 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
90 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
91 m_columnPos[0] = m_hSpacing;
93 if (!m_tableLayout || style()->isFixedTableLayout() != oldFixedTableLayout) {
95 m_tableLayout->willChangeTableLayout();
97 // According to the CSS2 spec, you only use fixed table layout if an
98 // explicit width is specified on the table. Auto width implies auto table layout.
99 if (style()->isFixedTableLayout())
100 m_tableLayout = adoptPtr(new FixedTableLayout(this));
102 m_tableLayout = adoptPtr(new AutoTableLayout(this));
105 // If border was changed, invalidate collapsed borders cache.
106 if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
107 invalidateCollapsedBorders();
110 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
114 RenderObject* o = before->previousSibling();
115 while (o && o != ptr)
116 o = o->previousSibling();
121 static inline bool needsTableSection(RenderObject* object)
123 // Return true if 'object' can't exist in an anonymous table without being
124 // wrapped in a table section box.
125 EDisplay display = object->style()->display();
126 return display != TABLE_CAPTION && display != TABLE_COLUMN_GROUP && display != TABLE_COLUMN;
129 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
131 bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
133 if (child->isTableCaption())
134 wrapInAnonymousSection = false;
135 else if (child->isRenderTableCol()) {
136 m_hasColElements = true;
137 wrapInAnonymousSection = false;
138 } else if (child->isTableSection()) {
139 switch (child->style()->display()) {
140 case TABLE_HEADER_GROUP:
141 resetSectionPointerIfNotBefore(m_head, beforeChild);
143 m_head = toRenderTableSection(child);
145 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
147 m_firstBody = toRenderTableSection(child);
149 wrapInAnonymousSection = false;
151 case TABLE_FOOTER_GROUP:
152 resetSectionPointerIfNotBefore(m_foot, beforeChild);
154 m_foot = toRenderTableSection(child);
155 wrapInAnonymousSection = false;
159 case TABLE_ROW_GROUP:
160 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
162 m_firstBody = toRenderTableSection(child);
163 wrapInAnonymousSection = false;
166 ASSERT_NOT_REACHED();
169 wrapInAnonymousSection = true;
171 if (child->isTableSection())
172 setNeedsSectionRecalc();
174 if (!wrapInAnonymousSection) {
175 if (beforeChild && beforeChild->parent() != this)
176 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
178 RenderBox::addChild(child, beforeChild);
182 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
183 lastChild()->addChild(child);
187 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
188 RenderObject* section = beforeChild->previousSibling();
189 if (section && section->isTableSection() && section->isAnonymous()) {
190 section->addChild(child);
195 RenderObject* lastBox = beforeChild;
196 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && needsTableSection(lastBox))
197 lastBox = lastBox->parent();
198 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
199 if (beforeChild == lastBox)
200 beforeChild = lastBox->firstChild();
201 lastBox->addChild(child, beforeChild);
205 if (beforeChild && !beforeChild->isTableSection() && needsTableSection(beforeChild))
208 RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
209 addChild(section, beforeChild);
210 section->addChild(child);
213 void RenderTable::addCaption(const RenderTableCaption* caption)
215 ASSERT(m_captions.find(caption) == kNotFound);
216 m_captions.append(const_cast<RenderTableCaption*>(caption));
219 void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
221 size_t index = m_captions.find(oldCaption);
222 ASSERT(index != kNotFound);
223 if (index == kNotFound)
226 m_captions.remove(index);
229 void RenderTable::invalidateCachedColumns()
231 m_columnRenderersValid = false;
232 m_columnRenderers.resize(0);
235 void RenderTable::addColumn(const RenderTableCol*)
237 invalidateCachedColumns();
240 void RenderTable::removeColumn(const RenderTableCol*)
242 invalidateCachedColumns();
243 // We don't really need to recompute our sections, but we need to update our
244 // column count and whether we have a column. Currently, we only have one
245 // size-fit-all flag but we may have to consider splitting it.
246 setNeedsSectionRecalc();
249 void RenderTable::updateLogicalWidth()
251 recalcSectionsIfNeeded();
253 if (isOutOfFlowPositioned()) {
254 LogicalExtentComputedValues computedValues;
255 computePositionedLogicalWidth(computedValues);
256 setLogicalWidth(computedValues.m_extent);
257 setLogicalLeft(computedValues.m_position);
258 setMarginStart(computedValues.m_margins.m_start);
259 setMarginEnd(computedValues.m_margins.m_end);
262 RenderBlock* cb = containingBlock();
264 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
265 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
266 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
268 Length styleLogicalWidth = style()->logicalWidth();
269 if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
270 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
272 // Subtract out any fixed margins from our available width for auto width tables.
273 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
274 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
275 LayoutUnit marginTotal = marginStart + marginEnd;
277 // Subtract out our margins to get the available content width.
278 LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
279 if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock)
280 availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb));
282 // Ensure we aren't bigger than our available width.
283 setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
286 // Ensure we aren't bigger than our max-width style.
287 Length styleMaxLogicalWidth = style()->logicalMaxWidth();
288 if ((styleMaxLogicalWidth.isSpecified() && !styleMaxLogicalWidth.isNegative()) || styleMaxLogicalWidth.isIntrinsic()) {
289 LayoutUnit computedMaxLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMaxLogicalWidth, availableLogicalWidth);
290 setLogicalWidth(min<int>(logicalWidth(), computedMaxLogicalWidth));
293 // Ensure we aren't smaller than our min preferred width. This MUST be done after 'max-width' as
294 // we ignore it if it means we wouldn't accomodate our content.
295 setLogicalWidth(max<int>(logicalWidth(), minPreferredLogicalWidth()));
297 // Ensure we aren't smaller than our min-width style.
298 Length styleMinLogicalWidth = style()->logicalMinWidth();
299 if ((styleMinLogicalWidth.isSpecified() && !styleMinLogicalWidth.isNegative()) || styleMinLogicalWidth.isIntrinsic()) {
300 LayoutUnit computedMinLogicalWidth = convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth);
301 setLogicalWidth(max<int>(logicalWidth(), computedMinLogicalWidth));
304 // Finally, with our true width determined, compute our margins for real.
307 if (!hasPerpendicularContainingBlock) {
308 ComputedMarginValues marginValues;
309 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection();
310 computeInlineDirectionMargins(cb, availableLogicalWidth, logicalWidth(),
311 hasInvertedDirection ? marginValues.m_start : marginValues.m_end,
312 hasInvertedDirection ? marginValues.m_end : marginValues.m_start);
313 setMarginStart(marginValues.m_start);
314 setMarginEnd(marginValues.m_end);
316 setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth));
317 setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth));
320 // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
321 // its own content which doesn't match CSS nor what authors expect.
322 // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
323 // https://code.google.com/p/chromium/issues/detail?id=241198
324 ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt());
327 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
328 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
330 if (styleLogicalWidth.isIntrinsic())
331 return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
333 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
334 LayoutUnit borders = 0;
335 bool isCSSTable = !isHTMLTableElement(node());
336 if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
337 borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
339 return minimumValueForLength(styleLogicalWidth, availableWidth) + borders;
342 LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
344 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
345 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
346 LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter;
347 LayoutUnit computedLogicalHeight = 0;
348 if (styleLogicalHeight.isFixed()) {
349 // HTML tables size as though CSS height includes border/padding, CSS tables do not.
350 LayoutUnit borders = LayoutUnit();
351 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
352 if (isHTMLTableElement(node()) || style()->boxSizing() == BORDER_BOX) {
353 borders = borderAndPadding;
355 computedLogicalHeight = styleLogicalHeight.value() - borders;
356 } else if (styleLogicalHeight.isPercent())
357 computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
358 else if (styleLogicalHeight.isIntrinsic())
359 computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding);
361 ASSERT_NOT_REACHED();
362 return max<LayoutUnit>(0, computedLogicalHeight);
365 void RenderTable::layoutCaption(RenderTableCaption* caption)
367 LayoutRect captionRect(caption->frameRect());
369 if (caption->needsLayout()) {
370 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
371 // so that it does not mistakenly think any floats in the previous caption intrude into it.
372 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight()));
373 // If RenderTableCaption ever gets a layout() function, use it here.
374 caption->layoutIfNeeded();
376 // Apply the margins to the location now that they are definitely available from layout
377 LayoutUnit captionLogicalTop = collapsedMarginBeforeForChild(caption) + logicalHeight();
378 if (view()->layoutState()->isPaginated()) {
379 captionLogicalTop += caption->paginationStrut();
380 caption->setPaginationStrut(0);
382 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), captionLogicalTop));
384 if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
385 caption->repaintDuringLayoutIfMoved(captionRect);
387 setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption));
390 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
392 if (extraLogicalHeight <= 0)
395 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
396 if (RenderTableSection* section = firstBody())
397 extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
399 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
400 // However our current distribution algorithm does not round properly and thus we can have some remaining height.
401 // ASSERT(!topSection() || !extraLogicalHeight);
404 void RenderTable::simplifiedNormalFlowLayout()
406 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
407 section->layoutIfNeeded();
408 section->computeOverflowFromCells();
412 void RenderTable::layout()
414 ASSERT(needsLayout());
416 if (simplifiedLayout())
419 // Note: RenderTable is handled differently than other RenderBlocks and the LayoutScope
420 // must be created before the table begins laying out.
421 FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this);
423 recalcSectionsIfNeeded();
424 // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
425 // to call this before we call borderStart/borderEnd to avoid getting a stale value.
426 recalcBordersInRowDirection();
428 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
429 SubtreeLayoutScope layouter(*this);
432 // If any table section moved vertically, we will just repaint everything from that
433 // section down (it is quite unlikely that any of the following sections
435 bool sectionMoved = false;
436 LayoutUnit movedSectionLogicalTop = 0;
438 LayoutStateMaintainer statePusher(*this, locationOffset());
442 LayoutUnit oldLogicalWidth = logicalWidth();
443 updateLogicalWidth();
445 if (logicalWidth() != oldLogicalWidth) {
446 for (unsigned i = 0; i < m_captions.size(); i++)
447 layouter.setNeedsLayout(m_captions[i]);
449 // FIXME: The optimisation below doesn't work since the internal table
450 // layout could have changed. We need to add a flag to the table
451 // layout that tells us if something has changed in the min max
452 // calculations to do it correctly.
453 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
454 m_tableLayout->layout();
456 LayoutUnit totalSectionLogicalHeight = 0;
457 LayoutUnit oldTableLogicalTop = 0;
458 for (unsigned i = 0; i < m_captions.size(); i++)
459 oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
461 bool collapsing = collapseBorders();
463 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
464 if (child->isTableSection()) {
465 RenderTableSection* section = toRenderTableSection(child);
466 if (m_columnLogicalWidthChanged)
467 layouter.setChildNeedsLayout(section);
468 section->layoutIfNeeded();
469 totalSectionLogicalHeight += section->calcRowLogicalHeight();
471 section->recalcOuterBorder();
472 ASSERT(!section->needsLayout());
473 } else if (child->isRenderTableCol()) {
474 child->layoutIfNeeded();
475 ASSERT(!child->needsLayout());
477 // FIXME: We should never have other type of children (they should be wrapped in an
478 // anonymous table section) but our code is too crazy and this can happen in practice.
479 // Until this is fixed, let's make sure we don't leave non laid out children in the tree.
480 child->layoutIfNeeded();
484 // FIXME: Collapse caption margin.
485 if (!m_captions.isEmpty()) {
486 for (unsigned i = 0; i < m_captions.size(); i++) {
487 if (m_captions[i]->style()->captionSide() == CAPBOTTOM)
489 layoutCaption(m_captions[i]);
491 if (logicalHeight() != oldTableLogicalTop) {
493 movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
497 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? LayoutUnit() : paddingBefore());
498 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? LayoutUnit() : paddingAfter());
500 setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
502 if (!isOutOfFlowPositioned())
503 updateLogicalHeight();
505 LayoutUnit computedLogicalHeight = 0;
507 Length logicalHeightLength = style()->logicalHeight();
508 if (logicalHeightLength.isIntrinsic() || (logicalHeightLength.isSpecified() && logicalHeightLength.isPositive()))
509 computedLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalHeightLength);
511 Length logicalMaxHeightLength = style()->logicalMaxHeight();
512 if (logicalMaxHeightLength.isIntrinsic() || (logicalMaxHeightLength.isSpecified() && !logicalMaxHeightLength.isNegative())) {
513 LayoutUnit computedMaxLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMaxHeightLength);
514 computedLogicalHeight = min(computedLogicalHeight, computedMaxLogicalHeight);
517 Length logicalMinHeightLength = style()->logicalMinHeight();
518 if (logicalMinHeightLength.isIntrinsic() || (logicalMinHeightLength.isSpecified() && !logicalMinHeightLength.isNegative())) {
519 LayoutUnit computedMinLogicalHeight = convertStyleLogicalHeightToComputedHeight(logicalMinHeightLength);
520 computedLogicalHeight = max(computedLogicalHeight, computedMinLogicalHeight);
523 distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
525 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
526 section->layoutRows();
528 if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document().inQuirksMode()) {
529 // Completely empty tables (with no sections or anything) should at least honor specified height
531 setLogicalHeight(logicalHeight() + computedLogicalHeight);
534 LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
536 sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
538 // position the table sections
539 RenderTableSection* section = topSection();
541 if (!sectionMoved && section->logicalTop() != logicalHeight()) {
543 movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x());
545 section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
547 setLogicalHeight(logicalHeight() + section->logicalHeight());
548 section = sectionBelow(section);
551 setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
553 for (unsigned i = 0; i < m_captions.size(); i++) {
554 if (m_captions[i]->style()->captionSide() != CAPBOTTOM)
556 layoutCaption(m_captions[i]);
559 if (isOutOfFlowPositioned())
560 updateLogicalHeight();
562 // table can be containing block of positioned elements.
563 // FIXME: Only pass true if width or height changed.
564 layoutPositionedObjects(true);
566 updateLayerTransform();
568 // Layout was changed, so probably borders too.
569 invalidateCollapsedBorders();
571 computeOverflow(clientLogicalBottom());
574 // FIXME: This value isn't the intrinsic content logical height, but we need
575 // to update the value as its used by flexbox layout. crbug.com/367324
576 updateIntrinsicContentLogicalHeight(contentLogicalHeight());
578 if (view()->layoutState()->pageLogicalHeight())
579 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
581 bool didFullRepaint = repainter.repaintAfterLayout();
582 // Repaint with our new bounds if they are different from our old bounds.
583 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()
584 && !didFullRepaint && sectionMoved) {
585 if (style()->isHorizontalWritingMode())
586 repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop));
588 repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height()));
591 m_columnLogicalWidthChanged = false;
595 // Collect all the unique border values that we want to paint in a sorted list.
596 void RenderTable::recalcCollapsedBorders()
598 if (m_collapsedBordersValid)
600 m_collapsedBordersValid = true;
601 m_collapsedBorders.clear();
602 for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
603 if (!section->isTableSection())
605 for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) {
606 if (!row->isTableRow())
608 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
609 if (!cell->isTableCell())
611 ASSERT(toRenderTableCell(cell)->table() == this);
612 toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders);
616 RenderTableCell::sortBorderValues(m_collapsedBorders);
620 void RenderTable::addOverflowFromChildren()
622 // Add overflow from borders.
623 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
624 // descendant objects, but since tables don't support overflow:auto, this works out fine.
625 if (collapseBorders()) {
626 int rightBorderOverflow = width() + outerBorderRight() - borderRight();
627 int leftBorderOverflow = borderLeft() - outerBorderLeft();
628 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
629 int topBorderOverflow = borderTop() - outerBorderTop();
630 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
631 if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
632 addLayoutOverflow(borderOverflowRect);
633 addVisualOverflow(borderOverflowRect);
637 // Add overflow from our caption.
638 for (unsigned i = 0; i < m_captions.size(); i++)
639 addOverflowFromChild(m_captions[i]);
641 // Add overflow from our sections.
642 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
643 addOverflowFromChild(section);
646 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
648 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
650 LayoutPoint adjustedPaintOffset = paintOffset + location();
652 PaintPhase paintPhase = paintInfo.phase;
654 if (!isDocumentElement()) {
655 LayoutRect overflowBox = visualOverflowRect();
656 flipForWritingMode(overflowBox);
657 overflowBox.moveBy(adjustedPaintOffset);
658 if (!overflowBox.intersects(paintInfo.rect))
662 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
663 paintObject(paintInfo, adjustedPaintOffset);
665 popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
668 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
670 PaintPhase paintPhase = paintInfo.phase;
671 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
672 paintBoxDecorations(paintInfo, paintOffset);
674 if (paintPhase == PaintPhaseMask) {
675 paintMask(paintInfo, paintOffset);
679 // We're done. We don't bother painting any children.
680 if (paintPhase == PaintPhaseBlockBackground)
683 // We don't paint our own background, but we do let the kids paint their backgrounds.
684 if (paintPhase == PaintPhaseChildBlockBackgrounds)
685 paintPhase = PaintPhaseChildBlockBackground;
687 PaintInfo info(paintInfo);
688 info.phase = paintPhase;
689 info.updatePaintingRootForChildren(this);
691 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
692 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
693 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
694 child->paint(info, childPoint);
698 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
699 recalcCollapsedBorders();
700 // Using our cached sorted styles, we then do individual passes,
701 // painting each style of border from lowest precedence to highest precedence.
702 info.phase = PaintPhaseCollapsedTableBorders;
703 size_t count = m_collapsedBorders.size();
704 for (size_t i = 0; i < count; ++i) {
705 m_currentBorder = &m_collapsedBorders[i];
706 for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
707 LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
708 section->paint(info, childPoint);
715 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
716 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
719 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
721 for (unsigned i = 0; i < m_captions.size(); i++) {
722 LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
723 bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
724 if (style()->isHorizontalWritingMode()) {
725 rect.setHeight(rect.height() - captionLogicalHeight);
727 rect.move(0, captionLogicalHeight);
729 rect.setWidth(rect.width() - captionLogicalHeight);
731 rect.move(captionLogicalHeight, 0);
736 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
738 if (!paintInfo.shouldPaintWithinRoot(this))
741 LayoutRect rect(paintOffset, size());
742 subtractCaptionRect(rect);
743 paintBoxDecorationsWithRect(paintInfo, paintOffset, rect);
746 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
748 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
751 LayoutRect rect(paintOffset, size());
752 subtractCaptionRect(rect);
754 paintMaskImages(paintInfo, rect);
757 void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
759 recalcSectionsIfNeeded();
760 // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
761 // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
762 // of reading out stale values.
763 const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
764 // FIXME: Restructure the table layout code so that we can make this method const.
765 const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
767 // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
770 void RenderTable::computePreferredLogicalWidths()
772 ASSERT(preferredLogicalWidthsDirty());
774 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
776 int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
777 m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
778 m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
780 m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
782 for (unsigned i = 0; i < m_captions.size(); i++)
783 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
785 RenderStyle* styleToUse = style();
786 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width.
787 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
788 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
789 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
792 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth.
793 if (styleToUse->logicalMaxWidth().isFixed()) {
794 // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'.
795 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
796 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
799 // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
800 // so a bunch of tests break doing this naively.
801 clearPreferredLogicalWidthsDirty();
804 RenderTableSection* RenderTable::topNonEmptySection() const
806 RenderTableSection* section = topSection();
807 if (section && !section->numRows())
808 section = sectionBelow(section, SkipEmptySections);
812 void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
814 // We split the column at "position", taking "firstSpan" cells from the span.
815 ASSERT(m_columns[position].span > firstSpan);
816 m_columns.insert(position, ColumnStruct(firstSpan));
817 m_columns[position + 1].span -= firstSpan;
819 // Propagate the change in our columns representation to the sections that don't need
820 // cell recalc. If they do, they will be synced up directly with m_columns later.
821 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
822 if (!child->isTableSection())
825 RenderTableSection* section = toRenderTableSection(child);
826 if (section->needsCellRecalc())
829 section->splitColumn(position, firstSpan);
832 m_columnPos.grow(numEffCols() + 1);
835 void RenderTable::appendColumn(unsigned span)
837 unsigned newColumnIndex = m_columns.size();
838 m_columns.append(ColumnStruct(span));
840 // Unless the table has cell(s) with colspan that exceed the number of columns afforded
841 // by the other rows in the table we can use the fast path when mapping columns to effective columns.
842 m_hasCellColspanThatDeterminesTableWidth = m_hasCellColspanThatDeterminesTableWidth || span > 1;
844 // Propagate the change in our columns representation to the sections that don't need
845 // cell recalc. If they do, they will be synced up directly with m_columns later.
846 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
847 if (!child->isTableSection())
850 RenderTableSection* section = toRenderTableSection(child);
851 if (section->needsCellRecalc())
854 section->appendColumn(newColumnIndex);
857 m_columnPos.grow(numEffCols() + 1);
860 RenderTableCol* RenderTable::firstColumn() const
862 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
863 if (child->isRenderTableCol())
864 return toRenderTableCol(child);
870 void RenderTable::updateColumnCache() const
872 ASSERT(m_hasColElements);
873 ASSERT(m_columnRenderers.isEmpty());
874 ASSERT(!m_columnRenderersValid);
876 for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
877 if (columnRenderer->isTableColumnGroupWithColumnChildren())
879 m_columnRenderers.append(columnRenderer);
881 m_columnRenderersValid = true;
884 RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
886 ASSERT(m_hasColElements);
888 if (!m_columnRenderersValid)
891 unsigned columnCount = 0;
892 for (unsigned i = 0; i < m_columnRenderers.size(); i++) {
893 RenderTableCol* columnRenderer = m_columnRenderers[i];
894 unsigned span = columnRenderer->span();
895 unsigned startCol = columnCount;
897 unsigned endCol = columnCount + span - 1;
899 if (columnCount > col) {
901 *startEdge = startCol == col;
903 *endEdge = endCol == col;
904 return columnRenderer;
910 void RenderTable::recalcSections() const
912 ASSERT(m_needsSectionRecalc);
917 m_hasColElements = false;
918 m_hasCellColspanThatDeterminesTableWidth = hasCellColspanThatDeterminesTableWidth();
920 // We need to get valid pointers to caption, head, foot and first body again
921 RenderObject* nextSibling;
922 for (RenderObject* child = firstChild(); child; child = nextSibling) {
923 nextSibling = child->nextSibling();
924 switch (child->style()->display()) {
926 case TABLE_COLUMN_GROUP:
927 m_hasColElements = true;
929 case TABLE_HEADER_GROUP:
930 if (child->isTableSection()) {
931 RenderTableSection* section = toRenderTableSection(child);
934 else if (!m_firstBody)
935 m_firstBody = section;
936 section->recalcCellsIfNeeded();
939 case TABLE_FOOTER_GROUP:
940 if (child->isTableSection()) {
941 RenderTableSection* section = toRenderTableSection(child);
944 else if (!m_firstBody)
945 m_firstBody = section;
946 section->recalcCellsIfNeeded();
949 case TABLE_ROW_GROUP:
950 if (child->isTableSection()) {
951 RenderTableSection* section = toRenderTableSection(child);
953 m_firstBody = section;
954 section->recalcCellsIfNeeded();
962 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
963 unsigned maxCols = 0;
964 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
965 if (child->isTableSection()) {
966 RenderTableSection* section = toRenderTableSection(child);
967 unsigned sectionCols = section->numColumns();
968 if (sectionCols > maxCols)
969 maxCols = sectionCols;
973 m_columns.resize(maxCols);
974 m_columnPos.resize(maxCols + 1);
976 ASSERT(selfNeedsLayout());
978 m_needsSectionRecalc = false;
981 int RenderTable::calcBorderStart() const
983 if (!collapseBorders())
984 return RenderBlock::borderStart();
986 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
990 unsigned borderWidth = 0;
992 const BorderValue& tableStartBorder = style()->borderStart();
993 if (tableStartBorder.style() == BHIDDEN)
995 if (tableStartBorder.style() > BHIDDEN)
996 borderWidth = tableStartBorder.width();
998 if (RenderTableCol* column = colElement(0)) {
999 // FIXME: We don't account for direction on columns and column groups.
1000 const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
1001 if (columnAdjoiningBorder.style() == BHIDDEN)
1003 if (columnAdjoiningBorder.style() > BHIDDEN)
1004 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
1005 // FIXME: This logic doesn't properly account for the first column in the first column-group case.
1008 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1009 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
1010 if (sectionAdjoiningBorder.style() == BHIDDEN)
1013 if (sectionAdjoiningBorder.style() > BHIDDEN)
1014 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1016 if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
1017 // FIXME: Make this work with perpendicular and flipped cells.
1018 const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
1019 if (startCellAdjoiningBorder.style() == BHIDDEN)
1022 const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
1023 if (firstRowAdjoiningBorder.style() == BHIDDEN)
1026 if (startCellAdjoiningBorder.style() > BHIDDEN)
1027 borderWidth = max(borderWidth, startCellAdjoiningBorder.width());
1028 if (firstRowAdjoiningBorder.style() > BHIDDEN)
1029 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1032 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1035 int RenderTable::calcBorderEnd() const
1037 if (!collapseBorders())
1038 return RenderBlock::borderEnd();
1040 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
1044 unsigned borderWidth = 0;
1046 const BorderValue& tableEndBorder = style()->borderEnd();
1047 if (tableEndBorder.style() == BHIDDEN)
1049 if (tableEndBorder.style() > BHIDDEN)
1050 borderWidth = tableEndBorder.width();
1052 unsigned endColumn = numEffCols() - 1;
1053 if (RenderTableCol* column = colElement(endColumn)) {
1054 // FIXME: We don't account for direction on columns and column groups.
1055 const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
1056 if (columnAdjoiningBorder.style() == BHIDDEN)
1058 if (columnAdjoiningBorder.style() > BHIDDEN)
1059 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
1060 // FIXME: This logic doesn't properly account for the last column in the last column-group case.
1063 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1064 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
1065 if (sectionAdjoiningBorder.style() == BHIDDEN)
1068 if (sectionAdjoiningBorder.style() > BHIDDEN)
1069 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1071 if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
1072 // FIXME: Make this work with perpendicular and flipped cells.
1073 const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
1074 if (endCellAdjoiningBorder.style() == BHIDDEN)
1077 const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
1078 if (firstRowAdjoiningBorder.style() == BHIDDEN)
1081 if (endCellAdjoiningBorder.style() > BHIDDEN)
1082 borderWidth = max(borderWidth, endCellAdjoiningBorder.width());
1083 if (firstRowAdjoiningBorder.style() > BHIDDEN)
1084 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1087 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1090 void RenderTable::recalcBordersInRowDirection()
1092 // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1093 m_borderStart = calcBorderStart();
1094 m_borderEnd = calcBorderEnd();
1097 int RenderTable::borderBefore() const
1099 if (collapseBorders()) {
1100 recalcSectionsIfNeeded();
1101 return outerBorderBefore();
1103 return RenderBlock::borderBefore();
1106 int RenderTable::borderAfter() const
1108 if (collapseBorders()) {
1109 recalcSectionsIfNeeded();
1110 return outerBorderAfter();
1112 return RenderBlock::borderAfter();
1115 int RenderTable::outerBorderBefore() const
1117 if (!collapseBorders())
1119 int borderWidth = 0;
1120 if (RenderTableSection* topSection = this->topSection()) {
1121 borderWidth = topSection->outerBorderBefore();
1122 if (borderWidth < 0)
1123 return 0; // Overridden by hidden
1125 const BorderValue& tb = style()->borderBefore();
1126 if (tb.style() == BHIDDEN)
1128 if (tb.style() > BHIDDEN)
1129 borderWidth = max<int>(borderWidth, tb.width() / 2);
1133 int RenderTable::outerBorderAfter() const
1135 if (!collapseBorders())
1137 int borderWidth = 0;
1139 if (RenderTableSection* section = bottomSection()) {
1140 borderWidth = section->outerBorderAfter();
1141 if (borderWidth < 0)
1142 return 0; // Overridden by hidden
1144 const BorderValue& tb = style()->borderAfter();
1145 if (tb.style() == BHIDDEN)
1147 if (tb.style() > BHIDDEN)
1148 borderWidth = max<int>(borderWidth, (tb.width() + 1) / 2);
1152 int RenderTable::outerBorderStart() const
1154 if (!collapseBorders())
1157 int borderWidth = 0;
1159 const BorderValue& tb = style()->borderStart();
1160 if (tb.style() == BHIDDEN)
1162 if (tb.style() > BHIDDEN)
1163 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1165 bool allHidden = true;
1166 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1167 int sw = section->outerBorderStart();
1171 borderWidth = max(borderWidth, sw);
1179 int RenderTable::outerBorderEnd() const
1181 if (!collapseBorders())
1184 int borderWidth = 0;
1186 const BorderValue& tb = style()->borderEnd();
1187 if (tb.style() == BHIDDEN)
1189 if (tb.style() > BHIDDEN)
1190 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1192 bool allHidden = true;
1193 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1194 int sw = section->outerBorderEnd();
1198 borderWidth = max(borderWidth, sw);
1206 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1208 recalcSectionsIfNeeded();
1210 if (section == m_head)
1213 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1214 while (prevSection) {
1215 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1217 prevSection = prevSection->previousSibling();
1219 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1220 prevSection = m_head;
1221 return toRenderTableSection(prevSection);
1224 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1226 recalcSectionsIfNeeded();
1228 if (section == m_foot)
1231 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1232 while (nextSection) {
1233 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1235 nextSection = nextSection->nextSibling();
1237 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1238 nextSection = m_foot;
1239 return toRenderTableSection(nextSection);
1242 RenderTableSection* RenderTable::bottomSection() const
1244 recalcSectionsIfNeeded();
1249 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1250 if (child->isTableSection())
1251 return toRenderTableSection(child);
1257 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1259 recalcSectionsIfNeeded();
1261 // Find the section and row to look in
1262 unsigned r = cell->rowIndex();
1263 RenderTableSection* section = 0;
1264 unsigned rAbove = 0;
1266 // cell is not in the first row, so use the above row in its own section
1267 section = cell->section();
1270 section = sectionAbove(cell->section(), SkipEmptySections);
1272 ASSERT(section->numRows());
1273 rAbove = section->numRows() - 1;
1277 // Look up the cell in the section's grid, which requires effective col index
1279 unsigned effCol = colToEffCol(cell->col());
1280 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1281 return aboveCell.primaryCell();
1286 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1288 recalcSectionsIfNeeded();
1290 // Find the section and row to look in
1291 unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1292 RenderTableSection* section = 0;
1293 unsigned rBelow = 0;
1294 if (r < cell->section()->numRows() - 1) {
1295 // The cell is not in the last row, so use the next row in the section.
1296 section = cell->section();
1299 section = sectionBelow(cell->section(), SkipEmptySections);
1304 // Look up the cell in the section's grid, which requires effective col index
1306 unsigned effCol = colToEffCol(cell->col());
1307 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1308 return belowCell.primaryCell();
1313 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1315 recalcSectionsIfNeeded();
1317 RenderTableSection* section = cell->section();
1318 unsigned effCol = colToEffCol(cell->col());
1322 // If we hit a colspan back up to a real cell.
1323 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1324 return prevCell.primaryCell();
1327 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1329 recalcSectionsIfNeeded();
1331 unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1332 if (effCol >= numEffCols())
1334 return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1337 RenderBlock* RenderTable::firstLineBlock() const
1342 void RenderTable::updateFirstLetter()
1346 int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1348 ASSERT(linePositionMode == PositionOnContainingLine);
1349 int baseline = firstLineBoxBaseline();
1350 if (baseline != -1) {
1352 return beforeMarginInLineDirection(direction) + baseline;
1356 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
1359 int RenderTable::inlineBlockBaseline(LineDirectionMode) const
1361 // Tables are skipped when computing an inline-block's baseline.
1365 int RenderTable::firstLineBoxBaseline() const
1367 // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1368 // doesn't define the baseline of a 'table' only an 'inline-table').
1369 // This is also needed to properly determine the baseline of a cell if it has a table child.
1371 if (isWritingModeRoot())
1374 recalcSectionsIfNeeded();
1376 const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1377 if (!topNonEmptySection)
1380 int baseline = topNonEmptySection->firstLineBoxBaseline();
1382 return topNonEmptySection->logicalTop() + baseline;
1384 // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
1388 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy)
1390 LayoutRect rect = RenderBlock::overflowClipRect(location, relevancy);
1392 // If we have a caption, expand the clip to include the caption.
1393 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1394 // for real until captions have been re-written.
1395 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1396 // supported. When we actually support left/right and stop mapping them to top/bottom,
1397 // we might have to hack this code first (depending on what order we do these bug fixes in).
1398 if (!m_captions.isEmpty()) {
1399 if (style()->isHorizontalWritingMode()) {
1400 rect.setHeight(height());
1401 rect.setY(location.y());
1403 rect.setWidth(width());
1404 rect.setX(location.x());
1411 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1413 LayoutPoint adjustedLocation = accumulatedOffset + location();
1415 // Check kids first.
1416 if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation))) {
1417 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1418 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1419 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1420 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1421 updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1428 // Check our bounds next.
1429 LayoutRect boundsRect(adjustedLocation, size());
1430 if (visibleToHitTestRequest(request) && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) {
1431 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation)));
1432 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1439 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1441 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1442 RenderTable* newTable = new RenderTable(0);
1443 newTable->setDocumentForAnonymous(&parent->document());
1444 newTable->setStyle(newStyle.release());
1448 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1450 ASSERT(cell->isFirstOrLastCellInRow());
1451 if (hasSameDirectionAs(cell->row()))
1452 return style()->borderStart();
1454 return style()->borderEnd();
1457 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1459 ASSERT(cell->isFirstOrLastCellInRow());
1460 if (hasSameDirectionAs(cell->row()))
1461 return style()->borderEnd();
1463 return style()->borderStart();