1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "mozilla/Util.h"
39 :
40 : #include "nsIDOMHTMLTableCellElement.h"
41 : #include "nsIDOMHTMLTableRowElement.h"
42 : #include "nsHTMLTableElement.h"
43 : #include "nsIDOMHTMLCollection.h"
44 : #include "nsIDOMEventTarget.h"
45 : #include "nsMappedAttributes.h"
46 : #include "nsGenericHTMLElement.h"
47 : #include "nsGkAtoms.h"
48 : #include "nsStyleConsts.h"
49 : #include "nsPresContext.h"
50 : #include "nsRuleData.h"
51 : #include "nsRuleWalker.h"
52 : #include "nsIDocument.h"
53 : #include "celldata.h"
54 :
55 : using namespace mozilla;
56 :
57 : class nsHTMLTableCellElement : public nsGenericHTMLElement,
58 : public nsIDOMHTMLTableCellElement
59 : {
60 : public:
61 : nsHTMLTableCellElement(already_AddRefed<nsINodeInfo> aNodeInfo);
62 : virtual ~nsHTMLTableCellElement();
63 :
64 : // nsISupports
65 : NS_DECL_ISUPPORTS_INHERITED
66 :
67 : // nsIDOMNode
68 0 : NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
69 :
70 : // nsIDOMElement
71 0 : NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
72 :
73 : // nsIDOMHTMLElement
74 0 : NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
75 :
76 : // nsIDOMHTMLTableCellElement
77 : NS_DECL_NSIDOMHTMLTABLECELLELEMENT
78 :
79 : virtual bool ParseAttribute(PRInt32 aNamespaceID,
80 : nsIAtom* aAttribute,
81 : const nsAString& aValue,
82 : nsAttrValue& aResult);
83 : virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
84 : NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
85 : NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
86 :
87 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
88 :
89 : virtual nsXPCClassInfo* GetClassInfo();
90 : protected:
91 : nsHTMLTableElement* GetTable() const;
92 :
93 : already_AddRefed<nsIDOMHTMLTableRowElement> GetRow() const;
94 : };
95 :
96 :
97 0 : NS_IMPL_NS_NEW_HTML_ELEMENT(TableCell)
98 :
99 :
100 0 : nsHTMLTableCellElement::nsHTMLTableCellElement(already_AddRefed<nsINodeInfo> aNodeInfo)
101 0 : : nsGenericHTMLElement(aNodeInfo)
102 : {
103 0 : }
104 :
105 0 : nsHTMLTableCellElement::~nsHTMLTableCellElement()
106 : {
107 0 : }
108 :
109 :
110 0 : NS_IMPL_ADDREF_INHERITED(nsHTMLTableCellElement, nsGenericElement)
111 0 : NS_IMPL_RELEASE_INHERITED(nsHTMLTableCellElement, nsGenericElement)
112 :
113 :
114 0 : DOMCI_NODE_DATA(HTMLTableCellElement, nsHTMLTableCellElement)
115 :
116 : // QueryInterface implementation for nsHTMLTableCellElement
117 0 : NS_INTERFACE_TABLE_HEAD(nsHTMLTableCellElement)
118 0 : NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLTableCellElement,
119 : nsIDOMHTMLTableCellElement)
120 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLTableCellElement,
121 : nsGenericHTMLElement)
122 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLTableCellElement)
123 :
124 :
125 0 : NS_IMPL_ELEMENT_CLONE(nsHTMLTableCellElement)
126 :
127 :
128 : // protected method
129 : already_AddRefed<nsIDOMHTMLTableRowElement>
130 0 : nsHTMLTableCellElement::GetRow() const
131 : {
132 0 : nsCOMPtr<nsIDOMHTMLTableRowElement> row = do_QueryInterface(GetParent());
133 0 : return row.forget();
134 : }
135 :
136 : // protected method
137 : nsHTMLTableElement*
138 0 : nsHTMLTableCellElement::GetTable() const
139 : {
140 0 : nsIContent *parent = GetParent();
141 0 : if (!parent) {
142 0 : return nsnull;
143 : }
144 :
145 : // parent should be a row.
146 0 : nsIContent* section = parent->GetParent();
147 0 : if (!section) {
148 0 : return nsnull;
149 : }
150 :
151 0 : if (section->IsHTML(nsGkAtoms::table)) {
152 : // XHTML, without a row group.
153 0 : return static_cast<nsHTMLTableElement*>(section);
154 : }
155 :
156 : // We have a row group.
157 0 : nsIContent* result = section->GetParent();
158 0 : if (result && result->IsHTML(nsGkAtoms::table)) {
159 0 : return static_cast<nsHTMLTableElement*>(result);
160 : }
161 :
162 0 : return nsnull;
163 : }
164 :
165 : NS_IMETHODIMP
166 0 : nsHTMLTableCellElement::GetCellIndex(PRInt32* aCellIndex)
167 : {
168 0 : *aCellIndex = -1;
169 :
170 0 : nsCOMPtr<nsIDOMHTMLTableRowElement> row = GetRow();
171 0 : if (!row) {
172 0 : return NS_OK;
173 : }
174 :
175 0 : nsCOMPtr<nsIDOMHTMLCollection> cells;
176 :
177 0 : row->GetCells(getter_AddRefs(cells));
178 :
179 0 : if (!cells) {
180 0 : return NS_OK;
181 : }
182 :
183 : PRUint32 numCells;
184 0 : cells->GetLength(&numCells);
185 :
186 0 : for (PRUint32 i = 0; i < numCells; i++) {
187 0 : nsCOMPtr<nsIDOMNode> node;
188 0 : cells->Item(i, getter_AddRefs(node));
189 :
190 0 : if (node.get() == static_cast<nsIDOMNode *>(this)) {
191 0 : *aCellIndex = i;
192 : break;
193 : }
194 : }
195 :
196 0 : return NS_OK;
197 : }
198 :
199 :
200 : NS_IMETHODIMP
201 0 : nsHTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
202 : {
203 0 : nsresult rv = nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
204 0 : NS_ENSURE_SUCCESS(rv, rv);
205 :
206 0 : if (nsHTMLTableElement* table = GetTable()) {
207 : nsMappedAttributes* tableInheritedAttributes =
208 0 : table->GetAttributesMappedForCell();
209 0 : if (tableInheritedAttributes) {
210 0 : aRuleWalker->Forward(tableInheritedAttributes);
211 : }
212 : }
213 0 : return NS_OK;
214 : }
215 :
216 :
217 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Abbr, abbr)
218 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Axis, axis)
219 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, BgColor, bgcolor)
220 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Ch, _char)
221 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, ChOff, charoff)
222 0 : NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, ColSpan, colspan, 1)
223 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Headers, headers)
224 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Height, height)
225 0 : NS_IMPL_BOOL_ATTR(nsHTMLTableCellElement, NoWrap, nowrap)
226 0 : NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLTableCellElement, RowSpan, rowspan, 1)
227 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Scope, scope)
228 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, VAlign, valign)
229 0 : NS_IMPL_STRING_ATTR(nsHTMLTableCellElement, Width, width)
230 :
231 :
232 : NS_IMETHODIMP
233 0 : nsHTMLTableCellElement::GetAlign(nsAString& aValue)
234 : {
235 0 : if (!GetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue)) {
236 : // There's no align attribute, ask the row for the alignment.
237 0 : nsCOMPtr<nsIDOMHTMLTableRowElement> row = GetRow();
238 0 : if (row) {
239 0 : return row->GetAlign(aValue);
240 : }
241 : }
242 :
243 0 : return NS_OK;
244 : }
245 :
246 : NS_IMETHODIMP
247 0 : nsHTMLTableCellElement::SetAlign(const nsAString& aValue)
248 : {
249 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue, true);
250 : }
251 :
252 :
253 : static const nsAttrValue::EnumTable kCellScopeTable[] = {
254 : { "row", NS_STYLE_CELL_SCOPE_ROW },
255 : { "col", NS_STYLE_CELL_SCOPE_COL },
256 : { "rowgroup", NS_STYLE_CELL_SCOPE_ROWGROUP },
257 : { "colgroup", NS_STYLE_CELL_SCOPE_COLGROUP },
258 : { 0 }
259 : };
260 :
261 : bool
262 0 : nsHTMLTableCellElement::ParseAttribute(PRInt32 aNamespaceID,
263 : nsIAtom* aAttribute,
264 : const nsAString& aValue,
265 : nsAttrValue& aResult)
266 : {
267 0 : if (aNamespaceID == kNameSpaceID_None) {
268 : /* ignore these attributes, stored simply as strings
269 : abbr, axis, ch, headers
270 : */
271 0 : if (aAttribute == nsGkAtoms::charoff) {
272 : /* attributes that resolve to integers with a min of 0 */
273 0 : return aResult.ParseIntWithBounds(aValue, 0);
274 : }
275 0 : if (aAttribute == nsGkAtoms::colspan) {
276 0 : bool res = aResult.ParseIntWithBounds(aValue, -1);
277 0 : if (res) {
278 0 : PRInt32 val = aResult.GetIntegerValue();
279 : // reset large colspan values as IE and opera do
280 : // quirks mode does not honor the special html 4 value of 0
281 0 : if (val > MAX_COLSPAN || val < 0 ||
282 0 : (0 == val && InNavQuirksMode(OwnerDoc()))) {
283 0 : aResult.SetTo(1);
284 : }
285 : }
286 0 : return res;
287 : }
288 0 : if (aAttribute == nsGkAtoms::rowspan) {
289 0 : bool res = aResult.ParseIntWithBounds(aValue, -1, MAX_ROWSPAN);
290 0 : if (res) {
291 0 : PRInt32 val = aResult.GetIntegerValue();
292 : // quirks mode does not honor the special html 4 value of 0
293 0 : if (val < 0 || (0 == val && InNavQuirksMode(OwnerDoc()))) {
294 0 : aResult.SetTo(1);
295 : }
296 : }
297 0 : return res;
298 : }
299 0 : if (aAttribute == nsGkAtoms::height) {
300 0 : return aResult.ParseSpecialIntValue(aValue);
301 : }
302 0 : if (aAttribute == nsGkAtoms::width) {
303 0 : return aResult.ParseSpecialIntValue(aValue);
304 : }
305 0 : if (aAttribute == nsGkAtoms::align) {
306 0 : return ParseTableCellHAlignValue(aValue, aResult);
307 : }
308 0 : if (aAttribute == nsGkAtoms::bgcolor) {
309 0 : return aResult.ParseColor(aValue);
310 : }
311 0 : if (aAttribute == nsGkAtoms::scope) {
312 0 : return aResult.ParseEnumValue(aValue, kCellScopeTable, false);
313 : }
314 0 : if (aAttribute == nsGkAtoms::valign) {
315 0 : return ParseTableVAlignValue(aValue, aResult);
316 : }
317 : }
318 :
319 : return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
320 0 : aResult);
321 : }
322 :
323 : static
324 0 : void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
325 : nsRuleData* aData)
326 : {
327 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
328 : // width: value
329 0 : nsCSSValue* width = aData->ValueForWidth();
330 0 : if (width->GetUnit() == eCSSUnit_Null) {
331 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
332 0 : if (value && value->Type() == nsAttrValue::eInteger) {
333 0 : if (value->GetIntegerValue() > 0)
334 0 : width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
335 : // else 0 implies auto for compatibility.
336 : }
337 0 : else if (value && value->Type() == nsAttrValue::ePercent) {
338 0 : if (value->GetPercentValue() > 0.0f)
339 0 : width->SetPercentValue(value->GetPercentValue());
340 : // else 0 implies auto for compatibility
341 : }
342 : }
343 :
344 : // height: value
345 0 : nsCSSValue* height = aData->ValueForHeight();
346 0 : if (height->GetUnit() == eCSSUnit_Null) {
347 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
348 0 : if (value && value->Type() == nsAttrValue::eInteger) {
349 0 : if (value->GetIntegerValue() > 0)
350 0 : height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
351 : // else 0 implies auto for compatibility.
352 : }
353 0 : else if (value && value->Type() == nsAttrValue::ePercent) {
354 0 : if (value->GetPercentValue() > 0.0f)
355 0 : height->SetPercentValue(value->GetPercentValue());
356 : // else 0 implies auto for compatibility
357 : }
358 : }
359 : }
360 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
361 0 : nsCSSValue* textAlign = aData->ValueForTextAlign();
362 0 : if (textAlign->GetUnit() == eCSSUnit_Null) {
363 : // align: enum
364 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
365 0 : if (value && value->Type() == nsAttrValue::eEnum)
366 0 : textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
367 : }
368 :
369 0 : nsCSSValue* whiteSpace = aData->ValueForWhiteSpace();
370 0 : if (whiteSpace->GetUnit() == eCSSUnit_Null) {
371 : // nowrap: enum
372 0 : if (aAttributes->GetAttr(nsGkAtoms::nowrap)) {
373 : // See if our width is not a nonzero integer width.
374 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
375 0 : nsCompatibility mode = aData->mPresContext->CompatibilityMode();
376 0 : if (!value || value->Type() != nsAttrValue::eInteger ||
377 0 : value->GetIntegerValue() == 0 ||
378 : eCompatibility_NavQuirks != mode) {
379 0 : whiteSpace->SetIntValue(NS_STYLE_WHITESPACE_NOWRAP, eCSSUnit_Enumerated);
380 : }
381 : }
382 : }
383 : }
384 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
385 0 : nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
386 0 : if (verticalAlign->GetUnit() == eCSSUnit_Null) {
387 : // valign: enum
388 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::valign);
389 0 : if (value && value->Type() == nsAttrValue::eEnum)
390 0 : verticalAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
391 : }
392 : }
393 :
394 0 : nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
395 0 : nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
396 0 : }
397 :
398 : NS_IMETHODIMP_(bool)
399 0 : nsHTMLTableCellElement::IsAttributeMapped(const nsIAtom* aAttribute) const
400 : {
401 : static const MappedAttributeEntry attributes[] = {
402 : { &nsGkAtoms::align },
403 : { &nsGkAtoms::valign },
404 : { &nsGkAtoms::nowrap },
405 : #if 0
406 : // XXXldb If these are implemented, they might need to move to
407 : // GetAttributeChangeHint (depending on how, and preferably not).
408 : { &nsGkAtoms::abbr },
409 : { &nsGkAtoms::axis },
410 : { &nsGkAtoms::headers },
411 : { &nsGkAtoms::scope },
412 : #endif
413 : { &nsGkAtoms::width },
414 : { &nsGkAtoms::height },
415 : { nsnull }
416 : };
417 :
418 : static const MappedAttributeEntry* const map[] = {
419 : attributes,
420 : sCommonAttributeMap,
421 : sBackgroundAttributeMap,
422 : };
423 :
424 0 : return FindAttributeDependence(aAttribute, map);
425 : }
426 :
427 : nsMapRuleToAttributesFunc
428 0 : nsHTMLTableCellElement::GetAttributeMappingFunction() const
429 : {
430 0 : return &MapAttributesIntoRule;
431 : }
|