• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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