📄 autotablelayout.cpp
字号:
/* * Copyright (C) 2002 Lars Knoll (knoll@kde.org) * (C) 2002 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. * * 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. * * 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 "AutoTableLayout.h"#include "RenderTable.h"#include "RenderTableCell.h"#include "RenderTableCol.h"#include "RenderTableSection.h"using namespace std;namespace WebCore {AutoTableLayout::AutoTableLayout(RenderTable* table) : TableLayout(table) , m_hasPercent(false) , m_percentagesDirty(true) , m_effWidthDirty(true) , m_totalPercent(0){}AutoTableLayout::~AutoTableLayout(){}/* recalculates the full structure needed to do layouting and minmax calculations. This is usually calculated on the fly, but needs to be done fully when table cells change dynamically*/void AutoTableLayout::recalcColumn(int effCol){ Layout &l = m_layoutStruct[effCol]; RenderObject* child = m_table->firstChild(); // first we iterate over all rows. RenderTableCell* fixedContributor = 0; RenderTableCell* maxContributor = 0; while (child) { if (child->isTableSection()) { RenderTableSection* section = static_cast<RenderTableSection*>(child); int numRows = section->numRows(); RenderTableCell* last = 0; for (int i = 0; i < numRows; i++) { RenderTableSection::CellStruct current = section->cellAt(i, effCol); RenderTableCell* cell = current.cell; bool cellHasContent = cell && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding()); if (cellHasContent) l.emptyCellsOnly = false; if (current.inColSpan) continue; if (cell && cell->colSpan() == 1) { // A cell originates in this column. Ensure we have // a min/max width of at least 1px for this column now. l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0); l.maxWidth = max(l.maxWidth, 1); if (cell->prefWidthsDirty()) cell->calcPrefWidths(); l.minWidth = max(cell->minPrefWidth(), l.minWidth); if (cell->maxPrefWidth() > l.maxWidth) { l.maxWidth = cell->maxPrefWidth(); maxContributor = cell; } Length w = cell->styleOrColWidth(); // FIXME: What is this arbitrary value? if (w.rawValue() > 32760) w.setRawValue(32760); if (w.isNegative()) w.setValue(0); switch(w.type()) { case Fixed: // ignore width=0 if (w.value() > 0 && (int)l.width.type() != Percent) { int wval = cell->calcBorderBoxWidth(w.value()); if (l.width.isFixed()) { // Nav/IE weirdness if ((wval > l.width.value()) || ((l.width.value() == wval) && (maxContributor == cell))) { l.width.setValue(wval); fixedContributor = cell; } } else { l.width.setValue(Fixed, wval); fixedContributor = cell; } } break; case Percent: m_hasPercent = true; if (w.isPositive() && (!l.width.isPercent() || w.rawValue() > l.width.rawValue())) l.width = w; break; case Relative: // FIXME: Need to understand this case and whether it makes sense to compare values // which are not necessarily of the same type. if (w.isAuto() || (w.isRelative() && w.value() > l.width.rawValue())) l.width = w; default: break; } } else { if (cell && (!effCol || section->cellAt(i, effCol-1).cell != cell)) { // This spanning cell originates in this column. Ensure we have // a min/max width of at least 1px for this column now. l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0); l.maxWidth = max(l.maxWidth, 1); insertSpanCell(cell); } last = cell; } } } child = child->nextSibling(); } // Nav/IE weirdness if (l.width.isFixed()) { if (m_table->style()->htmlHacks() && l.maxWidth > l.width.value() && fixedContributor != maxContributor) { l.width = Length(); fixedContributor = 0; } } l.maxWidth = max(l.maxWidth, l.minWidth); // ### we need to add col elements as well}void AutoTableLayout::fullRecalc(){ m_percentagesDirty = true; m_hasPercent = false; m_effWidthDirty = true; int nEffCols = m_table->numEffCols(); m_layoutStruct.resize(nEffCols); m_layoutStruct.fill(Layout()); m_spanCells.fill(0); RenderObject *child = m_table->firstChild(); Length grpWidth; int cCol = 0; while (child) { if (child->isTableCol()) { RenderTableCol *col = static_cast<RenderTableCol*>(child); int span = col->span(); if (col->firstChild()) { grpWidth = col->style()->width(); } else { Length w = col->style()->width(); if (w.isAuto()) w = grpWidth; if ((w.isFixed() || w.isPercent()) && w.isZero()) w = Length(); int cEffCol = m_table->colToEffCol(cCol); if (!w.isAuto() && span == 1 && cEffCol < nEffCols) { if (m_table->spanOfEffCol(cEffCol) == 1) { m_layoutStruct[cEffCol].width = w; if (w.isFixed() && m_layoutStruct[cEffCol].maxWidth < w.value()) m_layoutStruct[cEffCol].maxWidth = w.value(); } } cCol += span; } } else { break; } RenderObject *next = child->firstChild(); if (!next) next = child->nextSibling(); if (!next && child->parent()->isTableCol()) { next = child->parent()->nextSibling(); grpWidth = Length(); } child = next; } for (int i = 0; i < nEffCols; i++) recalcColumn(i);}static bool shouldScaleColumns(RenderTable* table){ // A special case. If this table is not fixed width and contained inside // a cell, then don't bloat the maxwidth by examining percentage growth. bool scale = true; while (table) { Length tw = table->style()->width(); if ((tw.isAuto() || tw.isPercent()) && !table->isPositioned()) { RenderBlock* cb = table->containingBlock(); while (cb && !cb->isRenderView() && !cb->isTableCell() && cb->style()->width().isAuto() && !cb->isPositioned()) cb = cb->containingBlock(); table = 0; if (cb && cb->isTableCell() && (cb->style()->width().isAuto() || cb->style()->width().isPercent())) { if (tw.isPercent()) scale = false; else { RenderTableCell* cell = static_cast<RenderTableCell*>(cb); if (cell->colSpan() > 1 || cell->table()->style()->width().isAuto()) scale = false; else table = cell->table(); } } } else table = 0; } return scale;}void AutoTableLayout::calcPrefWidths(int& minWidth, int& maxWidth){ fullRecalc(); int spanMaxWidth = calcEffectiveWidth(); minWidth = 0; maxWidth = 0; float maxPercent = 0; float maxNonPercent = 0; bool scaleColumns = shouldScaleColumns(m_table); // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero. // FIXME: Handle the 0% cases properly. const int epsilon = 1; int remainingPercent = 100 * percentScaleFactor; for (unsigned int i = 0; i < m_layoutStruct.size(); i++) { minWidth += m_layoutStruct[i].effMinWidth; maxWidth += m_layoutStruct[i].effMaxWidth; if (scaleColumns) { if (m_layoutStruct[i].effWidth.isPercent()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -