1 /*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 * (C) 1997 Torben Weis (weis@kde.org)
4 * (C) 1998 Waldo Bastian (bastian@kde.org)
5 * (C) 1999 Lars Knoll (knoll@kde.org)
6 * (C) 1999 Antti Koivisto (koivisto@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 "HTMLTableRowsCollection.h"
35 #include "HTMLTableRowElement.h"
36 #include "HTMLTableSectionElement.h"
37 #include "RenderTable.h"
38 #include "Text.h"
39
40 namespace WebCore {
41
42 using namespace HTMLNames;
43
HTMLTableElement(const QualifiedName & tagName,Document * doc)44 HTMLTableElement::HTMLTableElement(const QualifiedName& tagName, Document* doc)
45 : HTMLElement(tagName, doc)
46 , m_borderAttr(false)
47 , m_borderColorAttr(false)
48 , m_frameAttr(false)
49 , m_rulesAttr(UnsetRules)
50 , m_padding(1)
51 {
52 ASSERT(hasTagName(tableTag));
53 }
54
checkDTD(const Node * newChild)55 bool HTMLTableElement::checkDTD(const Node* newChild)
56 {
57 if (newChild->isTextNode())
58 return static_cast<const Text*>(newChild)->containsOnlyWhitespace();
59 return newChild->hasTagName(captionTag) ||
60 newChild->hasTagName(colTag) || newChild->hasTagName(colgroupTag) ||
61 newChild->hasTagName(theadTag) || newChild->hasTagName(tfootTag) ||
62 newChild->hasTagName(tbodyTag) || newChild->hasTagName(formTag) ||
63 newChild->hasTagName(scriptTag);
64 }
65
caption() const66 HTMLTableCaptionElement* HTMLTableElement::caption() const
67 {
68 for (Node* child = firstChild(); child; child = child->nextSibling()) {
69 if (child->hasTagName(captionTag))
70 return static_cast<HTMLTableCaptionElement*>(child);
71 }
72 return 0;
73 }
74
setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption,ExceptionCode & ec)75 void HTMLTableElement::setCaption(PassRefPtr<HTMLTableCaptionElement> newCaption, ExceptionCode& ec)
76 {
77 deleteCaption();
78 insertBefore(newCaption, firstChild(), ec);
79 }
80
tHead() const81 HTMLTableSectionElement* HTMLTableElement::tHead() const
82 {
83 for (Node* child = firstChild(); child; child = child->nextSibling()) {
84 if (child->hasTagName(theadTag))
85 return static_cast<HTMLTableSectionElement*>(child);
86 }
87 return 0;
88 }
89
setTHead(PassRefPtr<HTMLTableSectionElement> newHead,ExceptionCode & ec)90 void HTMLTableElement::setTHead(PassRefPtr<HTMLTableSectionElement> newHead, ExceptionCode& ec)
91 {
92 deleteTHead();
93
94 Node* child;
95 for (child = firstChild(); child; child = child->nextSibling())
96 if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag))
97 break;
98
99 insertBefore(newHead, child, ec);
100 }
101
tFoot() const102 HTMLTableSectionElement* HTMLTableElement::tFoot() const
103 {
104 for (Node* child = firstChild(); child; child = child->nextSibling()) {
105 if (child->hasTagName(tfootTag))
106 return static_cast<HTMLTableSectionElement*>(child);
107 }
108 return 0;
109 }
110
setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot,ExceptionCode & ec)111 void HTMLTableElement::setTFoot(PassRefPtr<HTMLTableSectionElement> newFoot, ExceptionCode& ec)
112 {
113 deleteTFoot();
114
115 Node* child;
116 for (child = firstChild(); child; child = child->nextSibling())
117 if (child->isElementNode() && !child->hasTagName(captionTag) && !child->hasTagName(colgroupTag) && !child->hasTagName(theadTag))
118 break;
119
120 insertBefore(newFoot, child, ec);
121 }
122
createTHead()123 PassRefPtr<HTMLElement> HTMLTableElement::createTHead()
124 {
125 if (HTMLTableSectionElement* existingHead = tHead())
126 return existingHead;
127 RefPtr<HTMLTableSectionElement> head = new HTMLTableSectionElement(theadTag, document());
128 ExceptionCode ec;
129 setTHead(head, ec);
130 return head.release();
131 }
132
deleteTHead()133 void HTMLTableElement::deleteTHead()
134 {
135 ExceptionCode ec;
136 removeChild(tHead(), ec);
137 }
138
createTFoot()139 PassRefPtr<HTMLElement> HTMLTableElement::createTFoot()
140 {
141 if (HTMLTableSectionElement* existingFoot = tFoot())
142 return existingFoot;
143 RefPtr<HTMLTableSectionElement> foot = new HTMLTableSectionElement(tfootTag, document());
144 ExceptionCode ec;
145 setTFoot(foot, ec);
146 return foot.release();
147 }
148
deleteTFoot()149 void HTMLTableElement::deleteTFoot()
150 {
151 ExceptionCode ec;
152 removeChild(tFoot(), ec);
153 }
154
createCaption()155 PassRefPtr<HTMLElement> HTMLTableElement::createCaption()
156 {
157 if (HTMLTableCaptionElement* existingCaption = caption())
158 return existingCaption;
159 RefPtr<HTMLTableCaptionElement> caption = new HTMLTableCaptionElement(captionTag, document());
160 ExceptionCode ec;
161 setCaption(caption, ec);
162 return caption.release();
163 }
164
deleteCaption()165 void HTMLTableElement::deleteCaption()
166 {
167 ExceptionCode ec;
168 removeChild(caption(), ec);
169 }
170
lastBody() const171 HTMLTableSectionElement* HTMLTableElement::lastBody() const
172 {
173 for (Node* child = lastChild(); child; child = child->previousSibling()) {
174 if (child->hasTagName(tbodyTag))
175 return static_cast<HTMLTableSectionElement*>(child);
176 }
177 return 0;
178 }
179
insertRow(int index,ExceptionCode & ec)180 PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec)
181 {
182 if (index < -1) {
183 ec = INDEX_SIZE_ERR;
184 return 0;
185 }
186
187 HTMLTableRowElement* lastRow = 0;
188 HTMLTableRowElement* row = 0;
189 if (index == -1)
190 lastRow = HTMLTableRowsCollection::lastRow(this);
191 else {
192 for (int i = 0; i <= index; ++i) {
193 row = HTMLTableRowsCollection::rowAfter(this, lastRow);
194 if (!row) {
195 if (i != index) {
196 ec = INDEX_SIZE_ERR;
197 return 0;
198 }
199 break;
200 }
201 lastRow = row;
202 }
203 }
204
205 Node* parent;
206 if (lastRow)
207 parent = row ? row->parent() : lastRow->parent();
208 else {
209 parent = lastBody();
210 if (!parent) {
211 RefPtr<HTMLTableSectionElement> newBody = new HTMLTableSectionElement(tbodyTag, document());
212 RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, document());
213 newBody->appendChild(newRow, ec);
214 appendChild(newBody.release(), ec);
215 return newRow.release();
216 }
217 }
218
219 RefPtr<HTMLTableRowElement> newRow = new HTMLTableRowElement(trTag, document());
220 parent->insertBefore(newRow, row, ec);
221 return newRow.release();
222 }
223
deleteRow(int index,ExceptionCode & ec)224 void HTMLTableElement::deleteRow(int index, ExceptionCode& ec)
225 {
226 HTMLTableRowElement* row = 0;
227 if (index == -1)
228 row = HTMLTableRowsCollection::lastRow(this);
229 else {
230 for (int i = 0; i <= index; ++i) {
231 row = HTMLTableRowsCollection::rowAfter(this, row);
232 if (!row)
233 break;
234 }
235 }
236 if (!row) {
237 ec = INDEX_SIZE_ERR;
238 return;
239 }
240 row->remove(ec);
241 }
242
addChild(PassRefPtr<Node> child)243 ContainerNode* HTMLTableElement::addChild(PassRefPtr<Node> child)
244 {
245 if (child->hasTagName(formTag)) {
246 // First add the child.
247 HTMLElement::addChild(child);
248
249 // Now simply return ourselves as the container to insert into.
250 // This has the effect of demoting the form to a leaf and moving it safely out of the way.
251 return this;
252 }
253
254 return HTMLElement::addChild(child.get());
255 }
256
mapToEntry(const QualifiedName & attrName,MappedAttributeEntry & result) const257 bool HTMLTableElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
258 {
259 if (attrName == backgroundAttr) {
260 result = (MappedAttributeEntry)(eLastEntry + document()->docID());
261 return false;
262 }
263
264 if (attrName == widthAttr ||
265 attrName == heightAttr ||
266 attrName == bgcolorAttr ||
267 attrName == cellspacingAttr ||
268 attrName == vspaceAttr ||
269 attrName == hspaceAttr ||
270 attrName == valignAttr) {
271 result = eUniversal;
272 return false;
273 }
274
275 if (attrName == bordercolorAttr || attrName == frameAttr || attrName == rulesAttr) {
276 result = eUniversal;
277 return true;
278 }
279
280 if (attrName == borderAttr) {
281 result = eTable;
282 return true;
283 }
284
285 if (attrName == alignAttr) {
286 result = eTable;
287 return false;
288 }
289
290 return HTMLElement::mapToEntry(attrName, result);
291 }
292
isTableCellAncestor(Node * n)293 static inline bool isTableCellAncestor(Node* n)
294 {
295 return n->hasTagName(theadTag) || n->hasTagName(tbodyTag) ||
296 n->hasTagName(tfootTag) || n->hasTagName(trTag) ||
297 n->hasTagName(thTag);
298 }
299
setTableCellsChanged(Node * n)300 static bool setTableCellsChanged(Node* n)
301 {
302 ASSERT(n);
303 bool cellChanged = false;
304
305 if (n->hasTagName(tdTag))
306 cellChanged = true;
307 else if (isTableCellAncestor(n)) {
308 for (Node* child = n->firstChild(); child; child = child->nextSibling())
309 cellChanged |= setTableCellsChanged(child);
310 }
311
312 if (cellChanged)
313 n->setChanged();
314
315 return cellChanged;
316 }
317
parseMappedAttribute(MappedAttribute * attr)318 void HTMLTableElement::parseMappedAttribute(MappedAttribute* attr)
319 {
320 CellBorders bordersBefore = cellBorders();
321 unsigned short oldPadding = m_padding;
322
323 if (attr->name() == widthAttr)
324 addCSSLength(attr, CSSPropertyWidth, attr->value());
325 else if (attr->name() == heightAttr)
326 addCSSLength(attr, CSSPropertyHeight, attr->value());
327 else if (attr->name() == borderAttr) {
328 m_borderAttr = true;
329 if (attr->decl()) {
330 RefPtr<CSSValue> val = attr->decl()->getPropertyCSSValue(CSSPropertyBorderLeftWidth);
331 if (val && val->isPrimitiveValue()) {
332 CSSPrimitiveValue* primVal = static_cast<CSSPrimitiveValue*>(val.get());
333 m_borderAttr = primVal->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER);
334 }
335 } else if (!attr->isNull()) {
336 int border = 0;
337 if (attr->isEmpty())
338 border = 1;
339 else
340 border = attr->value().toInt();
341 m_borderAttr = border;
342 addCSSLength(attr, CSSPropertyBorderWidth, String::number(border));
343 }
344 } else if (attr->name() == bgcolorAttr)
345 addCSSColor(attr, CSSPropertyBackgroundColor, attr->value());
346 else if (attr->name() == bordercolorAttr) {
347 m_borderColorAttr = attr->decl();
348 if (!attr->decl() && !attr->isEmpty()) {
349 addCSSColor(attr, CSSPropertyBorderColor, attr->value());
350 m_borderColorAttr = true;
351 }
352 } else if (attr->name() == backgroundAttr) {
353 String url = parseURL(attr->value());
354 if (!url.isEmpty())
355 addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string());
356 } else if (attr->name() == frameAttr) {
357 // Cache the value of "frame" so that the table can examine it later.
358 m_frameAttr = false;
359
360 // Whether or not to hide the top/right/bottom/left borders.
361 const int cTop = 0;
362 const int cRight = 1;
363 const int cBottom = 2;
364 const int cLeft = 3;
365 bool borders[4] = { false, false, false, false };
366
367 // void, above, below, hsides, vsides, lhs, rhs, box, border
368 if (equalIgnoringCase(attr->value(), "void"))
369 m_frameAttr = true;
370 else if (equalIgnoringCase(attr->value(), "above")) {
371 m_frameAttr = true;
372 borders[cTop] = true;
373 } else if (equalIgnoringCase(attr->value(), "below")) {
374 m_frameAttr = true;
375 borders[cBottom] = true;
376 } else if (equalIgnoringCase(attr->value(), "hsides")) {
377 m_frameAttr = true;
378 borders[cTop] = borders[cBottom] = true;
379 } else if (equalIgnoringCase(attr->value(), "vsides")) {
380 m_frameAttr = true;
381 borders[cLeft] = borders[cRight] = true;
382 } else if (equalIgnoringCase(attr->value(), "lhs")) {
383 m_frameAttr = true;
384 borders[cLeft] = true;
385 } else if (equalIgnoringCase(attr->value(), "rhs")) {
386 m_frameAttr = true;
387 borders[cRight] = true;
388 } else if (equalIgnoringCase(attr->value(), "box") ||
389 equalIgnoringCase(attr->value(), "border")) {
390 m_frameAttr = true;
391 borders[cTop] = borders[cBottom] = borders[cLeft] = borders[cRight] = true;
392 }
393
394 // Now map in the border styles of solid and hidden respectively.
395 if (m_frameAttr) {
396 addCSSProperty(attr, CSSPropertyBorderTopWidth, CSSValueThin);
397 addCSSProperty(attr, CSSPropertyBorderBottomWidth, CSSValueThin);
398 addCSSProperty(attr, CSSPropertyBorderLeftWidth, CSSValueThin);
399 addCSSProperty(attr, CSSPropertyBorderRightWidth, CSSValueThin);
400 addCSSProperty(attr, CSSPropertyBorderTopStyle, borders[cTop] ? CSSValueSolid : CSSValueHidden);
401 addCSSProperty(attr, CSSPropertyBorderBottomStyle, borders[cBottom] ? CSSValueSolid : CSSValueHidden);
402 addCSSProperty(attr, CSSPropertyBorderLeftStyle, borders[cLeft] ? CSSValueSolid : CSSValueHidden);
403 addCSSProperty(attr, CSSPropertyBorderRightStyle, borders[cRight] ? CSSValueSolid : CSSValueHidden);
404 }
405 } else if (attr->name() == rulesAttr) {
406 m_rulesAttr = UnsetRules;
407 if (equalIgnoringCase(attr->value(), "none"))
408 m_rulesAttr = NoneRules;
409 else if (equalIgnoringCase(attr->value(), "groups"))
410 m_rulesAttr = GroupsRules;
411 else if (equalIgnoringCase(attr->value(), "rows"))
412 m_rulesAttr = RowsRules;
413 if (equalIgnoringCase(attr->value(), "cols"))
414 m_rulesAttr = ColsRules;
415 if (equalIgnoringCase(attr->value(), "all"))
416 m_rulesAttr = AllRules;
417
418 // The presence of a valid rules attribute causes border collapsing to be enabled.
419 if (m_rulesAttr != UnsetRules)
420 addCSSProperty(attr, CSSPropertyBorderCollapse, CSSValueCollapse);
421 } else if (attr->name() == cellspacingAttr) {
422 if (!attr->value().isEmpty())
423 addCSSLength(attr, CSSPropertyBorderSpacing, attr->value());
424 } else if (attr->name() == cellpaddingAttr) {
425 if (!attr->value().isEmpty())
426 m_padding = max(0, attr->value().toInt());
427 else
428 m_padding = 1;
429 } else if (attr->name() == colsAttr) {
430 // ###
431 } else if (attr->name() == vspaceAttr) {
432 addCSSLength(attr, CSSPropertyMarginTop, attr->value());
433 addCSSLength(attr, CSSPropertyMarginBottom, attr->value());
434 } else if (attr->name() == hspaceAttr) {
435 addCSSLength(attr, CSSPropertyMarginLeft, attr->value());
436 addCSSLength(attr, CSSPropertyMarginRight, attr->value());
437 } else if (attr->name() == alignAttr) {
438 if (!attr->value().isEmpty()) {
439 if (equalIgnoringCase(attr->value(), "center")) {
440 addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto);
441 addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto);
442 } else
443 addCSSProperty(attr, CSSPropertyFloat, attr->value());
444 }
445 } else if (attr->name() == valignAttr) {
446 if (!attr->value().isEmpty())
447 addCSSProperty(attr, CSSPropertyVerticalAlign, attr->value());
448 } else
449 HTMLElement::parseMappedAttribute(attr);
450
451 if (bordersBefore != cellBorders() || oldPadding != m_padding) {
452 if (oldPadding != m_padding)
453 m_paddingDecl = 0;
454 bool cellChanged = false;
455 for (Node* child = firstChild(); child; child = child->nextSibling())
456 cellChanged |= setTableCellsChanged(child);
457 if (cellChanged)
458 setChanged();
459 }
460 }
461
additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration * > & results)462 void HTMLTableElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results)
463 {
464 if ((!m_borderAttr && !m_borderColorAttr) || m_frameAttr)
465 return;
466
467 AtomicString borderValue = m_borderColorAttr ? "solid" : "outset";
468 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, tableborderAttr, borderValue);
469 if (!decl) {
470 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
471 decl->setParent(document()->elementSheet());
472 decl->setNode(this);
473 decl->setStrictParsing(false); // Mapped attributes are just always quirky.
474
475 int v = m_borderColorAttr ? CSSValueSolid : CSSValueOutset;
476 decl->setProperty(CSSPropertyBorderTopStyle, v, false);
477 decl->setProperty(CSSPropertyBorderBottomStyle, v, false);
478 decl->setProperty(CSSPropertyBorderLeftStyle, v, false);
479 decl->setProperty(CSSPropertyBorderRightStyle, v, false);
480
481 setMappedAttributeDecl(ePersistent, tableborderAttr, borderValue, decl);
482 decl->setParent(0);
483 decl->setNode(0);
484 decl->setMappedState(ePersistent, tableborderAttr, borderValue);
485 }
486
487
488 results.append(decl);
489 }
490
cellBorders() const491 HTMLTableElement::CellBorders HTMLTableElement::cellBorders() const
492 {
493 switch (m_rulesAttr) {
494 case NoneRules:
495 case GroupsRules:
496 return NoBorders;
497 case AllRules:
498 return SolidBorders;
499 case ColsRules:
500 return SolidBordersColsOnly;
501 case RowsRules:
502 return SolidBordersRowsOnly;
503 case UnsetRules:
504 if (!m_borderAttr)
505 return NoBorders;
506 if (m_borderColorAttr)
507 return SolidBorders;
508 return InsetBorders;
509 }
510 ASSERT_NOT_REACHED();
511 return NoBorders;
512 }
513
addSharedCellDecls(Vector<CSSMutableStyleDeclaration * > & results)514 void HTMLTableElement::addSharedCellDecls(Vector<CSSMutableStyleDeclaration*>& results)
515 {
516 addSharedCellBordersDecl(results);
517 addSharedCellPaddingDecl(results);
518 }
519
addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration * > & results)520 void HTMLTableElement::addSharedCellBordersDecl(Vector<CSSMutableStyleDeclaration*>& results)
521 {
522 CellBorders borders = cellBorders();
523
524 static const AtomicString* cellBorderNames[] = { new AtomicString("none"), new AtomicString("solid"), new AtomicString("inset"), new AtomicString("solid-cols"), new AtomicString("solid-rows") };
525 const AtomicString& cellborderValue = *cellBorderNames[borders];
526 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, cellborderAttr, cellborderValue);
527 if (!decl) {
528 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
529 decl->setParent(document()->elementSheet());
530 decl->setNode(this);
531 decl->setStrictParsing(false); // Mapped attributes are just always quirky.
532
533 switch (borders) {
534 case SolidBordersColsOnly:
535 decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
536 decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
537 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
538 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
539 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
540 break;
541 case SolidBordersRowsOnly:
542 decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
543 decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
544 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
545 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
546 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
547 break;
548 case SolidBorders:
549 decl->setProperty(CSSPropertyBorderWidth, "1px", false);
550 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
551 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
552 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
553 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
554 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
555 break;
556 case InsetBorders:
557 decl->setProperty(CSSPropertyBorderWidth, "1px", false);
558 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueInset, false);
559 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueInset, false);
560 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueInset, false);
561 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueInset, false);
562 decl->setProperty(CSSPropertyBorderColor, "inherit", false);
563 break;
564 case NoBorders:
565 decl->setProperty(CSSPropertyBorderWidth, "0", false);
566 break;
567 }
568
569 setMappedAttributeDecl(ePersistent, cellborderAttr, *cellBorderNames[borders], decl);
570 decl->setParent(0);
571 decl->setNode(0);
572 decl->setMappedState(ePersistent, cellborderAttr, cellborderValue);
573 }
574
575 results.append(decl);
576 }
577
addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration * > & results)578 void HTMLTableElement::addSharedCellPaddingDecl(Vector<CSSMutableStyleDeclaration*>& results)
579 {
580 if (m_padding == 0)
581 return;
582
583 if (!m_paddingDecl) {
584 String paddingValue = String::number(m_padding);
585 m_paddingDecl = getMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue);
586 if (!m_paddingDecl) {
587 m_paddingDecl = CSSMappedAttributeDeclaration::create();
588 m_paddingDecl->setParent(document()->elementSheet());
589 m_paddingDecl->setNode(this);
590 m_paddingDecl->setStrictParsing(false); // Mapped attributes are just always quirky.
591
592 m_paddingDecl->setProperty(CSSPropertyPaddingTop, paddingValue, false);
593 m_paddingDecl->setProperty(CSSPropertyPaddingRight, paddingValue, false);
594 m_paddingDecl->setProperty(CSSPropertyPaddingBottom, paddingValue, false);
595 m_paddingDecl->setProperty(CSSPropertyPaddingLeft, paddingValue, false);
596 }
597 setMappedAttributeDecl(eUniversal, cellpaddingAttr, paddingValue, m_paddingDecl.get());
598 m_paddingDecl->setParent(0);
599 m_paddingDecl->setNode(0);
600 m_paddingDecl->setMappedState(eUniversal, cellpaddingAttr, paddingValue);
601 }
602
603 results.append(m_paddingDecl.get());
604 }
605
addSharedGroupDecls(bool rows,Vector<CSSMutableStyleDeclaration * > & results)606 void HTMLTableElement::addSharedGroupDecls(bool rows, Vector<CSSMutableStyleDeclaration*>& results)
607 {
608 if (m_rulesAttr != GroupsRules)
609 return;
610
611 AtomicString rulesValue = rows ? "rowgroups" : "colgroups";
612 CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(ePersistent, rulesAttr, rulesValue);
613 if (!decl) {
614 decl = CSSMappedAttributeDeclaration::create().releaseRef(); // This single ref pins us in the table until the document dies.
615 decl->setParent(document()->elementSheet());
616 decl->setNode(this);
617 decl->setStrictParsing(false); // Mapped attributes are just always quirky.
618
619 if (rows) {
620 decl->setProperty(CSSPropertyBorderTopWidth, CSSValueThin, false);
621 decl->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin, false);
622 decl->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid, false);
623 decl->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid, false);
624 } else {
625 decl->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin, false);
626 decl->setProperty(CSSPropertyBorderRightWidth, CSSValueThin, false);
627 decl->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid, false);
628 decl->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid, false);
629 }
630
631 setMappedAttributeDecl(ePersistent, rulesAttr, rulesValue, decl);
632 decl->setParent(0);
633 decl->setNode(0);
634 decl->setMappedState(ePersistent, rulesAttr, rulesValue);
635 }
636
637 results.append(decl);
638 }
639
attach()640 void HTMLTableElement::attach()
641 {
642 ASSERT(!attached());
643 HTMLElement::attach();
644 }
645
isURLAttribute(Attribute * attr) const646 bool HTMLTableElement::isURLAttribute(Attribute *attr) const
647 {
648 return attr->name() == backgroundAttr;
649 }
650
rows()651 PassRefPtr<HTMLCollection> HTMLTableElement::rows()
652 {
653 return HTMLTableRowsCollection::create(this);
654 }
655
tBodies()656 PassRefPtr<HTMLCollection> HTMLTableElement::tBodies()
657 {
658 return HTMLCollection::create(this, HTMLCollection::TableTBodies);
659 }
660
align() const661 String HTMLTableElement::align() const
662 {
663 return getAttribute(alignAttr);
664 }
665
setAlign(const String & value)666 void HTMLTableElement::setAlign(const String &value)
667 {
668 setAttribute(alignAttr, value);
669 }
670
bgColor() const671 String HTMLTableElement::bgColor() const
672 {
673 return getAttribute(bgcolorAttr);
674 }
675
setBgColor(const String & value)676 void HTMLTableElement::setBgColor(const String &value)
677 {
678 setAttribute(bgcolorAttr, value);
679 }
680
border() const681 String HTMLTableElement::border() const
682 {
683 return getAttribute(borderAttr);
684 }
685
setBorder(const String & value)686 void HTMLTableElement::setBorder(const String &value)
687 {
688 setAttribute(borderAttr, value);
689 }
690
cellPadding() const691 String HTMLTableElement::cellPadding() const
692 {
693 return getAttribute(cellpaddingAttr);
694 }
695
setCellPadding(const String & value)696 void HTMLTableElement::setCellPadding(const String &value)
697 {
698 setAttribute(cellpaddingAttr, value);
699 }
700
cellSpacing() const701 String HTMLTableElement::cellSpacing() const
702 {
703 return getAttribute(cellspacingAttr);
704 }
705
setCellSpacing(const String & value)706 void HTMLTableElement::setCellSpacing(const String &value)
707 {
708 setAttribute(cellspacingAttr, value);
709 }
710
frame() const711 String HTMLTableElement::frame() const
712 {
713 return getAttribute(frameAttr);
714 }
715
setFrame(const String & value)716 void HTMLTableElement::setFrame(const String &value)
717 {
718 setAttribute(frameAttr, value);
719 }
720
rules() const721 String HTMLTableElement::rules() const
722 {
723 return getAttribute(rulesAttr);
724 }
725
setRules(const String & value)726 void HTMLTableElement::setRules(const String &value)
727 {
728 setAttribute(rulesAttr, value);
729 }
730
summary() const731 String HTMLTableElement::summary() const
732 {
733 return getAttribute(summaryAttr);
734 }
735
setSummary(const String & value)736 void HTMLTableElement::setSummary(const String &value)
737 {
738 setAttribute(summaryAttr, value);
739 }
740
width() const741 String HTMLTableElement::width() const
742 {
743 return getAttribute(widthAttr);
744 }
745
setWidth(const String & value)746 void HTMLTableElement::setWidth(const String &value)
747 {
748 setAttribute(widthAttr, value);
749 }
750
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const751 void HTMLTableElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
752 {
753 HTMLElement::addSubresourceAttributeURLs(urls);
754
755 addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr)));
756 }
757
758 }
759