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 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 "CSSPropertyNames.h" 29 #include "CSSStyleSheet.h" 30 #include "CSSValueKeywords.h" 31 #include "ExceptionCode.h" 32 #include "HTMLNames.h" 33 #include "HTMLTableCaptionElement.h" 34 #include "HTMLTableRowElement.h" 35 #include "HTMLTableRowsCollection.h" 36 #include "HTMLTableSectionElement.h" 37 #include "MappedAttribute.h" 38 #include "RenderTable.h" 39 #include "Text.h" 40 41 namespace WebCore { 42 43 using namespace HTMLNames; 44 45 HTMLTableElement::HTMLTableElement(const QualifiedName& tagName, Document* doc) 46 : HTMLElement(tagName, doc) 47 , m_borderAttr(false) 48 , m_borderColorAttr(false) 49 , m_frameAttr(false) 50 , m_rulesAttr(UnsetRules) 51 , m_padding(1) 52 { 53 ASSERT(hasTagName(tableTag)); 54 } 55 56 bool HTMLTableElement::checkDTD(const Node* newChild) 57 { 58 if (newChild->isTextNode()) 59 return static_cast<const Text*>(newChild)->containsOnlyWhitespace(); 60 return newChild->hasTagName(captionTag) || 61 newChild->hasTagName(colTag) || newChild->hasTagName(colgroupTag) || 62 newChild->hasTagName(theadTag) || newChild->hasTagName(tfootTag) || 63 newChild->hasTagName(tbodyTag) || newChild->hasTagName(formTag) || 64 newChild->hasTagName(scriptTag); 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 = new HTMLTableSectionElement(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 = new HTMLTableSectionElement(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 = new HTMLTableCaptionElement(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 Node* parent; 207 if (lastRow) 208 parent = row ? row->parent() : lastRow->parent(); 209 else { 210 parent = lastBody(); 211 if (!parent) { 212 RefPtr<HTMLTableSectionElement> newBody = new HTMLTableSectionElement(tbodyTag, document()); 213 RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, document()); 214 newBody->appendChild(newRow, ec); 215 appendChild(newBody.release(), ec); 216 return newRow.release(); 217 } 218 } 219 220 RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, 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 ContainerNode* HTMLTableElement::addChild(PassRefPtr<Node> child) 245 { 246 if (child->hasTagName(formTag)) { 247 // First add the child. 248 HTMLElement::addChild(child); 249 250 // Now simply return ourselves as the container to insert into. 251 // This has the effect of demoting the form to a leaf and moving it safely out of the way. 252 return this; 253 } 254 255 return HTMLElement::addChild(child.get()); 256 } 257 258 bool HTMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 259 { 260 if (attrName == backgroundAttr) { 261 result = (MappedAttributeEntry)(eLastEntry + document()->docID()); 262 return false; 263 } 264 265 if (attrName == widthAttr || 266 attrName == heightAttr || 267 attrName == bgcolorAttr || 268 attrName == cellspacingAttr || 269 attrName == vspaceAttr || 270 attrName == hspaceAttr || 271 attrName == valignAttr) { 272 result = eUniversal; 273 return false; 274 } 275 276 if (attrName == bordercolorAttr || attrName == frameAttr || attrName == rulesAttr) { 277 result = eUniversal; 278 return true; 279 } 280 281 if (attrName == borderAttr) { 282 result = eTable; 283 return true; 284 } 285 286 if (attrName == alignAttr) { 287 result = eTable; 288 return false; 289 } 290 291 return HTMLElement::mapToEntry(attrName, result); 292 } 293 294 static inline bool isTableCellAncestor(Node* n) 295 { 296 return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) || 297 n->hasTagName(tfootTag) || n->hasTagName(trTag) || 298 n->hasTagName(thTag); 299 } 300 301 static bool setTableCellsChanged(Node* n) 302 { 303 ASSERT(n); 304 bool cellChanged = false; 305 306 if (n->hasTagName(tdTag)) 307 cellChanged = true; 308 else if (isTableCellAncestor(n)) { 309 for (Node* child = n->firstChild(); child; child = child->nextSibling()) 310 cellChanged |= setTableCellsChanged(child); 311 } 312 313 if (cellChanged) 314 n->setNeedsStyleRecalc(); 315 316 return cellChanged; 317 } 318 319 void HTMLTableElement::parseMappedAttribute(MappedAttribute* attr) 320 { 321 CellBorders bordersBefore = cellBorders(); 322 unsigned short oldPadding = m_padding; 323 324 if (attr->name() == widthAttr) 325 addCSSLength(attr, CSSPropertyWidth, attr->value()); 326 else if (attr->name() == heightAttr) 327 addCSSLength(attr, CSSPropertyHeight, attr->value()); 328 else if (attr->name() == borderAttr) { 329 m_borderAttr = true; 330 if (attr->decl()) { 331 RefPtr<CSSValue> val = attr->decl()->getPropertyCSSValue(CSSPropertyBorderLeftWidth); 332 if (val && val->isPrimitiveValue()) { 333 CSSPrimitiveValue* primVal = static_cast<CSSPrimitiveValue*>(val.get()); 334 m_borderAttr = primVal->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); 335 } 336 } else if (!attr->isNull()) { 337 int border = 0; 338 if (attr->isEmpty()) 339 border = 1; 340 else 341 border = attr->value().toInt(); 342 m_borderAttr = border; 343 addCSSLength(attr, CSSPropertyBorderWidth, String::number(border)); 344 } 345 } else if (attr->name() == bgcolorAttr) 346 addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); 347 else if (attr->name() == bordercolorAttr) { 348 m_borderColorAttr = attr->decl(); 349 if (!attr->decl() && !attr->isEmpty()) { 350 addCSSColor(attr, CSSPropertyBorderColor, attr->value()); 351 m_borderColorAttr = true; 352 } 353 } else if (attr->name() == backgroundAttr) { 354 String url = deprecatedParseURL(attr->value()); 355 if (!url.isEmpty()) 356 addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); 357 } else if (attr->name() == frameAttr) { 358 // Cache the value of "frame" so that the table can examine it later. 359 m_frameAttr = false; 360 361 // Whether or not to hide the top/right/bottom/left borders. 362 const int cTop = 0; 363 const int cRight = 1; 364 const int cBottom = 2; 365 const int cLeft = 3; 366 bool borders[4] = { false, false, false, false }; 367 368 // void, above, below, hsides, vsides, lhs, rhs, box, border 369 if (equalIgnoringCase(attr->value(), "void")) 370 m_frameAttr = true; 371 else if (equalIgnoringCase(attr->value(), "above")) { 372 m_frameAttr = true; 373 borders[cTop] = true; 374 } else if (equalIgnoringCase(attr->value(), "below")) { 375 m_frameAttr = true; 376 borders[cBottom] = true; 377 } else if (equalIgnoringCase(attr->value(), "hsides")) { 378 m_frameAttr = true; 379 borders[cTop] = borders[cBottom] = true; 380 } else if (equalIgnoringCase(attr->value(), "vsides")) { 381 m_frameAttr = true; 382 borders[cLeft] = borders[cRight] = true; 383 } else if (equalIgnoringCase(attr->value(), "lhs")) { 384 m_frameAttr = true; 385 borders[cLeft] = true; 386 } else if (equalIgnoringCase(attr->value(), "rhs")) { 387 m_frameAttr = true; 388 borders[cRight] = true; 389 } else if (equalIgnoringCase(attr->value(), "box") || 390 equalIgnoringCase(attr->value(), "border")) { 391 m_frameAttr = true; 392 borders[cTop] = borders[cBottom] = borders[cLeft] = borders[cRight] = true; 393 } 394 395 // Now map in the border styles of solid and hidden respectively. 396 if (m_frameAttr) { 397 addCSSProperty(attr, CSSPropertyBorderTopWidth, CSSValueThin); 398 addCSSProperty(attr, CSSPropertyBorderBottomWidth, CSSValueThin); 399 addCSSProperty(attr, CSSPropertyBorderLeftWidth, CSSValueThin); 400 addCSSProperty(attr, CSSPropertyBorderRightWidth, CSSValueThin); 401 addCSSProperty(attr, CSSPropertyBorderTopStyle, borders[cTop] ? CSSValueSolid : CSSValueHidden); 402 addCSSProperty(attr, CSSPropertyBorderBottomStyle, borders[cBottom] ? CSSValueSolid : CSSValueHidden); 403 addCSSProperty(attr, CSSPropertyBorderLeftStyle, borders[cLeft] ? CSSValueSolid : CSSValueHidden); 404 addCSSProperty(attr, CSSPropertyBorderRightStyle, borders[cRight] ? CSSValueSolid : CSSValueHidden); 405 } 406 } else if (attr->name() == rulesAttr) { 407 m_rulesAttr = UnsetRules; 408 if (equalIgnoringCase(attr->value(), "none")) 409 m_rulesAttr = NoneRules; 410 else if (equalIgnoringCase(attr->value(), "groups")) 411 m_rulesAttr = GroupsRules; 412 else if (equalIgnoringCase(attr->value(), "rows")) 413 m_rulesAttr = RowsRules; 414 if (equalIgnoringCase(attr->value(), "cols")) 415 m_rulesAttr = ColsRules; 416 if (equalIgnoringCase(attr->value(), "all")) 417 m_rulesAttr = AllRules; 418 419 // The presence of a valid rules attribute causes border collapsing to be enabled. 420 if (m_rulesAttr != UnsetRules) 421 addCSSProperty(attr, CSSPropertyBorderCollapse, CSSValueCollapse); 422 } else if (attr->name() == cellspacingAttr) { 423 if (!attr->value().isEmpty()) 424 addCSSLength(attr, CSSPropertyBorderSpacing, attr->value()); 425 } else if (attr->name() == cellpaddingAttr) { 426 if (!attr->value().isEmpty()) 427 m_padding = max(0, attr->value().toInt()); 428 else 429 m_padding = 1; 430 } else if (attr->name() == colsAttr) { 431 // ### 432 } else if (attr->name() == vspaceAttr) { 433 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 434 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 435 } else if (attr->name() == hspaceAttr) { 436 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 437 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 438 } else if (attr->name() == alignAttr) { 439 if (!attr->value().isEmpty()) { 440 if (equalIgnoringCase(attr->value(), "center")) { 441 addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto); 442 addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto); 443 } else 444 addCSSProperty(attr, CSSPropertyFloat, attr->value()); 445 } 446 } else if (attr->name() == valignAttr) { 447 if (!attr->value().isEmpty()) 448 addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value()); 449 } else 450 HTMLElement::parseMappedAttribute(attr); 451 452 if (bordersBefore != cellBorders() || oldPadding != m_padding) { 453 if (oldPadding != m_padding) 454 m_paddingDecl = 0; 455 bool cellChanged = false; 456 for (Node* child = firstChild(); child; child = child->nextSibling()) 457 cellChanged |= setTableCellsChanged(child); 458 if (cellChanged) 459 setNeedsStyleRecalc(); 460 } 461 } 462 463 void HTMLTableElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) 464 { 465 if ((!m_borderAttr && !m_borderColorAttr) || m_frameAttr) 466 return; 467 468 AtomicString borderValue = m_borderColorAttr ? "solid" : "outset"; 469 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, tableborderAttr, borderValue); 470 if (!decl) { 471 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. 472 decl->setParent(document()->elementSheet()); 473 decl->setNode(this); 474 decl->setStrictParsing(false); // Mapped attributes are just always quirky. 475 476 int v = m_borderColorAttr ? CSSValueSolid : CSSValueOutset; 477 decl->setProperty(CSSPropertyBorderTopStyle, v, false); 478 decl->setProperty(CSSPropertyBorderBottomStyle, v, false); 479 decl->setProperty(CSSPropertyBorderLeftStyle, v, false); 480 decl->setProperty(CSSPropertyBorderRightStyle, v, false); 481 482 setMappedAttributeDecl(ePersistent, tableborderAttr, borderValue, decl); 483 decl->setParent(0); 484 decl->setNode(0); 485 decl->setMappedState(ePersistent, tableborderAttr, borderValue); 486 } 487 488 489 results.append(decl); 490 } 491 492 HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const 493 { 494 switch (m_rulesAttr) { 495 case NoneRules: 496 case GroupsRules: 497 return NoBorders; 498 case AllRules: 499 return SolidBorders; 500 case ColsRules: 501 return SolidBordersColsOnly; 502 case RowsRules: 503 return SolidBordersRowsOnly; 504 case UnsetRules: 505 if (!m_borderAttr) 506 return NoBorders; 507 if (m_borderColorAttr) 508 return SolidBorders; 509 return InsetBorders; 510 } 511 ASSERT_NOT_REACHED(); 512 return NoBorders; 513 } 514 515 void HTMLTableElement::addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>& results) 516 { 517 addSharedCellBordersDecl(results); 518 addSharedCellPaddingDecl(results); 519 } 520 521 void HTMLTableElement::addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>& results) 522 { 523 CellBorders borders = cellBorders(); 524 525 static const AtomicString* cellBorderNames[] = { new AtomicString("none"), new AtomicString("solid"), new AtomicString("inset"), new AtomicString("solid-cols"), new AtomicString("solid-rows") }; 526 const AtomicString& cellborderValue = *cellBorderNames[borders]; 527 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, cellborderAttr, cellborderValue); 528 if (!decl) { 529 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. 530 decl->setParent(document()->elementSheet()); 531 decl->setNode(this); 532 decl->setStrictParsing(false); // Mapped attributes are just always quirky. 533 534 switch (borders) { 535 case SolidBordersColsOnly: 536 decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false); 537 decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false); 538 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); 539 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); 540 decl->setProperty(CSSPropertyBorderColor, "inherit", false); 541 break; 542 case SolidBordersRowsOnly: 543 decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false); 544 decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false); 545 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); 546 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); 547 decl->setProperty(CSSPropertyBorderColor, "inherit", false); 548 break; 549 case SolidBorders: 550 decl->setProperty(CSSPropertyBorderWidth, "1px", false); 551 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); 552 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); 553 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); 554 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); 555 decl->setProperty(CSSPropertyBorderColor, "inherit", false); 556 break; 557 case InsetBorders: 558 decl->setProperty(CSSPropertyBorderWidth, "1px", false); 559 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueInset, false); 560 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueInset, false); 561 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueInset, false); 562 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueInset, false); 563 decl->setProperty(CSSPropertyBorderColor, "inherit", false); 564 break; 565 case NoBorders: 566 decl->setProperty(CSSPropertyBorderWidth, "0", false); 567 break; 568 } 569 570 setMappedAttributeDecl(ePersistent, cellborderAttr, *cellBorderNames[borders], decl); 571 decl->setParent(0); 572 decl->setNode(0); 573 decl->setMappedState(ePersistent, cellborderAttr, cellborderValue); 574 } 575 576 results.append(decl); 577 } 578 579 void HTMLTableElement::addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>& results) 580 { 581 if (m_padding == 0) 582 return; 583 584 if (!m_paddingDecl) { 585 String paddingValue = String::number(m_padding); 586 m_paddingDecl = getMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue); 587 if (!m_paddingDecl) { 588 m_paddingDecl = CSSMappedAttributeDeclaration::create(); 589 m_paddingDecl->setParent(document()->elementSheet()); 590 m_paddingDecl->setNode(this); 591 m_paddingDecl->setStrictParsing(false); // Mapped attributes are just always quirky. 592 593 m_paddingDecl->setProperty(CSSPropertyPaddingTop, paddingValue, false); 594 m_paddingDecl->setProperty(CSSPropertyPaddingRight, paddingValue, false); 595 m_paddingDecl->setProperty(CSSPropertyPaddingBottom, paddingValue, false); 596 m_paddingDecl->setProperty(CSSPropertyPaddingLeft, paddingValue, false); 597 } 598 setMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue, m_paddingDecl.get()); 599 m_paddingDecl->setParent(0); 600 m_paddingDecl->setNode(0); 601 m_paddingDecl->setMappedState(eUniversal, cellpaddingAttr, paddingValue); 602 } 603 604 results.append(m_paddingDecl.get()); 605 } 606 607 void HTMLTableElement::addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>& results) 608 { 609 if (m_rulesAttr != GroupsRules) 610 return; 611 612 AtomicString rulesValue = rows ? "rowgroups" : "colgroups"; 613 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, rulesAttr, rulesValue); 614 if (!decl) { 615 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies. 616 decl->setParent(document()->elementSheet()); 617 decl->setNode(this); 618 decl->setStrictParsing(false); // Mapped attributes are just always quirky. 619 620 if (rows) { 621 decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false); 622 decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false); 623 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false); 624 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false); 625 } else { 626 decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false); 627 decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false); 628 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false); 629 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false); 630 } 631 632 setMappedAttributeDecl(ePersistent, rulesAttr, rulesValue, decl); 633 decl->setParent(0); 634 decl->setNode(0); 635 decl->setMappedState(ePersistent, rulesAttr, rulesValue); 636 } 637 638 results.append(decl); 639 } 640 641 void HTMLTableElement::attach() 642 { 643 ASSERT(!attached()); 644 HTMLElement::attach(); 645 } 646 647 bool HTMLTableElement::isURLAttribute(Attribute *attr) const 648 { 649 return attr->name() == backgroundAttr; 650 } 651 652 PassRefPtr<HTMLCollection> HTMLTableElement::rows() 653 { 654 return HTMLTableRowsCollection::create(this); 655 } 656 657 PassRefPtr<HTMLCollection> HTMLTableElement::tBodies() 658 { 659 return HTMLCollection::create(this, TableTBodies); 660 } 661 662 String HTMLTableElement::align() const 663 { 664 return getAttribute(alignAttr); 665 } 666 667 void HTMLTableElement::setAlign(const String &value) 668 { 669 setAttribute(alignAttr, value); 670 } 671 672 String HTMLTableElement::bgColor() const 673 { 674 return getAttribute(bgcolorAttr); 675 } 676 677 void HTMLTableElement::setBgColor(const String &value) 678 { 679 setAttribute(bgcolorAttr, value); 680 } 681 682 String HTMLTableElement::border() const 683 { 684 return getAttribute(borderAttr); 685 } 686 687 void HTMLTableElement::setBorder(const String &value) 688 { 689 setAttribute(borderAttr, value); 690 } 691 692 String HTMLTableElement::cellPadding() const 693 { 694 return getAttribute(cellpaddingAttr); 695 } 696 697 void HTMLTableElement::setCellPadding(const String &value) 698 { 699 setAttribute(cellpaddingAttr, value); 700 } 701 702 String HTMLTableElement::cellSpacing() const 703 { 704 return getAttribute(cellspacingAttr); 705 } 706 707 void HTMLTableElement::setCellSpacing(const String &value) 708 { 709 setAttribute(cellspacingAttr, value); 710 } 711 712 String HTMLTableElement::frame() const 713 { 714 return getAttribute(frameAttr); 715 } 716 717 void HTMLTableElement::setFrame(const String &value) 718 { 719 setAttribute(frameAttr, value); 720 } 721 722 String HTMLTableElement::rules() const 723 { 724 return getAttribute(rulesAttr); 725 } 726 727 void HTMLTableElement::setRules(const String &value) 728 { 729 setAttribute(rulesAttr, value); 730 } 731 732 String HTMLTableElement::summary() const 733 { 734 return getAttribute(summaryAttr); 735 } 736 737 void HTMLTableElement::setSummary(const String &value) 738 { 739 setAttribute(summaryAttr, value); 740 } 741 742 String HTMLTableElement::width() const 743 { 744 return getAttribute(widthAttr); 745 } 746 747 void HTMLTableElement::setWidth(const String &value) 748 { 749 setAttribute(widthAttr, value); 750 } 751 752 void HTMLTableElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 753 { 754 HTMLElement::addSubresourceAttributeURLs(urls); 755 756 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr))); 757 } 758 759 } 760