/* 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 qDebug("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 qDebug(" 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 qDebug(" 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 qDebug(" 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 qDebug("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 qDebug(" 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 qDebug(" 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 qDebug("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 qDebug(" 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 qDebug(" 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 qDebug("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 qDebug(" 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; // qDebug("calcEffectiveWidth: tMaxWidth=%d", tMaxWidth ); return tMaxWidth; }
/* 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 qDebug("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 }