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)
{
}
int FixedTableLayout::calcWidthArray(int)
{
int usedWidth = 0;
RenderObject* child = m_table->firstChild();
int nEffCols = m_table->numEffCols();
m_width.resize(nEffCols);
m_width.fill(Length(Auto));
int currentEffectiveColumn = 0;
Length grpWidth;
while (child && child->isTableCol()) {
RenderTableCol* col = toRenderTableCol(child);
if (col->firstChild())
grpWidth = col->style()->logicalWidth();
else {
Length w = col->style()->logicalWidth();
if (w.isAuto())
w = grpWidth;
int effWidth = 0;
if (w.isFixed() && w.value() > 0)
effWidth = w.value();
int span = col->span();
while (span) {
int 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 ((w.isFixed() || w.isPercent()) && w.isPositive()) {
m_width[currentEffectiveColumn] = w;
m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn;
usedWidth += effWidth * spanInCurrentEffectiveColumn;
}
span -= spanInCurrentEffectiveColumn;
currentEffectiveColumn++;
}
}
col->computePreferredLogicalWidths();
RenderObject* next = child->firstChild();
if (!next)
next = child->nextSibling();
if (!next && child->parent()->isTableCol()) {
next = child->parent()->nextSibling();
grpWidth = Length();
}
child = next;
}
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) {
int cCol = 0;
RenderObject* firstRow = section->firstChild();
child = firstRow->firstChild();
while (child) {
if (child->isTableCell()) {
RenderTableCell* cell = toRenderTableCell(child);
if (cell->preferredLogicalWidthsDirty())
cell->computePreferredLogicalWidths();
Length w = cell->styleOrColLogicalWidth();
int span = cell->colSpan();
int effWidth = 0;
if (w.isFixed() && w.isPositive())
effWidth = w.value();
int usedSpan = 0;
int 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 += effWidth * eSpan / span;
}
usedSpan += eSpan;
i++;
}
cCol += i;
}
child = child->nextSibling();
}
}
return usedWidth;
}
#define TABLE_MAX_WIDTH 15000
void FixedTableLayout::computePreferredLogicalWidths(int& minWidth, int& 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();
int nEffCols = m_table->numEffCols();
Vector<int> calcWidth(nEffCols, 0);
int numAuto = 0;
int autoSpan = 0;
int totalFixedWidth = 0;
int totalPercentWidth = 0;
float totalPercent = 0;
for (int 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] = m_width[i].calcValue(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 (int i = 0; i < nEffCols; i++) {
if (m_width[i].isFixed()) {
calcWidth[i] = calcWidth[i] * tableLogicalWidth / totalWidth;
totalFixedWidth += calcWidth[i];
}
}
}
if (totalPercent) {
totalPercentWidth = 0;
for (int 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 {
int remainingWidth = tableLogicalWidth - totalFixedWidth - totalPercentWidth - hspacing * (autoSpan - numAuto);
int lastAuto = 0;
for (int i = 0; i < nEffCols; i++) {
if (m_width[i].isAuto()) {
int span = m_table->spanOfEffCol(i);
int w = remainingWidth * span / autoSpan;
calcWidth[i] = w + hspacing * (span - 1);
remainingWidth -= w;
if (!remainingWidth)
break;
lastAuto = i;
numAuto--;
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 (int 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;
}
}