1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/HTMLTableCellElement.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/HTMLTableElement.h"
10 #include "mozilla/dom/HTMLTableRowElement.h"
11 #include "mozilla/MappedDeclarations.h"
12 #include "nsMappedAttributes.h"
13 #include "nsAttrValueInlines.h"
14 #include "celldata.h"
15 #include "mozilla/dom/HTMLTableCellElementBinding.h"
16 
17 NS_IMPL_NS_NEW_HTML_ELEMENT(TableCell)
18 
19 namespace mozilla::dom {
20 
21 HTMLTableCellElement::~HTMLTableCellElement() = default;
22 
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)23 JSObject* HTMLTableCellElement::WrapNode(JSContext* aCx,
24                                          JS::Handle<JSObject*> aGivenProto) {
25   return HTMLTableCellElement_Binding::Wrap(aCx, this, aGivenProto);
26 }
27 
NS_IMPL_ELEMENT_CLONE(HTMLTableCellElement)28 NS_IMPL_ELEMENT_CLONE(HTMLTableCellElement)
29 
30 // protected method
31 HTMLTableRowElement* HTMLTableCellElement::GetRow() const {
32   return HTMLTableRowElement::FromNodeOrNull(GetParent());
33 }
34 
35 // protected method
GetTable() const36 HTMLTableElement* HTMLTableCellElement::GetTable() const {
37   nsIContent* parent = GetParent();
38   if (!parent) {
39     return nullptr;
40   }
41 
42   // parent should be a row.
43   nsIContent* section = parent->GetParent();
44   if (!section) {
45     return nullptr;
46   }
47 
48   if (section->IsHTMLElement(nsGkAtoms::table)) {
49     // XHTML, without a row group.
50     return static_cast<HTMLTableElement*>(section);
51   }
52 
53   // We have a row group.
54   nsIContent* result = section->GetParent();
55   if (result && result->IsHTMLElement(nsGkAtoms::table)) {
56     return static_cast<HTMLTableElement*>(result);
57   }
58 
59   return nullptr;
60 }
61 
CellIndex() const62 int32_t HTMLTableCellElement::CellIndex() const {
63   HTMLTableRowElement* row = GetRow();
64   if (!row) {
65     return -1;
66   }
67 
68   nsIHTMLCollection* cells = row->Cells();
69   if (!cells) {
70     return -1;
71   }
72 
73   uint32_t numCells = cells->Length();
74   for (uint32_t i = 0; i < numCells; i++) {
75     if (cells->Item(i) == this) {
76       return i;
77     }
78   }
79 
80   return -1;
81 }
82 
83 nsMappedAttributes*
GetMappedAttributesInheritedFromTable() const84 HTMLTableCellElement::GetMappedAttributesInheritedFromTable() const {
85   if (HTMLTableElement* table = GetTable()) {
86     return table->GetAttributesMappedForCell();
87   }
88 
89   return nullptr;
90 }
91 
GetAlign(DOMString & aValue)92 void HTMLTableCellElement::GetAlign(DOMString& aValue) {
93   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue)) {
94     // There's no align attribute, ask the row for the alignment.
95     HTMLTableRowElement* row = GetRow();
96     if (row) {
97       row->GetAlign(aValue);
98     }
99   }
100 }
101 
102 static const nsAttrValue::EnumTable kCellScopeTable[] = {
103     {"row", NS_STYLE_CELL_SCOPE_ROW},
104     {"col", NS_STYLE_CELL_SCOPE_COL},
105     {"rowgroup", NS_STYLE_CELL_SCOPE_ROWGROUP},
106     {"colgroup", NS_STYLE_CELL_SCOPE_COLGROUP},
107     {nullptr, 0}};
108 
GetScope(DOMString & aScope)109 void HTMLTableCellElement::GetScope(DOMString& aScope) {
110   GetEnumAttr(nsGkAtoms::scope, nullptr, aScope);
111 }
112 
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)113 bool HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
114                                           nsAtom* aAttribute,
115                                           const nsAString& aValue,
116                                           nsIPrincipal* aMaybeScriptedPrincipal,
117                                           nsAttrValue& aResult) {
118   if (aNamespaceID == kNameSpaceID_None) {
119     /* ignore these attributes, stored simply as strings
120        abbr, axis, ch, headers
121     */
122     if (aAttribute == nsGkAtoms::colspan) {
123       aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
124       return true;
125     }
126     if (aAttribute == nsGkAtoms::rowspan) {
127       aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
128       // quirks mode does not honor the special html 4 value of 0
129       if (aResult.GetIntegerValue() == 0 && InNavQuirksMode(OwnerDoc())) {
130         aResult.SetTo(1, &aValue);
131       }
132       return true;
133     }
134     if (aAttribute == nsGkAtoms::height) {
135       return aResult.ParseNonzeroHTMLDimension(aValue);
136     }
137     if (aAttribute == nsGkAtoms::width) {
138       return aResult.ParseNonzeroHTMLDimension(aValue);
139     }
140     if (aAttribute == nsGkAtoms::align) {
141       return ParseTableCellHAlignValue(aValue, aResult);
142     }
143     if (aAttribute == nsGkAtoms::bgcolor) {
144       return aResult.ParseColor(aValue);
145     }
146     if (aAttribute == nsGkAtoms::scope) {
147       return aResult.ParseEnumValue(aValue, kCellScopeTable, false);
148     }
149     if (aAttribute == nsGkAtoms::valign) {
150       return ParseTableVAlignValue(aValue, aResult);
151     }
152   }
153 
154   return nsGenericHTMLElement::ParseBackgroundAttribute(
155              aNamespaceID, aAttribute, aValue, aResult) ||
156          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
157                                               aMaybeScriptedPrincipal, aResult);
158 }
159 
MapAttributesIntoRule(const nsMappedAttributes * aAttributes,MappedDeclarations & aDecls)160 void HTMLTableCellElement::MapAttributesIntoRule(
161     const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
162   MapImageSizeAttributesInto(aAttributes, aDecls);
163 
164   if (!aDecls.PropertyIsSet(eCSSProperty_white_space)) {
165     // nowrap: enum
166     if (aAttributes->GetAttr(nsGkAtoms::nowrap)) {
167       // See if our width is not a nonzero integer width.
168       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
169       nsCompatibility mode = aDecls.Document()->GetCompatibilityMode();
170       if (!value || value->Type() != nsAttrValue::eInteger ||
171           value->GetIntegerValue() == 0 || eCompatibility_NavQuirks != mode) {
172         aDecls.SetKeywordValue(eCSSProperty_white_space,
173                                StyleWhiteSpace::Nowrap);
174       }
175     }
176   }
177 
178   nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
179   nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aDecls);
180   nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
181   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
182 }
183 
NS_IMETHODIMP_(bool)184 NS_IMETHODIMP_(bool)
185 HTMLTableCellElement::IsAttributeMapped(const nsAtom* aAttribute) const {
186   static const MappedAttributeEntry attributes[] = {
187     {nsGkAtoms::align},
188     {nsGkAtoms::valign},
189     {nsGkAtoms::nowrap},
190 #if 0
191     // XXXldb If these are implemented, they might need to move to
192     // GetAttributeChangeHint (depending on how, and preferably not).
193     { nsGkAtoms::abbr },
194     { nsGkAtoms::axis },
195     { nsGkAtoms::headers },
196     { nsGkAtoms::scope },
197 #endif
198     {nsGkAtoms::width},
199     {nsGkAtoms::height},
200     {nullptr}
201   };
202 
203   static const MappedAttributeEntry* const map[] = {
204       attributes,
205       sCommonAttributeMap,
206       sBackgroundAttributeMap,
207   };
208 
209   return FindAttributeDependence(aAttribute, map);
210 }
211 
GetAttributeMappingFunction() const212 nsMapRuleToAttributesFunc HTMLTableCellElement::GetAttributeMappingFunction()
213     const {
214   return &MapAttributesIntoRule;
215 }
216 
217 }  // namespace mozilla::dom
218