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/rendering/AutoTableLayout.h"
33 #include "core/rendering/FixedTableLayout.h"
34 #include "core/rendering/GraphicsContextAnnotator.h"
35 #include "core/rendering/HitTestResult.h"
36 #include "core/rendering/LayoutRectRecorder.h"
37 #include "core/rendering/LayoutRepainter.h"
38 #include "core/rendering/RenderLayer.h"
39 #include "core/rendering/RenderTableCaption.h"
40 #include "core/rendering/RenderTableCell.h"
41 #include "core/rendering/RenderTableCol.h"
42 #include "core/rendering/RenderTableSection.h"
43 #include "core/rendering/RenderView.h"
44 #include "core/rendering/SubtreeLayoutScope.h"
45 #include "core/rendering/style/StyleInheritedData.h"
46 #include "platform/graphics/GraphicsContextStateSaver.h"
52 using namespace HTMLNames;
54 RenderTable::RenderTable(Element* element)
55 : RenderBlock(element)
60 , m_collapsedBordersValid(false)
61 , m_hasColElements(false)
62 , m_needsSectionRecalc(false)
63 , m_columnLogicalWidthChanged(false)
64 , m_columnRenderersValid(false)
70 setChildrenInline(false);
71 m_columnPos.fill(0, 1);
75 RenderTable::~RenderTable()
79 void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
81 RenderBlock::styleDidChange(diff, oldStyle);
82 propagateStyleToAnonymousChildren();
84 ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;
86 // In the collapsed border model, there is no cell spacing.
87 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
88 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
89 m_columnPos[0] = m_hSpacing;
91 if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
93 m_tableLayout->willChangeTableLayout();
95 // According to the CSS2 spec, you only use fixed table layout if an
96 // explicit width is specified on the table. Auto width implies auto table layout.
97 if (style()->tableLayout() == TFIXED && !style()->logicalWidth().isAuto())
98 m_tableLayout = adoptPtr(new FixedTableLayout(this));
100 m_tableLayout = adoptPtr(new AutoTableLayout(this));
103 // If border was changed, invalidate collapsed borders cache.
104 if (!needsLayout() && oldStyle && oldStyle->border() != style()->border())
105 invalidateCollapsedBorders();
108 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
112 RenderObject* o = before->previousSibling();
113 while (o && o != ptr)
114 o = o->previousSibling();
119 static inline bool needsTableSection(RenderObject* object)
121 // Return true if 'object' can't exist in an anonymous table without being
122 // wrapped in a table section box.
123 EDisplay display = object->style()->display();
124 return display != TABLE_CAPTION && display != TABLE_COLUMN_GROUP && display != TABLE_COLUMN;
127 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
129 bool wrapInAnonymousSection = !child->isOutOfFlowPositioned();
131 if (child->isTableCaption())
132 wrapInAnonymousSection = false;
133 else if (child->isRenderTableCol()) {
134 m_hasColElements = true;
135 wrapInAnonymousSection = false;
136 } else if (child->isTableSection()) {
137 switch (child->style()->display()) {
138 case TABLE_HEADER_GROUP:
139 resetSectionPointerIfNotBefore(m_head, beforeChild);
141 m_head = toRenderTableSection(child);
143 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
145 m_firstBody = toRenderTableSection(child);
147 wrapInAnonymousSection = false;
149 case TABLE_FOOTER_GROUP:
150 resetSectionPointerIfNotBefore(m_foot, beforeChild);
152 m_foot = toRenderTableSection(child);
153 wrapInAnonymousSection = false;
157 case TABLE_ROW_GROUP:
158 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
160 m_firstBody = toRenderTableSection(child);
161 wrapInAnonymousSection = false;
164 ASSERT_NOT_REACHED();
167 wrapInAnonymousSection = true;
169 if (child->isTableSection())
170 setNeedsSectionRecalc();
172 if (!wrapInAnonymousSection) {
173 if (beforeChild && beforeChild->parent() != this)
174 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
176 RenderBox::addChild(child, beforeChild);
180 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() && !lastChild()->isBeforeContent()) {
181 lastChild()->addChild(child);
185 if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
186 RenderObject* section = beforeChild->previousSibling();
187 if (section && section->isTableSection() && section->isAnonymous()) {
188 section->addChild(child);
193 RenderObject* lastBox = beforeChild;
194 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && needsTableSection(lastBox))
195 lastBox = lastBox->parent();
196 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
197 if (beforeChild == lastBox)
198 beforeChild = lastBox->firstChild();
199 lastBox->addChild(child, beforeChild);
203 if (beforeChild && !beforeChild->isTableSection() && needsTableSection(beforeChild))
206 RenderTableSection* section = RenderTableSection::createAnonymousWithParentRenderer(this);
207 addChild(section, beforeChild);
208 section->addChild(child);
211 void RenderTable::addCaption(const RenderTableCaption* caption)
213 ASSERT(m_captions.find(caption) == kNotFound);
214 m_captions.append(const_cast<RenderTableCaption*>(caption));
217 void RenderTable::removeCaption(const RenderTableCaption* oldCaption)
219 size_t index = m_captions.find(oldCaption);
220 ASSERT(index != kNotFound);
221 if (index == kNotFound)
224 m_captions.remove(index);
227 void RenderTable::invalidateCachedColumns()
229 m_columnRenderersValid = false;
230 m_columnRenderers.resize(0);
233 void RenderTable::addColumn(const RenderTableCol*)
235 invalidateCachedColumns();
238 void RenderTable::removeColumn(const RenderTableCol*)
240 invalidateCachedColumns();
241 // We don't really need to recompute our sections, but we need to update our
242 // column count and whether we have a column. Currently, we only have one
243 // size-fit-all flag but we may have to consider splitting it.
244 setNeedsSectionRecalc();
247 void RenderTable::updateLogicalWidth()
249 recalcSectionsIfNeeded();
251 if (isOutOfFlowPositioned()) {
252 LogicalExtentComputedValues computedValues;
253 computePositionedLogicalWidth(computedValues);
254 setLogicalWidth(computedValues.m_extent);
255 setLogicalLeft(computedValues.m_position);
256 setMarginStart(computedValues.m_margins.m_start);
257 setMarginEnd(computedValues.m_margins.m_end);
260 RenderBlock* cb = containingBlock();
262 LayoutUnit availableLogicalWidth = containingBlockLogicalWidthForContent();
263 bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
264 LayoutUnit containerWidthInInlineDirection = hasPerpendicularContainingBlock ? perpendicularContainingBlockLogicalHeight() : availableLogicalWidth;
266 Length styleLogicalWidth = style()->logicalWidth();
267 if ((styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive()) || styleLogicalWidth.isIntrinsic())
268 setLogicalWidth(convertStyleLogicalWidthToComputedWidth(styleLogicalWidth, containerWidthInInlineDirection));
270 // Subtract out any fixed margins from our available width for auto width tables.
271 LayoutUnit marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
272 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
273 LayoutUnit marginTotal = marginStart + marginEnd;
275 // Subtract out our margins to get the available content width.
276 LayoutUnit availableContentLogicalWidth = max<LayoutUnit>(0, containerWidthInInlineDirection - marginTotal);
277 if (shrinkToAvoidFloats() && cb->containsFloats() && !hasPerpendicularContainingBlock) {
278 // FIXME: Work with regions someday.
279 availableContentLogicalWidth = shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb), 0);
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 LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth;
309 if (avoidsFloats() && cb->containsFloats())
310 containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0); // FIXME: Work with regions someday.
311 ComputedMarginValues marginValues;
312 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection();
313 computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(),
314 hasInvertedDirection ? marginValues.m_start : marginValues.m_end,
315 hasInvertedDirection ? marginValues.m_end : marginValues.m_start);
316 setMarginStart(marginValues.m_start);
317 setMarginEnd(marginValues.m_end);
319 setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth));
320 setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth));
323 // We should NEVER shrink the table below the min-content logical width, or else the table can't accomodate
324 // its own content which doesn't match CSS nor what authors expect.
325 // FIXME: When we convert to sub-pixel layout for tables we can remove the int conversion
326 // https://code.google.com/p/chromium/issues/detail?id=241198
327 ASSERT(logicalWidth().toInt() >= minPreferredLogicalWidth().toInt());
330 // This method takes a RenderStyle's logical width, min-width, or max-width length and computes its actual value.
331 LayoutUnit RenderTable::convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth)
333 if (styleLogicalWidth.isIntrinsic())
334 return computeIntrinsicLogicalWidthUsing(styleLogicalWidth, availableWidth, bordersPaddingAndSpacingInRowDirection());
336 // HTML tables' width styles already include borders and paddings, but CSS tables' width styles do not.
337 LayoutUnit borders = 0;
338 bool isCSSTable = !node() || !node()->hasTagName(tableTag);
339 if (isCSSTable && styleLogicalWidth.isSpecified() && styleLogicalWidth.isPositive() && style()->boxSizing() == CONTENT_BOX)
340 borders = borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : paddingStart() + paddingEnd());
342 return minimumValueForLength(styleLogicalWidth, availableWidth) + borders;
345 LayoutUnit RenderTable::convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight)
347 LayoutUnit borderAndPaddingBefore = borderBefore() + (collapseBorders() ? LayoutUnit() : paddingBefore());
348 LayoutUnit borderAndPaddingAfter = borderAfter() + (collapseBorders() ? LayoutUnit() : paddingAfter());
349 LayoutUnit borderAndPadding = borderAndPaddingBefore + borderAndPaddingAfter;
350 LayoutUnit computedLogicalHeight = 0;
351 if (styleLogicalHeight.isFixed()) {
352 // HTML tables size as though CSS height includes border/padding, CSS tables do not.
353 LayoutUnit borders = LayoutUnit();
354 // FIXME: We cannot apply box-sizing: content-box on <table> which other browsers allow.
355 if ((node() && node()->hasTagName(tableTag)) || style()->boxSizing() == BORDER_BOX) {
356 borders = borderAndPadding;
358 computedLogicalHeight = styleLogicalHeight.value() - borders;
359 } else if (styleLogicalHeight.isPercent())
360 computedLogicalHeight = computePercentageLogicalHeight(styleLogicalHeight);
361 else if (styleLogicalHeight.isIntrinsic())
362 computedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(styleLogicalHeight, logicalHeight() - borderAndPadding, borderAndPadding);
364 ASSERT_NOT_REACHED();
365 return max<LayoutUnit>(0, computedLogicalHeight);
368 void RenderTable::layoutCaption(RenderTableCaption* caption)
370 LayoutRect captionRect(caption->frameRect());
372 if (caption->needsLayout()) {
373 // The margins may not be available but ensure the caption is at least located beneath any previous sibling caption
374 // so that it does not mistakenly think any floats in the previous caption intrude into it.
375 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), collapsedMarginBeforeForChild(caption) + logicalHeight()));
376 // If RenderTableCaption ever gets a layout() function, use it here.
377 caption->layoutIfNeeded();
379 // Apply the margins to the location now that they are definitely available from layout
380 LayoutUnit captionLogicalTop = collapsedMarginBeforeForChild(caption) + logicalHeight();
381 if (view()->layoutState()->isPaginated()) {
382 captionLogicalTop += caption->paginationStrut();
383 caption->setPaginationStrut(0);
385 caption->setLogicalLocation(LayoutPoint(caption->marginStart(), captionLogicalTop));
387 if (!selfNeedsLayout() && caption->checkForRepaintDuringLayout())
388 caption->repaintDuringLayoutIfMoved(captionRect);
390 setLogicalHeight(logicalHeight() + caption->logicalHeight() + collapsedMarginBeforeForChild(caption) + collapsedMarginAfterForChild(caption));
393 void RenderTable::distributeExtraLogicalHeight(int extraLogicalHeight)
395 if (extraLogicalHeight <= 0)
398 // FIXME: Distribute the extra logical height between all table sections instead of giving it all to the first one.
399 if (RenderTableSection* section = firstBody())
400 extraLogicalHeight -= section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
402 // FIXME: We really would like to enable this ASSERT to ensure that all the extra space has been distributed.
403 // However our current distribution algorithm does not round properly and thus we can have some remaining height.
404 // ASSERT(!topSection() || !extraLogicalHeight);
407 void RenderTable::simplifiedNormalFlowLayout()
409 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
410 section->layoutIfNeeded();
411 section->computeOverflowFromCells();
415 void RenderTable::layout()
417 ASSERT(needsLayout());
419 LayoutRectRecorder recorder(*this);
421 if (simplifiedLayout())
424 recalcSectionsIfNeeded();
425 // FIXME: We should do this recalc lazily in borderStart/borderEnd so that we don't have to make sure
426 // to call this before we call borderStart/borderEnd to avoid getting a stale value.
427 recalcBordersInRowDirection();
429 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
430 LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
434 LayoutUnit oldLogicalWidth = logicalWidth();
435 updateLogicalWidth();
437 SubtreeLayoutScope layouter(this);
439 if (logicalWidth() != oldLogicalWidth) {
440 for (unsigned i = 0; i < m_captions.size(); i++)
441 layouter.setNeedsLayout(m_captions[i]);
443 // FIXME: The optimisation below doesn't work since the internal table
444 // layout could have changed. we need to add a flag to the table
445 // layout that tells us if something has changed in the min max
446 // calculations to do it correctly.
447 // if ( oldWidth != width() || columns.size() + 1 != columnPos.size() )
448 m_tableLayout->layout();
450 LayoutUnit totalSectionLogicalHeight = 0;
451 LayoutUnit oldTableLogicalTop = 0;
452 for (unsigned i = 0; i < m_captions.size(); i++)
453 oldTableLogicalTop += m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
455 bool collapsing = collapseBorders();
457 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
458 if (child->isTableSection()) {
459 RenderTableSection* section = toRenderTableSection(child);
460 if (m_columnLogicalWidthChanged)
461 layouter.setChildNeedsLayout(section);
462 section->layoutIfNeeded();
463 totalSectionLogicalHeight += section->calcRowLogicalHeight();
465 section->recalcOuterBorder();
466 ASSERT(!section->needsLayout());
467 } else if (child->isRenderTableCol()) {
468 child->layoutIfNeeded();
469 ASSERT(!child->needsLayout());
471 // FIXME: We should never have other type of children (they should be wrapped in an
472 // anonymous table section) but our code is too crazy and this can happen in practice.
473 // Until this is fixed, let's make sure we don't leave non laid out children in the tree.
474 child->layoutIfNeeded();
478 // If any table section moved vertically, we will just repaint everything from that
479 // section down (it is quite unlikely that any of the following sections
481 bool sectionMoved = false;
482 LayoutUnit movedSectionLogicalTop = 0;
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());
575 if (view()->layoutState()->pageLogicalHeight())
576 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
578 bool didFullRepaint = repainter.repaintAfterLayout();
579 // Repaint with our new bounds if they are different from our old bounds.
580 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()
581 && !didFullRepaint && sectionMoved) {
582 if (style()->isHorizontalWritingMode())
583 repaintRectangle(LayoutRect(visualOverflowRect().x(), movedSectionLogicalTop, visualOverflowRect().width(), visualOverflowRect().maxY() - movedSectionLogicalTop));
585 repaintRectangle(LayoutRect(movedSectionLogicalTop, visualOverflowRect().y(), visualOverflowRect().maxX() - movedSectionLogicalTop, visualOverflowRect().height()));
588 m_columnLogicalWidthChanged = false;
592 // Collect all the unique border values that we want to paint in a sorted list.
593 void RenderTable::recalcCollapsedBorders()
595 if (m_collapsedBordersValid)
597 m_collapsedBordersValid = true;
598 m_collapsedBorders.clear();
599 for (RenderObject* section = firstChild(); section; section = section->nextSibling()) {
600 if (!section->isTableSection())
602 for (RenderObject* row = section->firstChild(); row; row = row->nextSibling()) {
603 if (!row->isTableRow())
605 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
606 if (!cell->isTableCell())
608 ASSERT(toRenderTableCell(cell)->table() == this);
609 toRenderTableCell(cell)->collectBorderValues(m_collapsedBorders);
613 RenderTableCell::sortBorderValues(m_collapsedBorders);
617 void RenderTable::addOverflowFromChildren()
619 // Add overflow from borders.
620 // Technically it's odd that we are incorporating the borders into layout overflow, which is only supposed to be about overflow from our
621 // descendant objects, but since tables don't support overflow:auto, this works out fine.
622 if (collapseBorders()) {
623 int rightBorderOverflow = width() + outerBorderRight() - borderRight();
624 int leftBorderOverflow = borderLeft() - outerBorderLeft();
625 int bottomBorderOverflow = height() + outerBorderBottom() - borderBottom();
626 int topBorderOverflow = borderTop() - outerBorderTop();
627 IntRect borderOverflowRect(leftBorderOverflow, topBorderOverflow, rightBorderOverflow - leftBorderOverflow, bottomBorderOverflow - topBorderOverflow);
628 if (borderOverflowRect != pixelSnappedBorderBoxRect()) {
629 addLayoutOverflow(borderOverflowRect);
630 addVisualOverflow(borderOverflowRect);
634 // Add overflow from our caption.
635 for (unsigned i = 0; i < m_captions.size(); i++)
636 addOverflowFromChild(m_captions[i]);
638 // Add overflow from our sections.
639 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section))
640 addOverflowFromChild(section);
643 void RenderTable::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
645 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
647 LayoutPoint adjustedPaintOffset = paintOffset + location();
649 PaintPhase paintPhase = paintInfo.phase;
652 LayoutRect overflowBox = visualOverflowRect();
653 flipForWritingMode(overflowBox);
654 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
655 overflowBox.moveBy(adjustedPaintOffset);
656 if (!overflowBox.intersects(paintInfo.rect))
660 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
661 paintObject(paintInfo, adjustedPaintOffset);
663 popContentsClip(paintInfo, paintPhase, adjustedPaintOffset);
666 void RenderTable::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
668 PaintPhase paintPhase = paintInfo.phase;
669 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
670 paintBoxDecorations(paintInfo, paintOffset);
672 if (paintPhase == PaintPhaseMask) {
673 paintMask(paintInfo, paintOffset);
677 // We're done. We don't bother painting any children.
678 if (paintPhase == PaintPhaseBlockBackground)
681 // We don't paint our own background, but we do let the kids paint their backgrounds.
682 if (paintPhase == PaintPhaseChildBlockBackgrounds)
683 paintPhase = PaintPhaseChildBlockBackground;
685 PaintInfo info(paintInfo);
686 info.phase = paintPhase;
687 info.updatePaintingRootForChildren(this);
689 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
690 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
691 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), paintOffset);
692 child->paint(info, childPoint);
696 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
697 recalcCollapsedBorders();
698 // Using our cached sorted styles, we then do individual passes,
699 // painting each style of border from lowest precedence to highest precedence.
700 info.phase = PaintPhaseCollapsedTableBorders;
701 size_t count = m_collapsedBorders.size();
702 for (size_t i = 0; i < count; ++i) {
703 m_currentBorder = &m_collapsedBorders[i];
704 for (RenderTableSection* section = bottomSection(); section; section = sectionAbove(section)) {
705 LayoutPoint childPoint = flipForWritingModeForChild(section, paintOffset);
706 section->paint(info, childPoint);
713 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
714 paintOutline(paintInfo, LayoutRect(paintOffset, size()));
717 void RenderTable::subtractCaptionRect(LayoutRect& rect) const
719 for (unsigned i = 0; i < m_captions.size(); i++) {
720 LayoutUnit captionLogicalHeight = m_captions[i]->logicalHeight() + m_captions[i]->marginBefore() + m_captions[i]->marginAfter();
721 bool captionIsBefore = (m_captions[i]->style()->captionSide() != CAPBOTTOM) ^ style()->isFlippedBlocksWritingMode();
722 if (style()->isHorizontalWritingMode()) {
723 rect.setHeight(rect.height() - captionLogicalHeight);
725 rect.move(0, captionLogicalHeight);
727 rect.setWidth(rect.width() - captionLogicalHeight);
729 rect.move(captionLogicalHeight, 0);
734 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
736 if (!paintInfo.shouldPaintWithinRoot(this))
739 LayoutRect rect(paintOffset, size());
740 subtractCaptionRect(rect);
741 paintBoxDecorationsWithRect(paintInfo, paintOffset, rect);
744 void RenderTable::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
746 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
749 LayoutRect rect(paintOffset, size());
750 subtractCaptionRect(rect);
752 paintMaskImages(paintInfo, rect);
755 void RenderTable::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const
757 recalcSectionsIfNeeded();
758 // FIXME: Do the recalc in borderStart/borderEnd and make those const_cast this call.
759 // Then m_borderStart/m_borderEnd will be transparent a cache and it removes the possibility
760 // of reading out stale values.
761 const_cast<RenderTable*>(this)->recalcBordersInRowDirection();
762 // FIXME: Restructure the table layout code so that we can make this method const.
763 const_cast<RenderTable*>(this)->m_tableLayout->computeIntrinsicLogicalWidths(minWidth, maxWidth);
765 // FIXME: We should include captions widths here like we do in computePreferredLogicalWidths.
768 void RenderTable::computePreferredLogicalWidths()
770 ASSERT(preferredLogicalWidthsDirty());
772 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
774 int bordersPaddingAndSpacing = bordersPaddingAndSpacingInRowDirection();
775 m_minPreferredLogicalWidth += bordersPaddingAndSpacing;
776 m_maxPreferredLogicalWidth += bordersPaddingAndSpacing;
778 m_tableLayout->applyPreferredLogicalWidthQuirks(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
780 for (unsigned i = 0; i < m_captions.size(); i++)
781 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_captions[i]->minPreferredLogicalWidth());
783 RenderStyle* styleToUse = style();
784 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for min-width.
785 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
786 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
787 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
790 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage or calc values for maxWidth.
791 if (styleToUse->logicalMaxWidth().isFixed()) {
792 // We don't constrain m_minPreferredLogicalWidth as the table should be at least the size of its min-content, regardless of 'max-width'.
793 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
794 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
797 // FIXME: We should be adding borderAndPaddingLogicalWidth here, but m_tableLayout->computePreferredLogicalWidths already does,
798 // so a bunch of tests break doing this naively.
799 clearPreferredLogicalWidthsDirty();
802 RenderTableSection* RenderTable::topNonEmptySection() const
804 RenderTableSection* section = topSection();
805 if (section && !section->numRows())
806 section = sectionBelow(section, SkipEmptySections);
810 void RenderTable::splitColumn(unsigned position, unsigned firstSpan)
812 // We split the column at "position", taking "firstSpan" cells from the span.
813 ASSERT(m_columns[position].span > firstSpan);
814 m_columns.insert(position, ColumnStruct(firstSpan));
815 m_columns[position + 1].span -= firstSpan;
817 // Propagate the change in our columns representation to the sections that don't need
818 // cell recalc. If they do, they will be synced up directly with m_columns later.
819 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
820 if (!child->isTableSection())
823 RenderTableSection* section = toRenderTableSection(child);
824 if (section->needsCellRecalc())
827 section->splitColumn(position, firstSpan);
830 m_columnPos.grow(numEffCols() + 1);
833 void RenderTable::appendColumn(unsigned span)
835 unsigned newColumnIndex = m_columns.size();
836 m_columns.append(ColumnStruct(span));
838 // Propagate the change in our columns representation to the sections that don't need
839 // cell recalc. If they do, they will be synced up directly with m_columns later.
840 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
841 if (!child->isTableSection())
844 RenderTableSection* section = toRenderTableSection(child);
845 if (section->needsCellRecalc())
848 section->appendColumn(newColumnIndex);
851 m_columnPos.grow(numEffCols() + 1);
854 RenderTableCol* RenderTable::firstColumn() const
856 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
857 if (child->isRenderTableCol())
858 return toRenderTableCol(child);
864 void RenderTable::updateColumnCache() const
866 ASSERT(m_hasColElements);
867 ASSERT(m_columnRenderers.isEmpty());
868 ASSERT(!m_columnRenderersValid);
870 for (RenderTableCol* columnRenderer = firstColumn(); columnRenderer; columnRenderer = columnRenderer->nextColumn()) {
871 if (columnRenderer->isTableColumnGroupWithColumnChildren())
873 m_columnRenderers.append(columnRenderer);
875 m_columnRenderersValid = true;
878 RenderTableCol* RenderTable::slowColElement(unsigned col, bool* startEdge, bool* endEdge) const
880 ASSERT(m_hasColElements);
882 if (!m_columnRenderersValid)
885 unsigned columnCount = 0;
886 for (unsigned i = 0; i < m_columnRenderers.size(); i++) {
887 RenderTableCol* columnRenderer = m_columnRenderers[i];
888 unsigned span = columnRenderer->span();
889 unsigned startCol = columnCount;
891 unsigned endCol = columnCount + span - 1;
893 if (columnCount > col) {
895 *startEdge = startCol == col;
897 *endEdge = endCol == col;
898 return columnRenderer;
904 void RenderTable::recalcSections() const
906 ASSERT(m_needsSectionRecalc);
911 m_hasColElements = false;
913 // We need to get valid pointers to caption, head, foot and first body again
914 RenderObject* nextSibling;
915 for (RenderObject* child = firstChild(); child; child = nextSibling) {
916 nextSibling = child->nextSibling();
917 switch (child->style()->display()) {
919 case TABLE_COLUMN_GROUP:
920 m_hasColElements = true;
922 case TABLE_HEADER_GROUP:
923 if (child->isTableSection()) {
924 RenderTableSection* section = toRenderTableSection(child);
927 else if (!m_firstBody)
928 m_firstBody = section;
929 section->recalcCellsIfNeeded();
932 case TABLE_FOOTER_GROUP:
933 if (child->isTableSection()) {
934 RenderTableSection* section = toRenderTableSection(child);
937 else if (!m_firstBody)
938 m_firstBody = section;
939 section->recalcCellsIfNeeded();
942 case TABLE_ROW_GROUP:
943 if (child->isTableSection()) {
944 RenderTableSection* section = toRenderTableSection(child);
946 m_firstBody = section;
947 section->recalcCellsIfNeeded();
955 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
956 unsigned maxCols = 0;
957 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
958 if (child->isTableSection()) {
959 RenderTableSection* section = toRenderTableSection(child);
960 unsigned sectionCols = section->numColumns();
961 if (sectionCols > maxCols)
962 maxCols = sectionCols;
966 m_columns.resize(maxCols);
967 m_columnPos.resize(maxCols + 1);
969 ASSERT(selfNeedsLayout());
971 m_needsSectionRecalc = false;
974 int RenderTable::calcBorderStart() const
976 if (!collapseBorders())
977 return RenderBlock::borderStart();
979 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
983 unsigned borderWidth = 0;
985 const BorderValue& tableStartBorder = style()->borderStart();
986 if (tableStartBorder.style() == BHIDDEN)
988 if (tableStartBorder.style() > BHIDDEN)
989 borderWidth = tableStartBorder.width();
991 if (RenderTableCol* column = colElement(0)) {
992 // FIXME: We don't account for direction on columns and column groups.
993 const BorderValue& columnAdjoiningBorder = column->style()->borderStart();
994 if (columnAdjoiningBorder.style() == BHIDDEN)
996 if (columnAdjoiningBorder.style() > BHIDDEN)
997 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
998 // FIXME: This logic doesn't properly account for the first column in the first column-group case.
1001 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1002 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableStart();
1003 if (sectionAdjoiningBorder.style() == BHIDDEN)
1006 if (sectionAdjoiningBorder.style() > BHIDDEN)
1007 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1009 if (const RenderTableCell* adjoiningStartCell = topNonEmptySection->firstRowCellAdjoiningTableStart()) {
1010 // FIXME: Make this work with perpendicular and flipped cells.
1011 const BorderValue& startCellAdjoiningBorder = adjoiningStartCell->borderAdjoiningTableStart();
1012 if (startCellAdjoiningBorder.style() == BHIDDEN)
1015 const BorderValue& firstRowAdjoiningBorder = adjoiningStartCell->row()->borderAdjoiningTableStart();
1016 if (firstRowAdjoiningBorder.style() == BHIDDEN)
1019 if (startCellAdjoiningBorder.style() > BHIDDEN)
1020 borderWidth = max(borderWidth, startCellAdjoiningBorder.width());
1021 if (firstRowAdjoiningBorder.style() > BHIDDEN)
1022 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1025 return (borderWidth + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1028 int RenderTable::calcBorderEnd() const
1030 if (!collapseBorders())
1031 return RenderBlock::borderEnd();
1033 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
1037 unsigned borderWidth = 0;
1039 const BorderValue& tableEndBorder = style()->borderEnd();
1040 if (tableEndBorder.style() == BHIDDEN)
1042 if (tableEndBorder.style() > BHIDDEN)
1043 borderWidth = tableEndBorder.width();
1045 unsigned endColumn = numEffCols() - 1;
1046 if (RenderTableCol* column = colElement(endColumn)) {
1047 // FIXME: We don't account for direction on columns and column groups.
1048 const BorderValue& columnAdjoiningBorder = column->style()->borderEnd();
1049 if (columnAdjoiningBorder.style() == BHIDDEN)
1051 if (columnAdjoiningBorder.style() > BHIDDEN)
1052 borderWidth = max(borderWidth, columnAdjoiningBorder.width());
1053 // FIXME: This logic doesn't properly account for the last column in the last column-group case.
1056 if (const RenderTableSection* topNonEmptySection = this->topNonEmptySection()) {
1057 const BorderValue& sectionAdjoiningBorder = topNonEmptySection->borderAdjoiningTableEnd();
1058 if (sectionAdjoiningBorder.style() == BHIDDEN)
1061 if (sectionAdjoiningBorder.style() > BHIDDEN)
1062 borderWidth = max(borderWidth, sectionAdjoiningBorder.width());
1064 if (const RenderTableCell* adjoiningEndCell = topNonEmptySection->firstRowCellAdjoiningTableEnd()) {
1065 // FIXME: Make this work with perpendicular and flipped cells.
1066 const BorderValue& endCellAdjoiningBorder = adjoiningEndCell->borderAdjoiningTableEnd();
1067 if (endCellAdjoiningBorder.style() == BHIDDEN)
1070 const BorderValue& firstRowAdjoiningBorder = adjoiningEndCell->row()->borderAdjoiningTableEnd();
1071 if (firstRowAdjoiningBorder.style() == BHIDDEN)
1074 if (endCellAdjoiningBorder.style() > BHIDDEN)
1075 borderWidth = max(borderWidth, endCellAdjoiningBorder.width());
1076 if (firstRowAdjoiningBorder.style() > BHIDDEN)
1077 borderWidth = max(borderWidth, firstRowAdjoiningBorder.width());
1080 return (borderWidth + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1083 void RenderTable::recalcBordersInRowDirection()
1085 // FIXME: We need to compute the collapsed before / after borders in the same fashion.
1086 m_borderStart = calcBorderStart();
1087 m_borderEnd = calcBorderEnd();
1090 int RenderTable::borderBefore() const
1092 if (collapseBorders()) {
1093 recalcSectionsIfNeeded();
1094 return outerBorderBefore();
1096 return RenderBlock::borderBefore();
1099 int RenderTable::borderAfter() const
1101 if (collapseBorders()) {
1102 recalcSectionsIfNeeded();
1103 return outerBorderAfter();
1105 return RenderBlock::borderAfter();
1108 int RenderTable::outerBorderBefore() const
1110 if (!collapseBorders())
1112 int borderWidth = 0;
1113 if (RenderTableSection* topSection = this->topSection()) {
1114 borderWidth = topSection->outerBorderBefore();
1115 if (borderWidth < 0)
1116 return 0; // Overridden by hidden
1118 const BorderValue& tb = style()->borderBefore();
1119 if (tb.style() == BHIDDEN)
1121 if (tb.style() > BHIDDEN)
1122 borderWidth = max<int>(borderWidth, tb.width() / 2);
1126 int RenderTable::outerBorderAfter() const
1128 if (!collapseBorders())
1130 int borderWidth = 0;
1132 if (RenderTableSection* section = bottomSection()) {
1133 borderWidth = section->outerBorderAfter();
1134 if (borderWidth < 0)
1135 return 0; // Overridden by hidden
1137 const BorderValue& tb = style()->borderAfter();
1138 if (tb.style() == BHIDDEN)
1140 if (tb.style() > BHIDDEN)
1141 borderWidth = max<int>(borderWidth, (tb.width() + 1) / 2);
1145 int RenderTable::outerBorderStart() const
1147 if (!collapseBorders())
1150 int borderWidth = 0;
1152 const BorderValue& tb = style()->borderStart();
1153 if (tb.style() == BHIDDEN)
1155 if (tb.style() > BHIDDEN)
1156 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 0 : 1)) / 2;
1158 bool allHidden = true;
1159 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1160 int sw = section->outerBorderStart();
1164 borderWidth = max(borderWidth, sw);
1172 int RenderTable::outerBorderEnd() const
1174 if (!collapseBorders())
1177 int borderWidth = 0;
1179 const BorderValue& tb = style()->borderEnd();
1180 if (tb.style() == BHIDDEN)
1182 if (tb.style() > BHIDDEN)
1183 borderWidth = (tb.width() + (style()->isLeftToRightDirection() ? 1 : 0)) / 2;
1185 bool allHidden = true;
1186 for (RenderTableSection* section = topSection(); section; section = sectionBelow(section)) {
1187 int sw = section->outerBorderEnd();
1191 borderWidth = max(borderWidth, sw);
1199 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1201 recalcSectionsIfNeeded();
1203 if (section == m_head)
1206 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
1207 while (prevSection) {
1208 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(prevSection)->numRows()))
1210 prevSection = prevSection->previousSibling();
1212 if (!prevSection && m_head && (skipEmptySections == DoNotSkipEmptySections || m_head->numRows()))
1213 prevSection = m_head;
1214 return toRenderTableSection(prevSection);
1217 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, SkipEmptySectionsValue skipEmptySections) const
1219 recalcSectionsIfNeeded();
1221 if (section == m_foot)
1224 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1225 while (nextSection) {
1226 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (skipEmptySections == DoNotSkipEmptySections || toRenderTableSection(nextSection)->numRows()))
1228 nextSection = nextSection->nextSibling();
1230 if (!nextSection && m_foot && (skipEmptySections == DoNotSkipEmptySections || m_foot->numRows()))
1231 nextSection = m_foot;
1232 return toRenderTableSection(nextSection);
1235 RenderTableSection* RenderTable::bottomSection() const
1237 recalcSectionsIfNeeded();
1242 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1243 if (child->isTableSection())
1244 return toRenderTableSection(child);
1250 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1252 recalcSectionsIfNeeded();
1254 // Find the section and row to look in
1255 unsigned r = cell->rowIndex();
1256 RenderTableSection* section = 0;
1257 unsigned rAbove = 0;
1259 // cell is not in the first row, so use the above row in its own section
1260 section = cell->section();
1263 section = sectionAbove(cell->section(), SkipEmptySections);
1265 ASSERT(section->numRows());
1266 rAbove = section->numRows() - 1;
1270 // Look up the cell in the section's grid, which requires effective col index
1272 unsigned effCol = colToEffCol(cell->col());
1273 RenderTableSection::CellStruct& aboveCell = section->cellAt(rAbove, effCol);
1274 return aboveCell.primaryCell();
1279 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1281 recalcSectionsIfNeeded();
1283 // Find the section and row to look in
1284 unsigned r = cell->rowIndex() + cell->rowSpan() - 1;
1285 RenderTableSection* section = 0;
1286 unsigned rBelow = 0;
1287 if (r < cell->section()->numRows() - 1) {
1288 // The cell is not in the last row, so use the next row in the section.
1289 section = cell->section();
1292 section = sectionBelow(cell->section(), SkipEmptySections);
1297 // Look up the cell in the section's grid, which requires effective col index
1299 unsigned effCol = colToEffCol(cell->col());
1300 RenderTableSection::CellStruct& belowCell = section->cellAt(rBelow, effCol);
1301 return belowCell.primaryCell();
1306 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1308 recalcSectionsIfNeeded();
1310 RenderTableSection* section = cell->section();
1311 unsigned effCol = colToEffCol(cell->col());
1315 // If we hit a colspan back up to a real cell.
1316 RenderTableSection::CellStruct& prevCell = section->cellAt(cell->rowIndex(), effCol - 1);
1317 return prevCell.primaryCell();
1320 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1322 recalcSectionsIfNeeded();
1324 unsigned effCol = colToEffCol(cell->col() + cell->colSpan());
1325 if (effCol >= numEffCols())
1327 return cell->section()->primaryCellAt(cell->rowIndex(), effCol);
1330 RenderBlock* RenderTable::firstLineBlock() const
1335 void RenderTable::updateFirstLetter()
1339 int RenderTable::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1341 ASSERT(linePositionMode == PositionOnContainingLine);
1342 int baseline = firstLineBoxBaseline();
1343 if (baseline != -1) {
1345 return beforeMarginInLineDirection(direction) + baseline;
1349 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
1352 int RenderTable::inlineBlockBaseline(LineDirectionMode) const
1354 // Tables are skipped when computing an inline-block's baseline.
1358 int RenderTable::firstLineBoxBaseline() const
1360 // The baseline of a 'table' is the same as the 'inline-table' baseline per CSS 3 Flexbox (CSS 2.1
1361 // doesn't define the baseline of a 'table' only an 'inline-table').
1362 // This is also needed to properly determine the baseline of a cell if it has a table child.
1364 if (isWritingModeRoot())
1367 recalcSectionsIfNeeded();
1369 const RenderTableSection* topNonEmptySection = this->topNonEmptySection();
1370 if (!topNonEmptySection)
1373 int baseline = topNonEmptySection->firstLineBoxBaseline();
1375 return topNonEmptySection->logicalTop() + baseline;
1377 // FIXME: A table row always has a baseline per CSS 2.1. Will this return the right value?
1381 LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1383 LayoutRect rect = RenderBlock::overflowClipRect(location, region, relevancy);
1385 // If we have a caption, expand the clip to include the caption.
1386 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1387 // for real until captions have been re-written.
1388 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1389 // supported. When we actually support left/right and stop mapping them to top/bottom,
1390 // we might have to hack this code first (depending on what order we do these bug fixes in).
1391 if (!m_captions.isEmpty()) {
1392 if (style()->isHorizontalWritingMode()) {
1393 rect.setHeight(height());
1394 rect.setY(location.y());
1396 rect.setWidth(width());
1397 rect.setX(location.x());
1404 bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1406 LayoutPoint adjustedLocation = accumulatedOffset + location();
1408 // Check kids first.
1409 if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) {
1410 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1411 if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) {
1412 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
1413 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1414 updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1421 // Check our bounds next.
1422 LayoutRect boundsRect(adjustedLocation, size());
1423 if (visibleToHitTestRequest(request) && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) {
1424 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation)));
1425 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1432 RenderTable* RenderTable::createAnonymousWithParentRenderer(const RenderObject* parent)
1434 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE);
1435 RenderTable* newTable = new RenderTable(0);
1436 newTable->setDocumentForAnonymous(&parent->document());
1437 newTable->setStyle(newStyle.release());
1441 const BorderValue& RenderTable::tableStartBorderAdjoiningCell(const RenderTableCell* cell) const
1443 ASSERT(cell->isFirstOrLastCellInRow());
1444 if (hasSameDirectionAs(cell->row()))
1445 return style()->borderStart();
1447 return style()->borderEnd();
1450 const BorderValue& RenderTable::tableEndBorderAdjoiningCell(const RenderTableCell* cell) const
1452 ASSERT(cell->isFirstOrLastCellInRow());
1453 if (hasSameDirectionAs(cell->row()))
1454 return style()->borderEnd();
1456 return style()->borderStart();