summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp b/src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp
new file mode 100644
index 0000000..f241f46
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/wml/WMLTableElement.cpp
@@ -0,0 +1,269 @@
+/**
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * 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, or (at your option) any later version.
+ *
+ * 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"
+
+#if ENABLE(WML)
+#include "WMLTableElement.h"
+
+#include "CharacterNames.h"
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "NodeList.h"
+#include "RenderObject.h"
+#include "Text.h"
+#include "WMLErrorHandling.h"
+#include "WMLNames.h"
+
+namespace WebCore {
+
+using namespace WMLNames;
+
+WMLTableElement::WMLTableElement(const QualifiedName& tagName, Document* doc)
+ : WMLElement(tagName, doc)
+ , m_columns(0)
+{
+}
+
+WMLTableElement::~WMLTableElement()
+{
+}
+
+bool WMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
+{
+ if (attrName == HTMLNames::alignAttr) {
+ result = eTable;
+ return false;
+ }
+
+ return WMLElement::mapToEntry(attrName, result);
+}
+
+void WMLTableElement::parseMappedAttribute(MappedAttribute* attr)
+{
+ if (attr->name() == columnsAttr) {
+ bool isNumber = false;
+ m_columns = attr->value().string().toUIntStrict(&isNumber);
+
+ // Spec: This required attribute specifies the number of columns for the table.
+ // The user agent must create a table with exactly the number of columns specified
+ // by the attribute value. It is an error to specify a value of zero (“0”).
+ if (!m_columns || !isNumber)
+ reportWMLError(document(), WMLErrorInvalidColumnsNumberInTable);
+ } else if (attr->name() == HTMLNames::alignAttr)
+ m_alignment = parseValueForbiddingVariableReferences(attr->value());
+ else
+ WMLElement::parseMappedAttribute(attr);
+}
+
+void WMLTableElement::finishParsingChildren()
+{
+ WMLElement::finishParsingChildren();
+
+ if (!m_columns) {
+ reportWMLError(document(), WMLErrorInvalidColumnsNumberInTable);
+ return;
+ }
+
+ Vector<WMLElement*> rowElements = scanTableChildElements(this, trTag);
+ if (rowElements.isEmpty())
+ return;
+
+ Vector<WMLElement*>::iterator it = rowElements.begin();
+ Vector<WMLElement*>::iterator end = rowElements.end();
+
+ for (; it != end; ++it) {
+ WMLElement* rowElement = (*it);
+
+ // Squeeze the table to fit in the desired number of columns
+ Vector<WMLElement*> columnElements = scanTableChildElements(rowElement, tdTag);
+ unsigned actualNumberOfColumns = columnElements.size();
+
+ if (actualNumberOfColumns > m_columns) {
+ joinSuperflousColumns(columnElements, rowElement);
+ columnElements = scanTableChildElements(rowElement, tdTag);
+ } else if (actualNumberOfColumns < m_columns) {
+ padWithEmptyColumns(columnElements, rowElement);
+ columnElements = scanTableChildElements(rowElement, tdTag);
+ }
+
+ // Layout cells according to the 'align' attribute
+ alignCells(columnElements, rowElement);
+ }
+}
+
+Vector<WMLElement*> WMLTableElement::scanTableChildElements(WMLElement* startElement, const QualifiedName& tagName) const
+{
+ Vector<WMLElement*> childElements;
+
+ RefPtr<NodeList> children = startElement->childNodes();
+ if (!children)
+ return childElements;
+
+ unsigned length = children->length();
+ for (unsigned i = 0; i < length; ++i) {
+ Node* child = children->item(i);
+ if (child->hasTagName(tagName))
+ childElements.append(static_cast<WMLElement*>(child));
+ }
+
+ return childElements;
+}
+
+void WMLTableElement::transferAllChildrenOfElementToTargetElement(WMLElement* sourceElement, WMLElement* targetElement, unsigned startOffset) const
+{
+ RefPtr<NodeList> children = sourceElement->childNodes();
+ if (!children)
+ return;
+
+ ExceptionCode ec = 0;
+
+ unsigned length = children->length();
+ for (unsigned i = startOffset; i < length; ++i) {
+ RefPtr<Node> clonedNode = children->item(i)->cloneNode(true);
+ targetElement->appendChild(clonedNode.release(), ec);
+ ASSERT(ec == 0);
+ }
+}
+
+bool WMLTableElement::tryMergeAdjacentTextCells(Node* item, Node* nextItem) const
+{
+ if (!item || !nextItem)
+ return false;
+
+ if (!item->isTextNode() || !nextItem->isTextNode())
+ return false;
+
+ Text* itemText = static_cast<Text*>(item);
+ Text* nextItemText = static_cast<Text*>(nextItem);
+
+ String newContent = " ";
+ newContent += nextItemText->data();
+
+ ExceptionCode ec = 0;
+ itemText->appendData(newContent, ec);
+ ASSERT(ec == 0);
+
+ return true;
+}
+
+void WMLTableElement::joinSuperflousColumns(Vector<WMLElement*>& columnElements, WMLElement* rowElement) const
+{
+ // Spec: If the actual number of columns in a row is greater than the value specified
+ // by this attribute, the extra columns of the row must be aggregated into the last
+ // column such that the row contains exactly the number of columns specified.
+ WMLElement* lastColumn = columnElements.at(m_columns - 1);
+ ASSERT(lastColumn);
+
+ // Merge superflous columns into a single one
+ RefPtr<WMLElement> newCell = new WMLElement(tdTag, document());
+ transferAllChildrenOfElementToTargetElement(lastColumn, newCell.get(), 0);
+
+ ExceptionCode ec = 0;
+ unsigned actualNumberOfColumns = columnElements.size();
+
+ for (unsigned i = m_columns; i < actualNumberOfColumns; ++i) {
+ WMLElement* columnElement = columnElements.at(i);
+ unsigned startOffset = 0;
+
+ // Spec: A single inter-word space must be inserted between two cells that are being aggregated.
+ if (tryMergeAdjacentTextCells(newCell->lastChild(), columnElement->firstChild()))
+ ++startOffset;
+
+ transferAllChildrenOfElementToTargetElement(columnElement, newCell.get(), startOffset);
+ }
+
+ // Remove the columns, that have just been merged
+ unsigned i = actualNumberOfColumns;
+ for (; i > m_columns; --i) {
+ rowElement->removeChild(columnElements.at(i - 1), ec);
+ ASSERT(ec == 0);
+ }
+
+ // Replace the last column in the row with the new merged column
+ rowElement->replaceChild(newCell.release(), lastColumn, ec);
+ ASSERT(ec == 0);
+}
+
+void WMLTableElement::padWithEmptyColumns(Vector<WMLElement*>& columnElements, WMLElement* rowElement) const
+{
+ // Spec: If the actual number of columns in a row is less than the value specified by the columns
+ // attribute, the row must be padded with empty columns effectively as if the user agent
+ // appended empty td elements to the row.
+ ExceptionCode ec = 0;
+
+ for (unsigned i = columnElements.size(); i < m_columns; ++i) {
+ RefPtr<WMLElement> newCell = new WMLElement(tdTag, document());
+ rowElement->appendChild(newCell.release(), ec);
+ ASSERT(ec == 0);
+ }
+}
+
+void WMLTableElement::alignCells(Vector<WMLElement*>& columnElements, WMLElement* rowElement) const
+{
+ // Spec: User agents should consider the current language when determining
+ // the default alignment and the direction of the table.
+ bool rtl = false;
+ if (RenderObject* renderer = rowElement->renderer()) {
+ if (RenderStyle* style = renderer->style())
+ rtl = style->direction() == RTL;
+ }
+
+ rowElement->setAttribute(HTMLNames::alignAttr, rtl ? "right" : "left");
+
+ if (m_alignment.isEmpty())
+ return;
+
+ unsigned alignLength = m_alignment.length();
+
+ Vector<WMLElement*>::iterator it = columnElements.begin();
+ Vector<WMLElement*>::iterator end = columnElements.end();
+
+ for (unsigned i = 0; it != end; ++it, ++i) {
+ if (i == alignLength)
+ break;
+
+ String alignmentValue;
+ switch (m_alignment[i]) {
+ case 'C':
+ alignmentValue = "center";
+ break;
+ case 'L':
+ alignmentValue = "left";
+ break;
+ case 'R':
+ alignmentValue = "right";
+ break;
+ default:
+ break;
+ }
+
+ if (alignmentValue.isEmpty())
+ continue;
+
+ (*it)->setAttribute(HTMLNames::alignAttr, alignmentValue);
+ }
+}
+
+}
+
+#endif