summaryrefslogtreecommitdiffstats
path: root/webkit/pending/RenderTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/pending/RenderTable.cpp')
-rw-r--r--webkit/pending/RenderTable.cpp1122
1 files changed, 0 insertions, 1122 deletions
diff --git a/webkit/pending/RenderTable.cpp b/webkit/pending/RenderTable.cpp
deleted file mode 100644
index 1a512d4..0000000
--- a/webkit/pending/RenderTable.cpp
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*
- * Copyright (C) 1997 Martin Jones (mjones@kde.org)
- * (C) 1997 Torben Weis (weis@kde.org)
- * (C) 1998 Waldo Bastian (bastian@kde.org)
- * (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "RenderTable.h"
-
-#include "AutoTableLayout.h"
-#include "DeleteButtonController.h"
-#include "Document.h"
-#include "FixedTableLayout.h"
-#include "FrameView.h"
-#include "HTMLNames.h"
-#include "RenderLayer.h"
-#include "RenderTableCell.h"
-#include "RenderTableCol.h"
-#include "RenderTableSection.h"
-#include "RenderView.h"
-#include "TextStream.h"
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-RenderTable::RenderTable(Node* node)
- : RenderBlock(node)
- , m_caption(0)
- , m_head(0)
- , m_foot(0)
- , m_firstBody(0)
- , m_tableLayout(0)
- , m_currentBorder(0)
- , m_frame(Void)
- , m_rules(None)
- , m_hasColElements(false)
- , m_needsSectionRecalc(0)
- , m_hSpacing(0)
- , m_vSpacing(0)
- , m_borderLeft(0)
- , m_borderRight(0)
-{
- m_columnPos.fill(0, 2);
- m_columns.fill(ColumnStruct(), 1);
-}
-
-RenderTable::~RenderTable()
-{
- delete m_tableLayout;
-}
-
-void RenderTable::setStyle(RenderStyle* newStyle)
-{
- ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO;
- RenderBlock::setStyle(newStyle);
-
- // In the collapsed border model, there is no cell spacing.
- m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();
- m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();
- m_columnPos[0] = m_hSpacing;
-
- if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {
- delete m_tableLayout;
-
- // According to the CSS2 spec, you only use fixed table layout if an
- // explicit width is specified on the table. Auto width implies auto table layout.
- if (style()->tableLayout() == TFIXED && !style()->width().isAuto())
- m_tableLayout = new FixedTableLayout(this);
- else
- m_tableLayout = new AutoTableLayout(this);
- }
-}
-
-static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before)
-{
- if (!before || !ptr)
- return;
- RenderObject* o = before->previousSibling();
- while (o && o != ptr)
- o = o->previousSibling();
- if (!o)
- ptr = 0;
-}
-
-void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild)
-{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild && isAfterContent(lastChild()))
- beforeChild = lastChild();
-
- bool wrapInAnonymousSection = true;
- bool isTableElement = element() && element()->hasTagName(tableTag);
-
- if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {
- // First caption wins.
- if (beforeChild && m_caption) {
- RenderObject* o = beforeChild->previousSibling();
- while (o && o != m_caption)
- o = o->previousSibling();
- if (!o)
- m_caption = 0;
- }
- if (!m_caption)
- m_caption = static_cast<RenderBlock*>(child);
- wrapInAnonymousSection = false;
- } else if (child->isTableCol()) {
- m_hasColElements = true;
- wrapInAnonymousSection = false;
- } else if (child->isTableSection()) {
- switch (child->style()->display()) {
- case TABLE_HEADER_GROUP:
- if (child->isTableSection()) {
- resetSectionPointerIfNotBefore(m_head, beforeChild);
- if (!m_head) {
- m_head = static_cast<RenderTableSection*>(child);
- } else {
- resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
- if (!m_firstBody)
- m_firstBody = static_cast<RenderTableSection*>(child);
- }
- }
- wrapInAnonymousSection = false;
- break;
- case TABLE_FOOTER_GROUP:
- if (child->isTableSection()) {
- resetSectionPointerIfNotBefore(m_foot, beforeChild);
- if (!m_foot) {
- m_foot = static_cast<RenderTableSection*>(child);
- wrapInAnonymousSection = false;
- break;
- }
- }
- // Fall through.
- case TABLE_ROW_GROUP:
- if (child->isTableSection()) {
- resetSectionPointerIfNotBefore(m_firstBody, beforeChild);
- if (!m_firstBody)
- m_firstBody = static_cast<RenderTableSection*>(child);
- }
- wrapInAnonymousSection = false;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- } else if (child->isTableCell() || child->isTableRow()) {
- wrapInAnonymousSection = true;
- } else {
- // Allow a form to just sit at the top level.
- wrapInAnonymousSection = !isTableElement || !child->element() || !(child->element()->hasTagName(formTag) && document()->isHTMLDocument());
-
- // 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.
- if (wrapInAnonymousSection && child->element() && child->element()->isHTMLElement() && static_cast<HTMLElement*>(child->element())->id() == DeleteButtonController::containerElementIdentifier)
- wrapInAnonymousSection = false;
- }
-
- if (!wrapInAnonymousSection) {
- // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.
- while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION)
- beforeChild = beforeChild->parent();
-
- RenderContainer::addChild(child, beforeChild);
- return;
- }
-
- if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {
- lastChild()->addChild(child);
- return;
- }
-
- RenderObject* lastBox = beforeChild;
- while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION)
- lastBox = lastBox->parent();
- if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {
- lastBox->addChild(child, beforeChild);
- return;
- }
-
- if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION)
- beforeChild = 0;
- RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);
- RenderStyle* newStyle = new (renderArena()) RenderStyle();
- newStyle->inheritFrom(style());
- newStyle->setDisplay(TABLE_ROW_GROUP);
- section->setStyle(newStyle);
- addChild(section, beforeChild);
- section->addChild(child);
-}
-
-void RenderTable::calcWidth()
-{
- if (isPositioned())
- calcAbsoluteHorizontal();
-
- RenderBlock* cb = containingBlock();
- int availableWidth = cb->availableWidth();
-
- LengthType widthType = style()->width().type();
- if (widthType > Relative && style()->width().isPositive()) {
- // Percent or fixed table
- m_width = style()->width().calcMinValue(availableWidth);
- m_width = max(minPrefWidth(), m_width);
- } else {
- // An auto width table should shrink to fit within the line width if necessary in order to
- // avoid overlapping floats.
- availableWidth = cb->lineWidth(m_y);
-
- // Subtract out any fixed margins from our available width for auto width tables.
- int marginTotal = 0;
- if (!style()->marginLeft().isAuto())
- marginTotal += style()->marginLeft().calcValue(availableWidth);
- if (!style()->marginRight().isAuto())
- marginTotal += style()->marginRight().calcValue(availableWidth);
-
- // Subtract out our margins to get the available content width.
- int availContentWidth = max(0, availableWidth - marginTotal);
-
- // Ensure we aren't bigger than our max width or smaller than our min width.
- m_width = min(availContentWidth, maxPrefWidth());
- }
-
- m_width = max(m_width, minPrefWidth());
-
- // Finally, with our true width determined, compute our margins for real.
- m_marginRight = 0;
- m_marginLeft = 0;
- calcHorizontalMargins(style()->marginLeft(), style()->marginRight(), availableWidth);
-}
-
-void RenderTable::layout()
-{
- ASSERT(needsLayout());
-
- if (layoutOnlyPositionedObjects())
- return;
-
- recalcSectionsIfNeeded();
-
- IntRect oldBounds;
- IntRect oldOutlineBox;
- bool checkForRepaint = checkForRepaintDuringLayout();
- if (checkForRepaint) {
- oldBounds = absoluteClippedOverflowRect();
- oldOutlineBox = absoluteOutlineBox();
- }
-
- view()->pushLayoutState(this, IntSize(m_x, m_y));
-
- m_height = 0;
- m_overflowHeight = 0;
- m_overflowTop = 0;
- initMaxMarginValues();
-
- int oldWidth = m_width;
- calcWidth();
-
- if (m_caption && m_width != oldWidth)
- m_caption->setNeedsLayout(true, false);
-
- // FIXME: The optimisation below doesn't work since the internal table
- // layout could have changed. we need to add a flag to the table
- // layout that tells us if something has changed in the min max
- // calculations to do it correctly.
-// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() )
- m_tableLayout->layout();
-
- setCellWidths();
-
- // layout child objects
- int calculatedHeight = 0;
- int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;
-
- RenderObject* child = firstChild();
- while (child) {
- // FIXME: What about a form that has a display value that makes it a table section?
- if (child->needsLayout() && !(child->element() && child->element()->hasTagName(formTag)))
- child->layout();
- if (child->isTableSection()) {
- static_cast<RenderTableSection*>(child)->calcRowHeight();
- calculatedHeight += static_cast<RenderTableSection*>(child)->layoutRows(0);
- }
- child = child->nextSibling();
- }
-
- m_overflowWidth = m_width + (collapseBorders() ? outerBorderRight() - borderRight() : 0);
- m_overflowLeft = collapseBorders() ? borderLeft() - outerBorderLeft() : 0;
-
- // If any table section moved vertically, we will just repaint everything from that
- // section down (it is quite unlikely that any of the following sections
- // did not shift).
- bool sectionMoved = false;
- int movedSectionTop = 0;
-
- // FIXME: Collapse caption margin.
- if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {
- IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
-
- m_caption->setPos(m_caption->marginLeft(), m_height);
- if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
- m_caption->repaintDuringLayoutIfMoved(captionRect);
-
- m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
- m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
- m_overflowTop = min(m_overflowTop, m_caption->yPos() + m_caption->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, m_caption->yPos() + m_caption->overflowHeight(false));
-
- if (m_height != oldTableTop) {
- sectionMoved = true;
- movedSectionTop = min(m_height, oldTableTop);
- }
- }
-
- int bpTop = borderTop() + (collapseBorders() ? 0 : paddingTop());
- int bpBottom = borderBottom() + (collapseBorders() ? 0 : paddingBottom());
-
- m_height += bpTop;
-
- int oldHeight = m_height;
- if (!isPositioned())
- calcHeight();
- m_height = oldHeight;
-
- Length h = style()->height();
- int th = 0;
- if (h.isFixed())
- // Tables size as though CSS height includes border/padding.
- th = h.value() - (bpTop + bpBottom);
- else if (h.isPercent())
- th = calcPercentageHeight(h);
- th = max(0, th);
-
- // layout rows
- if (th > calculatedHeight) {
- // we have to redistribute that height to get the constraint correctly
- // just force the first body to the height needed
- // FIXME: This should take height constraints on all table sections into account and distribute
- // accordingly. For now this should be good enough.
- if (m_firstBody) {
- m_firstBody->calcRowHeight();
- m_firstBody->layoutRows(th - calculatedHeight);
- } else if (!style()->htmlHacks())
- // Completely empty tables (with no sections or anything) should at least honor specified height
- // in strict mode.
- m_height += th;
- }
-
- int bl = borderLeft();
- if (!collapseBorders())
- bl += paddingLeft();
-
- // position the table sections
- RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
- while (section) {
- if (!sectionMoved && section->yPos() != m_height) {
- sectionMoved = true;
- movedSectionTop = min(m_height, section->yPos()) + section->overflowTop(false);
- }
- section->setPos(bl, m_height);
-
- m_height += section->height();
- m_overflowLeft = min(m_overflowLeft, section->xPos() + section->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, section->xPos() + section->overflowWidth(false));
- m_overflowTop = min(m_overflowTop, section->yPos() + section->overflowTop(false));
- m_overflowHeight = max(m_overflowHeight, section->yPos() + section->overflowHeight(false));
- section = sectionBelow(section);
- }
-
- m_height += bpBottom;
-
- if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {
- IntRect captionRect(m_caption->xPos(), m_caption->yPos(), m_caption->width(), m_caption->height());
-
- m_caption->setPos(m_caption->marginLeft(), m_height);
- if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())
- m_caption->repaintDuringLayoutIfMoved(captionRect);
-
- m_height += m_caption->height() + m_caption->marginTop() + m_caption->marginBottom();
- m_overflowLeft = min(m_overflowLeft, m_caption->xPos() + m_caption->overflowLeft(false));
- m_overflowWidth = max(m_overflowWidth, m_caption->xPos() + m_caption->overflowWidth(false));
- }
-
- if (isPositioned())
- calcHeight();
-
- m_overflowHeight = max(m_overflowHeight, m_height);
-
- // table can be containing block of positioned elements.
- // FIXME: Only pass true if width or height changed.
- layoutPositionedObjects(true);
-
- if (!hasOverflowClip()) {
- if (ShadowData* boxShadow = style()->boxShadow()) {
- m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
- m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
- m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
- m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
- }
- }
-
- view()->popLayoutState();
-
- bool didFullRepaint = true;
- // Repaint with our new bounds if they are different from our old bounds.
- if (checkForRepaint)
- didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
- if (!didFullRepaint && sectionMoved)
- repaintRectangle(IntRect(m_overflowLeft, movedSectionTop, m_overflowWidth - m_overflowLeft, m_overflowHeight - movedSectionTop));
-
- setNeedsLayout(false);
-}
-
-void RenderTable::setCellWidths()
-{
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isTableSection())
- static_cast<RenderTableSection*>(child)->setCellWidths();
- }
-}
-
-void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
-{
- tx += xPos();
- ty += yPos();
-
- PaintPhase paintPhase = paintInfo.phase;
-
- int os = 2 * maximalOutlineSize(paintPhase);
- if (ty + overflowTop(false) >= paintInfo.rect.bottom() + os || ty + overflowHeight(false) <= paintInfo.rect.y() - os)
- return;
- if (tx + overflowLeft(false) >= paintInfo.rect.right() + os || tx + overflowWidth(false) <= paintInfo.rect.x() - os)
- return;
-
- if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && hasBoxDecorations() && style()->visibility() == VISIBLE)
- paintBoxDecorations(paintInfo, tx, ty);
-
- // We're done. We don't bother painting any children.
- if (paintPhase == PaintPhaseBlockBackground)
- return;
-
- // We don't paint our own background, but we do let the kids paint their backgrounds.
- if (paintPhase == PaintPhaseChildBlockBackgrounds)
- paintPhase = PaintPhaseChildBlockBackground;
- PaintInfo info(paintInfo);
- info.phase = paintPhase;
- info.paintingRoot = paintingRootForChildren(paintInfo);
-
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->hasLayer() && (child->isTableSection() || child == m_caption))
- child->paint(info, tx, ty);
- }
-
- if (collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && style()->visibility() == VISIBLE) {
- // Collect all the unique border styles that we want to paint in a sorted list. Once we
- // have all the styles sorted, we then do individual passes, painting each style of border
- // from lowest precedence to highest precedence.
- info.phase = PaintPhaseCollapsedTableBorders;
- RenderTableCell::CollapsedBorderStyles borderStyles;
- RenderObject* stop = nextInPreOrderAfterChildren();
- for (RenderObject* o = firstChild(); o && o != stop; o = o->nextInPreOrder())
- if (o->isTableCell())
- static_cast<RenderTableCell*>(o)->collectBorderStyles(borderStyles);
- RenderTableCell::sortBorderStyles(borderStyles);
- size_t count = borderStyles.size();
- for (size_t i = 0; i < count; ++i) {
- m_currentBorder = &borderStyles[i];
- for (RenderObject* child = firstChild(); child; child = child->nextSibling())
- if (child->isTableSection())
- child->paint(info, tx, ty);
- }
- m_currentBorder = 0;
- }
-}
-
-void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
-{
- int w = width();
- int h = height();
-
- // Account for the caption.
- if (m_caption) {
- int captionHeight = (m_caption->height() + m_caption->marginBottom() + m_caption->marginTop());
- h -= captionHeight;
- if (m_caption->style()->captionSide() != CAPBOTTOM)
- ty += captionHeight;
- }
-
- int my = max(ty, paintInfo.rect.y());
- int mh;
- if (ty < paintInfo.rect.y())
- mh = max(0, h - (paintInfo.rect.y() - ty));
- else
- mh = min(paintInfo.rect.height(), h);
-
- paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
-
- paintBackground(paintInfo.context, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
-
- if (style()->hasBorder() && !collapseBorders())
- paintBorder(paintInfo.context, tx, ty, w, h, style());
-}
-
-void RenderTable::calcPrefWidths()
-{
- ASSERT(prefWidthsDirty());
-
- recalcSectionsIfNeeded();
- recalcHorizontalBorders();
-
- m_tableLayout->calcPrefWidths(m_minPrefWidth, m_maxPrefWidth);
-
- if (m_caption)
- m_minPrefWidth = max(m_minPrefWidth, m_caption->minPrefWidth());
-
- setPrefWidthsDirty(false);
-}
-
-void RenderTable::splitColumn(int pos, int firstSpan)
-{
- // we need to add a new columnStruct
- int oldSize = m_columns.size();
- m_columns.grow(oldSize + 1);
- int oldSpan = m_columns[pos].span;
- ASSERT(oldSpan > firstSpan);
- m_columns[pos].span = firstSpan;
- memmove(m_columns.data() + pos + 1, m_columns.data() + pos, (oldSize - pos) * sizeof(ColumnStruct));
- m_columns[pos + 1].span = oldSpan - firstSpan;
-
- // change width of all rows.
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isTableSection())
- static_cast<RenderTableSection*>(child)->splitColumn(pos, oldSize + 1);
- }
-
- m_columnPos.grow(numEffCols() + 1);
- setNeedsLayoutAndPrefWidthsRecalc();
-}
-
-void RenderTable::appendColumn(int span)
-{
- // easy case.
- int pos = m_columns.size();
- int newSize = pos + 1;
- m_columns.grow(newSize);
- m_columns[pos].span = span;
-
- // change width of all rows.
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isTableSection())
- static_cast<RenderTableSection*>(child)->appendColumn(pos);
- }
-
- m_columnPos.grow(numEffCols() + 1);
- setNeedsLayoutAndPrefWidthsRecalc();
-}
-
-RenderTableCol* RenderTable::colElement(int col, bool* startEdge, bool* endEdge) const
-{
- if (!m_hasColElements)
- return 0;
- RenderObject* child = firstChild();
- int cCol = 0;
-
- while (child) {
- if (child->isTableCol()) {
- RenderTableCol* colElem = static_cast<RenderTableCol*>(child);
- int span = colElem->span();
- if (!colElem->firstChild()) {
- int startCol = cCol;
- int endCol = cCol + span - 1;
- cCol += span;
- if (cCol > col) {
- if (startEdge)
- *startEdge = startCol == col;
- if (endEdge)
- *endEdge = endCol == col;
- return colElem;
- }
- }
-
- RenderObject* next = child->firstChild();
- if (!next)
- next = child->nextSibling();
- if (!next && child->parent()->isTableCol())
- next = child->parent()->nextSibling();
- child = next;
- } else if (child == m_caption)
- child = child->nextSibling();
- else
- break;
- }
-
- return 0;
-}
-
-void RenderTable::recalcSections() const
-{
- m_caption = 0;
- m_head = 0;
- m_foot = 0;
- m_firstBody = 0;
- m_hasColElements = false;
-
- // We need to get valid pointers to caption, head, foot and first body again
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- switch (child->style()->display()) {
- case TABLE_CAPTION:
- if (!m_caption && child->isRenderBlock()) {
- m_caption = static_cast<RenderBlock*>(child);
- m_caption->setNeedsLayout(true);
- }
- break;
- case TABLE_COLUMN:
- case TABLE_COLUMN_GROUP:
- m_hasColElements = true;
- break;
- case TABLE_HEADER_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = static_cast<RenderTableSection*>(child);
- if (!m_head)
- m_head = section;
- else if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
- }
- break;
- case TABLE_FOOTER_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = static_cast<RenderTableSection*>(child);
- if (!m_foot)
- m_foot = section;
- else if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
- }
- break;
- case TABLE_ROW_GROUP:
- if (child->isTableSection()) {
- RenderTableSection* section = static_cast<RenderTableSection*>(child);
- if (!m_firstBody)
- m_firstBody = section;
- section->recalcCellsIfNeeded();
- }
- break;
- default:
- break;
- }
- }
-
- // repair column count (addChild can grow it too much, because it always adds elements to the last row of a section)
- int maxCols = 0;
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isTableSection()) {
- RenderTableSection* section = static_cast<RenderTableSection*>(child);
- int sectionCols = section->numColumns();
- if (sectionCols > maxCols)
- maxCols = sectionCols;
- }
- }
-
- m_columns.resize(maxCols);
- m_columnPos.resize(maxCols + 1);
-
- ASSERT(selfNeedsLayout());
-
- m_needsSectionRecalc = false;
-}
-
-RenderObject* RenderTable::removeChildNode(RenderObject* child, bool fullRemove)
-{
- setNeedsSectionRecalc();
- return RenderContainer::removeChildNode(child, fullRemove);
-}
-
-int RenderTable::calcBorderLeft() const
-{
- if (collapseBorders()) {
- // Determined by the first cell of the first row. See the CSS 2.1 spec, section 17.6.2.
- if (!numEffCols())
- return 0;
-
- unsigned borderWidth = 0;
-
- const BorderValue& tb = style()->borderLeft();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = tb.width;
-
- int leftmostColumn = style()->direction() == RTL ? numEffCols() - 1 : 0;
- RenderTableCol* colGroup = colElement(leftmostColumn);
- if (colGroup) {
- const BorderValue& gb = style()->borderLeft();
- if (gb.style() == BHIDDEN)
- return 0;
- if (gb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
- }
-
- RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
- if (firstNonEmptySection && !firstNonEmptySection->numRows())
- firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
-
- if (firstNonEmptySection) {
- const BorderValue& sb = firstNonEmptySection->style()->borderLeft();
- if (sb.style() == BHIDDEN)
- return 0;
-
- if (sb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
-
- const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, leftmostColumn);
-
- if (cs.cell) {
- const BorderValue& cb = cs.cell->style()->borderLeft();
- if (cb.style() == BHIDDEN)
- return 0;
-
- const BorderValue& rb = cs.cell->parent()->style()->borderLeft();
- if (rb.style() == BHIDDEN)
- return 0;
-
- if (cb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
- if (rb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
- }
- }
- return borderWidth / 2;
- }
- return RenderBlock::borderLeft();
-}
-
-int RenderTable::calcBorderRight() const
-{
- if (collapseBorders()) {
- // Determined by the last cell of the first row. See the CSS 2.1 spec, section 17.6.2.
- if (!numEffCols())
- return 0;
-
- unsigned borderWidth = 0;
-
- const BorderValue& tb = style()->borderRight();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = tb.width;
-
- int rightmostColumn = style()->direction() == RTL ? 0 : numEffCols() - 1;
- RenderTableCol* colGroup = colElement(rightmostColumn);
- if (colGroup) {
- const BorderValue& gb = style()->borderRight();
- if (gb.style() == BHIDDEN)
- return 0;
- if (gb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(gb.width));
- }
-
- RenderTableSection* firstNonEmptySection = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);
- if (firstNonEmptySection && !firstNonEmptySection->numRows())
- firstNonEmptySection = sectionBelow(firstNonEmptySection, true);
-
- if (firstNonEmptySection) {
- const BorderValue& sb = firstNonEmptySection->style()->borderRight();
- if (sb.style() == BHIDDEN)
- return 0;
-
- if (sb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(sb.width));
-
- const RenderTableSection::CellStruct& cs = firstNonEmptySection->cellAt(0, rightmostColumn);
-
- if (cs.cell) {
- const BorderValue& cb = cs.cell->style()->borderRight();
- if (cb.style() == BHIDDEN)
- return 0;
-
- const BorderValue& rb = cs.cell->parent()->style()->borderRight();
- if (rb.style() == BHIDDEN)
- return 0;
-
- if (cb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(cb.width));
- if (rb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<unsigned>(rb.width));
- }
- }
- return (borderWidth + 1) / 2;
- }
- return RenderBlock::borderRight();
-}
-
-void RenderTable::recalcHorizontalBorders()
-{
- m_borderLeft = calcBorderLeft();
- m_borderRight = calcBorderRight();
-}
-
-int RenderTable::borderTop() const
-{
- if (collapseBorders())
- return outerBorderTop();
- return RenderBlock::borderTop();
-}
-
-int RenderTable::borderBottom() const
-{
- if (collapseBorders())
- return outerBorderBottom();
- return RenderBlock::borderBottom();
-}
-
-int RenderTable::outerBorderTop() const
-{
- if (!collapseBorders())
- return 0;
- int borderWidth = 0;
- RenderTableSection* topSection;
- if (m_head)
- topSection = m_head;
- else if (m_firstBody)
- topSection = m_firstBody;
- else if (m_foot)
- topSection = m_foot;
- else
- topSection = 0;
- if (topSection) {
- borderWidth = topSection->outerBorderTop();
- if (borderWidth == -1)
- return 0; // Overridden by hidden
- }
- const BorderValue& tb = style()->borderTop();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<int>(tb.width / 2));
- return borderWidth;
-}
-
-int RenderTable::outerBorderBottom() const
-{
- if (!collapseBorders())
- return 0;
- int borderWidth = 0;
- RenderTableSection* bottomSection;
- if (m_foot)
- bottomSection = m_foot;
- else {
- RenderObject* child;
- for (child = lastChild(); child && !child->isTableSection(); child = child->previousSibling())
- ;
- bottomSection = child ? static_cast<RenderTableSection*>(child) : 0;
- }
- if (bottomSection) {
- borderWidth = bottomSection->outerBorderBottom();
- if (borderWidth == -1)
- return 0; // Overridden by hidden
- }
- const BorderValue& tb = style()->borderBottom();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = max(borderWidth, static_cast<int>((tb.width + 1) / 2));
- return borderWidth;
-}
-
-int RenderTable::outerBorderLeft() const
-{
- if (!collapseBorders())
- return 0;
-
- int borderWidth = 0;
-
- const BorderValue& tb = style()->borderLeft();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = tb.width / 2;
-
- bool allHidden = true;
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->isTableSection())
- continue;
- int sw = static_cast<RenderTableSection*>(child)->outerBorderLeft();
- if (sw == -1)
- continue;
- else
- allHidden = false;
- borderWidth = max(borderWidth, sw);
- }
- if (allHidden)
- return 0;
-
- return borderWidth;
-}
-
-int RenderTable::outerBorderRight() const
-{
- if (!collapseBorders())
- return 0;
-
- int borderWidth = 0;
-
- const BorderValue& tb = style()->borderRight();
- if (tb.style() == BHIDDEN)
- return 0;
- if (tb.style() > BHIDDEN)
- borderWidth = (tb.width + 1) / 2;
-
- bool allHidden = true;
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (!child->isTableSection())
- continue;
- int sw = static_cast<RenderTableSection*>(child)->outerBorderRight();
- if (sw == -1)
- continue;
- else
- allHidden = false;
- borderWidth = max(borderWidth, sw);
- }
- if (allHidden)
- return 0;
-
- return borderWidth;
-}
-
-RenderTableSection* RenderTable::sectionAbove(const RenderTableSection* section, bool skipEmptySections) const
-{
- recalcSectionsIfNeeded();
-
- if (section == m_head)
- return 0;
-
- RenderObject* prevSection = section == m_foot ? lastChild() : section->previousSibling();
- while (prevSection) {
- if (prevSection->isTableSection() && prevSection != m_head && prevSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(prevSection)->numRows()))
- break;
- prevSection = prevSection->previousSibling();
- }
- if (!prevSection && m_head && (!skipEmptySections || m_head->numRows()))
- prevSection = m_head;
- return static_cast<RenderTableSection*>(prevSection);
-}
-
-RenderTableSection* RenderTable::sectionBelow(const RenderTableSection* section, bool skipEmptySections) const
-{
- recalcSectionsIfNeeded();
-
- if (section == m_foot)
- return 0;
-
- RenderObject* nextSection = section == m_head ? firstChild() : section->nextSibling();
- while (nextSection) {
- if (nextSection->isTableSection() && nextSection != m_head && nextSection != m_foot && (!skipEmptySections || static_cast<RenderTableSection*>(nextSection)->numRows()))
- break;
- nextSection = nextSection->nextSibling();
- }
- if (!nextSection && m_foot && (!skipEmptySections || m_foot->numRows()))
- nextSection = m_foot;
- return static_cast<RenderTableSection*>(nextSection);
-}
-
-RenderTableCell* RenderTable::cellAbove(const RenderTableCell* cell) const
-{
- recalcSectionsIfNeeded();
-
- // Find the section and row to look in
- int r = cell->row();
- RenderTableSection* section = 0;
- int rAbove = 0;
- if (r > 0) {
- // cell is not in the first row, so use the above row in its own section
- section = cell->section();
- rAbove = r - 1;
- } else {
- section = sectionAbove(cell->section(), true);
- if (section)
- rAbove = section->numRows() - 1;
- }
-
- // Look up the cell in the section's grid, which requires effective col index
- if (section) {
- int effCol = colToEffCol(cell->col());
- RenderTableSection::CellStruct aboveCell;
- // If we hit a span back up to a real cell.
- do {
- aboveCell = section->cellAt(rAbove, effCol);
- effCol--;
- } while (!aboveCell.cell && aboveCell.inColSpan && effCol >= 0);
- return aboveCell.cell;
- } else
- return 0;
-}
-
-RenderTableCell* RenderTable::cellBelow(const RenderTableCell* cell) const
-{
- recalcSectionsIfNeeded();
-
- // Find the section and row to look in
- int r = cell->row() + cell->rowSpan() - 1;
- RenderTableSection* section = 0;
- int rBelow = 0;
- if (r < cell->section()->numRows() - 1) {
- // The cell is not in the last row, so use the next row in the section.
- section = cell->section();
- rBelow = r + 1;
- } else {
- section = sectionBelow(cell->section(), true);
- if (section)
- rBelow = 0;
- }
-
- // Look up the cell in the section's grid, which requires effective col index
- if (section) {
- int effCol = colToEffCol(cell->col());
- RenderTableSection::CellStruct belowCell;
- // If we hit a colspan back up to a real cell.
- do {
- belowCell = section->cellAt(rBelow, effCol);
- effCol--;
- } while (!belowCell.cell && belowCell.inColSpan && effCol >= 0);
- return belowCell.cell;
- } else
- return 0;
-}
-
-RenderTableCell* RenderTable::cellBefore(const RenderTableCell* cell) const
-{
- recalcSectionsIfNeeded();
-
- RenderTableSection* section = cell->section();
- int effCol = colToEffCol(cell->col());
- if (!effCol)
- return 0;
-
- // If we hit a colspan back up to a real cell.
- RenderTableSection::CellStruct prevCell;
- do {
- prevCell = section->cellAt(cell->row(), effCol - 1);
- effCol--;
- } while (!prevCell.cell && prevCell.inColSpan && effCol >= 0);
- return prevCell.cell;
-}
-
-RenderTableCell* RenderTable::cellAfter(const RenderTableCell* cell) const
-{
- recalcSectionsIfNeeded();
-
- int effCol = colToEffCol(cell->col() + cell->colSpan());
- if (effCol >= numEffCols())
- return 0;
- return cell->section()->cellAt(cell->row(), effCol).cell;
-}
-
-RenderBlock* RenderTable::firstLineBlock() const
-{
- return 0;
-}
-
-void RenderTable::updateFirstLetter()
-{
-}
-
-IntRect RenderTable::getOverflowClipRect(int tx, int ty)
-{
- IntRect rect = RenderBlock::getOverflowClipRect(tx, ty);
-
- // If we have a caption, expand the clip to include the caption.
- // FIXME: Technically this is wrong, but it's virtually impossible to fix this
- // for real until captions have been re-written.
- // FIXME: This code assumes (like all our other caption code) that only top/bottom are
- // supported. When we actually support left/right and stop mapping them to top/bottom,
- // we might have to hack this code first (depending on what order we do these bug fixes in).
- if (m_caption) {
- rect.setHeight(height());
- rect.setY(ty);
- }
-
- return rect;
-}
-
-#ifndef NDEBUG
-void RenderTable::dump(TextStream* stream, DeprecatedString ind) const
-{
- if (m_caption)
- *stream << " tCaption";
- if (m_head)
- *stream << " head";
- if (m_foot)
- *stream << " foot";
-
- *stream << endl << ind << "cspans:";
- for (unsigned i = 0; i < m_columns.size(); i++)
- *stream << " " << m_columns[i].span;
- *stream << endl << ind;
-
- RenderBlock::dump(stream, ind);
-}
-#endif
-
-}