CSS 2.1 failure: table-columns-example-001 fails
[WebKit-https.git] / Source / WebCore / html / HTMLTableElement.cpp
index 59b063a..a22efa2 100644 (file)
@@ -4,7 +4,7 @@
  *           (C) 1998 Waldo Bastian (bastian@kde.org)
  *           (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010, 2011 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "HTMLTableElement.h"
 
 #include "Attribute.h"
+#include "CSSImageValue.h"
 #include "CSSPropertyNames.h"
 #include "CSSStyleSheet.h"
 #include "CSSValueKeywords.h"
+#include "CSSValuePool.h"
 #include "ExceptionCode.h"
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
@@ -185,13 +187,15 @@ PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec
         return 0;
     }
 
-    HTMLTableRowElement* lastRow = 0;
-    HTMLTableRowElement* row = 0;
+    RefPtr<Node> protectFromMutationEvents(this);
+
+    RefPtr<HTMLTableRowElement> lastRow = 0;
+    RefPtr<HTMLTableRowElement> row = 0;
     if (index == -1)
         lastRow = HTMLTableRowsCollection::lastRow(this);
     else {
         for (int i = 0; i <= index; ++i) {
-            row = HTMLTableRowsCollection::rowAfter(this, lastRow);
+            row = HTMLTableRowsCollection::rowAfter(this, lastRow.get());
             if (!row) {
                 if (i != index) {
                     ec = INDEX_SIZE_ERR;
@@ -203,7 +207,7 @@ PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec
         }
     }
 
-    ContainerNode* parent;
+    RefPtr<ContainerNode> parent;
     if (lastRow)
         parent = row ? row->parentNode() : lastRow->parentNode();
     else {
@@ -218,7 +222,7 @@ PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec
     }
 
     RefPtr<HTMLTableRowElement> newRow = HTMLTableRowElement::create(document());
-    parent->insertBefore(newRow, row, ec);
+    parent->insertBefore(newRow, row.get(), ec);
     return newRow.release();
 }
 
@@ -241,42 +245,6 @@ void HTMLTableElement::deleteRow(int index, ExceptionCode& ec)
     row->remove(ec);
 }
 
-bool HTMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
-{
-    if (attrName == backgroundAttr) {
-        result = (MappedAttributeEntry)(eLastEntry + document()->docID());
-        return false;
-    }
-    
-    if (attrName == widthAttr ||
-        attrName == heightAttr ||
-        attrName == bgcolorAttr ||
-        attrName == cellspacingAttr ||
-        attrName == vspaceAttr ||
-        attrName == hspaceAttr ||
-        attrName == valignAttr) {
-        result = eUniversal;
-        return false;
-    }
-    
-    if (attrName == bordercolorAttr || attrName == frameAttr || attrName == rulesAttr) {
-        result = eUniversal;
-        return true;
-    }
-    
-    if (attrName == borderAttr) {
-        result = eTable;
-        return true;
-    }
-    
-    if (attrName == alignAttr) {
-        result = eTable;
-        return false;
-    }
-
-    return HTMLElement::mapToEntry(attrName, result);
-}
-
 static inline bool isTableCellAncestor(Node* n)
 {
     return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) ||
@@ -302,93 +270,118 @@ static bool setTableCellsChanged(Node* n)
     return cellChanged;
 }
 
-void HTMLTableElement::parseMappedAttribute(Attribute* attr)
-{
-    CellBorders bordersBefore = cellBorders();
-    unsigned short oldPadding = m_padding;
+static bool getBordersFromFrameAttributeValue(const AtomicString& value, bool& borderTop, bool& borderRight, bool& borderBottom, bool& borderLeft)
+{
+    borderTop = false;
+    borderRight = false;
+    borderBottom = false;
+    borderLeft = false;
+
+    if (equalIgnoringCase(value, "above"))
+        borderTop = true;
+    else if (equalIgnoringCase(value, "below"))
+        borderBottom = true;
+    else if (equalIgnoringCase(value, "hsides"))
+        borderTop = borderBottom = true;
+    else if (equalIgnoringCase(value, "vsides"))
+        borderLeft = borderRight = true;
+    else if (equalIgnoringCase(value, "lhs"))
+        borderLeft = true;
+    else if (equalIgnoringCase(value, "rhs"))
+        borderRight = true;
+    else if (equalIgnoringCase(value, "box") || equalIgnoringCase(value, "border"))
+        borderTop = borderBottom = borderLeft = borderRight = true;
+    else if (!equalIgnoringCase(value, "void"))
+        return false;
+    return true;
+}
 
+void HTMLTableElement::collectStyleForAttribute(Attribute* attr, StylePropertySet* style)
+{
     if (attr->name() == widthAttr)
-        addCSSLength(attr, CSSPropertyWidth, attr->value());
+        addHTMLLengthToStyle(style, CSSPropertyWidth, attr->value());
     else if (attr->name() == heightAttr)
-        addCSSLength(attr, CSSPropertyHeight, attr->value());
-    else if (attr->name() == borderAttr)  {
-        m_borderAttr = true;
-        if (attr->decl()) {
-            RefPtr<CSSValue> val = attr->decl()->getPropertyCSSValue(CSSPropertyBorderLeftWidth);
-            if (val && val->isPrimitiveValue()) {
-                CSSPrimitiveValue* primVal = static_cast<CSSPrimitiveValue*>(val.get());
-                m_borderAttr = primVal->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER);
-            }
-        } else if (!attr->isNull()) {
-            int border = 0;
-            if (attr->isEmpty())
-                border = 1;
-            else
-                border = attr->value().toInt();
-            m_borderAttr = border;
-            addCSSLength(attr, CSSPropertyBorderWidth, String::number(border));
-        }
+        addHTMLLengthToStyle(style, CSSPropertyHeight, attr->value());
+    else if (attr->name() == borderAttr) {
+        int borderWidth = attr->isEmpty() ? 1 : attr->value().toInt();
+        addPropertyToAttributeStyle(style, CSSPropertyBorderWidth, borderWidth, CSSPrimitiveValue::CSS_PX);
+    } else if (attr->name() == bordercolorAttr) {
+        if (!attr->isEmpty())
+            addHTMLColorToStyle(style, CSSPropertyBorderColor, attr->value());
     } else if (attr->name() == bgcolorAttr)
-        addCSSColor(attr, CSSPropertyBackgroundColor, attr->value());
-    else if (attr->name() == bordercolorAttr) {
-        m_borderColorAttr = attr->decl();
-        if (!attr->decl() && !attr->isEmpty()) {
-            addCSSColor(attr, CSSPropertyBorderColor, attr->value());
-            m_borderColorAttr = true;
-        }
-    } else if (attr->name() == backgroundAttr) {
+        addHTMLColorToStyle(style, CSSPropertyBackgroundColor, attr->value());
+    else if (attr->name() == backgroundAttr) {
         String url = stripLeadingAndTrailingHTMLSpaces(attr->value());
         if (!url.isEmpty())
-            addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string());
+            style->setProperty(CSSProperty(CSSPropertyBackgroundImage, CSSImageValue::create(document()->completeURL(url).string())));
+    } else if (attr->name() == valignAttr) {
+        if (!attr->isEmpty())
+            addPropertyToAttributeStyle(style, CSSPropertyVerticalAlign, attr->value());
+    } else if (attr->name() == cellspacingAttr) {
+        if (!attr->isEmpty())
+            addHTMLLengthToStyle(style, CSSPropertyBorderSpacing, attr->value());
+    } else if (attr->name() == vspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginTop, attr->value());
+        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, attr->value());
+    } else if (attr->name() == hspaceAttr) {
+        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, attr->value());
+        addHTMLLengthToStyle(style, CSSPropertyMarginRight, attr->value());
+    } else if (attr->name() == alignAttr) {
+        if (!attr->value().isEmpty()) {
+            if (equalIgnoringCase(attr->value(), "center")) {
+                addPropertyToAttributeStyle(style, CSSPropertyWebkitMarginStart, CSSValueAuto);
+                addPropertyToAttributeStyle(style, CSSPropertyWebkitMarginEnd, CSSValueAuto);
+            } else
+                addPropertyToAttributeStyle(style, CSSPropertyFloat, attr->value());
+        }
+    } else if (attr->name() == rulesAttr) {
+        // The presence of a valid rules attribute causes border collapsing to be enabled.
+        if (m_rulesAttr != UnsetRules)
+            addPropertyToAttributeStyle(style, CSSPropertyBorderCollapse, CSSValueCollapse);
     } else if (attr->name() == frameAttr) {
-        // Cache the value of "frame" so that the table can examine it later.
-        m_frameAttr = false;
-        
-        // Whether or not to hide the top/right/bottom/left borders.
-        const int cTop = 0;
-        const int cRight = 1;
-        const int cBottom = 2;
-        const int cLeft = 3;
-        bool borders[4] = { false, false, false, false };
-        
-        // void, above, below, hsides, vsides, lhs, rhs, box, border
-        if (equalIgnoringCase(attr->value(), "void"))
-            m_frameAttr = true;
-        else if (equalIgnoringCase(attr->value(), "above")) {
-            m_frameAttr = true;
-            borders[cTop] = true;
-        } else if (equalIgnoringCase(attr->value(), "below")) {
-            m_frameAttr = true;
-            borders[cBottom] = true;
-        } else if (equalIgnoringCase(attr->value(), "hsides")) {
-            m_frameAttr = true;
-            borders[cTop] = borders[cBottom] = true;
-        } else if (equalIgnoringCase(attr->value(), "vsides")) {
-            m_frameAttr = true;
-            borders[cLeft] = borders[cRight] = true;
-        } else if (equalIgnoringCase(attr->value(), "lhs")) {
-            m_frameAttr = true;
-            borders[cLeft] = true;
-        } else if (equalIgnoringCase(attr->value(), "rhs")) {
-            m_frameAttr = true;
-            borders[cRight] = true;
-        } else if (equalIgnoringCase(attr->value(), "box") ||
-                   equalIgnoringCase(attr->value(), "border")) {
-            m_frameAttr = true;
-            borders[cTop] = borders[cBottom] = borders[cLeft] = borders[cRight] = true;
+        bool borderTop;
+        bool borderRight;
+        bool borderBottom;
+        bool borderLeft;
+        if (getBordersFromFrameAttributeValue(attr->value(), borderTop, borderRight, borderBottom, borderLeft)) {
+            addPropertyToAttributeStyle(style, CSSPropertyBorderWidth, CSSValueThin);
+            addPropertyToAttributeStyle(style, CSSPropertyBorderTopStyle, borderTop ? CSSValueSolid : CSSValueHidden);
+            addPropertyToAttributeStyle(style, CSSPropertyBorderBottomStyle, borderBottom ? CSSValueSolid : CSSValueHidden);
+            addPropertyToAttributeStyle(style, CSSPropertyBorderLeftStyle, borderLeft ? CSSValueSolid : CSSValueHidden);
+            addPropertyToAttributeStyle(style, CSSPropertyBorderRightStyle, borderRight ? CSSValueSolid : CSSValueHidden);
         }
-        
-        // Now map in the border styles of solid and hidden respectively.
-        if (m_frameAttr) {
-            addCSSProperty(attr, CSSPropertyBorderTopWidth, CSSValueThin);
-            addCSSProperty(attr, CSSPropertyBorderBottomWidth, CSSValueThin);
-            addCSSProperty(attr, CSSPropertyBorderLeftWidth, CSSValueThin);
-            addCSSProperty(attr, CSSPropertyBorderRightWidth, CSSValueThin);
-            addCSSProperty(attr, CSSPropertyBorderTopStyle, borders[cTop] ? CSSValueSolid : CSSValueHidden);
-            addCSSProperty(attr, CSSPropertyBorderBottomStyle, borders[cBottom] ? CSSValueSolid : CSSValueHidden);
-            addCSSProperty(attr, CSSPropertyBorderLeftStyle, borders[cLeft] ? CSSValueSolid : CSSValueHidden);
-            addCSSProperty(attr, CSSPropertyBorderRightStyle, borders[cRight] ? CSSValueSolid : CSSValueHidden);
+    } else
+        HTMLElement::collectStyleForAttribute(attr, style);
+}
+
+bool HTMLTableElement::isPresentationAttribute(const QualifiedName& name) const
+{
+    if (name == widthAttr || name == heightAttr || name == bgcolorAttr || name == backgroundAttr || name == valignAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == cellspacingAttr || name == borderAttr || name == bordercolorAttr || name == frameAttr || name == rulesAttr)
+        return true;
+    return HTMLElement::isPresentationAttribute(name);
+}
+
+void HTMLTableElement::parseAttribute(Attribute* attr)
+{
+    CellBorders bordersBefore = cellBorders();
+    unsigned short oldPadding = m_padding;
+
+    if (attr->name() == borderAttr)  {
+        // FIXME: This attribute is a mess.
+        m_borderAttr = true;
+        if (!attr->isNull()) {
+            int border = attr->isEmpty() ? 1 : attr->value().toInt();
+            m_borderAttr = border;
         }
+    } else if (attr->name() == bordercolorAttr) {
+        m_borderColorAttr = !attr->isEmpty();
+    } else if (attr->name() == frameAttr) {
+        // FIXME: This attribute is a mess.
+        bool borderTop;
+        bool borderRight;
+        bool borderBottom;
+        bool borderLeft;
+        m_frameAttr = getBordersFromFrameAttributeValue(attr->value(), borderTop, borderRight, borderBottom, borderLeft);
     } else if (attr->name() == rulesAttr) {
         m_rulesAttr = UnsetRules;
         if (equalIgnoringCase(attr->value(), "none"))
@@ -401,13 +394,6 @@ void HTMLTableElement::parseMappedAttribute(Attribute* attr)
             m_rulesAttr = ColsRules;
         if (equalIgnoringCase(attr->value(), "all"))
             m_rulesAttr = AllRules;
-        
-        // The presence of a valid rules attribute causes border collapsing to be enabled.
-        if (m_rulesAttr != UnsetRules)
-            addCSSProperty(attr, CSSPropertyBorderCollapse, CSSValueCollapse);
-    } else if (attr->name() == cellspacingAttr) {
-        if (!attr->value().isEmpty())
-            addCSSLength(attr, CSSPropertyBorderSpacing, attr->value());
     } else if (attr->name() == cellpaddingAttr) {
         if (!attr->value().isEmpty())
             m_padding = max(0, attr->value().toInt());
@@ -415,29 +401,11 @@ void HTMLTableElement::parseMappedAttribute(Attribute* attr)
             m_padding = 1;
     } else if (attr->name() == colsAttr) {
         // ###
-    } else if (attr->name() == vspaceAttr) {
-        addCSSLength(attr, CSSPropertyMarginTop, attr->value());
-        addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
-    } else if (attr->name() == hspaceAttr) {
-        addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
-        addCSSLength(attr, CSSPropertyMarginRight, attr->value());
-    } else if (attr->name() == alignAttr) {
-        if (!attr->value().isEmpty()) {
-            if (equalIgnoringCase(attr->value(), "center")) {
-                addCSSProperty(attr, CSSPropertyWebkitMarginStart, CSSValueAuto);
-                addCSSProperty(attr, CSSPropertyWebkitMarginEnd, CSSValueAuto);
-            } else
-                addCSSProperty(attr, CSSPropertyFloat, attr->value());
-        }
-    } else if (attr->name() == valignAttr) {
-        if (!attr->value().isEmpty())
-            addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value());
     } else
-        HTMLElement::parseMappedAttribute(attr);
+        HTMLElement::parseAttribute(attr);
 
     if (bordersBefore != cellBorders() || oldPadding != m_padding) {
-        if (oldPadding != m_padding)
-            m_paddingDecl = 0;
+        m_sharedCellStyle = 0;
         bool cellChanged = false;
         for (Node* child = firstChild(); child; child = child->nextSibling())
             cellChanged |= setTableCellsChanged(child);
@@ -446,33 +414,37 @@ void HTMLTableElement::parseMappedAttribute(Attribute* attr)
     }
 }
 
-void HTMLTableElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results)
+static StylePropertySet* leakBorderStyle(int value)
 {
-    if ((!m_borderAttr && !m_borderColorAttr) || m_frameAttr)
-        return;
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+    style->setProperty(CSSPropertyBorderTopStyle, value);
+    style->setProperty(CSSPropertyBorderBottomStyle, value);
+    style->setProperty(CSSPropertyBorderLeftStyle, value);
+    style->setProperty(CSSPropertyBorderRightStyle, value);
+    return style.release().leakRef();
+}
 
-    AtomicString borderValue = m_borderColorAttr ? "solid" : "outset";
-    CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, tableborderAttr, borderValue);
-    if (!decl) {
-        decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
-        decl->setParent(document()->elementSheet());
-        decl->setNode(this);
-        decl->setStrictParsing(false); // Mapped attributes are just always quirky.
-        
-        int v = m_borderColorAttr ? CSSValueSolid : CSSValueOutset;
-        decl->setProperty(CSSPropertyBorderTopStyle, v, false);
-        decl->setProperty(CSSPropertyBorderBottomStyle, v, false);
-        decl->setProperty(CSSPropertyBorderLeftStyle, v, false);
-        decl->setProperty(CSSPropertyBorderRightStyle, v, false);
-
-        setMappedAttributeDecl(ePersistent, tableborderAttr, borderValue, decl);
-        decl->setParent(0);
-        decl->setNode(0);
-        decl->setMappedState(ePersistent, tableborderAttr, borderValue);
-    }
-    
+StylePropertySet* HTMLTableElement::additionalAttributeStyle()
+{
+    if (m_frameAttr)
+        return 0;
     
-    results.append(decl);
+    if (!m_borderAttr && !m_borderColorAttr) {
+        // Setting the border to 'hidden' allows it to win over any border
+        // set on the table's cells during border-conflict resolution.
+        if (m_rulesAttr != UnsetRules) {
+            static StylePropertySet* solidBorderStyle = leakBorderStyle(CSSValueHidden);
+            return solidBorderStyle;
+        }
+        return 0;
+    }
+
+    if (m_borderColorAttr) {
+        static StylePropertySet* solidBorderStyle = leakBorderStyle(CSSValueSolid);
+        return solidBorderStyle;
+    }
+    static StylePropertySet* outsetBorderStyle = leakBorderStyle(CSSValueOutset);
+    return outsetBorderStyle;
 }
 
 HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
@@ -498,159 +470,98 @@ HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
     return NoBorders;
 }
 
-void HTMLTableElement::addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>& results)
-{
-    addSharedCellBordersDecl(results);
-    addSharedCellPaddingDecl(results);
-}
-
-void HTMLTableElement::addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>& results)
-{
-    CellBorders borders = cellBorders();
+PassRefPtr<StylePropertySet> HTMLTableElement::createSharedCellStyle()
+{
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+
+    switch (cellBorders()) {
+    case SolidBordersColsOnly:
+        style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case SolidBordersRowsOnly:
+        style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case SolidBorders:
+        style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
+        style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueSolid));
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case InsetBorders:
+        style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
+        style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueInset));
+        style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
+        break;
+    case NoBorders:
+        style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PX));
+        break;
+    }
 
-    static const AtomicString* cellBorderNames[] = { new AtomicString("none"), new AtomicString("solid"), new AtomicString("inset"), new AtomicString("solid-cols"), new AtomicString("solid-rows") };
-    const AtomicString& cellborderValue = *cellBorderNames[borders];
-    CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, cellborderAttr, cellborderValue);
-    if (!decl) {
-        decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
-        decl->setParent(document()->elementSheet());
-        decl->setNode(this);
-        decl->setStrictParsing(false); // Mapped attributes are just always quirky.
-        
-        switch (borders) {
-            case SolidBordersColsOnly:
-                decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
-                decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
-                decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderColor, "inherit", false);
-                break;
-            case SolidBordersRowsOnly:
-                decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
-                decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
-                decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderColor, "inherit", false);
-                break;
-            case SolidBorders:
-                decl->setProperty(CSSPropertyBorderWidth, "1px", false);
-                decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
-                decl->setProperty(CSSPropertyBorderColor, "inherit", false);
-                break;
-            case InsetBorders:
-                decl->setProperty(CSSPropertyBorderWidth, "1px", false);
-                decl->setProperty(CSSPropertyBorderTopStyle, CSSValueInset, false);
-                decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueInset, false);
-                decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueInset, false);
-                decl->setProperty(CSSPropertyBorderRightStyle, CSSValueInset, false);
-                decl->setProperty(CSSPropertyBorderColor, "inherit", false);
-                break;
-            case NoBorders:
-                decl->setProperty(CSSPropertyBorderWidth, "0", false);
-                break;
-        }
+    if (m_padding)
+        style->setProperty(CSSPropertyPadding, cssValuePool().createValue(m_padding, CSSPrimitiveValue::CSS_PX));
 
-        setMappedAttributeDecl(ePersistent, cellborderAttr, *cellBorderNames[borders], decl);
-        decl->setParent(0);
-        decl->setNode(0);
-        decl->setMappedState(ePersistent, cellborderAttr, cellborderValue);
-    }
-    
-    results.append(decl);
+    return style.release();
 }
 
-void HTMLTableElement::addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>& results)
+StylePropertySet* HTMLTableElement::additionalCellStyle()
 {
-    if (m_padding == 0)
-        return;
-
-    if (!m_paddingDecl) {
-        String paddingValue = String::number(m_padding);
-        m_paddingDecl = getMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue);
-        if (!m_paddingDecl) {
-            m_paddingDecl = CSSMappedAttributeDeclaration::create();
-            m_paddingDecl->setParent(document()->elementSheet());
-            m_paddingDecl->setNode(this);
-            m_paddingDecl->setStrictParsing(false); // Mapped attributes are just always quirky.
-            
-            m_paddingDecl->setProperty(CSSPropertyPaddingTop, paddingValue, false);
-            m_paddingDecl->setProperty(CSSPropertyPaddingRight, paddingValue, false);
-            m_paddingDecl->setProperty(CSSPropertyPaddingBottom, paddingValue, false);
-            m_paddingDecl->setProperty(CSSPropertyPaddingLeft, paddingValue, false);
-        }
-        setMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue, m_paddingDecl.get());
-        m_paddingDecl->setParent(0);
-        m_paddingDecl->setNode(0);
-        m_paddingDecl->setMappedState(eUniversal, cellpaddingAttr, paddingValue);
-    }
-    
-    results.append(m_paddingDecl.get());
+    if (!m_sharedCellStyle)
+        m_sharedCellStyle = createSharedCellStyle();
+    return m_sharedCellStyle.get();
 }
 
-void HTMLTableElement::addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>& results)
+static StylePropertySet* leakGroupBorderStyle(int rows)
 {
-    if (m_rulesAttr != GroupsRules)
-        return;
-
-    AtomicString rulesValue = rows ? "rowgroups" : "colgroups";
-    CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, rulesAttr, rulesValue);
-    if (!decl) {
-        decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
-        decl->setParent(document()->elementSheet());
-        decl->setNode(this);
-        decl->setStrictParsing(false); // Mapped attributes are just always quirky.
-        
-        if (rows) {
-            decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
-            decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
-            decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
-            decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
-        } else {
-            decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
-            decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
-            decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
-            decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
-        }
-
-        setMappedAttributeDecl(ePersistent, rulesAttr, rulesValue, decl);
-        decl->setParent(0);
-        decl->setNode(0);
-        decl->setMappedState(ePersistent, rulesAttr, rulesValue);
+    RefPtr<StylePropertySet> style = StylePropertySet::create();
+    if (rows) {
+        style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
+    } else {
+        style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
+        style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
+        style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
     }
-
-    results.append(decl);
+    return style.release().leakRef();
 }
 
-CollectionCache* HTMLTableElement::collectionCache() const
+StylePropertySet* HTMLTableElement::additionalGroupStyle(bool rows)
 {
-    if (!m_collectionCache)
-        m_collectionCache = adoptPtr(new CollectionCache());
-
-    return m_collectionCache.get();
-}
+    if (m_rulesAttr != GroupsRules)
+        return 0;
 
-void HTMLTableElement::attach()
-{
-    ASSERT(!attached());
-    HTMLElement::attach();
+    if (rows) {
+        static StylePropertySet* rowBorderStyle = leakGroupBorderStyle(true);
+        return rowBorderStyle;
+    }
+    static StylePropertySet* columnBorderStyle = leakGroupBorderStyle(false);
+    return columnBorderStyle;
 }
 
 bool HTMLTableElement::isURLAttribute(Attribute *attr) const
 {
-    return attr->name() == backgroundAttr;
+    return attr->name() == backgroundAttr || HTMLElement::isURLAttribute(attr);
 }
 
-PassRefPtr<HTMLCollection> HTMLTableElement::rows()
+HTMLCollection* HTMLTableElement::rows()
 {
-    return HTMLTableRowsCollection::create(this);
+    if (!m_rowsCollection)
+        m_rowsCollection = HTMLTableRowsCollection::create(this);
+    return m_rowsCollection.get();
 }
 
-PassRefPtr<HTMLCollection> HTMLTableElement::tBodies()
+HTMLCollection* HTMLTableElement::tBodies()
 {
-    return HTMLCollection::create(this, TableTBodies);
+    return ensureCachedHTMLCollection(TableTBodies);
 }
 
 String HTMLTableElement::rules() const