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