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