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, 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 "HTMLTableCellElement.h"
27
28#include "CSSPropertyNames.h"
29#include "CSSValueKeywords.h"
30#include "HTMLNames.h"
31#include "HTMLParserIdioms.h"
32#include "HTMLTableElement.h"
33#include "RenderTableCell.h"
34#include <wtf/IsoMallocInlines.h>
35
36namespace WebCore {
37
38WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLTableCellElement);
39
40using namespace HTMLNames;
41
42// These limits are defined in the HTML specification:
43// - https://html.spec.whatwg.org/#dom-tdth-colspan
44// - https://html.spec.whatwg.org/#dom-tdth-rowspan
45static const unsigned minColspan = 1;
46static const unsigned maxColspan = 1000;
47static const unsigned defaultColspan = 1;
48static const unsigned minRowspan = 0;
49static const unsigned maxRowspan = 65534;
50static const unsigned defaultRowspan = 1;
51
52Ref<HTMLTableCellElement> HTMLTableCellElement::create(const QualifiedName& tagName, Document& document)
53{
54 return adoptRef(*new HTMLTableCellElement(tagName, document));
55}
56
57HTMLTableCellElement::HTMLTableCellElement(const QualifiedName& tagName, Document& document)
58 : HTMLTablePartElement(tagName, document)
59{
60 ASSERT(tagName == thTag || tagName == tdTag);
61}
62
63unsigned HTMLTableCellElement::colSpan() const
64{
65 return clampHTMLNonNegativeIntegerToRange(attributeWithoutSynchronization(colspanAttr), minColspan, maxColspan, defaultColspan);
66}
67
68unsigned HTMLTableCellElement::rowSpan() const
69{
70 // FIXME: a rowSpan equal to 0 should be allowed, and mean that the cell is to span all the remaining rows in the row group.
71 return std::max(1u, rowSpanForBindings());
72}
73
74unsigned HTMLTableCellElement::rowSpanForBindings() const
75{
76 return clampHTMLNonNegativeIntegerToRange(attributeWithoutSynchronization(rowspanAttr), minRowspan, maxRowspan, defaultRowspan);
77}
78
79int HTMLTableCellElement::cellIndex() const
80{
81 int index = 0;
82 if (!parentElement() || !parentElement()->hasTagName(trTag))
83 return -1;
84
85 for (const Node * node = previousSibling(); node; node = node->previousSibling()) {
86 if (node->hasTagName(tdTag) || node->hasTagName(thTag))
87 index++;
88 }
89
90 return index;
91}
92
93bool HTMLTableCellElement::isPresentationAttribute(const QualifiedName& name) const
94{
95 if (name == nowrapAttr || name == widthAttr || name == heightAttr)
96 return true;
97 return HTMLTablePartElement::isPresentationAttribute(name);
98}
99
100void HTMLTableCellElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
101{
102 if (name == nowrapAttr)
103 addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValueWebkitNowrap);
104 else if (name == widthAttr) {
105 if (!value.isEmpty()) {
106 int widthInt = value.toInt();
107 if (widthInt > 0) // width="0" is ignored for compatibility with WinIE.
108 addHTMLLengthToStyle(style, CSSPropertyWidth, value);
109 }
110 } else if (name == heightAttr) {
111 if (!value.isEmpty()) {
112 int heightInt = value.toInt();
113 if (heightInt > 0) // height="0" is ignored for compatibility with WinIE.
114 addHTMLLengthToStyle(style, CSSPropertyHeight, value);
115 }
116 } else
117 HTMLTablePartElement::collectStyleForPresentationAttribute(name, value, style);
118}
119
120void HTMLTableCellElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
121{
122 if (name == rowspanAttr) {
123 if (is<RenderTableCell>(renderer()))
124 downcast<RenderTableCell>(*renderer()).colSpanOrRowSpanChanged();
125 } else if (name == colspanAttr) {
126 if (is<RenderTableCell>(renderer()))
127 downcast<RenderTableCell>(*renderer()).colSpanOrRowSpanChanged();
128 } else
129 HTMLTablePartElement::parseAttribute(name, value);
130}
131
132const StyleProperties* HTMLTableCellElement::additionalPresentationAttributeStyle() const
133{
134 if (RefPtr<HTMLTableElement> table = findParentTable())
135 return table->additionalCellStyle();
136 return 0;
137}
138
139bool HTMLTableCellElement::isURLAttribute(const Attribute& attribute) const
140{
141 return attribute.name() == backgroundAttr || HTMLTablePartElement::isURLAttribute(attribute);
142}
143
144String HTMLTableCellElement::abbr() const
145{
146 return attributeWithoutSynchronization(abbrAttr);
147}
148
149String HTMLTableCellElement::axis() const
150{
151 return attributeWithoutSynchronization(axisAttr);
152}
153
154void HTMLTableCellElement::setColSpan(unsigned n)
155{
156 setAttributeWithoutSynchronization(colspanAttr, AtomicString::number(limitToOnlyHTMLNonNegative(n, 1)));
157}
158
159String HTMLTableCellElement::headers() const
160{
161 return attributeWithoutSynchronization(headersAttr);
162}
163
164void HTMLTableCellElement::setRowSpanForBindings(unsigned n)
165{
166 setAttributeWithoutSynchronization(rowspanAttr, AtomicString::number(limitToOnlyHTMLNonNegative(n, 1)));
167}
168
169const AtomicString& HTMLTableCellElement::scope() const
170{
171 // https://html.spec.whatwg.org/multipage/tables.html#attr-th-scope
172 static NeverDestroyed<const AtomicString> row("row", AtomicString::ConstructFromLiteral);
173 static NeverDestroyed<const AtomicString> col("col", AtomicString::ConstructFromLiteral);
174 static NeverDestroyed<const AtomicString> rowgroup("rowgroup", AtomicString::ConstructFromLiteral);
175 static NeverDestroyed<const AtomicString> colgroup("colgroup", AtomicString::ConstructFromLiteral);
176
177 const AtomicString& value = attributeWithoutSynchronization(HTMLNames::scopeAttr);
178
179 if (equalIgnoringASCIICase(value, row))
180 return row;
181 if (equalIgnoringASCIICase(value, col))
182 return col;
183 if (equalIgnoringASCIICase(value, rowgroup))
184 return rowgroup;
185 if (equalIgnoringASCIICase(value, colgroup))
186 return colgroup;
187 return emptyAtom();
188}
189
190void HTMLTableCellElement::setScope(const AtomicString& scope)
191{
192 setAttributeWithoutSynchronization(scopeAttr, scope);
193}
194
195void HTMLTableCellElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
196{
197 HTMLTablePartElement::addSubresourceAttributeURLs(urls);
198
199 addSubresourceURL(urls, document().completeURL(attributeWithoutSynchronization(backgroundAttr)));
200}
201
202HTMLTableCellElement* HTMLTableCellElement::cellAbove() const
203{
204 auto* cellRenderer = renderer();
205 if (!is<RenderTableCell>(cellRenderer))
206 return nullptr;
207
208 auto& tableCellRenderer = downcast<RenderTableCell>(*cellRenderer);
209 auto* cellAboveRenderer = tableCellRenderer.table()->cellAbove(&tableCellRenderer);
210 if (!cellAboveRenderer)
211 return nullptr;
212
213 return downcast<HTMLTableCellElement>(cellAboveRenderer->element());
214}
215
216} // namespace WebCore
217