📄 table_layout.cpp
字号:
if ( cell->maxWidth() > l.maxWidth ) {
l.maxWidth = cell->maxWidth();
maxContributor = cell;
}
Length w = cell->style()->width();
if ( w.value > 32760 )
w.value = 32760;
if ( w.value < 0 )
w.value = 0;
switch( w.type ) {
case Fixed:
// ignore width=0
if ( w.value > 0 && (int)l.width.type != Percent ) {
int wval = w.value + (cell->paddingLeft()+cell->paddingRight());
if ( l.width.type == Fixed ) {
// Nav/IE weirdness
if ((wval > l.width.value) ||
((l.width.value == wval) && (maxContributor == cell))) {
l.width.value = wval;
fixedContributor = cell;
}
} else {
l.width.type = Fixed;
l.width.value = wval;
fixedContributor = cell;
}
}
break;
case Percent:
hasPercent = true;
if ( w.value > 0 && (l.width.type != Percent || w.value > l.width.value ) )
l.width = w;
break;
case Relative:
if ( w.type == Variable || (w.type == Relative && 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 = QMAX(l.minWidth, 1);
l.maxWidth = QMAX(l.maxWidth, 1);
insertSpanCell( cell );
}
last = cell;
}
}
}
child = child->nextSibling();
}
// Nav/IE weirdness
if ( l.width.type == Fixed ) {
if ( table->style()->htmlHacks()
&& (l.maxWidth > l.width.value) && (fixedContributor != maxContributor)) {
l.width = Length();
fixedContributor = 0;
}
}
l.maxWidth = kMax(l.maxWidth, 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
}
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.type == Fixed && w.value == 0) ||
(w.type == Percent && w.value == 0) )
w = Length();
int cEffCol = table->colToEffCol( cCol );
#ifdef DEBUG_LAYOUT
qDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.value, w.type, span, table->spanOfEffCol(cEffCol ) );
#endif
if ( (int)w.type != Variable && 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
qDebug("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.type == Percent ) {
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 ) {
minWidth = kMax( minWidth, int( tw.value ) );
maxWidth = minWidth;
}
table->m_maxWidth = maxWidth;
table->m_minWidth = minWidth;
#ifdef DEBUG_LAYOUT
qDebug(" 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->hBorderSpacing();
#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->style()->width();
if ( !(w.type == Relative) && 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 behaviour anyway. mozilla doesn't do this so I decided we don't neither.
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.type != Percent) {
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.type == Percent ) {
if ( totalPercent > w.value || allColsArePercent ) {
// can't satify this condition, treat as variable
w = Length();
} else {
int spanMax = QMAX( maxWidth, cMaxWidth );
#ifdef DEBUG_LAYOUT
qDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.value, totalPercent );
#endif
tMaxWidth = QMAX( tMaxWidth, spanMax * 100 / w.value );
// all non percent columns in the span get percent vlaues to sum up correctly.
int percentMissing = w.value - totalPercent;
int totalWidth = 0;
for ( unsigned int pos = col; pos < lastCol; pos++ ) {
if ( !(layoutStruct[pos].width.type == Percent ) )
totalWidth += layoutStruct[pos].effMaxWidth;
}
for ( unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++ ) {
if ( !(layoutStruct[pos].width.type == Percent ) ) {
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 = QMAX( 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 {
#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.type == Fixed && haveVariable && fixedWidth <= cMinWidth ) {
int w = QMAX( 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.type == Fixed && haveVariable && fixedWidth <= cMinWidth) ) {
int w = QMAX( layoutStruct[pos].effMinWidth, cMinWidth * layoutStruct[pos].effMaxWidth / maxw );
w = QMIN(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -