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, 2010, 2011 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 "core/html/HTMLTableElement.h"
     27 
     28 #include "CSSPropertyNames.h"
     29 #include "CSSValueKeywords.h"
     30 #include "HTMLNames.h"
     31 #include "bindings/v8/ExceptionState.h"
     32 #include "bindings/v8/ExceptionStatePlaceholder.h"
     33 #include "core/css/CSSImageValue.h"
     34 #include "core/css/CSSValuePool.h"
     35 #include "core/css/StylePropertySet.h"
     36 #include "core/dom/Attribute.h"
     37 #include "core/dom/ExceptionCode.h"
     38 #include "core/html/HTMLTableCaptionElement.h"
     39 #include "core/html/HTMLTableRowElement.h"
     40 #include "core/html/HTMLTableRowsCollection.h"
     41 #include "core/html/HTMLTableSectionElement.h"
     42 #include "core/html/parser/HTMLParserIdioms.h"
     43 #include "core/rendering/RenderTable.h"
     44 #include "wtf/StdLibExtras.h"
     45 
     46 namespace WebCore {
     47 
     48 using namespace HTMLNames;
     49 
     50 HTMLTableElement::HTMLTableElement(Document& document)
     51     : HTMLElement(tableTag, document)
     52     , m_borderAttr(false)
     53     , m_borderColorAttr(false)
     54     , m_frameAttr(false)
     55     , m_rulesAttr(UnsetRules)
     56     , m_padding(1)
     57 {
     58     ScriptWrappable::init(this);
     59 }
     60 
     61 PassRefPtr<HTMLTableElement> HTMLTableElement::create(Document& document)
     62 {
     63     return adoptRef(new HTMLTableElement(document));
     64 }
     65 
     66 HTMLTableCaptionElement* HTMLTableElement::caption() const
     67 {
     68     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     69         if (child->hasTagName(captionTag))
     70             return toHTMLTableCaptionElement(child);
     71     }
     72     return 0;
     73 }
     74 
     75 void HTMLTableElement::setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption, ExceptionState& exceptionState)
     76 {
     77     deleteCaption();
     78     insertBefore(newCaption, firstChild(), exceptionState);
     79 }
     80 
     81 HTMLTableSectionElement* HTMLTableElement::tHead() const
     82 {
     83     for (Node* child = firstChild(); child; child = child->nextSibling()) {
     84         if (child->hasTagName(theadTag))
     85             return toHTMLTableSectionElement(child);
     86     }
     87     return 0;
     88 }
     89 
     90 void HTMLTableElement::setTHead(PassRefPtr<HTMLTableSectionElement> newHead, ExceptionState& exceptionState)
     91 {
     92     deleteTHead();
     93 
     94     Node* child;
     95     for (child = firstChild(); child; child = child->nextSibling())
     96         if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag))
     97             break;
     98 
     99     insertBefore(newHead, child, exceptionState);
    100 }
    101 
    102 HTMLTableSectionElement* HTMLTableElement::tFoot() const
    103 {
    104     for (Node* child = firstChild(); child; child = child->nextSibling()) {
    105         if (child->hasTagName(tfootTag))
    106             return toHTMLTableSectionElement(child);
    107     }
    108     return 0;
    109 }
    110 
    111 void HTMLTableElement::setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot, ExceptionState& exceptionState)
    112 {
    113     deleteTFoot();
    114 
    115     Node* child;
    116     for (child = firstChild(); child; child = child->nextSibling())
    117         if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag) && !child->hasTagName(theadTag))
    118             break;
    119 
    120     insertBefore(newFoot, child, exceptionState);
    121 }
    122 
    123 PassRefPtr<HTMLElement> HTMLTableElement::createTHead()
    124 {
    125     if (HTMLTableSectionElement* existingHead = tHead())
    126         return existingHead;
    127     RefPtr<HTMLTableSectionElement> head = HTMLTableSectionElement::create(theadTag, document());
    128     setTHead(head, IGNORE_EXCEPTION);
    129     return head.release();
    130 }
    131 
    132 void HTMLTableElement::deleteTHead()
    133 {
    134     removeChild(tHead(), IGNORE_EXCEPTION);
    135 }
    136 
    137 PassRefPtr<HTMLElement> HTMLTableElement::createTFoot()
    138 {
    139     if (HTMLTableSectionElement* existingFoot = tFoot())
    140         return existingFoot;
    141     RefPtr<HTMLTableSectionElement> foot = HTMLTableSectionElement::create(tfootTag, document());
    142     setTFoot(foot, IGNORE_EXCEPTION);
    143     return foot.release();
    144 }
    145 
    146 void HTMLTableElement::deleteTFoot()
    147 {
    148     removeChild(tFoot(), IGNORE_EXCEPTION);
    149 }
    150 
    151 PassRefPtr<HTMLElement> HTMLTableElement::createTBody()
    152 {
    153     RefPtr<HTMLTableSectionElement> body = HTMLTableSectionElement::create(tbodyTag, document());
    154     Node* referenceElement = lastBody() ? lastBody()->nextSibling() : 0;
    155 
    156     insertBefore(body, referenceElement);
    157     return body.release();
    158 }
    159 
    160 PassRefPtr<HTMLElement> HTMLTableElement::createCaption()
    161 {
    162     if (HTMLTableCaptionElement* existingCaption = caption())
    163         return existingCaption;
    164     RefPtr<HTMLTableCaptionElement> caption = HTMLTableCaptionElement::create(document());
    165     setCaption(caption, IGNORE_EXCEPTION);
    166     return caption.release();
    167 }
    168 
    169 void HTMLTableElement::deleteCaption()
    170 {
    171     removeChild(caption(), IGNORE_EXCEPTION);
    172 }
    173 
    174 HTMLTableSectionElement* HTMLTableElement::lastBody() const
    175 {
    176     for (Node* child = lastChild(); child; child = child->previousSibling()) {
    177         if (child->hasTagName(tbodyTag))
    178             return toHTMLTableSectionElement(child);
    179     }
    180     return 0;
    181 }
    182 
    183 PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionState& exceptionState)
    184 {
    185     if (index < -1) {
    186         exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is less than -1.");
    187         return 0;
    188     }
    189 
    190     RefPtr<Node> protectFromMutationEvents(this);
    191 
    192     RefPtr<HTMLTableRowElement> lastRow = 0;
    193     RefPtr<HTMLTableRowElement> row = 0;
    194     if (index == -1)
    195         lastRow = HTMLTableRowsCollection::lastRow(this);
    196     else {
    197         for (int i = 0; i <= index; ++i) {
    198             row = HTMLTableRowsCollection::rowAfter(this, lastRow.get());
    199             if (!row) {
    200                 if (i != index) {
    201                     exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is greater than the number of rows in the table (" + String::number(i) + ").");
    202                     return 0;
    203                 }
    204                 break;
    205             }
    206             lastRow = row;
    207         }
    208     }
    209 
    210     RefPtr<ContainerNode> parent;
    211     if (lastRow)
    212         parent = row ? row->parentNode() : lastRow->parentNode();
    213     else {
    214         parent = lastBody();
    215         if (!parent) {
    216             RefPtr<HTMLTableSectionElement> newBody = HTMLTableSectionElement::create(tbodyTag, document());
    217             RefPtr<HTMLTableRowElement> newRow = HTMLTableRowElement::create(document());
    218             newBody->appendChild(newRow, exceptionState);
    219             appendChild(newBody.release(), exceptionState);
    220             return newRow.release();
    221         }
    222     }
    223 
    224     RefPtr<HTMLTableRowElement> newRow = HTMLTableRowElement::create(document());
    225     parent->insertBefore(newRow, row.get(), exceptionState);
    226     return newRow.release();
    227 }
    228 
    229 void HTMLTableElement::deleteRow(int index, ExceptionState& exceptionState)
    230 {
    231     if (index < -1) {
    232         exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is less than -1.");
    233         return;
    234     }
    235 
    236     HTMLTableRowElement* row = 0;
    237     int i = 0;
    238     if (index == -1)
    239         row = HTMLTableRowsCollection::lastRow(this);
    240     else {
    241         for (i = 0; i <= index; ++i) {
    242             row = HTMLTableRowsCollection::rowAfter(this, row);
    243             if (!row)
    244                 break;
    245         }
    246     }
    247     if (!row) {
    248         exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is greater than the number of rows in the table (" + String::number(i) + ").");
    249         return;
    250     }
    251     row->remove(exceptionState);
    252 }
    253 
    254 static inline bool isTableCellAncestor(Node* n)
    255 {
    256     return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) ||
    257            n->hasTagName(tfootTag) || n->hasTagName(trTag) ||
    258            n->hasTagName(thTag);
    259 }
    260 
    261 static bool setTableCellsChanged(Node* n)
    262 {
    263     ASSERT(n);
    264     bool cellChanged = false;
    265 
    266     if (n->hasTagName(tdTag))
    267         cellChanged = true;
    268     else if (isTableCellAncestor(n)) {
    269         for (Node* child = n->firstChild(); child; child = child->nextSibling())
    270             cellChanged |= setTableCellsChanged(child);
    271     }
    272 
    273     if (cellChanged)
    274        n->setNeedsStyleRecalc();
    275 
    276     return cellChanged;
    277 }
    278 
    279 static bool getBordersFromFrameAttributeValue(const AtomicString& value, bool& borderTop, bool& borderRight, bool& borderBottom, bool& borderLeft)
    280 {
    281     borderTop = false;
    282     borderRight = false;
    283     borderBottom = false;
    284     borderLeft = false;
    285 
    286     if (equalIgnoringCase(value, "above"))
    287         borderTop = true;
    288     else if (equalIgnoringCase(value, "below"))
    289         borderBottom = true;
    290     else if (equalIgnoringCase(value, "hsides"))
    291         borderTop = borderBottom = true;
    292     else if (equalIgnoringCase(value, "vsides"))
    293         borderLeft = borderRight = true;
    294     else if (equalIgnoringCase(value, "lhs"))
    295         borderLeft = true;
    296     else if (equalIgnoringCase(value, "rhs"))
    297         borderRight = true;
    298     else if (equalIgnoringCase(value, "box") || equalIgnoringCase(value, "border"))
    299         borderTop = borderBottom = borderLeft = borderRight = true;
    300     else if (!equalIgnoringCase(value, "void"))
    301         return false;
    302     return true;
    303 }
    304 
    305 void HTMLTableElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
    306 {
    307     if (name == widthAttr)
    308         addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    309     else if (name == heightAttr)
    310         addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    311     else if (name == borderAttr)
    312         addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, parseBorderWidthAttribute(value), CSSPrimitiveValue::CSS_PX);
    313     else if (name == bordercolorAttr) {
    314         if (!value.isEmpty())
    315             addHTMLColorToStyle(style, CSSPropertyBorderColor, value);
    316     } else if (name == bgcolorAttr)
    317         addHTMLColorToStyle(style, CSSPropertyBackgroundColor, value);
    318     else if (name == backgroundAttr) {
    319         String url = stripLeadingAndTrailingHTMLSpaces(value);
    320         if (!url.isEmpty())
    321             style->setProperty(CSSProperty(CSSPropertyBackgroundImage, CSSImageValue::create(document().completeURL(url).string())));
    322     } else if (name == valignAttr) {
    323         if (!value.isEmpty())
    324             addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
    325     } else if (name == cellspacingAttr) {
    326         if (!value.isEmpty())
    327             addHTMLLengthToStyle(style, CSSPropertyBorderSpacing, value);
    328     } else if (name == vspaceAttr) {
    329         addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
    330         addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
    331     } else if (name == hspaceAttr) {
    332         addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
    333         addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
    334     } else if (name == alignAttr) {
    335         if (!value.isEmpty()) {
    336             if (equalIgnoringCase(value, "center")) {
    337                 addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarginStart, CSSValueAuto);
    338                 addPropertyToPresentationAttributeStyle(style, CSSPropertyWebkitMarginEnd, CSSValueAuto);
    339             } else
    340                 addPropertyToPresentationAttributeStyle(style, CSSPropertyFloat, value);
    341         }
    342     } else if (name == rulesAttr) {
    343         // The presence of a valid rules attribute causes border collapsing to be enabled.
    344         if (m_rulesAttr != UnsetRules)
    345             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderCollapse, CSSValueCollapse);
    346     } else if (name == frameAttr) {
    347         bool borderTop;
    348         bool borderRight;
    349         bool borderBottom;
    350         bool borderLeft;
    351         if (getBordersFromFrameAttributeValue(value, borderTop, borderRight, borderBottom, borderLeft)) {
    352             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, CSSValueThin);
    353             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopStyle, borderTop ? CSSValueSolid : CSSValueHidden);
    354             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomStyle, borderBottom ? CSSValueSolid : CSSValueHidden);
    355             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderLeftStyle, borderLeft ? CSSValueSolid : CSSValueHidden);
    356             addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightStyle, borderRight ? CSSValueSolid : CSSValueHidden);
    357         }
    358     } else
    359         HTMLElement::collectStyleForPresentationAttribute(name, value, style);
    360 }
    361 
    362 bool HTMLTableElement::isPresentationAttribute(const QualifiedName& name) const
    363 {
    364     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)
    365         return true;
    366     return HTMLElement::isPresentationAttribute(name);
    367 }
    368 
    369 void HTMLTableElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    370 {
    371     CellBorders bordersBefore = cellBorders();
    372     unsigned short oldPadding = m_padding;
    373 
    374     if (name == borderAttr)  {
    375         // FIXME: This attribute is a mess.
    376         m_borderAttr = parseBorderWidthAttribute(value);
    377     } else if (name == bordercolorAttr) {
    378         m_borderColorAttr = !value.isEmpty();
    379     } else if (name == frameAttr) {
    380         // FIXME: This attribute is a mess.
    381         bool borderTop;
    382         bool borderRight;
    383         bool borderBottom;
    384         bool borderLeft;
    385         m_frameAttr = getBordersFromFrameAttributeValue(value, borderTop, borderRight, borderBottom, borderLeft);
    386     } else if (name == rulesAttr) {
    387         m_rulesAttr = UnsetRules;
    388         if (equalIgnoringCase(value, "none"))
    389             m_rulesAttr = NoneRules;
    390         else if (equalIgnoringCase(value, "groups"))
    391             m_rulesAttr = GroupsRules;
    392         else if (equalIgnoringCase(value, "rows"))
    393             m_rulesAttr = RowsRules;
    394         else if (equalIgnoringCase(value, "cols"))
    395             m_rulesAttr = ColsRules;
    396         else if (equalIgnoringCase(value, "all"))
    397             m_rulesAttr = AllRules;
    398     } else if (name == cellpaddingAttr) {
    399         if (!value.isEmpty())
    400             m_padding = max(0, value.toInt());
    401         else
    402             m_padding = 1;
    403     } else if (name == colsAttr) {
    404         // ###
    405     } else
    406         HTMLElement::parseAttribute(name, value);
    407 
    408     if (bordersBefore != cellBorders() || oldPadding != m_padding) {
    409         m_sharedCellStyle = 0;
    410         bool cellChanged = false;
    411         for (Node* child = firstChild(); child; child = child->nextSibling())
    412             cellChanged |= setTableCellsChanged(child);
    413         if (cellChanged)
    414             setNeedsStyleRecalc();
    415     }
    416 }
    417 
    418 static PassRefPtr<StylePropertySet> createBorderStyle(CSSValueID value)
    419 {
    420     RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
    421     style->setProperty(CSSPropertyBorderTopStyle, value);
    422     style->setProperty(CSSPropertyBorderBottomStyle, value);
    423     style->setProperty(CSSPropertyBorderLeftStyle, value);
    424     style->setProperty(CSSPropertyBorderRightStyle, value);
    425     return style.release();
    426 }
    427 
    428 const StylePropertySet* HTMLTableElement::additionalPresentationAttributeStyle()
    429 {
    430     if (m_frameAttr)
    431         return 0;
    432 
    433     if (!m_borderAttr && !m_borderColorAttr) {
    434         // Setting the border to 'hidden' allows it to win over any border
    435         // set on the table's cells during border-conflict resolution.
    436         if (m_rulesAttr != UnsetRules) {
    437             DEFINE_STATIC_REF(StylePropertySet, solidBorderStyle, (createBorderStyle(CSSValueHidden)));
    438             return solidBorderStyle;
    439         }
    440         return 0;
    441     }
    442 
    443     if (m_borderColorAttr) {
    444         DEFINE_STATIC_REF(StylePropertySet, solidBorderStyle, (createBorderStyle(CSSValueSolid)));
    445         return solidBorderStyle;
    446     }
    447     DEFINE_STATIC_REF(StylePropertySet, outsetBorderStyle, (createBorderStyle(CSSValueOutset)));
    448     return outsetBorderStyle;
    449 }
    450 
    451 HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
    452 {
    453     switch (m_rulesAttr) {
    454         case NoneRules:
    455         case GroupsRules:
    456             return NoBorders;
    457         case AllRules:
    458             return SolidBorders;
    459         case ColsRules:
    460             return SolidBordersColsOnly;
    461         case RowsRules:
    462             return SolidBordersRowsOnly;
    463         case UnsetRules:
    464             if (!m_borderAttr)
    465                 return NoBorders;
    466             if (m_borderColorAttr)
    467                 return SolidBorders;
    468             return InsetBorders;
    469     }
    470     ASSERT_NOT_REACHED();
    471     return NoBorders;
    472 }
    473 
    474 PassRefPtr<StylePropertySet> HTMLTableElement::createSharedCellStyle()
    475 {
    476     RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
    477 
    478     switch (cellBorders()) {
    479     case SolidBordersColsOnly:
    480         style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
    481         style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
    482         style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
    483         style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
    484         style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
    485         break;
    486     case SolidBordersRowsOnly:
    487         style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
    488         style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
    489         style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
    490         style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
    491         style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
    492         break;
    493     case SolidBorders:
    494         style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
    495         style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueSolid));
    496         style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
    497         break;
    498     case InsetBorders:
    499         style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX));
    500         style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueInset));
    501         style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue());
    502         break;
    503     case NoBorders:
    504         // If 'rules=none' then allow any borders set at cell level to take effect.
    505         break;
    506     }
    507 
    508     if (m_padding)
    509         style->setProperty(CSSPropertyPadding, cssValuePool().createValue(m_padding, CSSPrimitiveValue::CSS_PX));
    510 
    511     return style.release();
    512 }
    513 
    514 const StylePropertySet* HTMLTableElement::additionalCellStyle()
    515 {
    516     if (!m_sharedCellStyle)
    517         m_sharedCellStyle = createSharedCellStyle();
    518     return m_sharedCellStyle.get();
    519 }
    520 
    521 static PassRefPtr<StylePropertySet> createGroupBorderStyle(int rows)
    522 {
    523     RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
    524     if (rows) {
    525         style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin);
    526         style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin);
    527         style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid);
    528         style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid);
    529     } else {
    530         style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin);
    531         style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin);
    532         style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid);
    533         style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid);
    534     }
    535     return style.release();
    536 }
    537 
    538 const StylePropertySet* HTMLTableElement::additionalGroupStyle(bool rows)
    539 {
    540     if (m_rulesAttr != GroupsRules)
    541         return 0;
    542 
    543     if (rows) {
    544         DEFINE_STATIC_REF(StylePropertySet, rowBorderStyle, (createGroupBorderStyle(true)));
    545         return rowBorderStyle;
    546     }
    547     DEFINE_STATIC_REF(StylePropertySet, columnBorderStyle, (createGroupBorderStyle(false)));
    548     return columnBorderStyle;
    549 }
    550 
    551 bool HTMLTableElement::isURLAttribute(const Attribute& attribute) const
    552 {
    553     return attribute.name() == backgroundAttr || HTMLElement::isURLAttribute(attribute);
    554 }
    555 
    556 PassRefPtr<HTMLCollection> HTMLTableElement::rows()
    557 {
    558     return ensureCachedHTMLCollection(TableRows);
    559 }
    560 
    561 PassRefPtr<HTMLCollection> HTMLTableElement::tBodies()
    562 {
    563     return ensureCachedHTMLCollection(TableTBodies);
    564 }
    565 
    566 const AtomicString& HTMLTableElement::rules() const
    567 {
    568     return getAttribute(rulesAttr);
    569 }
    570 
    571 const AtomicString& HTMLTableElement::summary() const
    572 {
    573     return getAttribute(summaryAttr);
    574 }
    575 
    576 void HTMLTableElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
    577 {
    578     HTMLElement::addSubresourceAttributeURLs(urls);
    579 
    580     addSubresourceURL(urls, document().completeURL(getAttribute(backgroundAttr)));
    581 }
    582 
    583 }
    584