📄 rendertablesection.cpp
字号:
/* * 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, 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 "RenderTableSection.h"#include "CachedImage.h"#include "Document.h"#include "HTMLNames.h"#include "RenderTableCell.h"#include "RenderTableCol.h"#include "RenderTableRow.h"#include "RenderView.h"#include <limits>#include <wtf/Vector.h>using namespace std;namespace WebCore {using namespace HTMLNames;RenderTableSection::RenderTableSection(Node* node) : RenderBox(node) , m_gridRows(0) , m_cCol(0) , m_cRow(-1) , m_needsCellRecalc(false) , m_outerBorderLeft(0) , m_outerBorderRight(0) , m_outerBorderTop(0) , m_outerBorderBottom(0) , m_overflowLeft(0) , m_overflowWidth(0) , m_overflowTop(0) , m_overflowHeight(0) , m_hasOverflowingCell(false){ // init RenderObject attributes setInline(false); // our object is not Inline}RenderTableSection::~RenderTableSection(){ clearGrid();}void RenderTableSection::destroy(){ RenderTable* recalcTable = table(); RenderBox::destroy(); // recalc cell info because RenderTable has unguarded pointers // stored that point to this RenderTableSection. if (recalcTable) recalcTable->setNeedsSectionRecalc();}void RenderTableSection::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 isTableSection = node() && (node()->hasTagName(theadTag) || node()->hasTagName(tbodyTag) || node()->hasTagName(tfootTag)); if (!child->isTableRow()) { if (isTableSection && child->node() && child->node()->hasTagName(formTag) && document()->isHTMLDocument()) { RenderBox::addChild(child, beforeChild); return; } RenderObject* last = beforeChild; if (!last) last = lastChild(); if (last && last->isAnonymous()) { last->addChild(child); return; } // If beforeChild is inside an anonymous cell/row, insert into the cell or into // the anonymous row containing it, if there is one. RenderObject* lastBox = last; while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow()) lastBox = lastBox->parent(); if (lastBox && lastBox->isAnonymous()) { lastBox->addChild(child, beforeChild); return; } RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(TABLE_ROW); row->setStyle(newStyle.release()); addChild(row, beforeChild); row->addChild(child); return; } if (beforeChild) setNeedsCellRecalc(); ++m_cRow; m_cCol = 0; // make sure we have enough rows if (!ensureRows(m_cRow + 1)) return; m_grid[m_cRow].rowRenderer = static_cast<RenderTableRow*>(child); if (!beforeChild) { m_grid[m_cRow].height = child->style()->height(); if (m_grid[m_cRow].height.isRelative()) m_grid[m_cRow].height = Length(); } // If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that. while (beforeChild && beforeChild->parent() != this) beforeChild = beforeChild->parent(); ASSERT(!beforeChild || beforeChild->isTableRow() || isTableSection && beforeChild->node() && beforeChild->node()->hasTagName(formTag) && document()->isHTMLDocument()); RenderBox::addChild(child, beforeChild);}void RenderTableSection::removeChild(RenderObject* oldChild){ setNeedsCellRecalc(); RenderBox::removeChild(oldChild);}bool RenderTableSection::ensureRows(int numRows){ int nRows = m_gridRows; if (numRows > nRows) { if (numRows > static_cast<int>(m_grid.size())) { size_t maxSize = numeric_limits<size_t>::max() / sizeof(RowStruct); if (static_cast<size_t>(numRows) > maxSize) return false; m_grid.grow(numRows); } m_gridRows = numRows; int nCols = max(1, table()->numEffCols()); CellStruct emptyCellStruct; emptyCellStruct.cell = 0; emptyCellStruct.inColSpan = false; for (int r = nRows; r < numRows; r++) { m_grid[r].row = new Row(nCols); m_grid[r].row->fill(emptyCellStruct); m_grid[r].rowRenderer = 0; m_grid[r].baseline = 0; m_grid[r].height = Length(); } } return true;}void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row){ int rSpan = cell->rowSpan(); int cSpan = cell->colSpan(); Vector<RenderTable::ColumnStruct>& columns = table()->columns(); int nCols = columns.size(); // ### mozilla still seems to do the old HTML way, even for strict DTD // (see the annotation on table cell layouting in the CSS specs and the testcase below: // <TABLE border> // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4 // <TR><TD colspan="2">5 // </TABLE> while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).cell || cellAt(m_cRow, m_cCol).inColSpan)) m_cCol++; if (rSpan == 1) { // we ignore height settings on rowspan cells Length height = cell->style()->height(); if (height.isPositive() || (height.isRelative() && height.value() >= 0)) { Length cRowHeight = m_grid[m_cRow].height; switch (height.type()) { case Percent: if (!(cRowHeight.isPercent()) || (cRowHeight.isPercent() && cRowHeight.rawValue() < height.rawValue())) m_grid[m_cRow].height = height; break; case Fixed: if (cRowHeight.type() < Percent || (cRowHeight.isFixed() && cRowHeight.value() < height.value())) m_grid[m_cRow].height = height; break; case Relative: default: break; } } } // make sure we have enough rows if (!ensureRows(m_cRow + rSpan)) return; m_grid[m_cRow].rowRenderer = row; int col = m_cCol; // tell the cell where it is CellStruct currentCell; currentCell.cell = cell; currentCell.inColSpan = false; while (cSpan) { int currentSpan; if (m_cCol >= nCols) { table()->appendColumn(cSpan); currentSpan = cSpan; } else { if (cSpan < columns[m_cCol].span) table()->splitColumn(m_cCol, cSpan); currentSpan = columns[m_cCol].span; } for (int r = 0; r < rSpan; r++) { CellStruct& c = cellAt(m_cRow + r, m_cCol); if (currentCell.cell && !c.cell) c.cell = currentCell.cell; if (currentCell.inColSpan) c.inColSpan = true; } m_cCol++; cSpan -= currentSpan; currentCell.cell = 0; currentCell.inColSpan = true; } if (cell) { cell->setRow(m_cRow); cell->setCol(table()->effColToCol(col)); }}void RenderTableSection::setCellWidths(){ Vector<int>& columnPos = table()->columnPositions(); LayoutStateMaintainer statePusher(view()); for (int i = 0; i < m_gridRows; i++) { Row& row = *m_grid[i].row; int cols = row.size(); for (int j = 0; j < cols; j++) { CellStruct current = row[j]; RenderTableCell* cell = current.cell; if (!cell) continue; int endCol = j; int cspan = cell->colSpan(); while (cspan && endCol < cols) { cspan -= table()->columns()[endCol].span; endCol++; } int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing(); int oldWidth = cell->width(); if (w != oldWidth) { cell->setNeedsLayout(true); if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) { if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. statePusher.push(this, IntSize(x(), y())); } cell->repaint(); } cell->updateWidth(w); } } } statePusher.pop(); // only pops if we pushed}int RenderTableSection::calcRowHeight(){#ifndef NDEBUG setNeedsLayoutIsForbidden(true);#endif ASSERT(!needsLayout()); RenderTableCell* cell; int spacing = table()->vBorderSpacing(); LayoutStateMaintainer statePusher(view()); m_rowPos.resize(m_gridRows + 1); m_rowPos[0] = spacing; for (int r = 0; r < m_gridRows; r++) { m_rowPos[r + 1] = 0; m_grid[r].baseline = 0; int baseline = 0; int bdesc = 0; int ch = m_grid[r].height.calcMinValue(0); int pos = m_rowPos[r] + ch + (m_grid[r].rowRenderer ? spacing : 0); m_rowPos[r + 1] = max(m_rowPos[r + 1], pos); Row* row = m_grid[r].row; int totalCols = row->size(); for (int c = 0; c < totalCols; c++) { CellStruct current = cellAt(r, c); cell = current.cell; if (!cell || current.inColSpan) continue; if (r < m_gridRows - 1 && cellAt(r + 1, c).cell == cell) continue; int indx = max(r - cell->rowSpan() + 1, 0); if (cell->overrideSize() != -1) { if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. statePusher.push(this, IntSize(x(), y())); } cell->setOverrideSize(-1); cell->setChildNeedsLayout(true, false); cell->layoutIfNeeded(); } int adjustedPaddingTop = cell->paddingTop() - cell->intrinsicPaddingTop(); int adjustedPaddingBottom = cell->paddingBottom() - cell->intrinsicPaddingBottom(); int adjustedHeight = cell->height() - (cell->intrinsicPaddingTop() + cell->intrinsicPaddingBottom()); // Explicit heights use the border box in quirks mode. In strict mode do the right // thing and actually add in the border and padding. ch = cell->style()->height().calcValue(0) + (cell->style()->htmlHacks() ? 0 : (adjustedPaddingTop + adjustedPaddingBottom + cell->borderTop() + cell->borderBottom())); ch = max(ch, adjustedHeight); pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0); m_rowPos[r + 1] = max(m_rowPos[r + 1], pos); // find out the baseline EVerticalAlign va = cell->style()->verticalAlign(); if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { int b = cell->baselinePosition(); if (b > cell->borderTop() + cell->paddingTop()) { baseline = max(baseline, b - cell->intrinsicPaddingTop()); bdesc = max(bdesc, m_rowPos[indx] + ch - (b - cell->intrinsicPaddingTop())); } } } //do we have baseline aligned elements? if (baseline) { // increase rowheight if baseline requires m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0)); m_grid[r].baseline = baseline; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -