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