summaryrefslogtreecommitdiffstats
path: root/khtml/rendering/table_layout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/rendering/table_layout.cpp')
-rw-r--r--khtml/rendering/table_layout.cpp1193
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