diff options
Diffstat (limited to 'WebCore/rendering/AutoTableLayout.cpp')
-rw-r--r-- | WebCore/rendering/AutoTableLayout.cpp | 619 |
1 files changed, 291 insertions, 328 deletions
diff --git a/WebCore/rendering/AutoTableLayout.cpp b/WebCore/rendering/AutoTableLayout.cpp index bf1bcd9..bb0df0b 100644 --- a/WebCore/rendering/AutoTableLayout.cpp +++ b/WebCore/rendering/AutoTableLayout.cpp @@ -1,7 +1,7 @@ /* * 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. + * Copyright (C) 2003, 2006, 2008, 2010 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 @@ -34,9 +34,7 @@ namespace WebCore { AutoTableLayout::AutoTableLayout(RenderTable* table) : TableLayout(table) , m_hasPercent(false) - , m_percentagesDirty(true) - , m_effWidthDirty(true) - , m_totalPercent(0) + , m_effectiveLogicalWidthDirty(true) { } @@ -44,21 +42,14 @@ 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. + Layout& columnLayout = m_layoutStruct[effCol]; RenderTableCell* fixedContributor = 0; RenderTableCell* maxContributor = 0; - while (child) { + for (RenderObject* child = m_table->firstChild(); child; child = child->nextSibling()) { if (child->isTableCol()) toRenderTableCol(child)->computePreferredLogicalWidths(); else if (child->isTableSection()) { @@ -70,142 +61,131 @@ void AutoTableLayout::recalcColumn(int effCol) bool cellHasContent = cell && !current.inColSpan && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding()); if (cellHasContent) - l.emptyCellsOnly = false; + columnLayout.emptyCellsOnly = false; - if (current.inColSpan) + if (current.inColSpan || !cell) continue; - if (cell && cell->colSpan() == 1) { + + if (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); + columnLayout.minLogicalWidth = max(columnLayout.minLogicalWidth, cellHasContent ? 1 : 0); + columnLayout.maxLogicalWidth = max(columnLayout.maxLogicalWidth, 1); if (cell->preferredLogicalWidthsDirty()) cell->computePreferredLogicalWidths(); - l.minWidth = max(cell->minPreferredLogicalWidth(), l.minWidth); - if (cell->maxPreferredLogicalWidth() > l.maxWidth) { - l.maxWidth = cell->maxPreferredLogicalWidth(); + columnLayout.minLogicalWidth = max(cell->minPreferredLogicalWidth(), columnLayout.minLogicalWidth); + if (cell->maxPreferredLogicalWidth() > columnLayout.maxLogicalWidth) { + columnLayout.maxLogicalWidth = cell->maxPreferredLogicalWidth(); maxContributor = cell; } - Length w = cell->styleOrColWidth(); + Length cellLogicalWidth = cell->styleOrColLogicalWidth(); // FIXME: What is this arbitrary value? - if (w.rawValue() > 32760) - w.setRawValue(32760); - if (w.isNegative()) - w.setValue(0); - switch (w.type()) { + if (cellLogicalWidth.rawValue() > 32760) + cellLogicalWidth.setRawValue(32760); + if (cellLogicalWidth.isNegative()) + cellLogicalWidth.setValue(0); + switch (cellLogicalWidth.type()) { case Fixed: // ignore width=0 - if (w.value() > 0 && (int)l.width.type() != Percent) { - int wval = cell->computeBorderBoxLogicalWidth(w.value()); - if (l.width.isFixed()) { + if (cellLogicalWidth.value() > 0 && columnLayout.logicalWidth.type() != Percent) { + int logicalWidth = cell->computeBorderBoxLogicalWidth(cellLogicalWidth.value()); + if (columnLayout.logicalWidth.isFixed()) { // Nav/IE weirdness - if ((wval > l.width.value()) || - ((l.width.value() == wval) && (maxContributor == cell))) { - l.width.setValue(wval); + if ((logicalWidth > columnLayout.logicalWidth.value()) || + ((columnLayout.logicalWidth.value() == logicalWidth) && (maxContributor == cell))) { + columnLayout.logicalWidth.setValue(logicalWidth); fixedContributor = cell; } } else { - l.width.setValue(Fixed, wval); + columnLayout.logicalWidth.setValue(Fixed, logicalWidth); fixedContributor = cell; } } break; case Percent: m_hasPercent = true; - if (w.isPositive() && (!l.width.isPercent() || w.rawValue() > l.width.rawValue())) - l.width = w; + if (cellLogicalWidth.isPositive() && (!columnLayout.logicalWidth.isPercent() || cellLogicalWidth.rawValue() > columnLayout.logicalWidth.rawValue())) + columnLayout.logicalWidth = cellLogicalWidth; 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; + if (cellLogicalWidth.isAuto() || (cellLogicalWidth.isRelative() && cellLogicalWidth.value() > columnLayout.logicalWidth.rawValue())) + columnLayout.logicalWidth = cellLogicalWidth; default: break; } - } else { - if (cell && (!effCol || section->primaryCellAt(i, effCol-1) != 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); - } + } else if (!effCol || section->primaryCellAt(i, effCol - 1) != cell) { + // This spanning cell originates in this column. Ensure we have + // a min/max width of at least 1px for this column now. + columnLayout.minLogicalWidth = max(columnLayout.minLogicalWidth, cellHasContent ? 1 : 0); + columnLayout.maxLogicalWidth = max(columnLayout.maxLogicalWidth, 1); + insertSpanCell(cell); } } } - child = child->nextSibling(); } // Nav/IE weirdness - if (l.width.isFixed()) { - if (m_table->document()->inQuirksMode() && l.maxWidth > l.width.value() && fixedContributor != maxContributor) { - l.width = Length(); + if (columnLayout.logicalWidth.isFixed()) { + if (m_table->document()->inQuirksMode() && columnLayout.maxLogicalWidth > columnLayout.logicalWidth.value() && fixedContributor != maxContributor) { + columnLayout.logicalWidth = Length(); fixedContributor = 0; } } - l.maxWidth = max(l.maxWidth, l.minWidth); - - // ### we need to add col elements as well + columnLayout.maxLogicalWidth = max(columnLayout.maxLogicalWidth, columnLayout.minLogicalWidth); } void AutoTableLayout::fullRecalc() { - m_percentagesDirty = true; m_hasPercent = false; - m_effWidthDirty = true; + m_effectiveLogicalWidthDirty = 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 = toRenderTableCol(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; + RenderObject* child = m_table->firstChild(); + Length groupLogicalWidth; + int currentColumn = 0; + while (child && child->isTableCol()) { + RenderTableCol* col = toRenderTableCol(child); + int span = col->span(); + if (col->firstChild()) + groupLogicalWidth = col->style()->logicalWidth(); + else { + Length colLogicalWidth = col->style()->logicalWidth(); + if (colLogicalWidth.isAuto()) + colLogicalWidth = groupLogicalWidth; + if ((colLogicalWidth.isFixed() || colLogicalWidth.isPercent()) && colLogicalWidth.isZero()) + colLogicalWidth = Length(); + int effCol = m_table->colToEffCol(currentColumn); + if (!colLogicalWidth.isAuto() && span == 1 && effCol < nEffCols && m_table->spanOfEffCol(effCol) == 1) { + m_layoutStruct[effCol].logicalWidth = colLogicalWidth; + if (colLogicalWidth.isFixed() && m_layoutStruct[effCol].maxLogicalWidth < colLogicalWidth.value()) + m_layoutStruct[effCol].maxLogicalWidth = colLogicalWidth.value(); } - } else { - break; + currentColumn += span; } - RenderObject *next = child->firstChild(); + RenderObject* next = child->firstChild(); if (!next) next = child->nextSibling(); if (!next && child->parent()->isTableCol()) { next = child->parent()->nextSibling(); - grpWidth = Length(); + groupLogicalWidth = Length(); } child = next; } - for (int i = 0; i < nEffCols; i++) recalcColumn(i); } +// FIXME: This needs to be adapted for vertical writing modes. static bool shouldScaleColumns(RenderTable* table) { // A special case. If this table is not fixed width and contained inside @@ -243,7 +223,7 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth { fullRecalc(); - int spanMaxWidth = calcEffectiveWidth(); + int spanMaxLogicalWidth = calcEffectiveLogicalWidth(); minWidth = 0; maxWidth = 0; float maxPercent = 0; @@ -255,17 +235,17 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth 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; + for (size_t i = 0; i < m_layoutStruct.size(); ++i) { + minWidth += m_layoutStruct[i].effectiveMinLogicalWidth; + maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth; if (scaleColumns) { - if (m_layoutStruct[i].effWidth.isPercent()) { - int percent = min(m_layoutStruct[i].effWidth.rawValue(), remainingPercent); - float pw = static_cast<float>(m_layoutStruct[i].effMaxWidth) * 100 * percentScaleFactor / max(percent, epsilon); - maxPercent = max(pw, maxPercent); + if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) { + int percent = min(m_layoutStruct[i].effectiveLogicalWidth.rawValue(), remainingPercent); + float logicalWidth = static_cast<float>(m_layoutStruct[i].effectiveMaxLogicalWidth) * 100 * percentScaleFactor / max(percent, epsilon); + maxPercent = max(logicalWidth, maxPercent); remainingPercent -= percent; } else - maxNonPercent += m_layoutStruct[i].effMaxWidth; + maxNonPercent += m_layoutStruct[i].effectiveMaxLogicalWidth; } } @@ -275,15 +255,15 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth maxWidth = max(maxWidth, static_cast<int>(min(maxPercent, INT_MAX / 2.0f))); } - maxWidth = max(maxWidth, spanMaxWidth); - - int bs = m_table->bordersPaddingAndSpacing(); - minWidth += bs; - maxWidth += bs; + maxWidth = max(maxWidth, spanMaxLogicalWidth); - Length tw = m_table->style()->width(); - if (tw.isFixed() && tw.value() > 0) { - minWidth = max(minWidth, tw.value()); + int bordersPaddingAndSpacing = m_table->bordersPaddingAndSpacingInRowDirection(); + minWidth += bordersPaddingAndSpacing; + maxWidth += bordersPaddingAndSpacing; + + Length tableLogicalWidth = m_table->style()->logicalWidth(); + if (tableLogicalWidth.isFixed() && tableLogicalWidth.value() > 0) { + minWidth = max(minWidth, tableLogicalWidth.value()); maxWidth = minWidth; } } @@ -292,50 +272,52 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth This method takes care of colspans. effWidth is the same as width for cells without colspans. If we have colspans, they get modified. */ -int AutoTableLayout::calcEffectiveWidth() +int AutoTableLayout::calcEffectiveLogicalWidth() { - float tMaxWidth = 0; + float maxLogicalWidth = 0; - unsigned int nEffCols = m_layoutStruct.size(); - int hspacing = m_table->hBorderSpacing(); + size_t nEffCols = m_layoutStruct.size(); + int spacingInRowDirection = m_table->hBorderSpacing(); - for (unsigned int i = 0; i < nEffCols; i++) { - m_layoutStruct[i].effWidth = m_layoutStruct[i].width; - m_layoutStruct[i].effMinWidth = m_layoutStruct[i].minWidth; - m_layoutStruct[i].effMaxWidth = m_layoutStruct[i].maxWidth; + for (size_t i = 0; i < nEffCols; ++i) { + m_layoutStruct[i].effectiveLogicalWidth = m_layoutStruct[i].logicalWidth; + m_layoutStruct[i].effectiveMinLogicalWidth = m_layoutStruct[i].minLogicalWidth; + m_layoutStruct[i].effectiveMaxLogicalWidth = m_layoutStruct[i].maxLogicalWidth; } - for (unsigned int i = 0; i < m_spanCells.size(); i++) { - RenderTableCell *cell = m_spanCells[i]; + for (size_t i = 0; i < m_spanCells.size(); ++i) { + RenderTableCell* cell = m_spanCells[i]; if (!cell) break; + int span = cell->colSpan(); - Length w = cell->styleOrColWidth(); - if (!w.isRelative() && w.isZero()) - w = Length(); // make it Auto + Length cellLogicalWidth = cell->styleOrColLogicalWidth(); + if (!cellLogicalWidth.isRelative() && cellLogicalWidth.isZero()) + cellLogicalWidth = Length(); // make it Auto - int col = m_table->colToEffCol(cell->col()); - unsigned int lastCol = col; - int cMinWidth = cell->minPreferredLogicalWidth() + hspacing; - float cMaxWidth = cell->maxPreferredLogicalWidth() + hspacing; + int effCol = m_table->colToEffCol(cell->col()); + size_t lastCol = effCol; + int cellMinLogicalWidth = cell->minPreferredLogicalWidth() + spacingInRowDirection; + float cellMaxLogicalWidth = cell->maxPreferredLogicalWidth() + spacingInRowDirection; int totalPercent = 0; - int minWidth = 0; - float maxWidth = 0; + int spanMinLogicalWidth = 0; + float spanMaxLogicalWidth = 0; bool allColsArePercent = true; bool allColsAreFixed = true; bool haveAuto = false; bool spanHasEmptyCellsOnly = true; int fixedWidth = 0; while (lastCol < nEffCols && span > 0) { - switch (m_layoutStruct[lastCol].width.type()) { + Layout& columnLayout = m_layoutStruct[lastCol]; + switch (columnLayout.logicalWidth.type()) { case Percent: - totalPercent += m_layoutStruct[lastCol].width.rawValue(); + totalPercent += columnLayout.logicalWidth.rawValue(); allColsAreFixed = false; break; case Fixed: - if (m_layoutStruct[lastCol].width.value() > 0) { - fixedWidth += m_layoutStruct[lastCol].width.value(); + if (columnLayout.logicalWidth.value() > 0) { + fixedWidth += columnLayout.logicalWidth.value(); allColsArePercent = false; // IE resets effWidth to Auto here, but this breaks the konqueror about page and seems to be some bad // legacy behaviour anyway. mozilla doesn't do this so I decided we don't neither. @@ -353,116 +335,112 @@ int AutoTableLayout::calcEffectiveWidth() // <tr><td>1</td><td colspan=2>2-3</tr> // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr> // </table> - if (!m_layoutStruct[lastCol].effWidth.isPercent()) { - m_layoutStruct[lastCol].effWidth = Length(); + if (!columnLayout.effectiveLogicalWidth.isPercent()) { + columnLayout.effectiveLogicalWidth = Length(); allColsArePercent = false; - } - else - totalPercent += m_layoutStruct[lastCol].effWidth.rawValue(); + } else + totalPercent += columnLayout.effectiveLogicalWidth.rawValue(); allColsAreFixed = false; } - if (!m_layoutStruct[lastCol].emptyCellsOnly) + if (!columnLayout.emptyCellsOnly) spanHasEmptyCellsOnly = false; span -= m_table->spanOfEffCol(lastCol); - minWidth += m_layoutStruct[lastCol].effMinWidth; - maxWidth += m_layoutStruct[lastCol].effMaxWidth; + spanMinLogicalWidth += columnLayout.effectiveMinLogicalWidth; + spanMaxLogicalWidth += columnLayout.effectiveMaxLogicalWidth; lastCol++; - cMinWidth -= hspacing; - cMaxWidth -= hspacing; + cellMinLogicalWidth -= spacingInRowDirection; + cellMaxLogicalWidth -= spacingInRowDirection; } // adjust table max width if needed - if (w.isPercent()) { - if (totalPercent > w.rawValue() || allColsArePercent) { + if (cellLogicalWidth.isPercent()) { + if (totalPercent > cellLogicalWidth.rawValue() || allColsArePercent) { // can't satify this condition, treat as variable - w = Length(); + cellLogicalWidth = Length(); } else { - float spanMax = max(maxWidth, cMaxWidth); - tMaxWidth = max(tMaxWidth, spanMax * 100 * percentScaleFactor / w.rawValue()); + maxLogicalWidth = max(maxLogicalWidth, max(spanMaxLogicalWidth, cellMaxLogicalWidth) * 100 * percentScaleFactor / cellLogicalWidth.rawValue()); // all non percent columns in the span get percent values to sum up correctly. - int percentMissing = w.rawValue() - totalPercent; + int percentMissing = cellLogicalWidth.rawValue() - totalPercent; float totalWidth = 0; - for (unsigned int pos = col; pos < lastCol; pos++) { - if (!(m_layoutStruct[pos].effWidth.isPercent())) - totalWidth += m_layoutStruct[pos].effMaxWidth; + for (unsigned pos = effCol; pos < lastCol; ++pos) { + if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) + totalWidth += m_layoutStruct[pos].effectiveMaxLogicalWidth; } - for (unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++) { - if (!(m_layoutStruct[pos].effWidth.isPercent())) { - int percent = static_cast<int>(percentMissing * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / totalWidth); - totalWidth -= m_layoutStruct[pos].effMaxWidth; + for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++pos) { + if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) { + int percent = static_cast<int>(percentMissing * static_cast<float>(m_layoutStruct[pos].effectiveMaxLogicalWidth) / totalWidth); + totalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWidth; percentMissing -= percent; if (percent > 0) - m_layoutStruct[pos].effWidth.setRawValue(Percent, percent); + m_layoutStruct[pos].effectiveLogicalWidth.setRawValue(Percent, percent); else - m_layoutStruct[pos].effWidth = Length(); + m_layoutStruct[pos].effectiveLogicalWidth = Length(); } } - } } // make sure minWidth and maxWidth of the spanning cell are honoured - if (cMinWidth > minWidth) { + if (cellMinLogicalWidth > spanMinLogicalWidth) { if (allColsAreFixed) { - for (unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++) { - int w = max(m_layoutStruct[pos].effMinWidth, cMinWidth * m_layoutStruct[pos].width.value() / fixedWidth); - fixedWidth -= m_layoutStruct[pos].width.value(); - cMinWidth -= w; - m_layoutStruct[pos].effMinWidth = w; + for (unsigned pos = effCol; fixedWidth > 0 && pos < lastCol; ++pos) { + int cellLogicalWidth = max(m_layoutStruct[pos].effectiveMinLogicalWidth, cellMinLogicalWidth * m_layoutStruct[pos].logicalWidth.value() / fixedWidth); + fixedWidth -= m_layoutStruct[pos].logicalWidth.value(); + cellMinLogicalWidth -= cellLogicalWidth; + m_layoutStruct[pos].effectiveMinLogicalWidth = cellLogicalWidth; } - } else { - float maxw = maxWidth; - int minw = minWidth; + float remainingMaxLogicalWidth = spanMaxLogicalWidth; + int remainingMinLogicalWidth = spanMinLogicalWidth; // Give min to variable first, to fixed second, and to others third. - for (unsigned int pos = col; maxw >= 0 && pos < lastCol; pos++) { - if (m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth) { - int w = max(m_layoutStruct[pos].effMinWidth, m_layoutStruct[pos].width.value()); - fixedWidth -= m_layoutStruct[pos].width.value(); - minw -= m_layoutStruct[pos].effMinWidth; - maxw -= m_layoutStruct[pos].effMaxWidth; - cMinWidth -= w; - m_layoutStruct[pos].effMinWidth = w; + for (unsigned pos = effCol; remainingMaxLogicalWidth >= 0 && pos < lastCol; ++pos) { + if (m_layoutStruct[pos].logicalWidth.isFixed() && haveAuto && fixedWidth <= cellMinLogicalWidth) { + int colMinLogicalWidth = max(m_layoutStruct[pos].effectiveMinLogicalWidth, m_layoutStruct[pos].logicalWidth.value()); + fixedWidth -= m_layoutStruct[pos].logicalWidth.value(); + remainingMinLogicalWidth -= m_layoutStruct[pos].effectiveMinLogicalWidth; + remainingMaxLogicalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWidth; + cellMinLogicalWidth -= colMinLogicalWidth; + m_layoutStruct[pos].effectiveMinLogicalWidth = colMinLogicalWidth; } } - for (unsigned int pos = col; maxw >= 0 && pos < lastCol && minw < cMinWidth; pos++) { - if (!(m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth)) { - int w = max(m_layoutStruct[pos].effMinWidth, static_cast<int>(maxw ? cMinWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxw : cMinWidth)); - w = min(m_layoutStruct[pos].effMinWidth+(cMinWidth-minw), w); - - maxw -= m_layoutStruct[pos].effMaxWidth; - minw -= m_layoutStruct[pos].effMinWidth; - cMinWidth -= w; - m_layoutStruct[pos].effMinWidth = w; + for (unsigned pos = effCol; remainingMaxLogicalWidth >= 0 && pos < lastCol && remainingMinLogicalWidth < cellMinLogicalWidth; ++pos) { + if (!(m_layoutStruct[pos].logicalWidth.isFixed() && haveAuto && fixedWidth <= cellMinLogicalWidth)) { + int colMinLogicalWidth = max(m_layoutStruct[pos].effectiveMinLogicalWidth, static_cast<int>(remainingMaxLogicalWidth ? cellMinLogicalWidth * static_cast<float>(m_layoutStruct[pos].effectiveMaxLogicalWidth) / remainingMaxLogicalWidth : cellMinLogicalWidth)); + colMinLogicalWidth = min(m_layoutStruct[pos].effectiveMinLogicalWidth + (cellMinLogicalWidth - remainingMinLogicalWidth), colMinLogicalWidth); + remainingMaxLogicalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWidth; + remainingMinLogicalWidth -= m_layoutStruct[pos].effectiveMinLogicalWidth; + cellMinLogicalWidth -= colMinLogicalWidth; + m_layoutStruct[pos].effectiveMinLogicalWidth = colMinLogicalWidth; } } } } - if (!(w.isPercent())) { - if (cMaxWidth > maxWidth) { - for (unsigned int pos = col; maxWidth >= 0 && pos < lastCol; pos++) { - int w = max(m_layoutStruct[pos].effMaxWidth, static_cast<int>(maxWidth ? cMaxWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxWidth : cMaxWidth)); - maxWidth -= m_layoutStruct[pos].effMaxWidth; - cMaxWidth -= w; - m_layoutStruct[pos].effMaxWidth = w; + if (!cellLogicalWidth.isPercent()) { + if (cellMaxLogicalWidth > spanMaxLogicalWidth) { + for (unsigned pos = effCol; spanMaxLogicalWidth >= 0 && pos < lastCol; ++pos) { + int colMaxLogicalWidth = max(m_layoutStruct[pos].effectiveMaxLogicalWidth, static_cast<int>(spanMaxLogicalWidth ? cellMaxLogicalWidth * static_cast<float>(m_layoutStruct[pos].effectiveMaxLogicalWidth) / spanMaxLogicalWidth : cellMaxLogicalWidth)); + spanMaxLogicalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWidth; + cellMaxLogicalWidth -= colMaxLogicalWidth; + m_layoutStruct[pos].effectiveMaxLogicalWidth = colMaxLogicalWidth; } } } else { - for (unsigned int pos = col; pos < lastCol; pos++) - m_layoutStruct[pos].maxWidth = max(m_layoutStruct[pos].maxWidth, m_layoutStruct[pos].minWidth); + for (unsigned pos = effCol; pos < lastCol; ++pos) + m_layoutStruct[pos].maxLogicalWidth = max(m_layoutStruct[pos].maxLogicalWidth, m_layoutStruct[pos].minLogicalWidth); } // treat span ranges consisting of empty cells only as if they had content - if (spanHasEmptyCellsOnly) - for (unsigned int pos = col; pos < lastCol; pos++) + if (spanHasEmptyCellsOnly) { + for (unsigned pos = effCol; pos < lastCol; ++pos) m_layoutStruct[pos].emptyCellsOnly = false; + } } - m_effWidthDirty = false; + m_effectiveLogicalWidthDirty = false; - return static_cast<int>(min(tMaxWidth, INT_MAX / 2.0f)); + return static_cast<int>(min(maxLogicalWidth, INT_MAX / 2.0f)); } /* gets all cells that originate in a column and have a cellspan > 1 @@ -470,6 +448,7 @@ int AutoTableLayout::calcEffectiveWidth() */ void AutoTableLayout::insertSpanCell(RenderTableCell *cell) { + ASSERT_ARG(cell, cell && cell->colSpan() != 1); if (!cell || cell->colSpan() == 1) return; @@ -498,17 +477,17 @@ void AutoTableLayout::layout() return; #endif // table layout based on the values collected in the layout structure. - int tableWidth = m_table->width() - m_table->bordersPaddingAndSpacing(); - int available = tableWidth; - int nEffCols = m_table->numEffCols(); + int tableLogicalWidth = m_table->logicalWidth() - m_table->bordersPaddingAndSpacingInRowDirection(); + int available = tableLogicalWidth; + size_t nEffCols = m_table->numEffCols(); - if (nEffCols != (int)m_layoutStruct.size()) { + if (nEffCols != m_layoutStruct.size()) { fullRecalc(); nEffCols = m_table->numEffCols(); } - if (m_effWidthDirty) - calcEffectiveWidth(); + if (m_effectiveLogicalWidthDirty) + calcEffectiveLogicalWidth(); bool havePercent = false; int totalRelative = 0; @@ -518,35 +497,35 @@ void AutoTableLayout::layout() float totalFixed = 0; int totalPercent = 0; int allocAuto = 0; - int numAutoEmptyCellsOnly = 0; + unsigned numAutoEmptyCellsOnly = 0; // fill up every cell with its minWidth - for (int i = 0; i < nEffCols; i++) { - int w = m_layoutStruct[i].effMinWidth; - m_layoutStruct[i].calcWidth = w; - available -= w; - Length& width = m_layoutStruct[i].effWidth; - switch (width.type()) { + for (size_t i = 0; i < nEffCols; ++i) { + int cellLogicalWidth = m_layoutStruct[i].effectiveMinLogicalWidth; + m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; + available -= cellLogicalWidth; + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + switch (logicalWidth.type()) { case Percent: havePercent = true; - totalPercent += width.rawValue(); + totalPercent += logicalWidth.rawValue(); break; case Relative: - totalRelative += width.value(); + totalRelative += logicalWidth.value(); break; case Fixed: numFixed++; - totalFixed += m_layoutStruct[i].effMaxWidth; + totalFixed += m_layoutStruct[i].effectiveMaxLogicalWidth; // fall through break; case Auto: case Static: - if (m_layoutStruct[i].emptyCellsOnly) - numAutoEmptyCellsOnly++; + if (m_layoutStruct[i].emptyCellsOnly) + numAutoEmptyCellsOnly++; else { numAuto++; - totalAuto += m_layoutStruct[i].effMaxWidth; - allocAuto += w; + totalAuto += m_layoutStruct[i].effectiveMaxLogicalWidth; + allocAuto += cellLogicalWidth; } break; default: @@ -556,26 +535,26 @@ void AutoTableLayout::layout() // allocate width to percent cols if (available > 0 && havePercent) { - for (int i = 0; i < nEffCols; i++) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isPercent()) { - int w = max(int(m_layoutStruct[i].effMinWidth), width.calcMinValue(tableWidth)); - available += m_layoutStruct[i].calcWidth - w; - m_layoutStruct[i].calcWidth = w; + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isPercent()) { + int cellLogicalWidth = max(m_layoutStruct[i].effectiveMinLogicalWidth, logicalWidth.calcMinValue(tableLogicalWidth)); + available += m_layoutStruct[i].computedLogicalWidth - cellLogicalWidth; + m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; } } if (totalPercent > 100 * percentScaleFactor) { // remove overallocated space from the last columns - int excess = tableWidth*(totalPercent - 100 * percentScaleFactor) / (100 * percentScaleFactor); - for (int i = nEffCols-1; i >= 0; i--) { - if (m_layoutStruct[i].effWidth.isPercent()) { - int w = m_layoutStruct[i].calcWidth; - int reduction = min(w, excess); + int excess = tableLogicalWidth * (totalPercent - 100 * percentScaleFactor) / (100 * percentScaleFactor); + for (int i = nEffCols - 1; i >= 0; --i) { + if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) { + int cellLogicalWidth = m_layoutStruct[i].computedLogicalWidth; + int reduction = min(cellLogicalWidth, excess); // the lines below might look inconsistent, but that's the way it's handled in mozilla excess -= reduction; - int newWidth = max(static_cast<int>(m_layoutStruct[i].effMinWidth), w - reduction); - available += w - newWidth; - m_layoutStruct[i].calcWidth = newWidth; + int newLogicalWidth = max(m_layoutStruct[i].effectiveMinLogicalWidth, cellLogicalWidth - reduction); + available += cellLogicalWidth - newLogicalWidth; + m_layoutStruct[i].computedLogicalWidth = newLogicalWidth; } } } @@ -583,24 +562,24 @@ void AutoTableLayout::layout() // then allocate width to fixed cols if (available > 0) { - for (int i = 0; i < nEffCols; ++i) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isFixed() && width.value() > m_layoutStruct[i].calcWidth) { - available += m_layoutStruct[i].calcWidth - width.value(); - m_layoutStruct[i].calcWidth = width.value(); + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isFixed() && logicalWidth.value() > m_layoutStruct[i].computedLogicalWidth) { + available += m_layoutStruct[i].computedLogicalWidth - logicalWidth.value(); + m_layoutStruct[i].computedLogicalWidth = logicalWidth.value(); } } } // now satisfy relative if (available > 0) { - for (int i = 0; i < nEffCols; i++) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isRelative() && width.value() != 0) { + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isRelative() && logicalWidth.value() != 0) { // width=0* gets effMinWidth. - int w = width.value() * tableWidth / totalRelative; - available += m_layoutStruct[i].calcWidth - w; - m_layoutStruct[i].calcWidth = w; + int cellLogicalWidth = logicalWidth.value() * tableLogicalWidth / totalRelative; + available += m_layoutStruct[i].computedLogicalWidth - cellLogicalWidth; + m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; } } } @@ -608,42 +587,41 @@ void AutoTableLayout::layout() // now satisfy variable if (available > 0 && numAuto) { available += allocAuto; // this gets redistributed - for (int i = 0; i < nEffCols; i++) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isAuto() && totalAuto != 0 && !m_layoutStruct[i].emptyCellsOnly) { - int w = max(m_layoutStruct[i].calcWidth, static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalAuto)); - available -= w; - totalAuto -= m_layoutStruct[i].effMaxWidth; - m_layoutStruct[i].calcWidth = w; + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isAuto() && totalAuto && !m_layoutStruct[i].emptyCellsOnly) { + int cellLogicalWidth = max(m_layoutStruct[i].computedLogicalWidth, static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effectiveMaxLogicalWidth) / totalAuto)); + available -= cellLogicalWidth; + totalAuto -= m_layoutStruct[i].effectiveMaxLogicalWidth; + m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth; } } } // spread over fixed columns if (available > 0 && numFixed) { - // still have some width to spread, distribute to fixed columns - for (int i = 0; i < nEffCols; i++) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isFixed()) { - int w = static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalFixed); - available -= w; - totalFixed -= m_layoutStruct[i].effMaxWidth; - m_layoutStruct[i].calcWidth += w; + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isFixed()) { + int cellLogicalWidth = static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effectiveMaxLogicalWidth) / totalFixed); + available -= cellLogicalWidth; + totalFixed -= m_layoutStruct[i].effectiveMaxLogicalWidth; + m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth; } } } // spread over percent colums if (available > 0 && m_hasPercent && totalPercent < 100 * percentScaleFactor) { - // still have some width to spread, distribute weighted to percent columns - for (int i = 0; i < nEffCols; i++) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isPercent()) { - int w = available * width.rawValue() / totalPercent; - available -= w; - totalPercent -= width.rawValue(); - m_layoutStruct[i].calcWidth += w; - if (!available || !totalPercent) break; + for (size_t i = 0; i < nEffCols; ++i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isPercent()) { + int cellLogicalWidth = available * logicalWidth.rawValue() / totalPercent; + available -= cellLogicalWidth; + totalPercent -= logicalWidth.rawValue(); + m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth; + if (!available || !totalPercent) + break; } } } @@ -652,15 +630,14 @@ void AutoTableLayout::layout() if (available > 0 && nEffCols > numAutoEmptyCellsOnly) { int total = nEffCols - numAutoEmptyCellsOnly; // still have some width to spread - int i = nEffCols; - while (i--) { + for (int i = nEffCols - 1; i >= 0; --i) { // variable columns with empty cells only don't get any width - if (m_layoutStruct[i].effWidth.isAuto() && m_layoutStruct[i].emptyCellsOnly) + if (m_layoutStruct[i].effectiveLogicalWidth.isAuto() && m_layoutStruct[i].emptyCellsOnly) continue; - int w = available / total; - available -= w; + int cellLogicalWidth = available / total; + available -= cellLogicalWidth; total--; - m_layoutStruct[i].calcWidth += w; + m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth; } } @@ -674,21 +651,21 @@ void AutoTableLayout::layout() // (4) Percent // This is basically the reverse of how we grew the cells. if (available < 0) { - int mw = 0; - for (int i = nEffCols-1; i >= 0; i--) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isAuto()) - mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth; + int logicalWidthBeyondMin = 0; + for (int i = nEffCols - 1; i >= 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isAuto()) + logicalWidthBeyondMin += m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; } - for (int i = nEffCols-1; i >= 0 && mw > 0; i--) { - Length &width = m_layoutStruct[i].effWidth; - if (width.isAuto()) { - int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - m_layoutStruct[i].calcWidth += reduce; + for (int i = nEffCols - 1; i >= 0 && logicalWidthBeyondMin > 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isAuto()) { + int minMaxDiff = m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; + int reduce = available * minMaxDiff / logicalWidthBeyondMin; + m_layoutStruct[i].computedLogicalWidth += reduce; available -= reduce; - mw -= minMaxDiff; + logicalWidthBeyondMin -= minMaxDiff; if (available >= 0) break; } @@ -696,21 +673,21 @@ void AutoTableLayout::layout() } if (available < 0) { - int mw = 0; - for (int i = nEffCols-1; i >= 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isRelative()) - mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth; + int logicalWidthBeyondMin = 0; + for (int i = nEffCols - 1; i >= 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isRelative()) + logicalWidthBeyondMin += m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; } - for (int i = nEffCols-1; i >= 0 && mw > 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isRelative()) { - int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - m_layoutStruct[i].calcWidth += reduce; + for (int i = nEffCols - 1; i >= 0 && logicalWidthBeyondMin > 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isRelative()) { + int minMaxDiff = m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; + int reduce = available * minMaxDiff / logicalWidthBeyondMin; + m_layoutStruct[i].computedLogicalWidth += reduce; available -= reduce; - mw -= minMaxDiff; + logicalWidthBeyondMin -= minMaxDiff; if (available >= 0) break; } @@ -718,21 +695,21 @@ void AutoTableLayout::layout() } if (available < 0) { - int mw = 0; - for (int i = nEffCols-1; i >= 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isFixed()) - mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth; + int logicalWidthBeyondMin = 0; + for (int i = nEffCols - 1; i >= 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isFixed()) + logicalWidthBeyondMin += m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; } - for (int i = nEffCols-1; i >= 0 && mw > 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isFixed()) { - int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - m_layoutStruct[i].calcWidth += reduce; + for (int i = nEffCols - 1; i >= 0 && logicalWidthBeyondMin > 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isFixed()) { + int minMaxDiff = m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; + int reduce = available * minMaxDiff / logicalWidthBeyondMin; + m_layoutStruct[i].computedLogicalWidth += reduce; available -= reduce; - mw -= minMaxDiff; + logicalWidthBeyondMin -= minMaxDiff; if (available >= 0) break; } @@ -740,21 +717,21 @@ void AutoTableLayout::layout() } if (available < 0) { - int mw = 0; - for (int i = nEffCols-1; i >= 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isPercent()) - mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth; + int logicalWidthBeyondMin = 0; + for (int i = nEffCols - 1; i >= 0; --i) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isPercent()) + logicalWidthBeyondMin += m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; } - for (int i = nEffCols-1; i >= 0 && mw > 0; i--) { - Length& width = m_layoutStruct[i].effWidth; - if (width.isPercent()) { - int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - m_layoutStruct[i].calcWidth += reduce; + for (int i = nEffCols-1; i >= 0 && logicalWidthBeyondMin > 0; i--) { + Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth; + if (logicalWidth.isPercent()) { + int minMaxDiff = m_layoutStruct[i].computedLogicalWidth - m_layoutStruct[i].effectiveMinLogicalWidth; + int reduce = available * minMaxDiff / logicalWidthBeyondMin; + m_layoutStruct[i].computedLogicalWidth += reduce; available -= reduce; - mw -= minMaxDiff; + logicalWidthBeyondMin -= minMaxDiff; if (available >= 0) break; } @@ -763,25 +740,11 @@ void AutoTableLayout::layout() } int pos = 0; - for (int i = 0; i < nEffCols; i++) { + for (size_t i = 0; i < nEffCols; ++i) { m_table->columnPositions()[i] = pos; - pos += m_layoutStruct[i].calcWidth + m_table->hBorderSpacing(); + pos += m_layoutStruct[i].computedLogicalWidth + m_table->hBorderSpacing(); } m_table->columnPositions()[m_table->columnPositions().size() - 1] = pos; } - -void AutoTableLayout::calcPercentages() const -{ - unsigned totalPercent = 0; - for (unsigned i = 0; i < m_layoutStruct.size(); i++) { - if (m_layoutStruct[i].width.isPercent()) - totalPercent += m_layoutStruct[i].width.rawValue(); - } - m_totalPercent = totalPercent / percentScaleFactor; - m_percentagesDirty = false; -} - -#undef DEBUG_LAYOUT - } |