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 "RenderTableCell.h"
40 #include "RenderTableCol.h"
41 #include "RenderTableSection.h"
42 #include "RenderView.h"
48 using namespace HTMLNames;
50 RenderTable::RenderTable(Node* node)
57 , m_hasColElements(false)
58 , m_needsSectionRecalc(0)
64 setChildrenInline(false);
65 m_columnPos.fill(0, 2);
66 m_columns.fill(ColumnStruct(), 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));
96 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
100 RenderObject* o = before->previousSibling();
101 while (o && o != ptr)
102 o = o->previousSibling();
107 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
109 // Make sure we don't append things after :after-generated content if we have it.
110 if (!beforeChild && isAfterContent(lastChild()))
111 beforeChild = lastChild();
113 bool wrapInAnonymousSection = !child->isPositioned();
115 if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
116 // First caption wins.
117 if (beforeChild && m_caption) {
118 RenderObject* o = beforeChild->previousSibling();
119 while (o && o != m_caption)
120 o = o->previousSibling();
123 setNeedsSectionRecalc();
127 m_caption = toRenderBlock(child);
129 setNeedsSectionRecalc();
130 wrapInAnonymousSection = false;
131 } else if (child->isTableCol()) {
132 m_hasColElements = true;
133 wrapInAnonymousSection = false;
134 } else if (child->isTableSection()) {
135 switch (child->style()->display()) {
136 case TABLE_HEADER_GROUP:
137 resetSectionPointerIfNotBefore(m_head, beforeChild);
139 m_head = toRenderTableSection(child);
141 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
143 m_firstBody = toRenderTableSection(child);
145 wrapInAnonymousSection = false;
147 case TABLE_FOOTER_GROUP:
148 resetSectionPointerIfNotBefore(m_foot, beforeChild);
150 m_foot = toRenderTableSection(child);
151 wrapInAnonymousSection = false;
155 case TABLE_ROW_GROUP:
156 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
158 m_firstBody = toRenderTableSection(child);
159 wrapInAnonymousSection = false;
162 ASSERT_NOT_REACHED();
164 } else if (child->isTableCell() || child->isTableRow())
165 wrapInAnonymousSection = true;
167 wrapInAnonymousSection = true;
169 if (!wrapInAnonymousSection) {
170 // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
171 while (beforeChild && beforeChild->parent() != this)
172 beforeChild = beforeChild->parent();
174 RenderBox::addChild(child, beforeChild);
178 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
179 lastChild()->addChild(child);
183 RenderObject* lastBox = beforeChild;
184 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
185 lastBox = lastBox->parent();
186 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
187 if (beforeChild == lastBox)
188 beforeChild = lastBox->firstChild();
189 lastBox->addChild(child, beforeChild);
193 if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
195 RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
196 RefPtr<RenderStyle> newStyle = RenderStyle::create();
197 newStyle->inheritFrom(style());
198 newStyle->setDisplay(TABLE_ROW_GROUP);
199 section->setStyle(newStyle.release());
200 addChild(section, beforeChild);
201 section->addChild(child);
204 void RenderTable::removeChild(RenderObject* oldChild)
206 RenderBox::removeChild(oldChild);
208 if (m_caption && oldChild == m_caption && node())
209 node()->setNeedsStyleRecalc();
210 setNeedsSectionRecalc();
213 void RenderTable::computeLogicalWidth()
216 computePositionedLogicalWidth();
218 RenderBlock* cb = containingBlock();
220 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
221 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
222 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
224 LengthType logicalWidthType = style()->logicalWidth().type();
225 if (logicalWidthType > Relative && style()->logicalWidth().isPositive()) {
226 // Percent or fixed table
227 setLogicalWidth(style()->logicalWidth().calcMinValue(containerWidthInInlineDirection));
228 setLogicalWidth(max(minPreferredLogicalWidth(), logicalWidth()));
230 // Subtract out any fixed margins from our available width for auto width tables.
231 LayoutUnit marginTotal = 0;
232 if (!style()->marginStart().isAuto())
233 marginTotal += style()->marginStart().calcValue(availableLogicalWidth);
234 if (!style()->marginEnd().isAuto())
235 marginTotal += style()->marginEnd().calcValue(availableLogicalWidth);
237 // Subtract out our margins to get the available content width.
238 LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
240 // Ensure we aren't bigger than our max width or smaller than our min width.
241 setLogicalWidth(min(availableContentLogicalWidth, maxPreferredLogicalWidth()));
244 setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
246 // Finally, with our true width determined, compute our margins for real.
249 if (!hasPerpendicularContainingBlock)
250 computeInlineDirectionMargins(cb, availableLogicalWidth, logicalWidth());
252 setMarginStart(style()->marginStart().calcMinValue(availableLogicalWidth));
253 setMarginEnd(style()->marginEnd().calcMinValue(availableLogicalWidth));
257 void RenderTable::adjustLogicalHeightForCaption()
260 IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());
262 m_caption->setLogicalLocation(IntPoint(m_caption->marginStart(), m_caption->marginBefore() + logicalHeight()));
263 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
264 m_caption->repaintDuringLayoutIfMoved(captionRect);
266 setLogicalHeight(logicalHeight() + m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter());
269 void RenderTable::layout()
271 ASSERT(needsLayout());
273 if (simplifiedLayout())
276 recalcSectionsIfNeeded();
278 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
279 LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
284 initMaxMarginValues();
286 LayoutUnit oldLogicalWidth = logicalWidth();
287 computeLogicalWidth();
289 if (m_caption && logicalWidth() != oldLogicalWidth)
290 m_caption->setNeedsLayout(true, false);
292 // FIXME: The optimisation below doesn't work since the internal table
293 // layout could have changed. we need to add a flag to the table
294 // layout that tells us if something has changed in the min max
295 // calculations to do it correctly.
296 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
297 m_tableLayout->layout();
299 setCellLogicalWidths();
301 LayoutUnit totalSectionLogicalHeight = 0;
302 LayoutUnit oldTableLogicalTop = m_caption ? m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter() : 0;
304 bool collapsing = collapseBorders();
306 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
307 if (child->isTableSection()) {
308 child->layoutIfNeeded();
309 RenderTableSection* section = toRenderTableSection(child);
310 totalSectionLogicalHeight += section->calcRowLogicalHeight();
312 section->recalcOuterBorder();
313 ASSERT(!section->needsLayout());
314 } else if (child->isTableCol()) {
315 child->layoutIfNeeded();
316 ASSERT(!child->needsLayout());
320 // Only lay out one caption, since it's the only one we're going to end up painting.
322 m_caption->layoutIfNeeded();
324 // If any table section moved vertically, we will just repaint everything from that
325 // section down (it is quite unlikely that any of the following sections
327 bool sectionMoved = false;
328 LayoutUnit movedSectionLogicalTop = 0;
330 // FIXME: Collapse caption margin.
331 if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
332 adjustLogicalHeightForCaption();
333 if (logicalHeight() != oldTableLogicalTop) {
335 movedSectionLogicalTop = min(logicalHeight(), oldTableLogicalTop);
339 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapsing ? 0 : paddingBefore());
340 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapsing ? 0 : paddingAfter());
342 setLogicalHeight(logicalHeight() + borderAndPaddingBefore);
345 computeLogicalHeight();
347 Length logicalHeightLength = style()->logicalHeight();
348 LayoutUnit computedLogicalHeight = 0;
349 if (logicalHeightLength.isFixed()) {
350 // Tables size as though CSS height includes border/padding.
351 computedLogicalHeight = logicalHeightLength.value() - (borderAndPaddingBefore + borderAndPaddingAfter);
352 } else if (logicalHeightLength.isPercent())
353 computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength);
354 computedLogicalHeight = max<LayoutUnit>(0, computedLogicalHeight);
356 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
357 if (child->isTableSection())
358 // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
359 toRenderTableSection(child)->layoutRows(child == m_firstBody ? max<LayoutUnit>(0, computedLogicalHeight - totalSectionLogicalHeight) : 0);
362 if (!m_firstBody && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) {
363 // Completely empty tables (with no sections or anything) should at least honor specified height
365 setLogicalHeight(logicalHeight() + computedLogicalHeight);
368 LayoutUnit sectionLogicalLeft = style()->isLeftToRightDirection() ? borderStart() : borderEnd();
370 sectionLogicalLeft += style()->isLeftToRightDirection() ? paddingStart() : paddingEnd();
372 // position the table sections
373 RenderTableSection* section = topSection();
375 if (!sectionMoved && section->logicalTop() != logicalHeight()) {
377 movedSectionLogicalTop = min(logicalHeight(), section->logicalTop()) + (style()->isHorizontalWritingMode() ? section->minYVisualOverflow() : section->minXVisualOverflow());
379 section->setLogicalLocation(LayoutPoint(sectionLogicalLeft, logicalHeight()));
381 setLogicalHeight(logicalHeight() + section->logicalHeight());
382 section = sectionBelow(section);
385 setLogicalHeight(logicalHeight() + borderAndPaddingAfter);
387 if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM)
388 adjustLogicalHeightForCaption();
391 computeLogicalHeight();
393 // table can be containing block of positioned elements.
394 // FIXME: Only pass true if width or height changed.
395 layoutPositionedObjects(true);
397 updateLayerTransform();
399 computeOverflow(clientLogicalBottom());
403 if (view()->layoutState()->pageLogicalHeight())
404 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop()));
406 bool didFullRepaint = repainter.repaintAfterLayout();
407 // Repaint with our new bounds if they are different from our old bounds.
408 if (!didFullRepaint && sectionMoved) {
409 if (style()->isHorizontalWritingMode())
410 repaintRectangle(LayoutRect(minXVisualOverflow(), movedSectionLogicalTop, maxXVisualOverflow() - minXVisualOverflow(), maxYVisualOverflow() - movedSectionLogicalTop));
412 repaintRectangle(LayoutRect(movedSectionLogicalTop, minYVisualOverflow(), maxXVisualOverflow() - movedSectionLogicalTop, maxYVisualOverflow() - minYVisualOverflow()));
415 setNeedsLayout(false);
418 void RenderTable::addOverflowFromChildren()
420 // Add overflow from borders.
421 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
422 // descendant objects, but since tables don't support overflow:auto, this works out fine.
423 if (collapseBorders()) {
424 int rightBorderOverflow = width() + outerBorderRight() - borderRight();
425 int leftBorderOverflow = borderLeft() - outerBorderLeft();
426 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
427 int topBorderOverflow = borderTop() - outerBorderTop();
428 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
429 if (borderOverflowRect != borderBoxRect()) {
430 addLayoutOverflow(borderOverflowRect);
431 addVisualOverflow(borderOverflowRect);
435 // Add overflow from our caption.
437 addOverflowFromChild(m_caption);
439 // Add overflow from our sections.
440 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
441 if (child->isTableSection()) {
442 RenderTableSection* section = toRenderTableSection(child);
443 addOverflowFromChild(section);
448 void RenderTable::setCellLogicalWidths()
450 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
451 if (child->isTableSection())
452 toRenderTableSection(child)->setCellLogicalWidths();
456 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
458 LayoutPoint adjustedPaintOffset = paintOffset + location();
460 PaintPhase paintPhase = paintInfo.phase;
463 LayoutRect overflowBox = visualOverflowRect();
464 flipForWritingMode(overflowBox);
465 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
466 overflowBox.moveBy(adjustedPaintOffset);
467 if (!overflowBox.intersects(paintInfo.rect))
471 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
472 paintObject(paintInfo, adjustedPaintOffset);
474 popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
477 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
479 PaintPhase paintPhase = paintInfo.phase;
480 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
481 paintBoxDecorations(paintInfo, paintOffset);
483 if (paintPhase == PaintPhaseMask) {
484 paintMask(paintInfo, paintOffset);
488 // We're done. We don't bother painting any children.
489 if (paintPhase == PaintPhaseBlockBackground)
492 // We don't paint our own background, but we do let the kids paint their backgrounds.
493 if (paintPhase == PaintPhaseChildBlockBackgrounds)
494 paintPhase = PaintPhaseChildBlockBackground;
496 PaintInfo info(paintInfo);
497 info.phase = paintPhase;
498 info.updatePaintingRootForChildren(this);
500 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
501 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) {
502 LayoutPoint childPoint = flipForWritingMode(toRenderBox(child), paintOffset, ParentToChildFlippingAdjustment);
503 child->paint(info, childPoint);
507 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
508 // Collect all the unique border styles that we want to paint in a sorted list. Once we
509 // have all the styles sorted, we then do individual passes, painting each style of border
510 // from lowest precedence to highest precedence.
511 info.phase = PaintPhaseCollapsedTableBorders;
512 RenderTableCell::CollapsedBorderStyles borderStyles;
513 RenderObject* stop = nextInPreOrderAfterChildren();
514 for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder()) {
515 if (o->isTableCell())
516 toRenderTableCell(o)->collectBorderStyles(borderStyles);
518 RenderTableCell::sortBorderStyles(borderStyles);
519 size_t count = borderStyles.size();
520 for (size_t i = 0; i < count; ++i) {
521 m_currentBorder = &borderStyles[i];
522 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
523 if (child->isTableSection()) {
524 LayoutPoint childPoint = flipForWritingMode(toRenderTableSection(child), paintOffset, ParentToChildFlippingAdjustment);
525 child->paint(info, childPoint);
532 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
533 paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
536 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
541 LayoutUnit captionLogicalHeight = m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter();
542 bool captionIsBefore = (m_caption->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
543 if (style()->isHorizontalWritingMode()) {
544 rect.setHeight(rect.height() - captionLogicalHeight);
546 rect.move(0, captionLogicalHeight);
548 rect.setWidth(rect.width() - captionLogicalHeight);
550 rect.move(captionLogicalHeight, 0);
554 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
556 if (!paintInfo.shouldPaintWithinRoot(this))
559 LayoutRect rect(paintOffset, size());
560 subtractCaptionRect(rect);
562 paintBoxShadow(paintInfo, rect, style(), Normal);
563 paintBackground(paintInfo, rect);
564 paintBoxShadow(paintInfo, rect, style(), Inset);
566 if (style()->hasBorder() && !collapseBorders())
567 paintBorder(paintInfo, rect, style());
570 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
572 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
575 LayoutRect rect(paintOffset, size());
576 subtractCaptionRect(rect);
578 paintMaskImages(paintInfo, rect);
581 void RenderTable::computePreferredLogicalWidths()
583 ASSERT(preferredLogicalWidthsDirty());
585 recalcSectionsIfNeeded();
586 recalcBordersInRowDirection();
588 m_tableLayout->computePreferredLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
591 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_caption->minPreferredLogicalWidth());
593 setPreferredLogicalWidthsDirty(false);
596 RenderTableSection* RenderTable::topNonEmptySection() const
598 RenderTableSection* section = topSection();
599 if (section && !section->numRows())
600 section = sectionBelow(section, SkipEmptySections);
604 void RenderTable::splitColumn(int pos, int firstSpan)
606 // we need to add a new columnStruct
607 int oldSize = m_columns.size();
608 m_columns.grow(oldSize + 1);
609 int oldSpan = m_columns[pos].span;
610 ASSERT(oldSpan > firstSpan);
611 m_columns[pos].span = firstSpan;
612 memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
613 m_columns[pos + 1].span = oldSpan - firstSpan;
615 // change width of all rows.
616 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
617 if (child->isTableSection())
618 toRenderTableSection(child)->splitColumn(pos, firstSpan);
621 m_columnPos.grow(numEffCols() + 1);
622 setNeedsLayoutAndPrefWidthsRecalc();
625 void RenderTable::appendColumn(int span)
628 int pos = m_columns.size();
629 int newSize = pos + 1;
630 m_columns.grow(newSize);
631 m_columns[pos].span = span;
633 // change width of all rows.
634 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
635 if (child->isTableSection())
636 toRenderTableSection(child)->appendColumn(pos);
639 m_columnPos.grow(numEffCols() + 1);
640 setNeedsLayoutAndPrefWidthsRecalc();
643 RenderTableCol* RenderTable::nextColElement(RenderTableCol* current) const
645 RenderObject* next = current->firstChild();
647 next = current->nextSibling();
648 if (!next && current->parent()->isTableCol())
649 next = current->parent()->nextSibling();
652 if (next->isTableCol())
653 return toRenderTableCol(next);
654 if (next != m_caption)
656 next = next->nextSibling();
662 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
664 if (!m_hasColElements)
666 RenderObject* child = firstChild();
670 if (child->isTableCol())
672 if (child != m_caption)
674 child = child->nextSibling();
679 RenderTableCol* colElem = toRenderTableCol(child);
681 int span = colElem->span();
682 if (!colElem->firstChild()) {
684 int endCol = cCol + span - 1;
688 *startEdge = startCol == col;
690 *endEdge = endCol == col;
694 colElem = nextColElement(colElem);
700 void RenderTable::recalcCaption(RenderBlock* caption) const
704 m_caption->setNeedsLayout(true);
706 // Make sure to null out the child's renderer.
707 if (Node* node = caption->node())
708 node->setRenderer(0);
710 // Destroy the child now.
715 void RenderTable::recalcSections() const
721 m_hasColElements = false;
723 // We need to get valid pointers to caption, head, foot and first body again
724 RenderObject* nextSibling;
725 for (RenderObject* child = firstChild(); child; child = nextSibling) {
726 nextSibling = child->nextSibling();
727 switch (child->style()->display()) {
729 if (child->isRenderBlock())
730 recalcCaption(toRenderBlock(child));
733 case TABLE_COLUMN_GROUP:
734 m_hasColElements = true;
736 case TABLE_HEADER_GROUP:
737 if (child->isTableSection()) {
738 RenderTableSection* section = toRenderTableSection(child);
741 else if (!m_firstBody)
742 m_firstBody = section;
743 section->recalcCellsIfNeeded();
746 case TABLE_FOOTER_GROUP:
747 if (child->isTableSection()) {
748 RenderTableSection* section = toRenderTableSection(child);
751 else if (!m_firstBody)
752 m_firstBody = section;
753 section->recalcCellsIfNeeded();
756 case TABLE_ROW_GROUP:
757 if (child->isTableSection()) {
758 RenderTableSection* section = toRenderTableSection(child);
760 m_firstBody = section;
761 section->recalcCellsIfNeeded();
769 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
771 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
772 if (child->isTableSection()) {
773 RenderTableSection* section = toRenderTableSection(child);
774 int sectionCols = section->numColumns();
775 if (sectionCols > maxCols)
776 maxCols = sectionCols;
780 m_columns.resize(maxCols);
781 m_columnPos.resize(maxCols + 1);
783 ASSERT(selfNeedsLayout());
785 m_needsSectionRecalc = false;
788 LayoutUnit RenderTable::calcBorderStart() const
790 if (collapseBorders()) {
791 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
795 LayoutUnit borderWidth = 0;
797 const BorderValue& tb = style()->borderStart();
798 if (tb.style() == BHIDDEN)
800 if (tb.style() > BHIDDEN)
801 borderWidth = tb.width();
803 if (RenderTableCol* colGroup = colElement(0)) {
804 const BorderValue& gb = colGroup->style()->borderStart();
805 if (gb.style() == BHIDDEN)
807 if (gb.style() > BHIDDEN)
808 borderWidth = max<LayoutUnit>(borderWidth, gb.width());
811 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
812 const BorderValue& sb = topNonEmptySection->style()->borderStart();
813 if (sb.style() == BHIDDEN)
816 if (sb.style() > BHIDDEN)
817 borderWidth = max<LayoutUnit>(borderWidth, sb.width());
819 const RenderTableSection::CellStruct& cs = topNonEmptySection->cellAt(0, 0);
822 const BorderValue& cb = cs.primaryCell()->style()->borderStart(); // FIXME: Make this work with perpendicualr and flipped cells.
823 if (cb.style() == BHIDDEN)
826 const BorderValue& rb = cs.primaryCell()->parent()->style()->borderStart();
827 if (rb.style() == BHIDDEN)
830 if (cb.style() > BHIDDEN)
831 borderWidth = max<LayoutUnit>(borderWidth, cb.width());
832 if (rb.style() > BHIDDEN)
833 borderWidth = max<LayoutUnit>(borderWidth, rb.width());
836 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
838 return RenderBlock::borderStart();
841 LayoutUnit RenderTable::calcBorderEnd() const
843 if (collapseBorders()) {
844 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
848 LayoutUnit borderWidth = 0;
850 const BorderValue& tb = style()->borderEnd();
851 if (tb.style() == BHIDDEN)
853 if (tb.style() > BHIDDEN)
854 borderWidth = tb.width();
856 int endColumn = numEffCols() - 1;
857 if (RenderTableCol* colGroup = colElement(endColumn)) {
858 const BorderValue& gb = colGroup->style()->borderEnd();
859 if (gb.style() == BHIDDEN)
861 if (gb.style() > BHIDDEN)
862 borderWidth = max<LayoutUnit>(borderWidth, gb.width());
865 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
866 const BorderValue& sb = topNonEmptySection->style()->borderEnd();
867 if (sb.style() == BHIDDEN)
870 if (sb.style() > BHIDDEN)
871 borderWidth = max<LayoutUnit>(borderWidth, sb.width());
873 const RenderTableSection::CellStruct& cs = topNonEmptySection->cellAt(0, endColumn);
876 const BorderValue& cb = cs.primaryCell()->style()->borderEnd(); // FIXME: Make this work with perpendicular and flipped cells.
877 if (cb.style() == BHIDDEN)
880 const BorderValue& rb = cs.primaryCell()->parent()->style()->borderEnd();
881 if (rb.style() == BHIDDEN)
884 if (cb.style() > BHIDDEN)
885 borderWidth = max<LayoutUnit>(borderWidth, cb.width());
886 if (rb.style() > BHIDDEN)
887 borderWidth = max<LayoutUnit>(borderWidth, rb.width());
890 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
892 return RenderBlock::borderEnd();
895 void RenderTable::recalcBordersInRowDirection()
897 m_borderStart = calcBorderStart();
898 m_borderEnd = calcBorderEnd();
901 LayoutUnit RenderTable::borderBefore() const
903 if (collapseBorders())
904 return outerBorderBefore();
905 return RenderBlock::borderBefore();
908 LayoutUnit RenderTable::borderAfter() const
910 if (collapseBorders())
911 return outerBorderAfter();
912 return RenderBlock::borderAfter();
915 LayoutUnit RenderTable::outerBorderBefore() const
917 if (!collapseBorders())
919 LayoutUnit borderWidth = 0;
920 if (RenderTableSection* topSection = this->topSection()) {
921 borderWidth = topSection->outerBorderBefore();
923 return 0; // Overridden by hidden
925 const BorderValue& tb = style()->borderBefore();
926 if (tb.style() == BHIDDEN)
928 if (tb.style() > BHIDDEN)
929 borderWidth = max<LayoutUnit>(borderWidth, tb.width() / 2);
933 LayoutUnit RenderTable::outerBorderAfter() const
935 if (!collapseBorders())
937 LayoutUnit borderWidth = 0;
938 RenderTableSection* bottomSection;
940 bottomSection = m_foot;
943 for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling()) { }
944 bottomSection = child ? toRenderTableSection(child) : 0;
947 borderWidth = bottomSection->outerBorderAfter();
949 return 0; // Overridden by hidden
951 const BorderValue& tb = style()->borderAfter();
952 if (tb.style() == BHIDDEN)
954 if (tb.style() > BHIDDEN)
955 borderWidth = max<LayoutUnit>(borderWidth, (tb.width() + 1) / 2);
959 LayoutUnit RenderTable::outerBorderStart() const
961 if (!collapseBorders())
964 LayoutUnit borderWidth = 0;
966 const BorderValue& tb = style()->borderStart();
967 if (tb.style() == BHIDDEN)
969 if (tb.style() > BHIDDEN)
970 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
972 bool allHidden = true;
973 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
974 if (!child->isTableSection())
976 LayoutUnit sw = toRenderTableSection(child)->outerBorderStart();
980 borderWidth = max(borderWidth, sw);
988 LayoutUnit RenderTable::outerBorderEnd() const
990 if (!collapseBorders())
993 LayoutUnit borderWidth = 0;
995 const BorderValue& tb = style()->borderEnd();
996 if (tb.style() == BHIDDEN)
998 if (tb.style() > BHIDDEN)
999 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1001 bool allHidden = true;
1002 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1003 if (!child->isTableSection())
1005 LayoutUnit sw = toRenderTableSection(child)->outerBorderEnd();
1009 borderWidth = max(borderWidth, sw);
1017 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1019 recalcSectionsIfNeeded();
1021 if (section == m_head)
1024 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1025 while (prevSection) {
1026 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1028 prevSection = prevSection->previousSibling();
1030 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1031 prevSection = m_head;
1032 return toRenderTableSection(prevSection);
1035 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1037 recalcSectionsIfNeeded();
1039 if (section == m_foot)
1042 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1043 while (nextSection) {
1044 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1046 nextSection = nextSection->nextSibling();
1048 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1049 nextSection = m_foot;
1050 return toRenderTableSection(nextSection);
1053 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1055 recalcSectionsIfNeeded();
1057 // Find the section and row to look in
1058 int r = cell->row();
1059 RenderTableSection* section = 0;
1062 // cell is not in the first row, so use the above row in its own section
1063 section = cell->section();
1066 section = sectionAbove(cell->section(), SkipEmptySections);
1068 rAbove = section->numRows() - 1;
1071 // Look up the cell in the section's grid, which requires effective col index
1073 int effCol = colToEffCol(cell->col());
1074 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1075 return aboveCell.primaryCell();
1080 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1082 recalcSectionsIfNeeded();
1084 // Find the section and row to look in
1085 int r = cell->row() + cell->rowSpan() - 1;
1086 RenderTableSection* section = 0;
1088 if (r < cell->section()->numRows() - 1) {
1089 // The cell is not in the last row, so use the next row in the section.
1090 section = cell->section();
1093 section = sectionBelow(cell->section(), SkipEmptySections);
1098 // Look up the cell in the section's grid, which requires effective col index
1100 int effCol = colToEffCol(cell->col());
1101 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1102 return belowCell.primaryCell();
1107 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1109 recalcSectionsIfNeeded();
1111 RenderTableSection* section = cell->section();
1112 int effCol = colToEffCol(cell->col());
1116 // If we hit a colspan back up to a real cell.
1117 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->row(), effCol - 1);
1118 return prevCell.primaryCell();
1121 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1123 recalcSectionsIfNeeded();
1125 int effCol = colToEffCol(cell->col() + cell->colSpan());
1126 if (effCol >= numEffCols())
1128 return cell->section()->primaryCellAt(cell->row(), effCol);
1131 RenderBlock* RenderTable::firstLineBlock() const
1136 void RenderTable::updateFirstLetter()
1140 LayoutUnit RenderTable::firstLineBoxBaseline() const
1142 if (isWritingModeRoot())
1145 recalcSectionsIfNeeded();
1147 const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1148 if (!topNonEmptySection)
1151 return topNonEmptySection->logicalTop() + topNonEmptySection->firstLineBoxBaseline();
1154 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy)
1156 LayoutRect rect = RenderBlock::overflowClipRect(location, relevancy);
1158 // If we have a caption, expand the clip to include the caption.
1159 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1160 // for real until captions have been re-written.
1161 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1162 // supported. When we actually support left/right and stop mapping them to top/bottom,
1163 // we might have to hack this code first (depending on what order we do these bug fixes in).
1165 if (style()->isHorizontalWritingMode()) {
1166 rect.setHeight(height());
1167 rect.setY(location.y());
1169 rect.setWidth(width());
1170 rect.setX(location.x());
1177 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1179 LayoutPoint adjustedLocation = accumulatedOffset + location();
1181 // Check kids first.
1182 if (!hasOverflowClip() || overflowClipRect(adjustedLocation).intersects(result.rectForPoint(pointInContainer))) {
1183 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1184 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child == m_caption)) {
1185 LayoutPoint childPoint = flipForWritingMode(toRenderBox(child), adjustedLocation, ParentToChildFlippingAdjustment);
1186 if (child->nodeAtPoint(request, result, pointInContainer, childPoint, action)) {
1187 updateHitTestResult(result, toLayoutPoint(pointInContainer - childPoint));
1194 // Check our bounds next.
1195 LayoutRect boundsRect(adjustedLocation, size());
1196 if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && boundsRect.intersects(result.rectForPoint(pointInContainer))) {
1197 updateHitTestResult(result, flipForWritingMode(pointInContainer - toLayoutSize(adjustedLocation)));
1198 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))