Example #1
0
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
    qDebug("FixedTableLayout::calcWidthArray()" );
    qDebug("    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
		qDebug("    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
			qDebug("    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
    qDebug("    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
		qDebug("    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
			qDebug("    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 {
			qDebug("    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;

}
Example #2
0
/* 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
}
Example #3
0
/*
  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;
}
int FixedTableLayout::calcWidthArray(int tableWidth)
{
    int usedWidth = 0;

    // iterate over all <col> elements
    RenderObject* child = m_table->firstChild();
    int cCol = 0;
    int nEffCols = m_table->numEffCols();
    m_width.resize(nEffCols);
    m_width.fill(Length(Auto));

    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.isAuto())
                    w = grpWidth;
                int effWidth = 0;
                if (w.isFixed() && w.value() > 0)
                    effWidth = w.value();
                
                int usedSpan = 0;
                int i = 0;
                while (usedSpan < span) {
                    if(cCol + i >= nEffCols) {
                        m_table->appendColumn(span - usedSpan);
                        nEffCols++;
                        m_width.resize(nEffCols);
                        m_width[nEffCols-1] = Length();
                    }
                    int eSpan = m_table->spanOfEffCol(cCol+i);
                    if ((w.isFixed() || w.isPercent()) && w.isPositive()) {
                        m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan);
                        usedWidth += effWidth * eSpan;
                    }
                    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;
    }

    // Iterate over the first row in case some are unspecified.
    RenderTableSection* section = m_table->header();
    if (!section)
        section = m_table->firstBody();
    if (!section)
        section = m_table->footer();
    if (section && !section->numRows())
        section = m_table->sectionBelow(section, true);
    if (section) {
        cCol = 0;
        RenderObject* firstRow = section->firstChild();
        child = firstRow->firstChild();
        while (child) {
            if (child->isTableCell()) {
                RenderTableCell* cell = static_cast<RenderTableCell*>(child);
                if (cell->prefWidthsDirty())
                    cell->calcPrefWidths();

                Length w = cell->styleOrColWidth();
                int span = cell->colSpan();
                int effWidth = 0;
                if (w.isFixed() && w.isPositive())
                    effWidth = w.value();
                
                int usedSpan = 0;
                int i = 0;
                while (usedSpan < span) {
                    ASSERT(cCol + i < nEffCols);
                    int eSpan = m_table->spanOfEffCol(cCol + i);
                    // Only set if no col element has already set it.
                    if (m_width[cCol + i].isAuto() && w.type() != Auto) {
                        m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan / span);
                        usedWidth += effWidth * eSpan / span;
                    }
                    usedSpan += eSpan;
                    i++;
                }
                cCol += i;
            }
            child = child->nextSibling();
        }
    }

    return usedWidth;
}