summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering/FixedTableLayout.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/rendering/FixedTableLayout.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/rendering/FixedTableLayout.cpp')
-rw-r--r--Source/WebCore/rendering/FixedTableLayout.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/FixedTableLayout.cpp b/Source/WebCore/rendering/FixedTableLayout.cpp
new file mode 100644
index 0000000..3285d15
--- /dev/null
+++ b/Source/WebCore/rendering/FixedTableLayout.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2002 Lars Knoll (knoll@kde.org)
+ * (C) 2002 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FixedTableLayout.h"
+
+#include "RenderTable.h"
+#include "RenderTableCell.h"
+#include "RenderTableCol.h"
+#include "RenderTableSection.h"
+
+/*
+ The text below is from the CSS 2.1 specs.
+
+ Fixed table layout
+
+ With this (fast) algorithm, the horizontal layout of the table does
+ not depend on the contents of the cells; it only depends on the
+ table's width, the width of the columns, and borders or cell
+ spacing.
+
+ The table's width may be specified explicitly with the 'width'
+ property. A value of 'auto' (for both 'display: table' and 'display:
+ inline-table') means use the automatic table layout algorithm.
+
+ In the fixed table layout algorithm, the width of each column is
+ determined as follows:
+
+ 1. A column element with a value other than 'auto' for the 'width'
+ property sets the width for that column.
+
+ 2. Otherwise, a cell in the first row with a value other than
+ 'auto' for the 'width' property sets the width for that column. If
+ the cell spans more than one column, the width is divided over the
+ columns.
+
+ 3. Any remaining columns equally divide the remaining horizontal
+ table space (minus borders or cell spacing).
+
+ The width of the table is then the greater of the value of the
+ 'width' property for the table element and the sum of the column
+ widths (plus cell spacing or borders). If the table is wider than
+ the columns, the extra space should be distributed over the columns.
+
+
+ In this manner, the user agent can begin to lay out the table once
+ the entire first row has been received. Cells in subsequent rows do
+ not affect column widths. Any cell that has content that overflows
+ uses the 'overflow' property to determine whether to clip the
+ overflow content.
+*/
+
+using namespace std;
+
+namespace WebCore {
+
+FixedTableLayout::FixedTableLayout(RenderTable* table)
+ : TableLayout(table)
+{
+}
+
+int FixedTableLayout::calcWidthArray(int)
+{
+ int usedWidth = 0;
+
+ // iterate over all <col> elements
+ 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].setRawValue(w.type(), w.rawValue() * 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;
+ }
+
+ // 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) {
+ 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) {
+ 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;
+}
+
+// Use a very large value (in effect infinite). But not too large!
+// numeric_limits<int>::max() will too easily overflow widths.
+// Keep this in synch with BLOCK_MAX_WIDTH in RenderBlock.cpp
+#define TABLE_MAX_WIDTH 15000
+
+void FixedTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth)
+{
+ // FIXME: This entire calculation is incorrect for both minwidth and maxwidth.
+
+ // we might want to wait until we have all of the first row before
+ // layouting for the first time.
+
+ // only need to calculate the minimum width as the sum of the
+ // cols/cells with a fixed width.
+ //
+ // The maximum width is max(minWidth, tableWidth).
+ 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;
+
+ // This quirk is very similar to one that exists in RenderBlock::calcBlockPrefWidths().
+ // Here's the example for this one:
+ /*
+ <table style="width:100%; background-color:red"><tr><td>
+ <table style="background-color:blue"><tr><td>
+ <table style="width:100%; background-color:green; table-layout:fixed"><tr><td>
+ Content
+ </td></tr></table>
+ </td></tr></table>
+ </td></tr></table>
+ */
+ // In this example, the two inner tables should be as large as the outer table.
+ // We can achieve this effect by making the maxwidth of fixed tables with percentage
+ // widths be infinite.
+ 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;
+ int totalRawPercent = 0;
+
+ // Compute requirements and try to satisfy fixed and percent widths.
+ // Percentages are of the table's width, so for example
+ // for a table width of 100px with columns (40px, 10%), the 10% compute
+ // to 10px here, and will scale up to 20px in the final (80px, 20px).
+ 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];
+ totalRawPercent += m_width[i].rawValue();
+ } 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 there are no auto columns, or if the total is too wide, take
+ // what we have and scale it to fit as necessary.
+ if (totalWidth != tableLogicalWidth) {
+ // Fixed widths only scale up
+ 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 (totalRawPercent) {
+ totalPercentWidth = 0;
+ for (int i = 0; i < nEffCols; i++) {
+ if (m_width[i].isPercent()) {
+ calcWidth[i] = m_width[i].rawValue() * (tableLogicalWidth - totalFixedWidth) / totalRawPercent;
+ totalPercentWidth += calcWidth[i];
+ }
+ }
+ }
+ totalWidth = totalFixedWidth + totalPercentWidth;
+ }
+ } else {
+ // Divide the remaining width among the auto columns.
+ 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;
+ }
+ }
+ // Last one gets the remainder.
+ if (remainingWidth)
+ calcWidth[lastAuto] += remainingWidth;
+ totalWidth = tableLogicalWidth;
+ }
+
+ if (totalWidth < tableLogicalWidth) {
+ // Spread extra space over columns.
+ 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;
+}
+
+} // namespace WebCore