Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1997 Martin Jones (mjones (at) kde.org)
      3  *           (C) 1997 Torben Weis (weis (at) kde.org)
      4  *           (C) 1998 Waldo Bastian (bastian (at) kde.org)
      5  *           (C) 1999 Lars Knoll (knoll (at) kde.org)
      6  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      7  * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 #include "HTMLTableElement.h"
     27 
     28 #include "CSSPropertyNames.h"
     29 #include "CSSStyleSheet.h"
     30 #include "CSSValueKeywords.h"
     31 #include "ExceptionCode.h"
     32 #include "HTMLNames.h"
     33 #include "HTMLTableCaptionElement.h"
     34 #include "HTMLTableRowElement.h"
     35 #include "HTMLTableRowsCollection.h"
     36 #include "HTMLTableSectionElement.h"
     37 #include "MappedAttribute.h"
     38 #include "RenderTable.h"
     39 #include "Text.h"
     40 
     41 namespace WebCore {
     42 
     43 using namespace HTMLNames;
     44 
     45 HTMLTableElement::HTMLTableElement(const QualifiedName& tagName, Document* doc)
     46     : HTMLElement(tagName, doc)
     47     , m_borderAttr(false)
     48     , m_borderColorAttr(false)
     49     , m_frameAttr(false)
     50     , m_rulesAttr(UnsetRules)
     51     , m_padding(1)
     52 {
     53     ASSERT(hasTagName(tableTag));
     54 }
     55 
     56 bool HTMLTableElement::checkDTD(const Node* newChild)
     57 {
     58     if (newChild->isTextNode())
     59         return static_cast<const Text*>(newChild)->containsOnlyWhitespace();
     60     return newChild->hasTagName(captionTag) ||
     61            newChild->hasTagName(colTag) || newChild->hasTagName(colgroupTag) ||
     62            newChild->hasTagName(theadTag) || newChild->hasTagName(tfootTag) ||
     63            newChild->hasTagName(tbodyTag) || newChild->hasTagName(formTag) ||
     64            newChild->hasTagName(scriptTag);
     65 }
     66 
     67 HTMLTableCaptionElement* HTMLTableElement::caption() const
     68 {
     69     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     70         if (child->hasTagName(captionTag))
     71             return static_cast<HTMLTableCaptionElement*>(child);
     72     }
     73     return 0;
     74 }
     75 
     76 void HTMLTableElement::setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption, ExceptionCode& ec)
     77 {
     78     deleteCaption();
     79     insertBefore(newCaption, firstChild(), ec);
     80 }
     81 
     82 HTMLTableSectionElement* HTMLTableElement::tHead() const
     83 {
     84     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     85         if (child->hasTagName(theadTag))
     86             return static_cast<HTMLTableSectionElement*>(child);
     87     }
     88     return 0;
     89 }
     90 
     91 void HTMLTableElement::setTHead(PassRefPtr<HTMLTableSectionElement> newHead, ExceptionCode& ec)
     92 {
     93     deleteTHead();
     94 
     95     Node* child;
     96     for (child = firstChild(); child; child = child->nextSibling())
     97         if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag))
     98             break;
     99 
    100     insertBefore(newHead, child, ec);
    101 }
    102 
    103 HTMLTableSectionElement* HTMLTableElement::tFoot() const
    104 {
    105     for (Node* child = firstChild(); child; child = child->nextSibling()) {
    106         if (child->hasTagName(tfootTag))
    107             return static_cast<HTMLTableSectionElement*>(child);
    108     }
    109     return 0;
    110 }
    111 
    112 void HTMLTableElement::setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot, ExceptionCode& ec)
    113 {
    114     deleteTFoot();
    115 
    116     Node* child;
    117     for (child = firstChild(); child; child = child->nextSibling())
    118         if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag) && !child->hasTagName(theadTag))
    119             break;
    120 
    121     insertBefore(newFoot, child, ec);
    122 }
    123 
    124 PassRefPtr<HTMLElement> HTMLTableElement::createTHead()
    125 {
    126     if (HTMLTableSectionElement* existingHead = tHead())
    127         return existingHead;
    128     RefPtr<HTMLTableSectionElement> head = new HTMLTableSectionElement(theadTag, document());
    129     ExceptionCode ec;
    130     setTHead(head, ec);
    131     return head.release();
    132 }
    133 
    134 void HTMLTableElement::deleteTHead()
    135 {
    136     ExceptionCode ec;
    137     removeChild(tHead(), ec);
    138 }
    139 
    140 PassRefPtr<HTMLElement> HTMLTableElement::createTFoot()
    141 {
    142     if (HTMLTableSectionElement* existingFoot = tFoot())
    143         return existingFoot;
    144     RefPtr<HTMLTableSectionElement> foot = new HTMLTableSectionElement(tfootTag, document());
    145     ExceptionCode ec;
    146     setTFoot(foot, ec);
    147     return foot.release();
    148 }
    149 
    150 void HTMLTableElement::deleteTFoot()
    151 {
    152     ExceptionCode ec;
    153     removeChild(tFoot(), ec);
    154 }
    155 
    156 PassRefPtr<HTMLElement> HTMLTableElement::createCaption()
    157 {
    158     if (HTMLTableCaptionElement* existingCaption = caption())
    159         return existingCaption;
    160     RefPtr<HTMLTableCaptionElement> caption = new HTMLTableCaptionElement(captionTag, document());
    161     ExceptionCode ec;
    162     setCaption(caption, ec);
    163     return caption.release();
    164 }
    165 
    166 void HTMLTableElement::deleteCaption()
    167 {
    168     ExceptionCode ec;
    169     removeChild(caption(), ec);
    170 }
    171 
    172 HTMLTableSectionElement* HTMLTableElement::lastBody() const
    173 {
    174     for (Node* child = lastChild(); child; child = child->previousSibling()) {
    175         if (child->hasTagName(tbodyTag))
    176             return static_cast<HTMLTableSectionElement*>(child);
    177     }
    178     return 0;
    179 }
    180 
    181 PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec)
    182 {
    183     if (index < -1) {
    184         ec = INDEX_SIZE_ERR;
    185         return 0;
    186     }
    187 
    188     HTMLTableRowElement* lastRow = 0;
    189     HTMLTableRowElement* row = 0;
    190     if (index == -1)
    191         lastRow = HTMLTableRowsCollection::lastRow(this);
    192     else {
    193         for (int i = 0; i <= index; ++i) {
    194             row = HTMLTableRowsCollection::rowAfter(this, lastRow);
    195             if (!row) {
    196                 if (i != index) {
    197                     ec = INDEX_SIZE_ERR;
    198                     return 0;
    199                 }
    200                 break;
    201             }
    202             lastRow = row;
    203         }
    204     }
    205 
    206     Node* parent;
    207     if (lastRow)
    208         parent = row ? row->parent() : lastRow->parent();
    209     else {
    210         parent = lastBody();
    211         if (!parent) {
    212             RefPtr<HTMLTableSectionElement> newBody = new HTMLTableSectionElement(tbodyTag, document());
    213             RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, document());
    214             newBody->appendChild(newRow, ec);
    215             appendChild(newBody.release(), ec);
    216             return newRow.release();
    217         }
    218     }
    219 
    220     RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, document());
    221     parent->insertBefore(newRow, row, ec);
    222     return newRow.release();
    223 }
    224 
    225 void HTMLTableElement::deleteRow(int index, ExceptionCode& ec)
    226 {
    227     HTMLTableRowElement* row = 0;
    228     if (index == -1)
    229         row = HTMLTableRowsCollection::lastRow(this);
    230     else {
    231         for (int i = 0; i <= index; ++i) {
    232             row = HTMLTableRowsCollection::rowAfter(this, row);
    233             if (!row)
    234                 break;
    235         }
    236     }
    237     if (!row) {
    238         ec = INDEX_SIZE_ERR;
    239         return;
    240     }
    241     row->remove(ec);
    242 }
    243 
    244 ContainerNode* HTMLTableElement::addChild(PassRefPtr<Node> child)
    245 {
    246     if (child->hasTagName(formTag)) {
    247         // First add the child.
    248         HTMLElement::addChild(child);
    249 
    250         // Now simply return ourselves as the container to insert into.
    251         // This has the effect of demoting the form to a leaf and moving it safely out of the way.
    252         return this;
    253     }
    254 
    255     return HTMLElement::addChild(child.get());
    256 }
    257 
    258 bool HTMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
    259 {
    260     if (attrName == backgroundAttr) {
    261         result = (MappedAttributeEntry)(eLastEntry + document()->docID());
    262         return false;
    263     }
    264 
    265     if (attrName == widthAttr ||
    266         attrName == heightAttr ||
    267         attrName == bgcolorAttr ||
    268         attrName == cellspacingAttr ||
    269         attrName == vspaceAttr ||
    270         attrName == hspaceAttr ||
    271         attrName == valignAttr) {
    272         result = eUniversal;
    273         return false;
    274     }
    275 
    276     if (attrName == bordercolorAttr || attrName == frameAttr || attrName == rulesAttr) {
    277         result = eUniversal;
    278         return true;
    279     }
    280 
    281     if (attrName == borderAttr) {
    282         result = eTable;
    283         return true;
    284     }
    285 
    286     if (attrName == alignAttr) {
    287         result = eTable;
    288         return false;
    289     }
    290 
    291     return HTMLElement::mapToEntry(attrName, result);
    292 }
    293 
    294 static inline bool isTableCellAncestor(Node* n)
    295 {
    296     return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) ||
    297            n->hasTagName(tfootTag) || n->hasTagName(trTag) ||
    298            n->hasTagName(thTag);
    299 }
    300 
    301 static bool setTableCellsChanged(Node* n)
    302 {
    303     ASSERT(n);
    304     bool cellChanged = false;
    305 
    306     if (n->hasTagName(tdTag))
    307         cellChanged = true;
    308     else if (isTableCellAncestor(n)) {
    309         for (Node* child = n->firstChild(); child; child = child->nextSibling())
    310             cellChanged |= setTableCellsChanged(child);
    311     }
    312 
    313     if (cellChanged)
    314        n->setNeedsStyleRecalc();
    315 
    316     return cellChanged;
    317 }
    318 
    319 void HTMLTableElement::parseMappedAttribute(MappedAttribute* attr)
    320 {
    321     CellBorders bordersBefore = cellBorders();
    322     unsigned short oldPadding = m_padding;
    323 
    324     if (attr->name() == widthAttr)
    325         addCSSLength(attr, CSSPropertyWidth, attr->value());
    326     else if (attr->name() == heightAttr)
    327         addCSSLength(attr, CSSPropertyHeight, attr->value());
    328     else if (attr->name() == borderAttr)  {
    329         m_borderAttr = true;
    330         if (attr->decl()) {
    331             RefPtr<CSSValue> val = attr->decl()->getPropertyCSSValue(CSSPropertyBorderLeftWidth);
    332             if (val && val->isPrimitiveValue()) {
    333                 CSSPrimitiveValue* primVal = static_cast<CSSPrimitiveValue*>(val.get());
    334                 m_borderAttr = primVal->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER);
    335             }
    336         } else if (!attr->isNull()) {
    337             int border = 0;
    338             if (attr->isEmpty())
    339                 border = 1;
    340             else
    341                 border = attr->value().toInt();
    342             m_borderAttr = border;
    343             addCSSLength(attr, CSSPropertyBorderWidth, String::number(border));
    344         }
    345     } else if (attr->name() == bgcolorAttr)
    346         addCSSColor(attr, CSSPropertyBackgroundColor, attr->value());
    347     else if (attr->name() == bordercolorAttr) {
    348         m_borderColorAttr = attr->decl();
    349         if (!attr->decl() && !attr->isEmpty()) {
    350             addCSSColor(attr, CSSPropertyBorderColor, attr->value());
    351             m_borderColorAttr = true;
    352         }
    353     } else if (attr->name() == backgroundAttr) {
    354         String url = deprecatedParseURL(attr->value());
    355         if (!url.isEmpty())
    356             addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string());
    357     } else if (attr->name() == frameAttr) {
    358         // Cache the value of "frame" so that the table can examine it later.
    359         m_frameAttr = false;
    360 
    361         // Whether or not to hide the top/right/bottom/left borders.
    362         const int cTop = 0;
    363         const int cRight = 1;
    364         const int cBottom = 2;
    365         const int cLeft = 3;
    366         bool borders[4] = { false, false, false, false };
    367 
    368         // void, above, below, hsides, vsides, lhs, rhs, box, border
    369         if (equalIgnoringCase(attr->value(), "void"))
    370             m_frameAttr = true;
    371         else if (equalIgnoringCase(attr->value(), "above")) {
    372             m_frameAttr = true;
    373             borders[cTop] = true;
    374         } else if (equalIgnoringCase(attr->value(), "below")) {
    375             m_frameAttr = true;
    376             borders[cBottom] = true;
    377         } else if (equalIgnoringCase(attr->value(), "hsides")) {
    378             m_frameAttr = true;
    379             borders[cTop] = borders[cBottom] = true;
    380         } else if (equalIgnoringCase(attr->value(), "vsides")) {
    381             m_frameAttr = true;
    382             borders[cLeft] = borders[cRight] = true;
    383         } else if (equalIgnoringCase(attr->value(), "lhs")) {
    384             m_frameAttr = true;
    385             borders[cLeft] = true;
    386         } else if (equalIgnoringCase(attr->value(), "rhs")) {
    387             m_frameAttr = true;
    388             borders[cRight] = true;
    389         } else if (equalIgnoringCase(attr->value(), "box") ||
    390                    equalIgnoringCase(attr->value(), "border")) {
    391             m_frameAttr = true;
    392             borders[cTop] = borders[cBottom] = borders[cLeft] = borders[cRight] = true;
    393         }
    394 
    395         // Now map in the border styles of solid and hidden respectively.
    396         if (m_frameAttr) {
    397             addCSSProperty(attr, CSSPropertyBorderTopWidth, CSSValueThin);
    398             addCSSProperty(attr, CSSPropertyBorderBottomWidth, CSSValueThin);
    399             addCSSProperty(attr, CSSPropertyBorderLeftWidth, CSSValueThin);
    400             addCSSProperty(attr, CSSPropertyBorderRightWidth, CSSValueThin);
    401             addCSSProperty(attr, CSSPropertyBorderTopStyle, borders[cTop] ? CSSValueSolid : CSSValueHidden);
    402             addCSSProperty(attr, CSSPropertyBorderBottomStyle, borders[cBottom] ? CSSValueSolid : CSSValueHidden);
    403             addCSSProperty(attr, CSSPropertyBorderLeftStyle, borders[cLeft] ? CSSValueSolid : CSSValueHidden);
    404             addCSSProperty(attr, CSSPropertyBorderRightStyle, borders[cRight] ? CSSValueSolid : CSSValueHidden);
    405         }
    406     } else if (attr->name() == rulesAttr) {
    407         m_rulesAttr = UnsetRules;
    408         if (equalIgnoringCase(attr->value(), "none"))
    409             m_rulesAttr = NoneRules;
    410         else if (equalIgnoringCase(attr->value(), "groups"))
    411             m_rulesAttr = GroupsRules;
    412         else if (equalIgnoringCase(attr->value(), "rows"))
    413             m_rulesAttr = RowsRules;
    414         if (equalIgnoringCase(attr->value(), "cols"))
    415             m_rulesAttr = ColsRules;
    416         if (equalIgnoringCase(attr->value(), "all"))
    417             m_rulesAttr = AllRules;
    418 
    419         // The presence of a valid rules attribute causes border collapsing to be enabled.
    420         if (m_rulesAttr != UnsetRules)
    421             addCSSProperty(attr, CSSPropertyBorderCollapse, CSSValueCollapse);
    422     } else if (attr->name() == cellspacingAttr) {
    423         if (!attr->value().isEmpty())
    424             addCSSLength(attr, CSSPropertyBorderSpacing, attr->value());
    425     } else if (attr->name() == cellpaddingAttr) {
    426         if (!attr->value().isEmpty())
    427             m_padding = max(0, attr->value().toInt());
    428         else
    429             m_padding = 1;
    430     } else if (attr->name() == colsAttr) {
    431         // ###
    432     } else if (attr->name() == vspaceAttr) {
    433         addCSSLength(attr, CSSPropertyMarginTop, attr->value());
    434         addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
    435     } else if (attr->name() == hspaceAttr) {
    436         addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
    437         addCSSLength(attr, CSSPropertyMarginRight, attr->value());
    438     } else if (attr->name() == alignAttr) {
    439         if (!attr->value().isEmpty()) {
    440             if (equalIgnoringCase(attr->value(), "center")) {
    441                 addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto);
    442                 addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto);
    443             } else
    444                 addCSSProperty(attr, CSSPropertyFloat, attr->value());
    445         }
    446     } else if (attr->name() == valignAttr) {
    447         if (!attr->value().isEmpty())
    448             addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value());
    449     } else
    450         HTMLElement::parseMappedAttribute(attr);
    451 
    452     if (bordersBefore != cellBorders() || oldPadding != m_padding) {
    453         if (oldPadding != m_padding)
    454             m_paddingDecl = 0;
    455         bool cellChanged = false;
    456         for (Node* child = firstChild(); child; child = child->nextSibling())
    457             cellChanged |= setTableCellsChanged(child);
    458         if (cellChanged)
    459             setNeedsStyleRecalc();
    460     }
    461 }
    462 
    463 void HTMLTableElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results)
    464 {
    465     if ((!m_borderAttr && !m_borderColorAttr) || m_frameAttr)
    466         return;
    467 
    468     AtomicString borderValue = m_borderColorAttr ? "solid" : "outset";
    469     CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, tableborderAttr, borderValue);
    470     if (!decl) {
    471         decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
    472         decl->setParent(document()->elementSheet());
    473         decl->setNode(this);
    474         decl->setStrictParsing(false); // Mapped attributes are just always quirky.
    475 
    476         int v = m_borderColorAttr ? CSSValueSolid : CSSValueOutset;
    477         decl->setProperty(CSSPropertyBorderTopStyle, v, false);
    478         decl->setProperty(CSSPropertyBorderBottomStyle, v, false);
    479         decl->setProperty(CSSPropertyBorderLeftStyle, v, false);
    480         decl->setProperty(CSSPropertyBorderRightStyle, v, false);
    481 
    482         setMappedAttributeDecl(ePersistent, tableborderAttr, borderValue, decl);
    483         decl->setParent(0);
    484         decl->setNode(0);
    485         decl->setMappedState(ePersistent, tableborderAttr, borderValue);
    486     }
    487 
    488 
    489     results.append(decl);
    490 }
    491 
    492 HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
    493 {
    494     switch (m_rulesAttr) {
    495         case NoneRules:
    496         case GroupsRules:
    497             return NoBorders;
    498         case AllRules:
    499             return SolidBorders;
    500         case ColsRules:
    501             return SolidBordersColsOnly;
    502         case RowsRules:
    503             return SolidBordersRowsOnly;
    504         case UnsetRules:
    505             if (!m_borderAttr)
    506                 return NoBorders;
    507             if (m_borderColorAttr)
    508                 return SolidBorders;
    509             return InsetBorders;
    510     }
    511     ASSERT_NOT_REACHED();
    512     return NoBorders;
    513 }
    514 
    515 void HTMLTableElement::addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>& results)
    516 {
    517     addSharedCellBordersDecl(results);
    518     addSharedCellPaddingDecl(results);
    519 }
    520 
    521 void HTMLTableElement::addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>& results)
    522 {
    523     CellBorders borders = cellBorders();
    524 
    525     static const AtomicString* cellBorderNames[] = { new AtomicString("none"), new AtomicString("solid"), new AtomicString("inset"), new AtomicString("solid-cols"), new AtomicString("solid-rows") };
    526     const AtomicString& cellborderValue = *cellBorderNames[borders];
    527     CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, cellborderAttr, cellborderValue);
    528     if (!decl) {
    529         decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
    530         decl->setParent(document()->elementSheet());
    531         decl->setNode(this);
    532         decl->setStrictParsing(false); // Mapped attributes are just always quirky.
    533 
    534         switch (borders) {
    535             case SolidBordersColsOnly:
    536                 decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
    537                 decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
    538                 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
    539                 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
    540                 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
    541                 break;
    542             case SolidBordersRowsOnly:
    543                 decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
    544                 decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
    545                 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
    546                 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
    547                 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
    548                 break;
    549             case SolidBorders:
    550                 decl->setProperty(CSSPropertyBorderWidth, "1px", false);
    551                 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
    552                 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
    553                 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
    554                 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
    555                 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
    556                 break;
    557             case InsetBorders:
    558                 decl->setProperty(CSSPropertyBorderWidth, "1px", false);
    559                 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueInset, false);
    560                 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueInset, false);
    561                 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueInset, false);
    562                 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueInset, false);
    563                 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
    564                 break;
    565             case NoBorders:
    566                 decl->setProperty(CSSPropertyBorderWidth, "0", false);
    567                 break;
    568         }
    569 
    570         setMappedAttributeDecl(ePersistent, cellborderAttr, *cellBorderNames[borders], decl);
    571         decl->setParent(0);
    572         decl->setNode(0);
    573         decl->setMappedState(ePersistent, cellborderAttr, cellborderValue);
    574     }
    575 
    576     results.append(decl);
    577 }
    578 
    579 void HTMLTableElement::addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>& results)
    580 {
    581     if (m_padding == 0)
    582         return;
    583 
    584     if (!m_paddingDecl) {
    585         String paddingValue = String::number(m_padding);
    586         m_paddingDecl = getMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue);
    587         if (!m_paddingDecl) {
    588             m_paddingDecl = CSSMappedAttributeDeclaration::create();
    589             m_paddingDecl->setParent(document()->elementSheet());
    590             m_paddingDecl->setNode(this);
    591             m_paddingDecl->setStrictParsing(false); // Mapped attributes are just always quirky.
    592 
    593             m_paddingDecl->setProperty(CSSPropertyPaddingTop, paddingValue, false);
    594             m_paddingDecl->setProperty(CSSPropertyPaddingRight, paddingValue, false);
    595             m_paddingDecl->setProperty(CSSPropertyPaddingBottom, paddingValue, false);
    596             m_paddingDecl->setProperty(CSSPropertyPaddingLeft, paddingValue, false);
    597         }
    598         setMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue, m_paddingDecl.get());
    599         m_paddingDecl->setParent(0);
    600         m_paddingDecl->setNode(0);
    601         m_paddingDecl->setMappedState(eUniversal, cellpaddingAttr, paddingValue);
    602     }
    603 
    604     results.append(m_paddingDecl.get());
    605 }
    606 
    607 void HTMLTableElement::addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>& results)
    608 {
    609     if (m_rulesAttr != GroupsRules)
    610         return;
    611 
    612     AtomicString rulesValue = rows ? "rowgroups" : "colgroups";
    613     CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, rulesAttr, rulesValue);
    614     if (!decl) {
    615         decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
    616         decl->setParent(document()->elementSheet());
    617         decl->setNode(this);
    618         decl->setStrictParsing(false); // Mapped attributes are just always quirky.
    619 
    620         if (rows) {
    621             decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
    622             decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
    623             decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
    624             decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
    625         } else {
    626             decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
    627             decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
    628             decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
    629             decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
    630         }
    631 
    632         setMappedAttributeDecl(ePersistent, rulesAttr, rulesValue, decl);
    633         decl->setParent(0);
    634         decl->setNode(0);
    635         decl->setMappedState(ePersistent, rulesAttr, rulesValue);
    636     }
    637 
    638     results.append(decl);
    639 }
    640 
    641 void HTMLTableElement::attach()
    642 {
    643     ASSERT(!attached());
    644     HTMLElement::attach();
    645 }
    646 
    647 bool HTMLTableElement::isURLAttribute(Attribute *attr) const
    648 {
    649     return attr->name() == backgroundAttr;
    650 }
    651 
    652 PassRefPtr<HTMLCollection> HTMLTableElement::rows()
    653 {
    654     return HTMLTableRowsCollection::create(this);
    655 }
    656 
    657 PassRefPtr<HTMLCollection> HTMLTableElement::tBodies()
    658 {
    659     return HTMLCollection::create(this, TableTBodies);
    660 }
    661 
    662 String HTMLTableElement::align() const
    663 {
    664     return getAttribute(alignAttr);
    665 }
    666 
    667 void HTMLTableElement::setAlign(const String &value)
    668 {
    669     setAttribute(alignAttr, value);
    670 }
    671 
    672 String HTMLTableElement::bgColor() const
    673 {
    674     return getAttribute(bgcolorAttr);
    675 }
    676 
    677 void HTMLTableElement::setBgColor(const String &value)
    678 {
    679     setAttribute(bgcolorAttr, value);
    680 }
    681 
    682 String HTMLTableElement::border() const
    683 {
    684     return getAttribute(borderAttr);
    685 }
    686 
    687 void HTMLTableElement::setBorder(const String &value)
    688 {
    689     setAttribute(borderAttr, value);
    690 }
    691 
    692 String HTMLTableElement::cellPadding() const
    693 {
    694     return getAttribute(cellpaddingAttr);
    695 }
    696 
    697 void HTMLTableElement::setCellPadding(const String &value)
    698 {
    699     setAttribute(cellpaddingAttr, value);
    700 }
    701 
    702 String HTMLTableElement::cellSpacing() const
    703 {
    704     return getAttribute(cellspacingAttr);
    705 }
    706 
    707 void HTMLTableElement::setCellSpacing(const String &value)
    708 {
    709     setAttribute(cellspacingAttr, value);
    710 }
    711 
    712 String HTMLTableElement::frame() const
    713 {
    714     return getAttribute(frameAttr);
    715 }
    716 
    717 void HTMLTableElement::setFrame(const String &value)
    718 {
    719     setAttribute(frameAttr, value);
    720 }
    721 
    722 String HTMLTableElement::rules() const
    723 {
    724     return getAttribute(rulesAttr);
    725 }
    726 
    727 void HTMLTableElement::setRules(const String &value)
    728 {
    729     setAttribute(rulesAttr, value);
    730 }
    731 
    732 String HTMLTableElement::summary() const
    733 {
    734     return getAttribute(summaryAttr);
    735 }
    736 
    737 void HTMLTableElement::setSummary(const String &value)
    738 {
    739     setAttribute(summaryAttr, value);
    740 }
    741 
    742 String HTMLTableElement::width() const
    743 {
    744     return getAttribute(widthAttr);
    745 }
    746 
    747 void HTMLTableElement::setWidth(const String &value)
    748 {
    749     setAttribute(widthAttr, value);
    750 }
    751 
    752 void HTMLTableElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
    753 {
    754     HTMLElement::addSubresourceAttributeURLs(urls);
    755 
    756     addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
    757 }
    758 
    759 }
    760