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