FixedTableLayout.cpp [plain text]
#include "config.h"
#include "FixedTableLayout.h"
#include "RenderTable.h"
#include "RenderTableCell.h"
#include "RenderTableCol.h"
#include "RenderTableSection.h"
using namespace std;
namespace WebCore {
FixedTableLayout::FixedTableLayout(RenderTable* table)
: TableLayout(table)
{
}
static RenderObject* nextCol(RenderObject* child)
{
if (RenderObject* next = child->firstChild())
return next;
if (RenderObject* next = child->nextSibling())
return next;
if (child->parent()->isTableCol())
return child->parent()->nextSibling();
return 0;
}
int FixedTableLayout::calcWidthArray(int)
{
int usedWidth = 0;
unsigned nEffCols = m_table->numEffCols();
m_width.resize(nEffCols);
m_width.fill(Length(Auto));
unsigned currentEffectiveColumn = 0;
for (RenderObject* child = m_table->firstChild();child && child->isTableCol(); child = nextCol(child)) {
RenderTableCol* col = toRenderTableCol(child);
col->computePreferredLogicalWidths();
if (col->isTableColGroup())
continue;
Length colStyleLogicalWidth = col->style()->logicalWidth();
int effectiveColWidth = 0;
if (colStyleLogicalWidth.isFixed() && colStyleLogicalWidth.value() > 0)
effectiveColWidth = colStyleLogicalWidth.value();
unsigned span = col->span();
while (span) {
unsigned spanInCurrentEffectiveColumn;
if (currentEffectiveColumn >= nEffCols) {
m_table->appendColumn(span);
nEffCols++;
m_width.append(Length());
spanInCurrentEffectiveColumn = span;
} else {
if (span < m_table->spanOfEffCol(currentEffectiveColumn)) {
m_table->splitColumn(currentEffectiveColumn, span);
nEffCols++;
m_width.append(Length());
}
spanInCurrentEffectiveColumn = m_table->spanOfEffCol(currentEffectiveColumn);
}
if ((colStyleLogicalWidth.isFixed() || colStyleLogicalWidth.isPercent()) && colStyleLogicalWidth.isPositive()) {
m_width[currentEffectiveColumn] = colStyleLogicalWidth;
m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn;
usedWidth += effectiveColWidth * spanInCurrentEffectiveColumn;
}
span -= spanInCurrentEffectiveColumn;
currentEffectiveColumn++;
}
}
RenderTableSection* section = m_table->topNonEmptySection();
if (section) {
unsigned cCol = 0;
RenderObject* firstRow = section->firstChild();
RenderObject* child = firstRow->firstChild();
while (child) {
if (child->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(child);
if (cell->preferredLogicalWidthsDirty())
cell->computePreferredLogicalWidths();
Length w = cell->styleOrColLogicalWidth();
unsigned span = cell->colSpan();
int effectiveColWidth = 0;
if (w.isFixed() && w.isPositive()) {
w.setValue(w.value() + cell->borderAndPaddingLogicalWidth());
effectiveColWidth = w.value();
}
unsigned usedSpan = 0;
unsigned i = 0;
while (usedSpan < span && cCol + i < nEffCols) {
float eSpan = m_table->spanOfEffCol(cCol + i);
if (m_width[cCol + i].isAuto() && w.type() != Auto) {
m_width[cCol + i] = w;
m_width[cCol + i] *= eSpan / span;
usedWidth += effectiveColWidth * eSpan / span;
}
usedSpan += eSpan;
i++;
}
cCol += i;
}
child = child->nextSibling();
}
}
return usedWidth;
}
#define TABLE_MAX_WIDTH 15000
void FixedTableLayout::computePreferredLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth)
{
int bordersPaddingAndSpacing = m_table->bordersPaddingAndSpacingInRowDirection();
int tableLogicalWidth = m_table->style()->logicalWidth().isFixed() ? m_table->style()->logicalWidth().value() - bordersPaddingAndSpacing : 0;
int mw = calcWidthArray(tableLogicalWidth) + bordersPaddingAndSpacing;
minWidth = max(mw, tableLogicalWidth);
maxWidth = minWidth;
if (m_table->document()->inQuirksMode() && m_table->style()->logicalWidth().isPercent() && maxWidth < TABLE_MAX_WIDTH)
maxWidth = TABLE_MAX_WIDTH;
}
void FixedTableLayout::layout()
{
int tableLogicalWidth = m_table->logicalWidth() - m_table->bordersPaddingAndSpacingInRowDirection();
unsigned nEffCols = m_table->numEffCols();
if (nEffCols != m_width.size()) {
calcWidthArray(tableLogicalWidth);
nEffCols = m_table->numEffCols();
}
Vector<int> calcWidth(nEffCols, 0);
unsigned numAuto = 0;
unsigned autoSpan = 0;
int totalFixedWidth = 0;
int totalPercentWidth = 0;
float totalPercent = 0;
for (unsigned i = 0; i < nEffCols; i++) {
if (m_width[i].isFixed()) {
calcWidth[i] = m_width[i].value();
totalFixedWidth += calcWidth[i];
} else if (m_width[i].isPercent()) {
calcWidth[i] = valueForLength(m_width[i], tableLogicalWidth);
totalPercentWidth += calcWidth[i];
totalPercent += m_width[i].percent();
} else if (m_width[i].isAuto()) {
numAuto++;
autoSpan += m_table->spanOfEffCol(i);
}
}
int hspacing = m_table->hBorderSpacing();
int totalWidth = totalFixedWidth + totalPercentWidth;
if (!numAuto || totalWidth > tableLogicalWidth) {
if (totalWidth != tableLogicalWidth) {
if (totalFixedWidth && totalWidth < tableLogicalWidth) {
totalFixedWidth = 0;
for (unsigned i = 0; i < nEffCols; i++) {
if (m_width[i].isFixed()) {
calcWidth[i] = calcWidth[i] * tableLogicalWidth / totalWidth;
totalFixedWidth += calcWidth[i];
}
}
}
if (totalPercent) {
totalPercentWidth = 0;
for (unsigned i = 0; i < nEffCols; i++) {
if (m_width[i].isPercent()) {
calcWidth[i] = m_width[i].percent() * (tableLogicalWidth - totalFixedWidth) / totalPercent;
totalPercentWidth += calcWidth[i];
}
}
}
totalWidth = totalFixedWidth + totalPercentWidth;
}
} else {
ASSERT(autoSpan >= numAuto);
int remainingWidth = tableLogicalWidth - totalFixedWidth - totalPercentWidth - hspacing * (autoSpan - numAuto);
int lastAuto = 0;
for (unsigned i = 0; i < nEffCols; i++) {
if (m_width[i].isAuto()) {
unsigned span = m_table->spanOfEffCol(i);
int w = remainingWidth * span / autoSpan;
calcWidth[i] = w + hspacing * (span - 1);
remainingWidth -= w;
if (!remainingWidth)
break;
lastAuto = i;
numAuto--;
ASSERT(autoSpan >= span);
autoSpan -= span;
}
}
if (remainingWidth)
calcWidth[lastAuto] += remainingWidth;
totalWidth = tableLogicalWidth;
}
if (totalWidth < tableLogicalWidth) {
int remainingWidth = tableLogicalWidth - totalWidth;
int total = nEffCols;
while (total) {
int w = remainingWidth / total;
remainingWidth -= w;
calcWidth[--total] += w;
}
if (nEffCols > 0)
calcWidth[nEffCols - 1] += remainingWidth;
}
int pos = 0;
for (unsigned i = 0; i < nEffCols; i++) {
m_table->columnPositions()[i] = pos;
pos += calcWidth[i] + hspacing;
}
int colPositionsSize = m_table->columnPositions().size();
if (colPositionsSize > 0)
m_table->columnPositions()[colPositionsSize - 1] = pos;
}
}