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 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 "DeleteButtonController.h"
32 #include "FixedTableLayout.h"
33 #include "FrameView.h"
34 #include "HTMLNames.h"
35 #include "RenderLayer.h"
36 #include "RenderTableCell.h"
37 #include "RenderTableCol.h"
38 #include "RenderTableSection.h"
39 #include "RenderView.h"
45 using namespace HTMLNames;
47 RenderTable::RenderTable(Node* node)
57 , m_hasColElements(false)
58 , m_needsSectionRecalc(0)
64 m_columnPos.fill(0, 2);
65 m_columns.fill(ColumnStruct(), 1);
68 RenderTable::~RenderTable()
73 void RenderTable::setStyle(RenderStyle* newStyle)
75 ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO;
76 RenderBlock::setStyle(newStyle);
78 // In the collapsed border model, there is no cell spacing.
79 m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
80 m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
81 m_columnPos[0] = m_hSpacing;
83 if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
86 // According to the CSS2 spec, you only use fixed table layout if an
87 // explicit width is specified on the table. Auto width implies auto table layout.
88 if (style()->tableLayout() == TFIXED && !style()->width().isAuto())
89 m_tableLayout = new FixedTableLayout(this);
91 m_tableLayout = new AutoTableLayout(this);
95 static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
99 RenderObject* o = before->previousSibling();
100 while (o && o != ptr)
101 o = o->previousSibling();
106 void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
108 // Make sure we don't append things after :after-generated content if we have it.
109 if (!beforeChild && isAfterContent(lastChild()))
110 beforeChild = lastChild();
112 bool wrapInAnonymousSection = true;
113 bool isTableElement = element() && element()->hasTagName(tableTag);
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();
125 m_caption = static_cast<RenderBlock*>(child);
126 wrapInAnonymousSection = false;
127 } else if (child->isTableCol()) {
128 m_hasColElements = true;
129 wrapInAnonymousSection = false;
130 } else if (child->isTableSection()) {
131 switch (child->style()->display()) {
132 case TABLE_HEADER_GROUP:
133 if (child->isTableSection()) {
134 resetSectionPointerIfNotBefore(m_head, beforeChild);
136 m_head = static_cast<RenderTableSection*>(child);
138 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
140 m_firstBody = static_cast<RenderTableSection*>(child);
143 wrapInAnonymousSection = false;
145 case TABLE_FOOTER_GROUP:
146 if (child->isTableSection()) {
147 resetSectionPointerIfNotBefore(m_foot, beforeChild);
149 m_foot = static_cast<RenderTableSection*>(child);
150 wrapInAnonymousSection = false;
155 case TABLE_ROW_GROUP:
156 if (child->isTableSection()) {
157 resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
159 m_firstBody = static_cast<RenderTableSection*>(child);
161 wrapInAnonymousSection = false;
164 ASSERT_NOT_REACHED();
166 } else if (child->isTableCell() || child->isTableRow()) {
167 wrapInAnonymousSection = true;
169 // Allow a form to just sit at the top level.
170 wrapInAnonymousSection = !isTableElement || !child->element() || !(child->element()->hasTagName(formTag) && document()->isHTMLDocument());
172 // FIXME: Allow the delete button container element to sit at the top level. This is needed until http://bugs.webkit.org/show_bug.cgi?id=11363 is fixed.
173 if (wrapInAnonymousSection && child->element() && child->element()->isHTMLElement() && static_cast<HTMLElement*>(child->element())->id() == DeleteButtonController::containerElementIdentifier)
174 wrapInAnonymousSection = false;
177 if (!wrapInAnonymousSection) {
178 // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
179 while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION)
180 beforeChild = beforeChild->parent();
182 RenderContainer::addChild(child, beforeChild);
186 if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
187 lastChild()->addChild(child);
191 RenderObject* lastBox = beforeChild;
192 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)
193 lastBox = lastBox->parent();
194 if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
195 lastBox->addChild(child, beforeChild);
199 if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)
201 RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
202 RenderStyle* newStyle = new (renderArena()) RenderStyle();
203 newStyle->inheritFrom(style());
204 newStyle->setDisplay(TABLE_ROW_GROUP);
205 section->setStyle(newStyle);
206 addChild(section, beforeChild);
207 section->addChild(child);
210 void RenderTable::calcWidth()
213 calcAbsoluteHorizontal();
215 RenderBlock* cb = containingBlock();
216 int availableWidth = cb->availableWidth();
218 LengthType widthType = style()->width().type();
219 if (widthType > Relative && style()->width().isPositive()) {
220 // Percent or fixed table
221 m_width = style()->width().calcMinValue(availableWidth);
222 m_width = max(minPrefWidth(), m_width);
224 // An auto width table should shrink to fit within the line width if necessary in order to
225 // avoid overlapping floats.
226 availableWidth = cb->lineWidth(m_y);
228 // Subtract out any fixed margins from our available width for auto width tables.
230 if (!style()->marginLeft().isAuto())
231 marginTotal += style()->marginLeft().calcValue(availableWidth);
232 if (!style()->marginRight().isAuto())
233 marginTotal += style()->marginRight().calcValue(availableWidth);
235 // Subtract out our margins to get the available content width.
236 int availContentWidth = max(0, availableWidth - marginTotal);
238 // Ensure we aren't bigger than our max width or smaller than our min width.
239 m_width = min(availContentWidth, maxPrefWidth());
242 m_width = max(m_width, minPrefWidth());
244 // Finally, with our true width determined, compute our margins for real.
247 calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
250 void RenderTable::layout()
252 ASSERT(needsLayout());
254 if (layoutOnlyPositionedObjects())
257 recalcSectionsIfNeeded();
260 IntRect oldOutlineBox;
261 bool checkForRepaint = checkForRepaintDuringLayout();
262 if (checkForRepaint) {
263 oldBounds = absoluteClippedOverflowRect();
264 oldOutlineBox = absoluteOutlineBox();
267 view()->pushLayoutState(this, IntSize(m_x, m_y));
270 m_overflowHeight = 0;
272 initMaxMarginValues();
274 int oldWidth = m_width;
277 if (m_caption && m_width != oldWidth)
278 m_caption->setNeedsLayout(true, false);
280 // FIXME: The optimisation below doesn't work since the internal table
281 // layout could have changed. we need to add a flag to the table
282 // layout that tells us if something has changed in the min max
283 // calculations to do it correctly.
284 // if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() )
285 m_tableLayout->layout();
289 // layout child objects
290 int calculatedHeight = 0;
291 int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;
293 bool collapsing = collapseBorders();
295 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
296 // FIXME: What about a form that has a display value that makes it a table section?
297 if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag)))
299 if (child->isTableSection()) {
300 RenderTableSection* section = static_cast<RenderTableSection*>(child);
301 calculatedHeight += section->calcRowHeight();
303 section->recalcOuterBorder();
307 m_overflowWidth = m_width + (collapsing ? outerBorderRight() - borderRight() : 0);
308 m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0;
310 // If any table section moved vertically, we will just repaint everything from that
311 // section down (it is quite unlikely that any of the following sections
313 bool sectionMoved = false;
314 int movedSectionTop = 0;
316 // FIXME: Collapse caption margin.
317 if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
318 IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
320 m_caption->setPos(m_caption->marginLeft(), m_height);
321 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
322 m_caption->repaintDuringLayoutIfMoved(captionRect);
324 m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
325 m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
326 m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
327 m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false));
328 m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false));
330 if (m_height != oldTableTop) {
332 movedSectionTop = min(m_height, oldTableTop);
336 int bpTop = borderTop() + (collapsing ? 0 : paddingTop());
337 int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom());
344 Length h = style()->height();
347 // Tables size as though CSS height includes border/padding.
348 th = h.value() - (bpTop + bpBottom);
349 else if (h.isPercent())
350 th = calcPercentageHeight(h);
353 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
354 if (!child->isTableSection())
356 // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.
357 static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0);
360 if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) {
361 // Completely empty tables (with no sections or anything) should at least honor specified height
366 int bl = borderLeft();
370 // position the table sections
371 RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
373 if (!sectionMoved && section->yPos() != m_height) {
375 movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false);
377 section->setPos(bl, m_height);
379 m_height += section->height();
380 m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false));
381 m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false));
382 m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false));
383 m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false));
384 section = sectionBelow(section);
387 m_height += bpBottom;
389 if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
390 IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
392 m_caption->setPos(m_caption->marginLeft(), m_height);
393 if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
394 m_caption->repaintDuringLayoutIfMoved(captionRect);
396 m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
397 m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
398 m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
404 m_overflowHeight = max(m_overflowHeight, m_height);
406 // table can be containing block of positioned elements.
407 // FIXME: Only pass true if width or height changed.
408 layoutPositionedObjects(true);
410 if (!hasOverflowClip()) {
411 for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
412 m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
413 m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
414 m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
415 m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
418 if (hasReflection()) {
419 IntRect reflection(reflectionBox());
420 m_overflowTop = min(m_overflowTop, reflection.y());
421 m_overflowHeight = max(m_overflowHeight, reflection.bottom());
422 m_overflowLeft = min(m_overflowLeft, reflection.x());
423 m_overflowHeight = max(m_overflowWidth, reflection.right());
427 view()->popLayoutState();
429 bool didFullRepaint = true;
430 // Repaint with our new bounds if they are different from our old bounds.
432 didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
433 if (!didFullRepaint && sectionMoved)
434 repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop));
436 setNeedsLayout(false);
439 void RenderTable::setCellWidths()
441 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
442 if (child->isTableSection())
443 static_cast<RenderTableSection*>(child)->setCellWidths();
447 void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
452 PaintPhase paintPhase = paintInfo.phase;
454 int os = 2 * maximalOutlineSize(paintPhase);
455 if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
457 if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
460 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
461 paintBoxDecorations(paintInfo, tx, ty);
463 if (paintPhase == PaintPhaseMask) {
464 paintMask(paintInfo, tx, ty);
468 // We're done. We don't bother painting any children.
469 if (paintPhase == PaintPhaseBlockBackground)
472 // We don't paint our own background, but we do let the kids paint their backgrounds.
473 if (paintPhase == PaintPhaseChildBlockBackgrounds)
474 paintPhase = PaintPhaseChildBlockBackground;
475 PaintInfo info(paintInfo);
476 info.phase = paintPhase;
477 info.paintingRoot = paintingRootForChildren(paintInfo);
479 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
480 if (!child->hasLayer() && (child->isTableSection() || child == m_caption))
481 child->paint(info, tx, ty);
484 if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
485 // Collect all the unique border styles that we want to paint in a sorted list. Once we
486 // have all the styles sorted, we then do individual passes, painting each style of border
487 // from lowest precedence to highest precedence.
488 info.phase = PaintPhaseCollapsedTableBorders;
489 RenderTableCell::CollapsedBorderStyles borderStyles;
490 RenderObject* stop = nextInPreOrderAfterChildren();
491 for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
492 if (o->isTableCell())
493 static_cast<RenderTableCell*>(o)->collectBorderStyles(borderStyles);
494 RenderTableCell::sortBorderStyles(borderStyles);
495 size_t count = borderStyles.size();
496 for (size_t i = 0; i < count; ++i) {
497 m_currentBorder = &borderStyles[i];
498 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
499 if (child->isTableSection())
500 child->paint(info, tx, ty);
506 void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
511 // Account for the caption.
513 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
515 if (m_caption->style()->captionSide() != CAPBOTTOM)
519 int my = max(ty, paintInfo.rect.y());
521 if (ty < paintInfo.rect.y())
522 mh = max(0, h - (paintInfo.rect.y() - ty));
524 mh = min(paintInfo.rect.height(), h);
526 paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
528 paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
530 if (style()->hasBorder() && !collapseBorders())
531 paintBorder(paintInfo.context, tx, ty, w, h, style());
534 void RenderTable::paintMask(PaintInfo& paintInfo, int tx, int ty)
536 if (style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
542 // Account for the caption.
544 int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
546 if (m_caption->style()->captionSide() != CAPBOTTOM)
550 int my = max(ty, paintInfo.rect.y());
552 if (ty < paintInfo.rect.y())
553 mh = max(0, h - (paintInfo.rect.y() - ty));
555 mh = min(paintInfo.rect.height(), h);
557 paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
560 void RenderTable::calcPrefWidths()
562 ASSERT(prefWidthsDirty());
564 recalcSectionsIfNeeded();
565 recalcHorizontalBorders();
567 m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth);
570 m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth());
572 setPrefWidthsDirty(false);
575 void RenderTable::splitColumn(int pos, int firstSpan)
577 // we need to add a new columnStruct
578 int oldSize = m_columns.size();
579 m_columns.grow(oldSize + 1);
580 int oldSpan = m_columns[pos].span;
581 ASSERT(oldSpan > firstSpan);
582 m_columns[pos].span = firstSpan;
583 memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
584 m_columns[pos + 1].span = oldSpan - firstSpan;
586 // change width of all rows.
587 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
588 if (child->isTableSection())
589 static_cast<RenderTableSection*>(child)->splitColumn(pos, oldSize + 1);
592 m_columnPos.grow(numEffCols() + 1);
593 setNeedsLayoutAndPrefWidthsRecalc();
596 void RenderTable::appendColumn(int span)
599 int pos = m_columns.size();
600 int newSize = pos + 1;
601 m_columns.grow(newSize);
602 m_columns[pos].span = span;
604 // change width of all rows.
605 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
606 if (child->isTableSection())
607 static_cast<RenderTableSection*>(child)->appendColumn(pos);
610 m_columnPos.grow(numEffCols() + 1);
611 setNeedsLayoutAndPrefWidthsRecalc();
614 RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
616 if (!m_hasColElements)
618 RenderObject* child = firstChild();
622 if (child->isTableCol()) {
623 RenderTableCol* colElem = static_cast<RenderTableCol*>(child);
624 int span = colElem->span();
625 if (!colElem->firstChild()) {
627 int endCol = cCol + span - 1;
631 *startEdge = startCol == col;
633 *endEdge = endCol == col;
638 RenderObject* next = child->firstChild();
640 next = child->nextSibling();
641 if (!next && child->parent()->isTableCol())
642 next = child->parent()->nextSibling();
644 } else if (child == m_caption)
645 child = child->nextSibling();
653 void RenderTable::recalcSections() const
659 m_hasColElements = false;
661 // We need to get valid pointers to caption, head, foot and first body again
662 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
663 switch (child->style()->display()) {
665 if (!m_caption && child->isRenderBlock()) {
666 m_caption = static_cast<RenderBlock*>(child);
667 m_caption->setNeedsLayout(true);
671 case TABLE_COLUMN_GROUP:
672 m_hasColElements = true;
674 case TABLE_HEADER_GROUP:
675 if (child->isTableSection()) {
676 RenderTableSection* section = static_cast<RenderTableSection*>(child);
679 else if (!m_firstBody)
680 m_firstBody = section;
681 section->recalcCellsIfNeeded();
684 case TABLE_FOOTER_GROUP:
685 if (child->isTableSection()) {
686 RenderTableSection* section = static_cast<RenderTableSection*>(child);
689 else if (!m_firstBody)
690 m_firstBody = section;
691 section->recalcCellsIfNeeded();
694 case TABLE_ROW_GROUP:
695 if (child->isTableSection()) {
696 RenderTableSection* section = static_cast<RenderTableSection*>(child);
698 m_firstBody = section;
699 section->recalcCellsIfNeeded();
707 // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
709 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
710 if (child->isTableSection()) {
711 RenderTableSection* section = static_cast<RenderTableSection*>(child);
712 int sectionCols = section->numColumns();
713 if (sectionCols > maxCols)
714 maxCols = sectionCols;
718 m_columns.resize(maxCols);
719 m_columnPos.resize(maxCols + 1);
721 ASSERT(selfNeedsLayout());
723 m_needsSectionRecalc = false;
726 RenderObject* RenderTable::removeChildNode(RenderObject* child, bool fullRemove)
728 setNeedsSectionRecalc();
729 return RenderContainer::removeChildNode(child, fullRemove);
732 int RenderTable::calcBorderLeft() const
734 if (collapseBorders()) {
735 // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
739 unsigned borderWidth = 0;
741 const BorderValue& tb = style()->borderLeft();
742 if (tb.style() == BHIDDEN)
744 if (tb.style() > BHIDDEN)
745 borderWidth = tb.width;
747 int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
748 RenderTableCol* colGroup = colElement(leftmostColumn);
750 const BorderValue& gb = style()->borderLeft();
751 if (gb.style() == BHIDDEN)
753 if (gb.style() > BHIDDEN)
754 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
757 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
758 if (firstNonEmptySection && !firstNonEmptySection->numRows())
759 firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
761 if (firstNonEmptySection) {
762 const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
763 if (sb.style() == BHIDDEN)
766 if (sb.style() > BHIDDEN)
767 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
769 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
772 const BorderValue& cb = cs.cell->style()->borderLeft();
773 if (cb.style() == BHIDDEN)
776 const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
777 if (rb.style() == BHIDDEN)
780 if (cb.style() > BHIDDEN)
781 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
782 if (rb.style() > BHIDDEN)
783 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
786 return borderWidth / 2;
788 return RenderBlock::borderLeft();
791 int RenderTable::calcBorderRight() const
793 if (collapseBorders()) {
794 // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
798 unsigned borderWidth = 0;
800 const BorderValue& tb = style()->borderRight();
801 if (tb.style() == BHIDDEN)
803 if (tb.style() > BHIDDEN)
804 borderWidth = tb.width;
806 int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
807 RenderTableCol* colGroup = colElement(rightmostColumn);
809 const BorderValue& gb = style()->borderRight();
810 if (gb.style() == BHIDDEN)
812 if (gb.style() > BHIDDEN)
813 borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
816 RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
817 if (firstNonEmptySection && !firstNonEmptySection->numRows())
818 firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
820 if (firstNonEmptySection) {
821 const BorderValue& sb = firstNonEmptySection->style()->borderRight();
822 if (sb.style() == BHIDDEN)
825 if (sb.style() > BHIDDEN)
826 borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
828 const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
831 const BorderValue& cb = cs.cell->style()->borderRight();
832 if (cb.style() == BHIDDEN)
835 const BorderValue& rb = cs.cell->parent()->style()->borderRight();
836 if (rb.style() == BHIDDEN)
839 if (cb.style() > BHIDDEN)
840 borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
841 if (rb.style() > BHIDDEN)
842 borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
845 return (borderWidth + 1) / 2;
847 return RenderBlock::borderRight();
850 void RenderTable::recalcHorizontalBorders()
852 m_borderLeft = calcBorderLeft();
853 m_borderRight = calcBorderRight();
856 int RenderTable::borderTop() const
858 if (collapseBorders())
859 return outerBorderTop();
860 return RenderBlock::borderTop();
863 int RenderTable::borderBottom() const
865 if (collapseBorders())
866 return outerBorderBottom();
867 return RenderBlock::borderBottom();
870 int RenderTable::outerBorderTop() const
872 if (!collapseBorders())
875 RenderTableSection* topSection;
878 else if (m_firstBody)
879 topSection = m_firstBody;
885 borderWidth = topSection->outerBorderTop();
886 if (borderWidth == -1)
887 return 0; // Overridden by hidden
889 const BorderValue& tb = style()->borderTop();
890 if (tb.style() == BHIDDEN)
892 if (tb.style() > BHIDDEN)
893 borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
897 int RenderTable::outerBorderBottom() const
899 if (!collapseBorders())
902 RenderTableSection* bottomSection;
904 bottomSection = m_foot;
907 for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling())
909 bottomSection = child ? static_cast<RenderTableSection*>(child) : 0;
912 borderWidth = bottomSection->outerBorderBottom();
913 if (borderWidth == -1)
914 return 0; // Overridden by hidden
916 const BorderValue& tb = style()->borderBottom();
917 if (tb.style() == BHIDDEN)
919 if (tb.style() > BHIDDEN)
920 borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
924 int RenderTable::outerBorderLeft() const
926 if (!collapseBorders())
931 const BorderValue& tb = style()->borderLeft();
932 if (tb.style() == BHIDDEN)
934 if (tb.style() > BHIDDEN)
935 borderWidth = tb.width / 2;
937 bool allHidden = true;
938 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
939 if (!child->isTableSection())
941 int sw = static_cast<RenderTableSection*>(child)->outerBorderLeft();
946 borderWidth = max(borderWidth, sw);
954 int RenderTable::outerBorderRight() const
956 if (!collapseBorders())
961 const BorderValue& tb = style()->borderRight();
962 if (tb.style() == BHIDDEN)
964 if (tb.style() > BHIDDEN)
965 borderWidth = (tb.width + 1) / 2;
967 bool allHidden = true;
968 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
969 if (!child->isTableSection())
971 int sw = static_cast<RenderTableSection*>(child)->outerBorderRight();
976 borderWidth = max(borderWidth, sw);
984 RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
986 recalcSectionsIfNeeded();
988 if (section == m_head)
991 RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
992 while (prevSection) {
993 if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows()))
995 prevSection = prevSection->previousSibling();
997 if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
998 prevSection = m_head;
999 return static_cast<RenderTableSection*>(prevSection);
1002 RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
1004 recalcSectionsIfNeeded();
1006 if (section == m_foot)
1009 RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
1010 while (nextSection) {
1011 if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows()))
1013 nextSection = nextSection->nextSibling();
1015 if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
1016 nextSection = m_foot;
1017 return static_cast<RenderTableSection*>(nextSection);
1020 RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
1022 recalcSectionsIfNeeded();
1024 // Find the section and row to look in
1025 int r = cell->row();
1026 RenderTableSection* section = 0;
1029 // cell is not in the first row, so use the above row in its own section
1030 section = cell->section();
1033 section = sectionAbove(cell->section(), true);
1035 rAbove = section->numRows() - 1;
1038 // Look up the cell in the section's grid, which requires effective col index
1040 int effCol = colToEffCol(cell->col());
1041 RenderTableSection::CellStruct aboveCell;
1042 // If we hit a span back up to a real cell.
1044 aboveCell = section->cellAt(rAbove, effCol);
1046 } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
1047 return aboveCell.cell;
1052 RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
1054 recalcSectionsIfNeeded();
1056 // Find the section and row to look in
1057 int r = cell->row() + cell->rowSpan() - 1;
1058 RenderTableSection* section = 0;
1060 if (r < cell->section()->numRows() - 1) {
1061 // The cell is not in the last row, so use the next row in the section.
1062 section = cell->section();
1065 section = sectionBelow(cell->section(), true);
1070 // Look up the cell in the section's grid, which requires effective col index
1072 int effCol = colToEffCol(cell->col());
1073 RenderTableSection::CellStruct belowCell;
1074 // If we hit a colspan back up to a real cell.
1076 belowCell = section->cellAt(rBelow, effCol);
1078 } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
1079 return belowCell.cell;
1084 RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
1086 recalcSectionsIfNeeded();
1088 RenderTableSection* section = cell->section();
1089 int effCol = colToEffCol(cell->col());
1093 // If we hit a colspan back up to a real cell.
1094 RenderTableSection::CellStruct prevCell;
1096 prevCell = section->cellAt(cell->row(), effCol - 1);
1098 } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
1099 return prevCell.cell;
1102 RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
1104 recalcSectionsIfNeeded();
1106 int effCol = colToEffCol(cell->col() + cell->colSpan());
1107 if (effCol >= numEffCols())
1109 return cell->section()->cellAt(cell->row(), effCol).cell;
1112 RenderBlock* RenderTable::firstLineBlock() const
1117 void RenderTable::updateFirstLetter()
1121 IntRect RenderTable::getOverflowClipRect(int tx, int ty)
1123 IntRect rect = RenderBlock::getOverflowClipRect(tx, ty);
1125 // If we have a caption, expand the clip to include the caption.
1126 // FIXME: Technically this is wrong, but it's virtually impossible to fix this
1127 // for real until captions have been re-written.
1128 // FIXME: This code assumes (like all our other caption code) that only top/bottom are
1129 // supported. When we actually support left/right and stop mapping them to top/bottom,
1130 // we might have to hack this code first (depending on what order we do these bug fixes in).
1132 rect.setHeight(height());