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 "RenderTable.h"
29 #include "AutoTableLayout.h"
30 #include "CollapsedBorderValue.h"
31 #include "DeleteButtonController.h"
33 #include "FixedTableLayout.h"
34 #include "FrameView.h"
35 #include "HitTestResult.h"
36 #include "HTMLNames.h"
37 #include "LayoutRepainter.h"
38 #include "RenderLayer.h"
39 #include "RenderTableCaption.h"
40 #include "RenderTableCell.h"
41 #include "RenderTableCol.h"
42 #include "RenderTableSection.h"
43 #include "RenderView.h"
49 using namespace HTMLNames;
51 RenderTable::RenderTable(Node* node)
57 , m_collapsedBordersValid(false)
58 , m_hasColElements(false)
59 , m_needsSectionRecalc(false)
65 setChildrenInline(false);
66 m_columnPos.fill(0, 1);
70 RenderTable::~RenderTable()
74 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
76 RenderBlock::styleDidChange(diff, oldStyle);
77 propagateStyleToAnonymousChildren();
79 ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
81 // In the collapsed border model, there is no cell spacing.
82 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
83 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
84 m_columnPos[0] = m_hSpacing;
86 if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
87 // According to the CSS2 spec, you only use fixed table layout if an
88 // explicit width is specified on the table. Auto width implies auto table layout.
89 if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto())
90 m_tableLayout = adoptPtr(new FixedTableLayout(this));
92 m_tableLayout = adoptPtr(new AutoTableLayout(this));
95 // If border was changed, invalidate collapsed borders cache.
96 if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
97 invalidateCollapsedBorders();
100 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
104 RenderObject* o = before->previousSibling();
105 while (o && o != ptr)
106 o = o->previousSibling();
111 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
113 // Make sure we don't append things after :after-generated content if we have it.
115 beforeChild = afterPseudoElementRenderer();
117 bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
119 if (child->isTableCaption()) {
120 m_captions.append(toRenderTableCaption(child));
121 wrapInAnonymousSection = false;
122 } else if (child->isRenderTableCol()) {
123 m_hasColElements = true;
124 wrapInAnonymousSection = false;
125 } else if (child->isTableSection()) {
126 switch (child->style()->display()) {
127 case TABLE_HEADER_GROUP:
128 resetSectionPointerIfNotBefore(m_head, beforeChild);
130 m_head = toRenderTableSection(child);
132 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
134 m_firstBody = toRenderTableSection(child);
136 wrapInAnonymousSection = false;
138 case TABLE_FOOTER_GROUP:
139 resetSectionPointerIfNotBefore(m_foot, beforeChild);
141 m_foot = toRenderTableSection(child);
142 wrapInAnonymousSection = false;
146 case TABLE_ROW_GROUP:
147 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
149 m_firstBody = toRenderTableSection(child);
150 wrapInAnonymousSection = false;
153 ASSERT_NOT_REACHED();
155 } else if (child->isTableCell() || child->isTableRow())
156 wrapInAnonymousSection = true;
158 wrapInAnonymousSection = true;
160 if (!wrapInAnonymousSection) {
161 if (beforeChild && beforeChild->parent() != this)
162 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
164 RenderBox::addChild(child, beforeChild);
168 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
169 lastChild()->addChild(child);
173 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
174 RenderObject* section = beforeChild->previousSibling();
175 if (section && section->isTableSection() && section->isAnonymous()) {
176 section->addChild(child);
181 RenderObject* lastBox = beforeChild;
182 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
183 lastBox = lastBox->parent();
184 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
185 if (beforeChild == lastBox)
186 beforeChild = lastBox->firstChild();
187 lastBox->addChild(child, beforeChild);
191 if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
194 RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
195 addChild(section, beforeChild);
196 section->addChild(child);
199 void RenderTable::removeChild(RenderObject* oldChild)
201 RenderBox::removeChild(oldChild);
203 size_t index = m_captions.find(oldChild);
204 if (index != notFound) {
205 m_captions.remove(index);
207 node()->setNeedsStyleRecalc();
209 setNeedsSectionRecalc();
212 void RenderTable::computeLogicalWidth()
214 recalcSectionsIfNeeded();
216 if (isOutOfFlowPositioned())
217 computePositionedLogicalWidth();
219 RenderBlock* cb = containingBlock();
220 RenderView* renderView = view();
222 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
223 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
224 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
226 Length styleLogicalWidth = style()->logicalWidth();
227 if (styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive())
228 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
230 // Subtract out any fixed margins from our available width for auto width tables.
231 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
232 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
233 LayoutUnit marginTotal = marginStart + marginEnd;
235 // Subtract out our margins to get the available content width.
236 LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
237 if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
238 // FIXME: Work with regions someday.
239 availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, 0, 0);
242 // Ensure we aren't bigger than our available width.
243 setLogicalWidth(min<int>(availableContentLogicalWidth, maxPreferredLogicalWidth()));
246 // Ensure we aren't smaller than our min preferred width.
247 setLogicalWidth(max<int>(logicalWidth(), minPreferredLogicalWidth()));
249 // Ensure we aren't smaller than our min-width style.
250 Length styleMinLogicalWidth = style()->logicalMinWidth();
251 if (styleMinLogicalWidth.isSpecified() && styleMinLogicalWidth.isPositive())
252 setLogicalWidth(max<int>(logicalWidth(), convertStyleLogicalWidthToComputedWidth(styleMinLogicalWidth, availableLogicalWidth)));
254 // Finally, with our true width determined, compute our margins for real.
257 if (!hasPerpendicularContainingBlock) {
258 LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
259 if (avoidsFloats() && cb->containsFloats())
260 containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0, 0); // FIXME: Work with regions someday.
261 computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth());
263 setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView));
264 setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView));
268 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
269 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
271 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
272 LayoutUnit borders = 0;
273 bool isCSSTable = !node() || !node()->hasTagName(tableTag);
274 if (isCSSTable && styleLogicalWidth.isFixed() && styleLogicalWidth.isPositive()) {
275 recalcBordersInRowDirection();
276 if (style()->boxSizing() == CONTENT_BOX)
277 borders = borderStart() + borderEnd() + (collapseBorders() ? ZERO_LAYOUT_UNIT : paddingStart() + paddingEnd());
279 return minimumValueForLength(styleLogicalWidth, availableWidth, view()) + borders;
282 void RenderTable::layoutCaption(RenderTableCaption* caption)
284 LayoutRect captionRect(caption->frameRect());
286 if (caption->needsLayout()) {
287 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
288 // so that it does not mistakenly think any floats in the previous caption intrude into it.
289 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
290 // If RenderTableCaption ever gets a layout() function, use it here.
291 caption->layoutIfNeeded();
293 // Apply the margins to the location now that they are definitely available from layout
294 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), caption->marginBefore() + logicalHeight()));
296 if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
297 caption->repaintDuringLayoutIfMoved(captionRect);
299 setLogicalHeight(logicalHeight() + caption->logicalHeight() + caption->marginBefore() + caption->marginAfter());
302 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
304 if (extraLogicalHeight <= 0)
307 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
308 if (RenderTableSection* section = firstBody())
309 extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
311 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
312 // However our current distribution algorithm does not round properly and thus we can have some remaining height.
313 // ASSERT(!topSection() || !extraLogicalHeight);
316 void RenderTable::layout()
318 ASSERT(needsLayout());
320 if (simplifiedLayout())
323 recalcSectionsIfNeeded();
325 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
326 LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
331 initMaxMarginValues();
333 LayoutUnit oldLogicalWidth = logicalWidth();
334 computeLogicalWidth();
336 if (logicalWidth() != oldLogicalWidth) {
337 for (unsigned i = 0; i < m_captions.size(); i++)
338 m_captions[i]->setNeedsLayout(true, MarkOnlyThis);
340 // FIXME: The optimisation below doesn't work since the internal table
341 // layout could have changed. we need to add a flag to the table
342 // layout that tells us if something has changed in the min max
343 // calculations to do it correctly.
344 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
345 m_tableLayout->layout();
347 setCellLogicalWidths();
349 LayoutUnit totalSectionLogicalHeight = 0;
350 LayoutUnit oldTableLogicalTop = 0;
351 for (unsigned i = 0; i < m_captions.size(); i++)
352 oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
354 bool collapsing = collapseBorders();
356 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
357 if (child->isTableSection()) {
358 child->layoutIfNeeded();
359 RenderTableSection* section = toRenderTableSection(child);
360 totalSectionLogicalHeight += section->calcRowLogicalHeight();
362 section->recalcOuterBorder();
363 ASSERT(!section->needsLayout());
364 } else if (child->isRenderTableCol()) {
365 child->layoutIfNeeded();
366 ASSERT(!child->needsLayout());
370 // If any table section moved vertically, we will just repaint everything from that
371 // section down (it is quite unlikely that any of the following sections
373 bool sectionMoved = false;
374 LayoutUnit movedSectionLogicalTop = 0;
376 // FIXME: Collapse caption margin.
377 if (!m_captions.isEmpty()) {
378 for (unsigned i = 0; i < m_captions.size(); i++) {
379 if (m_captions[i]->style()->captionSide() == CAPBOTTOM)
381 layoutCaption(m_captions[i]);
383 if (logicalHeight() != oldTableLogicalTop) {
385 movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
389 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? ZERO_LAYOUT_UNIT : paddingBefore());
390 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? ZERO_LAYOUT_UNIT : paddingAfter());
392 setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
394 if (!isOutOfFlowPositioned())
395 computeLogicalHeight();
397 Length logicalHeightLength = style()->logicalHeight();
398 LayoutUnit computedLogicalHeight = 0;
399 if (logicalHeightLength.isFixed()) {
400 // HTML tables size as though CSS height includes border/padding, CSS tables do not.
401 LayoutUnit borders = ZERO_LAYOUT_UNIT;
402 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
403 if ((node() && node()->hasTagName(tableTag)) || style()->boxSizing() == BORDER_BOX)
404 borders = borderAndPaddingBefore + borderAndPaddingAfter;
405 computedLogicalHeight = logicalHeightLength.value() - borders;
406 } else if (logicalHeightLength.isPercent())
407 computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength);
408 computedLogicalHeight = max<LayoutUnit>(0, computedLogicalHeight);
410 distributeExtraLogicalHeight(floorToInt(computedLogicalHeight - totalSectionLogicalHeight));
412 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
413 section->layoutRows();
415 if (!topSection() && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) {
416 // Completely empty tables (with no sections or anything) should at least honor specified height
418 setLogicalHeight(logicalHeight() + computedLogicalHeight);
421 LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
423 sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
425 // position the table sections
426 RenderTableSection* section = topSection();
428 if (!sectionMoved && section->logicalTop() != logicalHeight()) {
430 movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->visualOverflowRect().y() : section->visualOverflowRect().x());
432 section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
434 setLogicalHeight(logicalHeight() + section->logicalHeight());
435 section = sectionBelow(section);
438 setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
440 for (unsigned i = 0; i < m_captions.size(); i++) {
441 if (m_captions[i]->style()->captionSide() != CAPBOTTOM)
443 layoutCaption(m_captions[i]);
446 if (isOutOfFlowPositioned())
447 computeLogicalHeight();
449 // table can be containing block of positioned elements.
450 // FIXME: Only pass true if width or height changed.
451 layoutPositionedObjects(true);
453 updateLayerTransform();
455 // Layout was changed, so probably borders too.
456 invalidateCollapsedBorders();
458 computeOverflow(clientLogicalBottom());
462 if (view()->layoutState()->pageLogicalHeight())
463 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
465 bool didFullRepaint = repainter.repaintAfterLayout();
466 // Repaint with our new bounds if they are different from our old bounds.
467 if (!didFullRepaint && sectionMoved) {
468 if (style()->isHorizontalWritingMode())
469 repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop));
471 repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height()));
474 setNeedsLayout(false);
477 // Collect all the unique border values that we want to paint in a sorted list.
478 void RenderTable::recalcCollapsedBorders()
480 if (m_collapsedBordersValid)
482 m_collapsedBordersValid = true;
483 m_collapsedBorders.clear();
484 for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
485 if (!section->isTableSection())
487 for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) {
488 if (!row->isTableRow())
490 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
491 if (!cell->isTableCell())
493 ASSERT(toRenderTableCell(cell)->table() == this);
494 toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders);
498 RenderTableCell::sortBorderValues(m_collapsedBorders);
502 void RenderTable::addOverflowFromChildren()
504 // Add overflow from borders.
505 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
506 // descendant objects, but since tables don't support overflow:auto, this works out fine.
507 if (collapseBorders()) {
508 int rightBorderOverflow = width() + outerBorderRight() - borderRight();
509 int leftBorderOverflow = borderLeft() - outerBorderLeft();
510 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
511 int topBorderOverflow = borderTop() - outerBorderTop();
512 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
513 if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
514 addLayoutOverflow(borderOverflowRect);
515 addVisualOverflow(borderOverflowRect);
519 // Add overflow from our caption.
520 for (unsigned i = 0; i < m_captions.size(); i++)
521 addOverflowFromChild(m_captions[i]);
523 // Add overflow from our sections.
524 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
525 addOverflowFromChild(section);
528 void RenderTable::setCellLogicalWidths()
530 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
531 section->setCellLogicalWidths();
534 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
536 LayoutPoint adjustedPaintOffset = paintOffset + location();
538 PaintPhase paintPhase = paintInfo.phase;
541 LayoutRect overflowBox = visualOverflowRect();
542 flipForWritingMode(overflowBox);
543 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
544 overflowBox.moveBy(adjustedPaintOffset);
545 if (!overflowBox.intersects(paintInfo.rect))
549 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
550 paintObject(paintInfo, adjustedPaintOffset);
552 popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
555 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
557 PaintPhase paintPhase = paintInfo.phase;
558 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
559 paintBoxDecorations(paintInfo, paintOffset);
561 if (paintPhase == PaintPhaseMask) {
562 paintMask(paintInfo, paintOffset);
566 // We're done. We don't bother painting any children.
567 if (paintPhase == PaintPhaseBlockBackground)
570 // We don't paint our own background, but we do let the kids paint their backgrounds.
571 if (paintPhase == PaintPhaseChildBlockBackgrounds)
572 paintPhase = PaintPhaseChildBlockBackground;
574 PaintInfo info(paintInfo);
575 info.phase = paintPhase;
576 info.updatePaintingRootForChildren(this);
578 IntPoint alignedOffset = roundedIntPoint(paintOffset);
580 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
581 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
582 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), alignedOffset);
583 child->paint(info, childPoint);
587 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
588 recalcCollapsedBorders();
589 // Using our cached sorted styles, we then do individual passes,
590 // painting each style of border from lowest precedence to highest precedence.
591 info.phase = PaintPhaseCollapsedTableBorders;
592 size_t count = m_collapsedBorders.size();
593 for (size_t i = 0; i < count; ++i) {
594 m_currentBorder = &m_collapsedBorders[i];
595 for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
596 LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
597 section->paint(info, childPoint);
604 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
605 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
608 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
610 for (unsigned i = 0; i < m_captions.size(); i++) {
611 LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
612 bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
613 if (style()->isHorizontalWritingMode()) {
614 rect.setHeight(rect.height() - captionLogicalHeight);
616 rect.move(0, captionLogicalHeight);
618 rect.setWidth(rect.width() - captionLogicalHeight);
620 rect.move(captionLogicalHeight, 0);
625 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
627 if (!paintInfo.shouldPaintWithinRoot(this))
630 LayoutRect rect(paintOffset, size());
631 subtractCaptionRect(rect);
633 if (!boxShadowShouldBeAppliedToBackground(determineBackgroundBleedAvoidance(paintInfo.context)))
634 paintBoxShadow(paintInfo, rect, style(), Normal);
635 paintBackground(paintInfo, rect);
636 paintBoxShadow(paintInfo, rect, style(), Inset);
638 if (style()->hasBorder() && !collapseBorders())
639 paintBorder(paintInfo, rect, style());
642 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
644 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
647 LayoutRect rect(paintOffset, size());
648 subtractCaptionRect(rect);
650 paintMaskImages(paintInfo, rect);
653 void RenderTable::computePreferredLogicalWidths()
655 ASSERT(preferredLogicalWidthsDirty());
657 recalcSectionsIfNeeded();
658 recalcBordersInRowDirection();
660 m_tableLayout->computePreferredLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
662 for (unsigned i = 0; i < m_captions.size(); i++)
663 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
665 setPreferredLogicalWidthsDirty(false);
668 RenderTableSection* RenderTable::topNonEmptySection() const
670 RenderTableSection* section = topSection();
671 if (section && !section->numRows())
672 section = sectionBelow(section, SkipEmptySections);
676 void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
678 // we need to add a new columnStruct
679 unsigned oldSize = m_columns.size();
680 m_columns.grow(oldSize + 1);
681 unsigned oldSpan = m_columns[position].span;
682 ASSERT(oldSpan > firstSpan);
683 m_columns[position].span = firstSpan;
684 memmove(m_columns.data() + position + 1, m_columns.data() + position, (oldSize - position) * sizeof(ColumnStruct));
685 m_columns[position + 1].span = oldSpan - firstSpan;
687 // Propagate the change in our columns representation to the sections that don't need
688 // cell recalc. If they do, they will be synced up directly with m_columns later.
689 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
690 if (!child->isTableSection())
693 RenderTableSection* section = toRenderTableSection(child);
694 if (section->needsCellRecalc())
697 section->splitColumn(position, firstSpan);
700 m_columnPos.grow(numEffCols() + 1);
701 setNeedsLayoutAndPrefWidthsRecalc();
704 void RenderTable::appendColumn(unsigned span)
706 unsigned pos = m_columns.size();
707 unsigned newSize = pos + 1;
708 m_columns.grow(newSize);
709 m_columns[pos].span = span;
711 // Propagate the change in our columns representation to the sections that don't need
712 // cell recalc. If they do, they will be synced up directly with m_columns later.
713 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
714 if (!child->isTableSection())
717 RenderTableSection* section = toRenderTableSection(child);
718 if (section->needsCellRecalc())
721 section->appendColumn(pos);
724 m_columnPos.grow(numEffCols() + 1);
725 setNeedsLayoutAndPrefWidthsRecalc();
728 RenderTableCol* RenderTable::firstColumn() const
730 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
731 if (child->isRenderTableCol())
732 return toRenderTableCol(child);
734 // We allow only table-captions before columns or column-groups.
735 if (!child->isTableCaption())
742 RenderTableCol* RenderTable::colElement(unsigned col, bool* startEdge, bool* endEdge) const
744 if (!m_hasColElements)
747 unsigned columnCount = 0;
748 for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
749 if (columnRenderer->isTableColumnGroupWithColumnChildren())
752 unsigned span = columnRenderer->span();
753 unsigned startCol = columnCount;
755 unsigned endCol = columnCount + span - 1;
757 if (columnCount > col) {
759 *startEdge = startCol == col;
761 *endEdge = endCol == col;
762 return columnRenderer;
769 void RenderTable::recalcSections() const
771 ASSERT(m_needsSectionRecalc);
776 m_hasColElements = false;
779 // We need to get valid pointers to caption, head, foot and first body again
780 RenderObject* nextSibling;
781 for (RenderObject* child = firstChild(); child; child = nextSibling) {
782 nextSibling = child->nextSibling();
783 switch (child->style()->display()) {
785 if (child->isTableCaption())
786 m_captions.append(toRenderTableCaption(child));
789 case TABLE_COLUMN_GROUP:
790 m_hasColElements = true;
792 case TABLE_HEADER_GROUP:
793 if (child->isTableSection()) {
794 RenderTableSection* section = toRenderTableSection(child);
797 else if (!m_firstBody)
798 m_firstBody = section;
799 section->recalcCellsIfNeeded();
802 case TABLE_FOOTER_GROUP:
803 if (child->isTableSection()) {
804 RenderTableSection* section = toRenderTableSection(child);
807 else if (!m_firstBody)
808 m_firstBody = section;
809 section->recalcCellsIfNeeded();
812 case TABLE_ROW_GROUP:
813 if (child->isTableSection()) {
814 RenderTableSection* section = toRenderTableSection(child);
816 m_firstBody = section;
817 section->recalcCellsIfNeeded();
825 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
826 unsigned maxCols = 0;
827 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
828 if (child->isTableSection()) {
829 RenderTableSection* section = toRenderTableSection(child);
830 unsigned sectionCols = section->numColumns();
831 if (sectionCols > maxCols)
832 maxCols = sectionCols;
836 m_columns.resize(maxCols);
837 m_columnPos.resize(maxCols + 1);
839 ASSERT(selfNeedsLayout());
841 m_needsSectionRecalc = false;
844 int RenderTable::calcBorderStart() const
846 if (!collapseBorders())
847 return RenderBlock::borderStart();
849 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
853 unsigned borderWidth = 0;
855 const BorderValue& tableStartBorder = style()->borderStart();
856 if (tableStartBorder.style() == BHIDDEN)
858 if (tableStartBorder.style() > BHIDDEN)
859 borderWidth = tableStartBorder.width();
861 if (RenderTableCol* column = colElement(0)) {
862 // FIXME: We don't account for direction on columns and column groups.
863 const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
864 if (columnAdjoiningBorder.style() == BHIDDEN)
866 if (columnAdjoiningBorder.style() > BHIDDEN)
867 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
868 // FIXME: This logic doesn't properly account for the first column in the first column-group case.
871 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
872 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
873 if (sectionAdjoiningBorder.style() == BHIDDEN)
876 if (sectionAdjoiningBorder.style() > BHIDDEN)
877 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
879 if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
880 // FIXME: Make this work with perpendicular and flipped cells.
881 const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
882 if (startCellAdjoiningBorder.style() == BHIDDEN)
885 const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
886 if (firstRowAdjoiningBorder.style() == BHIDDEN)
889 if (startCellAdjoiningBorder.style() > BHIDDEN)
890 borderWidth = max(borderWidth, startCellAdjoiningBorder.width());
891 if (firstRowAdjoiningBorder.style() > BHIDDEN)
892 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
895 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
898 int RenderTable::calcBorderEnd() const
900 if (!collapseBorders())
901 return RenderBlock::borderEnd();
903 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
907 unsigned borderWidth = 0;
909 const BorderValue& tableEndBorder = style()->borderEnd();
910 if (tableEndBorder.style() == BHIDDEN)
912 if (tableEndBorder.style() > BHIDDEN)
913 borderWidth = tableEndBorder.width();
915 unsigned endColumn = numEffCols() - 1;
916 if (RenderTableCol* column = colElement(endColumn)) {
917 // FIXME: We don't account for direction on columns and column groups.
918 const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
919 if (columnAdjoiningBorder.style() == BHIDDEN)
921 if (columnAdjoiningBorder.style() > BHIDDEN)
922 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
923 // FIXME: This logic doesn't properly account for the last column in the last column-group case.
926 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
927 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
928 if (sectionAdjoiningBorder.style() == BHIDDEN)
931 if (sectionAdjoiningBorder.style() > BHIDDEN)
932 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
934 if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
935 // FIXME: Make this work with perpendicular and flipped cells.
936 const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
937 if (endCellAdjoiningBorder.style() == BHIDDEN)
940 const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
941 if (firstRowAdjoiningBorder.style() == BHIDDEN)
944 if (endCellAdjoiningBorder.style() > BHIDDEN)
945 borderWidth = max(borderWidth, endCellAdjoiningBorder.width());
946 if (firstRowAdjoiningBorder.style() > BHIDDEN)
947 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
950 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
953 void RenderTable::recalcBordersInRowDirection()
955 // FIXME: We need to compute the collapsed before / after borders in the same fashion.
956 m_borderStart = calcBorderStart();
957 m_borderEnd = calcBorderEnd();
960 int RenderTable::borderBefore() const
962 if (collapseBorders()) {
963 recalcSectionsIfNeeded();
964 return outerBorderBefore();
966 return RenderBlock::borderBefore();
969 int RenderTable::borderAfter() const
971 if (collapseBorders()) {
972 recalcSectionsIfNeeded();
973 return outerBorderAfter();
975 return RenderBlock::borderAfter();
978 int RenderTable::outerBorderBefore() const
980 if (!collapseBorders())
983 if (RenderTableSection* topSection = this->topSection()) {
984 borderWidth = topSection->outerBorderBefore();
986 return 0; // Overridden by hidden
988 const BorderValue& tb = style()->borderBefore();
989 if (tb.style() == BHIDDEN)
991 if (tb.style() > BHIDDEN)
992 borderWidth = max<int>(borderWidth, tb.width() / 2);
996 int RenderTable::outerBorderAfter() const
998 if (!collapseBorders())
1000 int borderWidth = 0;
1002 if (RenderTableSection* section = bottomSection()) {
1003 borderWidth = section->outerBorderAfter();
1004 if (borderWidth < 0)
1005 return 0; // Overridden by hidden
1007 const BorderValue& tb = style()->borderAfter();
1008 if (tb.style() == BHIDDEN)
1010 if (tb.style() > BHIDDEN)
1011 borderWidth = max<int>(borderWidth, (tb.width() + 1) / 2);
1015 int RenderTable::outerBorderStart() const
1017 if (!collapseBorders())
1020 int borderWidth = 0;
1022 const BorderValue& tb = style()->borderStart();
1023 if (tb.style() == BHIDDEN)
1025 if (tb.style() > BHIDDEN)
1026 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1028 bool allHidden = true;
1029 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1030 int sw = section->outerBorderStart();
1034 borderWidth = max(borderWidth, sw);
1042 int RenderTable::outerBorderEnd() const
1044 if (!collapseBorders())
1047 int borderWidth = 0;
1049 const BorderValue& tb = style()->borderEnd();
1050 if (tb.style() == BHIDDEN)
1052 if (tb.style() > BHIDDEN)
1053 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1055 bool allHidden = true;
1056 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1057 int sw = section->outerBorderEnd();
1061 borderWidth = max(borderWidth, sw);
1069 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1071 recalcSectionsIfNeeded();
1073 if (section == m_head)
1076 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1077 while (prevSection) {
1078 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1080 prevSection = prevSection->previousSibling();
1082 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1083 prevSection = m_head;
1084 return toRenderTableSection(prevSection);
1087 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1089 recalcSectionsIfNeeded();
1091 if (section == m_foot)
1094 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1095 while (nextSection) {
1096 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1098 nextSection = nextSection->nextSibling();
1100 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1101 nextSection = m_foot;
1102 return toRenderTableSection(nextSection);
1105 RenderTableSection* RenderTable::bottomSection() const
1107 recalcSectionsIfNeeded();
1112 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1113 if (child->isTableSection())
1114 return toRenderTableSection(child);
1120 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1122 recalcSectionsIfNeeded();
1124 // Find the section and row to look in
1125 unsigned r = cell->rowIndex();
1126 RenderTableSection* section = 0;
1127 unsigned rAbove = 0;
1129 // cell is not in the first row, so use the above row in its own section
1130 section = cell->section();
1133 section = sectionAbove(cell->section(), SkipEmptySections);
1135 ASSERT(section->numRows());
1136 rAbove = section->numRows() - 1;
1140 // Look up the cell in the section's grid, which requires effective col index
1142 unsigned effCol = colToEffCol(cell->col());
1143 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1144 return aboveCell.primaryCell();
1149 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1151 recalcSectionsIfNeeded();
1153 // Find the section and row to look in
1154 unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1155 RenderTableSection* section = 0;
1156 unsigned rBelow = 0;
1157 if (r < cell->section()->numRows() - 1) {
1158 // The cell is not in the last row, so use the next row in the section.
1159 section = cell->section();
1162 section = sectionBelow(cell->section(), SkipEmptySections);
1167 // Look up the cell in the section's grid, which requires effective col index
1169 unsigned effCol = colToEffCol(cell->col());
1170 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1171 return belowCell.primaryCell();
1176 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1178 recalcSectionsIfNeeded();
1180 RenderTableSection* section = cell->section();
1181 unsigned effCol = colToEffCol(cell->col());
1185 // If we hit a colspan back up to a real cell.
1186 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1187 return prevCell.primaryCell();
1190 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1192 recalcSectionsIfNeeded();
1194 unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1195 if (effCol >= numEffCols())
1197 return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1200 RenderBlock* RenderTable::firstLineBlock() const
1205 void RenderTable::updateFirstLetter()
1209 enum LineBox { FirstLineBox, LastLineBox };
1211 static LayoutUnit getLineBoxBaseline(const RenderTable* table, LineBox lineBox)
1213 if (table->isWritingModeRoot())
1216 table->recalcSectionsIfNeeded();
1218 const RenderTableSection* topNonEmptySection = table->topNonEmptySection();
1219 if (!topNonEmptySection)
1222 LayoutUnit baseline = topNonEmptySection->firstLineBoxBaseline();
1224 return topNonEmptySection->logicalTop() + baseline;
1226 // The 'first' linebox baseline in a table in the absence of any text in the first section
1227 // is the top of the table.
1228 if (lineBox == FirstLineBox)
1229 return topNonEmptySection->logicalTop();
1231 // The 'last' linebox baseline in a table is the baseline of text in the first
1232 // cell in the first row/section, so if there is no text do not return a baseline.
1236 LayoutUnit RenderTable::lastLineBoxBaseline() const
1238 return getLineBoxBaseline(this, LastLineBox);
1241 LayoutUnit RenderTable::firstLineBoxBaseline() const
1243 return getLineBoxBaseline(this, FirstLineBox);
1246 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1248 LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
1250 // If we have a caption, expand the clip to include the caption.
1251 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1252 // for real until captions have been re-written.
1253 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1254 // supported. When we actually support left/right and stop mapping them to top/bottom,
1255 // we might have to hack this code first (depending on what order we do these bug fixes in).
1256 if (!m_captions.isEmpty()) {
1257 if (style()->isHorizontalWritingMode()) {
1258 rect.setHeight(height());
1259 rect.setY(location.y());
1261 rect.setWidth(width());
1262 rect.setX(location.x());
1269 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1271 LayoutPoint adjustedLocation = accumulatedOffset + location();
1273 // Check kids first.
1274 if (!hasOverflowClip() || pointInContainer.intersects(overflowClipRect(adjustedLocation, pointInContainer.region()))) {
1275 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1276 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1277 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1278 if (child->nodeAtPoint(request, result, pointInContainer, childPoint, action)) {
1279 updateHitTestResult(result, toLayoutPoint(pointInContainer.point() - childPoint));
1286 // Check our bounds next.
1287 LayoutRect boundsRect(adjustedLocation, size());
1288 if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && pointInContainer.intersects(boundsRect)) {
1289 updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - toLayoutSize(adjustedLocation)));
1290 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))
1297 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1299 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1300 RenderTable* newTable = new (parent->renderArena()) RenderTable(parent->document() /* is anonymous */);
1301 newTable->setStyle(newStyle.release());
1305 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1307 ASSERT(cell->isFirstOrLastCellInRow());
1308 if (cell->section()->hasSameDirectionAsTable())
1309 return style()->borderStart();
1311 return style()->borderEnd();
1314 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1316 ASSERT(cell->isFirstOrLastCellInRow());
1317 if (cell->section()->hasSameDirectionAsTable())
1318 return style()->borderEnd();
1320 return style()->borderStart();