diff options
Diffstat (limited to 'khtml/rendering/table_layout.cpp')
-rw-r--r-- | khtml/rendering/table_layout.cpp | 1193 |
1 files changed, 0 insertions, 1193 deletions
diff --git a/khtml/rendering/table_layout.cpp b/khtml/rendering/table_layout.cpp deleted file mode 100644 index f745640e7..000000000 --- a/khtml/rendering/table_layout.cpp +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * This file is part of the HTML rendering engine for KDE. - * - * Copyright (C) 2002 Lars Knoll (knoll@kde.org) - * (C) 2002 Dirk Mueller (mueller@kde.org) - * - * 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 "table_layout.h" -#include "render_table.h" - -#include <kglobal.h> - -using namespace khtml; - -// #define DEBUG_LAYOUT - -/* - The text below is from the CSS 2.1 specs. - - Fixed table layout - ------------------ - - With this (fast) algorithm, the horizontal layout of the table does - not depend on the contents of the cells; it only depends on the - table's width, the width of the columns, and borders or cell - spacing. - - The table's width may be specified explicitly with the 'width' - property. A value of 'auto' (for both 'display: table' and 'display: - inline-table') means use the automatic table layout algorithm. - - In the fixed table layout algorithm, the width of each column is - determined as follows: - - 1. A column element with a value other than 'auto' for the 'width' - property sets the width for that column. - - 2. Otherwise, a cell in the first row with a value other than - 'auto' for the 'width' property sets the width for that column. If - the cell spans more than one column, the width is divided over the - columns. - - 3. Any remaining columns equally divide the remaining horizontal - table space (minus borders or cell spacing). - - The width of the table is then the greater of the value of the - 'width' property for the table element and the sum of the column - widths (plus cell spacing or borders). If the table is wider than - the columns, the extra space should be distributed over the columns. - - - In this manner, the user agent can begin to lay out the table once - the entire first row has been received. Cells in subsequent rows do - not affect column widths. Any cell that has content that overflows - uses the 'overflow' property to determine whether to clip the - overflow content. - -_____________________________________________________ - - This is not quite true when comparing to IE. IE always honors - table-layout:fixed and treats a variable table width as 100%. Makes - a lot of sense, and is implemented here the same way. - -*/ - -FixedTableLayout::FixedTableLayout( RenderTable *table ) - : TableLayout ( table ) -{ -} - -FixedTableLayout::~FixedTableLayout() -{ -} - -int FixedTableLayout::calcWidthArray() -{ - int usedWidth = 0; - - // iterate over all <col> elements - RenderObject *child = table->firstChild(); - int cCol = 0; - int nEffCols = table->numEffCols(); - width.resize( nEffCols ); - width.fill( Length( Variable ) ); - -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::calcWidthArray()" ); - tqDebug(" col elements:"); -#endif - - Length grpWidth; - 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.isVariable() ) - w = grpWidth; - int effWidth = 0; - if ( w.isFixed() && w.value() > 0 ) { - effWidth = w.value(); - effWidth = KMIN( effWidth, 32760 ); - } -#ifdef DEBUG_LAYOUT - tqDebug(" col element: effCol=%d, span=%d: %d w=%d type=%d", - cCol, span, effWidth, w.value(), w.type()); -#endif - int usedSpan = 0; - int i = 0; - while ( usedSpan < span ) { - if( cCol + i >= nEffCols ) { - table->appendColumn( span - usedSpan ); - nEffCols++; - width.resize( nEffCols ); - width[nEffCols-1] = Length(); - } - int eSpan = table->spanOfEffCol( cCol+i ); - if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) { - width[cCol+i] = Length( w.value() * eSpan, w.type() ); - usedWidth += effWidth * eSpan; -#ifdef DEBUG_LAYOUT - tqDebug(" setting effCol %d (span=%d) to width %d(type=%d)", - cCol+i, eSpan, width[cCol+i].value(), width[cCol+i].type() ); -#endif - } - usedSpan += eSpan; - i++; - } - cCol += i; - } - } else { - break; - } - - RenderObject *next = child->firstChild(); - if ( !next ) - next = child->nextSibling(); - if ( !next && child->parent()->isTableCol() ) { - next = child->parent()->nextSibling(); - grpWidth = Length(); - } - child = next; - } - -#ifdef DEBUG_LAYOUT - tqDebug(" first row:"); -#endif - // iterate over the first row in case some are unspecified. - RenderTableSection *section = table->head; - if ( !section ) - section = table->firstBody; - if ( !section ) - section = table->foot; - if ( section && section->firstChild() ) { - cCol = 0; - // get the first cell in the first row - child = section->firstChild()->firstChild(); - while ( child ) { - if ( child->isTableCell() ) { - RenderTableCell *cell = static_cast<RenderTableCell *>(child); - Length w = cell->styleOrColWidth(); - int span = cell->colSpan(); - int effWidth = 0; - if ( (w.isFixed() || w.isPercent()) && w.value() > 0 ) { - effWidth = w.value(); - effWidth = kMin( effWidth, 32760 ); - } -#ifdef DEBUG_LAYOUT - tqDebug(" table cell: effCol=%d, span=%d: %d", cCol, span, effWidth); -#endif - int usedSpan = 0; - int i = 0; - while ( usedSpan < span ) { - Q_ASSERT( cCol + i < nEffCols ); - int eSpan = table->spanOfEffCol( cCol+i ); - // only set if no col element has already set it. - if ( width[cCol+i].isVariable() && !w.isVariable() ) { - width[cCol+i] = Length( w.value()*eSpan, w.type() ); - usedWidth += effWidth*eSpan; -#ifdef DEBUG_LAYOUT - tqDebug(" setting effCol %d (span=%d) to width %d(type=%d)", - cCol+i, eSpan, width[cCol+i].value(), width[cCol+i].type() ); -#endif - } -#ifdef DEBUG_LAYOUT - else { - tqDebug(" width of col %d already defined (span=%d)", cCol, table->spanOfEffCol( cCol ) ); - } -#endif - usedSpan += eSpan; - i++; - } - cCol += i; - } else { - Q_ASSERT( false ); - } - child = child->nextSibling(); - } - } - - return usedWidth; - -} - -void FixedTableLayout::calcMinMaxWidth() -{ - // we might want to wait until we have all of the first row before - // layouting for the first time. - - // only need to calculate the minimum width as the sum of the - // cols/cells with a fixed width. - // - // The maximum width is kMax( minWidth, tableWidth ) if table - // width is fixed. If table width is percent, we set maxWidth to - // unlimited. - - int bs = table->bordersPaddingAndSpacing(); - int tableWidth = 0; - if (table->style()->width().isFixed()) { - tableWidth = table->calcBoxWidth(table->style()->width().value()); - } - - int mw = calcWidthArray() + bs; - table->m_minWidth = kMin( kMax( mw, tableWidth ), 0x7fff ); - table->m_maxWidth = table->m_minWidth; - - if ( !tableWidth ) { - bool haveNonFixed = false; - for ( unsigned int i = 0; i < width.size(); i++ ) { - if ( !width[i].isFixed() ) { - haveNonFixed = true; - break; - } - } - if ( haveNonFixed ) - table->m_maxWidth = 0x7fff; - } -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::calcMinMaxWidth: minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth ); -#endif -} - -void FixedTableLayout::layout() -{ - int tableWidth = table->width() - table->bordersPaddingAndSpacing(); - int available = tableWidth; - int nEffCols = table->numEffCols(); -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::layout: tableWidth=%d, numEffCols=%d", tableWidth, nEffCols); -#endif - - - TQMemArray<int> calcWidth; - calcWidth.resize( nEffCols ); - calcWidth.fill( -1 ); - - // first assign fixed width - for ( int i = 0; i < nEffCols; i++ ) { - if ( width[i].isFixed() ) { - calcWidth[i] = width[i].value(); - available -= width[i].value(); - } - } - - // assign percent width - if ( available > 0 ) { - int totalPercent = 0; - for ( int i = 0; i < nEffCols; i++ ) - if ( width[i].isPercent() ) - totalPercent += width[i].value(); - - // calculate how much to distribute to percent cells. - int base = tableWidth * totalPercent / 100; - if ( base > available ) - base = available; - -#ifdef DEBUG_LAYOUT - tqDebug("FixedTableLayout::layout: assigning percent width, base=%d, totalPercent=%d", base, totalPercent); -#endif - for ( int i = 0; available > 0 && i < nEffCols; i++ ) { - if ( width[i].isPercent() ) { - // totalPercent may be 0 below if all %-width specifed are 0%. (#172557) - int w = totalPercent ? base * width[i].value() / totalPercent : 0; - available -= w; - calcWidth[i] = w; - } - } - } - - // assign variable width - if ( available > 0 ) { - int totalVariable = 0; - for ( int i = 0; i < nEffCols; i++ ) - if ( width[i].isVariable() ) - totalVariable++; - - for ( int i = 0; available > 0 && i < nEffCols; i++ ) { - if ( width[i].isVariable() ) { - // totalVariable may be 0 below if all the variable widths specified are 0. - int w = totalVariable ? available / totalVariable : 0; - available -= w; - calcWidth[i] = w; - totalVariable--; - } - } - } - - for ( int i = 0; i < nEffCols; i++ ) - if ( calcWidth[i] < 0 ) - calcWidth[i] = 0; // IE gives min 1 px... - - // spread extra space over columns - if ( available > 0 ) { - int total = nEffCols; - // still have some width to spread - int i = nEffCols; - while ( i-- ) { - int w = available / total; - available -= w; - total--; - calcWidth[i] += w; - } - } - - int pos = 0; - int hspacing = table->borderHSpacing(); - for ( int i = 0; i < nEffCols; i++ ) { -#ifdef DEBUG_LAYOUT - tqDebug("col %d: %d (width %d)", i, pos, calcWidth[i] ); -#endif - table->columnPos[i] = pos; - pos += calcWidth[i] + hspacing; - } - table->columnPos[table->columnPos.size()-1] = pos; -} - -// ------------------------------------------------------------------------- -// ------------------------------------------------------------------------- - - -AutoTableLayout::AutoTableLayout( RenderTable* table ) - : TableLayout( table ) -{ - percentagesDirty = true; - effWidthDirty = true; - total_percent = 0; - hasPercent = false; -} - -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 = layoutStruct[effCol]; - - RenderObject *child = 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++ ) { - RenderTableCell *cell = section->cellAt( i, effCol ); - if ( cell == (RenderTableCell *)-1 ) - 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 = kMax(int( l.minWidth ), 1); - l.maxWidth = kMax(int( l.maxWidth ), 1); - - if ( !cell->minMaxKnown() ) - cell->calcMinMaxWidth(); - if ( cell->minWidth() > l.minWidth ) - l.minWidth = cell->minWidth(); - if ( cell->maxWidth() > l.maxWidth ) { - l.maxWidth = cell->maxWidth(); - maxContributor = cell; - } - - Length w = cell->styleOrColWidth(); - w.l.value = kMin( 32767, kMax( 0, w.value() ) ); - switch( w.type() ) { - case Fixed: - // ignore width=0 - if ( w.value() > 0 && !l.width.isPercent() ) { - int wval = cell->calcBoxWidth(w.value()); - if ( l.width.isFixed() ) { - // Nav/IE weirdness - if ((wval > l.width.value()) || - ((l.width.value() == wval) && (maxContributor == cell))) { - l.width.l.value = wval; - fixedContributor = cell; - } - } else { - l.width = Length( wval, Fixed ); - fixedContributor = cell; - } - } - break; - case Percent: - hasPercent = true; - if ( w.value() > 0 && (!l.width.isPercent() || w.value() > l.width.value() ) ) - l.width = w; - break; - case Relative: - if ( w.isVariable() || (w.isRelative() && w.value() > l.width.value() ) ) - l.width = w; - default: - break; - } - } else { - if ( cell && (!effCol || section->cellAt( 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 = kMax(int( l.minWidth ), 1); - l.maxWidth = kMax(int( l.maxWidth ), 1); - insertSpanCell( cell ); - } - last = cell; - } - } - } - child = child->nextSibling(); - } - - // Nav/IE weirdness - if ( l.width.isFixed() ) { - if ( table->style()->htmlHacks() - && (l.maxWidth > l.width.value()) && (fixedContributor != maxContributor)) { - l.width = Length(); - fixedContributor = 0; - } - } - - l.maxWidth = kMax(l.maxWidth, int(l.minWidth)); -#ifdef DEBUG_LAYOUT - tqDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.value(), l.width.type() ); -#endif - - // ### we need to add col elements aswell -} - - -void AutoTableLayout::fullRecalc() -{ - percentagesDirty = true; - hasPercent = false; - effWidthDirty = true; - - int nEffCols = table->numEffCols(); - layoutStruct.resize( nEffCols ); - layoutStruct.fill( Layout() ); - spanCells.fill( 0 ); - - RenderObject *child = 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.isVariable() ) - w = grpWidth; - if ( (w.isFixed() && w.value() == 0) || - (w.isPercent() && w.value() == 0) ) - w = Length(); - int cEffCol = table->colToEffCol( cCol ); -#ifdef DEBUG_LAYOUT - tqDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value(), w.type(), span, table->spanOfEffCol(cEffCol ) ); -#endif - if ( !w.isVariable() && span == 1 && cEffCol < nEffCols ) { - if ( table->spanOfEffCol( cEffCol ) == 1 ) { - layoutStruct[cEffCol].width = w; - if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value()) - 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.isVariable() || tw.isPercent()) && !table->isPositioned()) { - RenderBlock* cb = table->containingBlock(); - while (cb && !cb->isCanvas() && !cb->isTableCell() && - cb->style()->width().isVariable() && !cb->isPositioned()) - cb = cb->containingBlock(); - - table = 0; - if (cb && cb->isTableCell() && - (cb->style()->width().isVariable() || cb->style()->width().isPercent())) { - if (tw.isPercent()) - scale = false; - else { - RenderTableCell* cell = static_cast<RenderTableCell*>(cb); - if (cell->colSpan() > 1 || cell->table()->style()->width().isVariable()) - scale = false; - else - table = cell->table(); - } - } - } - else - table = 0; - } - return scale; -} - -void AutoTableLayout::calcMinMaxWidth() -{ -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::calcMinMaxWidth"); -#endif - fullRecalc(); - - int spanMaxWidth = calcEffectiveWidth(); - int minWidth = 0; - int maxWidth = 0; - int maxPercent = 0; - int maxNonPercent = 0; - - int remainingPercent = 100; - for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) { - minWidth += layoutStruct[i].effMinWidth; - maxWidth += layoutStruct[i].effMaxWidth; - if ( layoutStruct[i].effWidth.isPercent() ) { - int percent = kMin(layoutStruct[i].effWidth.value(), remainingPercent); - int pw = ( layoutStruct[i].effMaxWidth * 100) / kMax(percent, 1); - remainingPercent -= percent; - maxPercent = kMax( pw, maxPercent ); - } else { - maxNonPercent += layoutStruct[i].effMaxWidth; - } - } - - if (shouldScaleColumns(table)) { - maxNonPercent = (maxNonPercent * 100 + 50) / kMax(remainingPercent, 1); - maxWidth = kMax( maxNonPercent, maxWidth ); - maxWidth = kMax( maxWidth, maxPercent ); - } - - maxWidth = kMax( maxWidth, spanMaxWidth ); - - int bs = table->bordersPaddingAndSpacing(); - minWidth += bs; - maxWidth += bs; - - Length tw = table->style()->width(); - if ( tw.isFixed() && tw.value() > 0 ) { - int width = table->calcBoxWidth(tw.value()); - minWidth = kMax( minWidth, width ); - maxWidth = minWidth; - } - - table->m_maxWidth = kMin(maxWidth, 0x7fff); - table->m_minWidth = kMin(minWidth, 0x7fff); -#ifdef DEBUG_LAYOUT - tqDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth ); -#endif -} - -/* - 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 tMaxWidth = 0; - - unsigned int nEffCols = layoutStruct.size(); - int hspacing = table->borderHSpacing(); -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols ); -#endif - for ( unsigned int i = 0; i < nEffCols; i++ ) { - layoutStruct[i].effWidth = layoutStruct[i].width; - layoutStruct[i].effMinWidth = layoutStruct[i].minWidth; - layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth; - } - - for ( unsigned int i = 0; i < spanCells.size(); i++ ) { - RenderTableCell *cell = spanCells[i]; - if ( !cell || cell == (RenderTableCell *)-1 ) - break; - int span = cell->colSpan(); - - Length w = cell->styleOrColWidth(); - if ( !w.isRelative() && w.value() == 0 ) - w = Length(); // make it Variable - - int col = table->colToEffCol( cell->col() ); - unsigned int lastCol = col; - int cMinWidth = cell->minWidth() + hspacing; - int cMaxWidth = cell->maxWidth() + hspacing; - int totalPercent = 0; - int minWidth = 0; - int maxWidth = 0; - bool allColsArePercent = true; - bool allColsAreFixed = true; - bool haveVariable = false; - int fixedWidth = 0; -#ifdef DEBUG_LAYOUT - int cSpan = span; -#endif - while ( lastCol < nEffCols && span > 0 ) { - switch( layoutStruct[lastCol].width.type() ) { - case Percent: - totalPercent += layoutStruct[lastCol].width.value(); - allColsAreFixed = false; - break; - case Fixed: - if (layoutStruct[lastCol].width.value() > 0) { - fixedWidth += layoutStruct[lastCol].width.value(); - allColsArePercent = false; - // IE resets effWidth to Variable here, but this breaks the konqueror about page and seems to be some bad - // legacy behavior anyway. mozilla doesn't do this so I decided we don't either. - break; - } - // fall through - case Variable: - haveVariable = true; - // fall through - default: - // If the column is a percentage width, do not let the spanning cell overwrite the - // width value. This caused a mis-rendering on amazon.com. - // Sample snippet: - // <table border=2 width=100%>< - // <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 (!layoutStruct[lastCol].effWidth.isPercent()) { - layoutStruct[lastCol].effWidth = Length(); - allColsArePercent = false; - } - else - totalPercent += layoutStruct[lastCol].effWidth.value(); - allColsAreFixed = false; - } - span -= table->spanOfEffCol( lastCol ); - minWidth += layoutStruct[lastCol].effMinWidth; - maxWidth += layoutStruct[lastCol].effMaxWidth; - lastCol++; - cMinWidth -= hspacing; - cMaxWidth -= hspacing; - } -#ifdef DEBUG_LAYOUT - tqDebug(" colspan cell %p at effCol %d, span %d, type %d, value %d cmin=%d min=%d fixedwidth=%d", cell, col, cSpan, w.type(), w.value(), cMinWidth, minWidth, fixedWidth ); -#endif - - // adjust table max width if needed - if ( w.isPercent() ) { - if ( totalPercent > w.value() || allColsArePercent ) { - // can't satify this condition, treat as variable - w = Length(); - } else { - int spanMax = kMax( maxWidth, cMaxWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value(), totalPercent ); -#endif - tMaxWidth = kMax( tMaxWidth, spanMax * 100 / w.value() ); - - // all non percent columns in the span get percent values to sum up correctly. - int percentMissing = w.value() - totalPercent; - int totalWidth = 0; - for ( unsigned int pos = col; pos < lastCol; pos++ ) { - if ( !(layoutStruct[pos].width.isPercent() ) ) - totalWidth += layoutStruct[pos].effMaxWidth; - } - - for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) { - if ( !(layoutStruct[pos].width.isPercent() ) ) { - int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth; -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth ); -#endif - totalWidth -= layoutStruct[pos].effMaxWidth; - percentMissing -= percent; - if ( percent > 0 ) - layoutStruct[pos].effWidth = Length( percent, Percent ); - else - layoutStruct[pos].effWidth = Length(); - } - } - - } - } - - // make sure minWidth and maxWidth of the spanning cell are honoured - if ( cMinWidth > minWidth ) { - if ( allColsAreFixed ) { -#ifdef DEBUG_LAYOUT - tqDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol-1, cMinWidth, minWidth, fixedWidth ); -#endif - for ( unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++ ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), cMinWidth * layoutStruct[pos].width.value() / fixedWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - fixedWidth -= layoutStruct[pos].width.value(); - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - - } else if ( allColsArePercent ) { - int maxw = maxWidth; - int minw = minWidth; - int cminw = cMinWidth; - - for ( unsigned int pos = col; maxw > 0 && pos < lastCol; pos++ ) { - if ( layoutStruct[pos].effWidth.isPercent() && layoutStruct[pos].effWidth.value()>0 && fixedWidth <= cMinWidth) { - int w = layoutStruct[pos].effMinWidth; - w = kMax( w, cminw*layoutStruct[pos].effWidth.value()/totalPercent ); - w = kMin(layoutStruct[pos].effMinWidth+(cMinWidth-minw), w); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - minw -= layoutStruct[pos].effMinWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - } else { -#ifdef DEBUG_LAYOUT - tqDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol-1, cMinWidth, minWidth ); -#endif - int maxw = maxWidth; - int minw = minWidth; - - // Give min to variable first, to fixed second, and to others third. - for ( unsigned int pos = col; maxw > 0 && pos < lastCol; pos++ ) { - if ( layoutStruct[pos].width.isFixed() && haveVariable && fixedWidth <= cMinWidth ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), layoutStruct[pos].width.value() ); - fixedWidth -= layoutStruct[pos].width.value(); - minw -= layoutStruct[pos].effMinWidth; -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - - for ( unsigned int pos = col; maxw > 0 && pos < lastCol && minw < cMinWidth; pos++ ) { - if ( !(layoutStruct[pos].width.isFixed() && haveVariable && fixedWidth <= cMinWidth) ) { - int w = kMax( int( layoutStruct[pos].effMinWidth ), cMinWidth * layoutStruct[pos].effMaxWidth / maxw ); - w = kMin(layoutStruct[pos].effMinWidth+(cMinWidth-minw), w); - -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w ); -#endif - maxw -= layoutStruct[pos].effMaxWidth; - minw -= layoutStruct[pos].effMinWidth; - cMinWidth -= w; - layoutStruct[pos].effMinWidth = w; - } - } - } - } - if ( !w.isPercent() ) { - if ( cMaxWidth > maxWidth ) { -#ifdef DEBUG_LAYOUT - tqDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol-1, cMaxWidth ); -#endif - for ( unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++ ) { - int w = kMax( int( layoutStruct[pos].effMaxWidth ), cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth ); -#ifdef DEBUG_LAYOUT - tqDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w ); -#endif - maxWidth -= layoutStruct[pos].effMaxWidth; - cMaxWidth -= w; - layoutStruct[pos].effMaxWidth = w; - } - } - } else { - for ( unsigned int pos = col; pos < lastCol; pos++ ) - layoutStruct[pos].maxWidth = kMax(layoutStruct[pos].maxWidth, int(layoutStruct[pos].minWidth) ); - } - } - effWidthDirty = false; - -// tqDebug("calcEffectiveWidth: tMaxWidth=%d", tMaxWidth ); - return tMaxWidth; -} - -/* gets all cells that originate in a column and have a cellspan > 1 - Sorts them by increasing cellspan -*/ -void AutoTableLayout::insertSpanCell( RenderTableCell *cell ) -{ - if ( !cell || cell == (RenderTableCell *)-1 || cell->colSpan() == 1 ) - return; - -// tqDebug("inserting span cell %p with span %d", cell, cell->colSpan() ); - int size = spanCells.size(); - if ( !size || spanCells[size-1] != 0 ) { - spanCells.resize( size + 10 ); - for ( int i = 0; i < 10; i++ ) - spanCells[size+i] = 0; - size += 10; - } - - // add them in sort. This is a slow algorithm, and a binary search or a fast sorting after collection would be better - unsigned int pos = 0; - int span = cell->colSpan(); - while ( pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan() ) - pos++; - memmove( spanCells.data()+pos+1, spanCells.data()+pos, (size-pos-1)*sizeof( RenderTableCell * ) ); - spanCells[pos] = cell; -} - - -void AutoTableLayout::layout() -{ - // table layout based on the values collected in the layout structure. - int tableWidth = table->width() - table->bordersPaddingAndSpacing(); - int available = tableWidth; - int nEffCols = table->numEffCols(); - - if ( nEffCols != (int)layoutStruct.size() ) { - tqWarning("WARNING: nEffCols is not equal to layoutstruct!" ); - fullRecalc(); - nEffCols = table->numEffCols(); - } -#ifdef DEBUG_LAYOUT - tqDebug("AutoTableLayout::layout()"); -#endif - - if ( effWidthDirty ) - calcEffectiveWidth(); - -#ifdef DEBUG_LAYOUT - tqDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols ); - for ( int i = 0; i < nEffCols; i++ ) { - tqDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d", - i, layoutStruct[i].width.type(), layoutStruct[i].width.value(), - layoutStruct[i].minWidth, layoutStruct[i].maxWidth ); - tqDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d", - layoutStruct[i].effWidth.type(), layoutStruct[i].effWidth.value(), - layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth ); - } -#endif - - bool havePercent = false; - bool haveRelative = false; - int totalRelative = 0; - int numVariable = 0; - int numFixed = 0; - int totalVariable = 0; - int totalFixed = 0; - int totalPercent = 0; - int allocVariable = 0; - - // fill up every cell with it's minWidth - for ( int i = 0; i < nEffCols; i++ ) { - int w = layoutStruct[i].effMinWidth; - layoutStruct[i].calcWidth = w; - available -= w; - Length& width = layoutStruct[i].effWidth; - switch( width.type()) { - case Percent: - havePercent = true; - totalPercent += width.value(); - break; - case Relative: - haveRelative = true; - totalRelative += width.value(); - break; - case Fixed: - numFixed++; - totalFixed += layoutStruct[i].effMaxWidth; - // fall through - break; - case Variable: - case Static: - numVariable++; - totalVariable += layoutStruct[i].effMaxWidth; - allocVariable += w; - } - } - - // allocate width to percent cols - if ( available > 0 && havePercent ) { - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isPercent() ) { - int w = kMax ( int( layoutStruct[i].effMinWidth ), width.minWidth( tableWidth ) ); - available += layoutStruct[i].calcWidth - w; - layoutStruct[i].calcWidth = w; - } - } - if ( totalPercent > 100 ) { - // remove overallocated space from the last columns - int excess = tableWidth*(totalPercent-100)/100; - for ( int i = nEffCols-1; i >= 0; i-- ) { - if ( layoutStruct[i].effWidth.isPercent() ) { - int w = layoutStruct[i].calcWidth; - int reduction = kMin( w, excess ); - // the lines below might look inconsistent, but that's the way it's handled in mozilla - excess -= reduction; - int newWidth = kMax( int (layoutStruct[i].effMinWidth), w - reduction ); - available += w - newWidth; - layoutStruct[i].calcWidth = newWidth; - //tqDebug("col %d: reducing to %d px (reduction=%d)", i, newWidth, reduction ); - } - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("percent satisfied: available is %d", available); -#endif - - // then allocate width to fixed cols - if ( available > 0 ) { - for ( int i = 0; i < nEffCols; ++i ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isFixed() && width.value() > layoutStruct[i].calcWidth ) { - available += layoutStruct[i].calcWidth - width.value(); - layoutStruct[i].calcWidth = width.value(); - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("fixed satisfied: available is %d", available); -#endif - - // now satisfy relative - if ( available > 0 ) { - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isRelative() && width.value() ) { - // width=0* gets effMinWidth. - int w = width.value()*tableWidth/totalRelative; - available += layoutStruct[i].calcWidth - w; - layoutStruct[i].calcWidth = w; - } - } - } - - // now satisfy variable - if ( available > 0 && numVariable ) { - available += allocVariable; // this gets redistributed - //tqDebug("redistributing %dpx to %d variable columns. totalVariable=%d", available, numVariable, totalVariable ); - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isVariable() && totalVariable != 0 ) { - int w = kMax( int ( layoutStruct[i].calcWidth ), - available * layoutStruct[i].effMaxWidth / totalVariable ); - available -= w; - totalVariable -= layoutStruct[i].effMaxWidth; - layoutStruct[i].calcWidth = w; - } - } - } -#ifdef DEBUG_LAYOUT - tqDebug("variable satisfied: available is %d", available ); -#endif - - // spread over fixed colums - if ( available > 0 && numFixed) { - // still have some width to spread, distribute to fixed columns - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isFixed() ) { - int w = available * layoutStruct[i].effMaxWidth / totalFixed; - available -= w; - totalFixed -= layoutStruct[i].effMaxWidth; - layoutStruct[i].calcWidth += w; - } - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after fixed distribution: available=%d", available ); -#endif - - // spread over percent colums - if ( available > 0 && hasPercent && totalPercent < 100) { - // still have some width to spread, distribute weighted to percent columns - for ( int i = 0; i < nEffCols; i++ ) { - const Length &width = layoutStruct[i].effWidth; - if ( width.isPercent() ) { - int w = available * width.value() / totalPercent; - available -= w; - totalPercent -= width.value(); - layoutStruct[i].calcWidth += w; - if (!available || !totalPercent) break; - } - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after percent distribution: available=%d", available ); -#endif - - // spread over the rest - if ( available > 0 ) { - int total = nEffCols; - // still have some width to spread - int i = nEffCols; - while ( i-- ) { - int w = available / total; - available -= w; - total--; - layoutStruct[i].calcWidth += w; - } - } - -#ifdef DEBUG_LAYOUT - tqDebug("after equal distribution: available=%d", available ); -#endif - // if we have overallocated, reduce every cell according to the difference between desired width and minwidth - // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing. - if ( available < 0 ) { - // Need to reduce cells with the following prioritization: - // (1) Variable - // (2) Relative - // (3) Fixed - // (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 = layoutStruct[i].effWidth; - if (width.isVariable()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isVariable()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isRelative()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isRelative()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isFixed()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isFixed()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - - if (available < 0) { - int mw = 0; - for ( int i = nEffCols-1; i >= 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isPercent()) - mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; - } - - for ( int i = nEffCols-1; i >= 0 && mw > 0; i-- ) { - Length &width = layoutStruct[i].effWidth; - if (width.isPercent()) { - int minMaxDiff = layoutStruct[i].calcWidth-layoutStruct[i].effMinWidth; - int reduce = available * minMaxDiff / mw; - layoutStruct[i].calcWidth += reduce; - available -= reduce; - mw -= minMaxDiff; - if ( available >= 0 ) - break; - } - } - } - } - - //tqDebug( " final available=%d", available ); - - int pos = 0; - for ( int i = 0; i < nEffCols; i++ ) { -#ifdef DEBUG_LAYOUT - tqDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth ); -#endif - table->columnPos[i] = pos; - pos += layoutStruct[i].calcWidth + table->borderHSpacing(); - } - table->columnPos[table->columnPos.size()-1] = pos; - -} - - -void AutoTableLayout::calcPercentages() const -{ - total_percent = 0; - for ( unsigned int i = 0; i < layoutStruct.size(); i++ ) { - if ( layoutStruct[i].width.isPercent() ) - total_percent += layoutStruct[i].width.value(); - } - percentagesDirty = false; -} - -#undef DEBUG_LAYOUT |