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 "nsHTMLTableElement.h"
41 : #include "nsIDOMHTMLTableCaptionElem.h"
42 : #include "nsIDOMHTMLTableSectionElem.h"
43 : #include "nsCOMPtr.h"
44 : #include "nsIDOMEventTarget.h"
45 : #include "nsDOMError.h"
46 : #include "nsContentList.h"
47 : #include "nsGenericHTMLElement.h"
48 : #include "nsGkAtoms.h"
49 : #include "nsStyleConsts.h"
50 : #include "nsPresContext.h"
51 : #include "nsHTMLParts.h"
52 : #include "nsRuleData.h"
53 : #include "nsStyleContext.h"
54 : #include "nsIDocument.h"
55 : #include "nsContentUtils.h"
56 : #include "nsIDOMElement.h"
57 : #include "nsGenericHTMLElement.h"
58 : #include "nsIHTMLCollection.h"
59 : #include "nsHTMLStyleSheet.h"
60 : #include "dombindings.h"
61 :
62 : using namespace mozilla;
63 :
64 : /* ------------------------------ TableRowsCollection -------------------------------- */
65 : /**
66 : * This class provides a late-bound collection of rows in a table.
67 : * mParent is NOT ref-counted to avoid circular references
68 : */
69 : class TableRowsCollection : public nsIHTMLCollection,
70 : public nsWrapperCache
71 : {
72 : public:
73 : TableRowsCollection(nsHTMLTableElement *aParent);
74 : virtual ~TableRowsCollection();
75 :
76 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
77 : NS_DECL_NSIDOMHTMLCOLLECTION
78 :
79 0 : virtual nsINode* GetParentObject()
80 : {
81 0 : return mParent;
82 : }
83 :
84 : NS_IMETHOD ParentDestroyed();
85 :
86 1464 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
87 :
88 : // nsWrapperCache
89 0 : virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
90 : bool *triedToWrap)
91 : {
92 : return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
93 0 : triedToWrap);
94 : }
95 :
96 : protected:
97 : // Those rows that are not in table sections
98 : nsHTMLTableElement* mParent;
99 : nsRefPtr<nsContentList> mOrphanRows;
100 : };
101 :
102 :
103 0 : TableRowsCollection::TableRowsCollection(nsHTMLTableElement *aParent)
104 : : mParent(aParent)
105 : , mOrphanRows(new nsContentList(mParent,
106 : kNameSpaceID_XHTML,
107 : nsGkAtoms::tr,
108 : nsGkAtoms::tr,
109 0 : false))
110 : {
111 : // Mark ourselves as a proxy
112 0 : SetIsProxy();
113 0 : }
114 :
115 0 : TableRowsCollection::~TableRowsCollection()
116 : {
117 : // we do NOT have a ref-counted reference to mParent, so do NOT
118 : // release it! this is to avoid circular references. The
119 : // instantiator who provided mParent is responsible for managing our
120 : // reference for us.
121 0 : }
122 :
123 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(TableRowsCollection)
124 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TableRowsCollection)
125 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
126 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOrphanRows)
127 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
128 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TableRowsCollection)
129 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mOrphanRows,
130 : nsIDOMNodeList)
131 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
132 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
133 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TableRowsCollection)
134 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
135 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
136 :
137 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
138 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)
139 :
140 0 : NS_INTERFACE_TABLE_HEAD(TableRowsCollection)
141 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
142 0 : NS_INTERFACE_TABLE2(TableRowsCollection, nsIHTMLCollection,
143 : nsIDOMHTMLCollection)
144 0 : NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)
145 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLCollection)
146 0 : NS_INTERFACE_MAP_END
147 :
148 : // Macro that can be used to avoid copy/pasting code to iterate over the
149 : // rowgroups. _code should be the code to execute for each rowgroup. The
150 : // rowgroup's rows will be in the nsIDOMHTMLCollection* named "rows". Note
151 : // that this may be null at any time. This macro assumes an nsresult named
152 : // |rv| is in scope.
153 : #define DO_FOR_EACH_ROWGROUP(_code) \
154 : do { \
155 : if (mParent) { \
156 : /* THead */ \
157 : nsCOMPtr<nsIDOMHTMLTableSectionElement> rowGroup; \
158 : rowGroup = mParent->GetTHead(); \
159 : nsCOMPtr<nsIDOMHTMLCollection> rows; \
160 : if (rowGroup) { \
161 : rowGroup->GetRows(getter_AddRefs(rows)); \
162 : do { /* gives scoping */ \
163 : _code \
164 : } while (0); \
165 : } \
166 : /* TBodies */ \
167 : nsContentList *_tbodies = mParent->TBodies(); \
168 : nsINode * _node; \
169 : PRUint32 _tbodyIndex = 0; \
170 : _node = _tbodies->GetNodeAt(_tbodyIndex); \
171 : while (_node) { \
172 : rowGroup = do_QueryInterface(_node); \
173 : if (rowGroup) { \
174 : rowGroup->GetRows(getter_AddRefs(rows)); \
175 : do { /* gives scoping */ \
176 : _code \
177 : } while (0); \
178 : } \
179 : _node = _tbodies->GetNodeAt(++_tbodyIndex); \
180 : } \
181 : /* orphan rows */ \
182 : rows = mOrphanRows; \
183 : do { /* gives scoping */ \
184 : _code \
185 : } while (0); \
186 : /* TFoot */ \
187 : rowGroup = mParent->GetTFoot(); \
188 : rows = nsnull; \
189 : if (rowGroup) { \
190 : rowGroup->GetRows(getter_AddRefs(rows)); \
191 : do { /* gives scoping */ \
192 : _code \
193 : } while (0); \
194 : } \
195 : } \
196 : } while (0)
197 :
198 : static PRUint32
199 0 : CountRowsInRowGroup(nsIDOMHTMLCollection* rows)
200 : {
201 0 : PRUint32 length = 0;
202 :
203 0 : if (rows) {
204 0 : rows->GetLength(&length);
205 : }
206 :
207 0 : return length;
208 : }
209 :
210 : // we re-count every call. A better implementation would be to set
211 : // ourselves up as an observer of contentAppended, contentInserted,
212 : // and contentDeleted
213 : NS_IMETHODIMP
214 0 : TableRowsCollection::GetLength(PRUint32* aLength)
215 : {
216 0 : *aLength=0;
217 :
218 0 : DO_FOR_EACH_ROWGROUP(
219 : *aLength += CountRowsInRowGroup(rows);
220 : );
221 :
222 0 : return NS_OK;
223 : }
224 :
225 : // Returns the item at index aIndex if available. If null is returned,
226 : // then aCount will be set to the number of rows in this row collection.
227 : // Otherwise, the value of aCount is undefined.
228 : static nsIContent*
229 0 : GetItemOrCountInRowGroup(nsIDOMHTMLCollection* rows,
230 : PRUint32 aIndex, PRUint32* aCount)
231 : {
232 0 : *aCount = 0;
233 :
234 0 : if (rows) {
235 0 : rows->GetLength(aCount);
236 0 : if (aIndex < *aCount) {
237 0 : nsCOMPtr<nsINodeList> list = do_QueryInterface(rows);
238 0 : return list->GetNodeAt(aIndex);
239 : }
240 : }
241 :
242 0 : return nsnull;
243 : }
244 :
245 : nsIContent*
246 0 : TableRowsCollection::GetNodeAt(PRUint32 aIndex)
247 : {
248 0 : DO_FOR_EACH_ROWGROUP(
249 : PRUint32 count;
250 : nsIContent* node = GetItemOrCountInRowGroup(rows, aIndex, &count);
251 : if (node) {
252 : return node;
253 : }
254 :
255 : NS_ASSERTION(count <= aIndex, "GetItemOrCountInRowGroup screwed up");
256 : aIndex -= count;
257 : );
258 :
259 0 : return nsnull;
260 : }
261 :
262 : NS_IMETHODIMP
263 0 : TableRowsCollection::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
264 : {
265 0 : nsISupports* node = GetNodeAt(aIndex);
266 0 : if (!node) {
267 0 : *aReturn = nsnull;
268 :
269 0 : return NS_OK;
270 : }
271 :
272 0 : return CallQueryInterface(node, aReturn);
273 : }
274 :
275 : static nsISupports*
276 0 : GetNamedItemInRowGroup(nsIDOMHTMLCollection* aRows, const nsAString& aName,
277 : nsWrapperCache** aCache)
278 : {
279 0 : nsCOMPtr<nsIHTMLCollection> rows = do_QueryInterface(aRows);
280 0 : if (rows) {
281 0 : return rows->GetNamedItem(aName, aCache);
282 : }
283 :
284 0 : return nsnull;
285 : }
286 :
287 : nsISupports*
288 0 : TableRowsCollection::GetNamedItem(const nsAString& aName,
289 : nsWrapperCache** aCache)
290 : {
291 0 : DO_FOR_EACH_ROWGROUP(
292 : nsISupports* item = GetNamedItemInRowGroup(rows, aName, aCache);
293 : if (item) {
294 : return item;
295 : }
296 : );
297 0 : *aCache = nsnull;
298 0 : return nsnull;
299 : }
300 :
301 : NS_IMETHODIMP
302 0 : TableRowsCollection::NamedItem(const nsAString& aName,
303 : nsIDOMNode** aReturn)
304 : {
305 : nsWrapperCache *cache;
306 0 : nsISupports* item = GetNamedItem(aName, &cache);
307 0 : if (!item) {
308 0 : *aReturn = nsnull;
309 :
310 0 : return NS_OK;
311 : }
312 :
313 0 : return CallQueryInterface(item, aReturn);
314 : }
315 :
316 : NS_IMETHODIMP
317 0 : TableRowsCollection::ParentDestroyed()
318 : {
319 : // see comment in destructor, do NOT release mParent!
320 0 : mParent = nsnull;
321 :
322 0 : return NS_OK;
323 : }
324 :
325 : /* -------------------------- nsHTMLTableElement --------------------------- */
326 : // the class declaration is at the top of this file
327 :
328 :
329 0 : NS_IMPL_NS_NEW_HTML_ELEMENT(Table)
330 :
331 :
332 0 : nsHTMLTableElement::nsHTMLTableElement(already_AddRefed<nsINodeInfo> aNodeInfo)
333 : : nsGenericHTMLElement(aNodeInfo),
334 0 : mTableInheritedAttributes(TABLE_ATTRS_DIRTY)
335 : {
336 0 : }
337 :
338 0 : nsHTMLTableElement::~nsHTMLTableElement()
339 : {
340 0 : if (mRows) {
341 0 : mRows->ParentDestroyed();
342 : }
343 0 : ReleaseInheritedAttributes();
344 0 : }
345 :
346 :
347 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLTableElement)
348 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLTableElement, nsGenericHTMLElement)
349 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTBodies)
350 0 : if (tmp->mRows) {
351 0 : tmp->mRows->ParentDestroyed();
352 : }
353 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRows)
354 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
355 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLTableElement,
356 : nsGenericHTMLElement)
357 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTBodies,
358 : nsIDOMNodeList)
359 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRows)
360 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
361 :
362 0 : NS_IMPL_ADDREF_INHERITED(nsHTMLTableElement, nsGenericElement)
363 0 : NS_IMPL_RELEASE_INHERITED(nsHTMLTableElement, nsGenericElement)
364 :
365 :
366 0 : DOMCI_NODE_DATA(HTMLTableElement, nsHTMLTableElement)
367 :
368 : // QueryInterface implementation for nsHTMLTableElement
369 0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLTableElement)
370 0 : NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLTableElement, nsIDOMHTMLTableElement)
371 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLTableElement,
372 : nsGenericHTMLElement)
373 0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLTableElement)
374 :
375 :
376 0 : NS_IMPL_ELEMENT_CLONE(nsHTMLTableElement)
377 :
378 :
379 : // the DOM spec says border, cellpadding, cellSpacing are all "wstring"
380 : // in fact, they are integers or they are meaningless. so we store them
381 : // here as ints.
382 :
383 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Align, align)
384 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, BgColor, bgcolor)
385 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Border, border)
386 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, CellPadding, cellpadding)
387 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, CellSpacing, cellspacing)
388 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Frame, frame)
389 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Rules, rules)
390 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Summary, summary)
391 0 : NS_IMPL_STRING_ATTR(nsHTMLTableElement, Width, width)
392 :
393 :
394 : already_AddRefed<nsIDOMHTMLTableCaptionElement>
395 0 : nsHTMLTableElement::GetCaption()
396 : {
397 0 : for (nsIContent* cur = nsINode::GetFirstChild(); cur; cur = cur->GetNextSibling()) {
398 0 : nsCOMPtr<nsIDOMHTMLTableCaptionElement> caption = do_QueryInterface(cur);
399 0 : if (caption) {
400 0 : return caption.forget();
401 : }
402 : }
403 0 : return nsnull;
404 : }
405 :
406 : NS_IMETHODIMP
407 0 : nsHTMLTableElement::GetCaption(nsIDOMHTMLTableCaptionElement** aValue)
408 : {
409 0 : nsCOMPtr<nsIDOMHTMLTableCaptionElement> caption = GetCaption();
410 0 : caption.forget(aValue);
411 0 : return NS_OK;
412 : }
413 :
414 : NS_IMETHODIMP
415 0 : nsHTMLTableElement::SetCaption(nsIDOMHTMLTableCaptionElement* aValue)
416 : {
417 0 : nsresult rv = DeleteCaption();
418 :
419 0 : if (NS_SUCCEEDED(rv)) {
420 0 : if (aValue) {
421 0 : nsCOMPtr<nsIDOMNode> resultingChild;
422 0 : AppendChild(aValue, getter_AddRefs(resultingChild));
423 : }
424 : }
425 :
426 0 : return rv;
427 : }
428 :
429 : already_AddRefed<nsIDOMHTMLTableSectionElement>
430 0 : nsHTMLTableElement::GetSection(nsIAtom *aTag)
431 : {
432 0 : for (nsIContent* child = nsINode::GetFirstChild();
433 : child;
434 0 : child = child->GetNextSibling()) {
435 0 : nsCOMPtr<nsIDOMHTMLTableSectionElement> section = do_QueryInterface(child);
436 0 : if (section && child->NodeInfo()->Equals(aTag)) {
437 0 : return section.forget();
438 : }
439 : }
440 0 : return nsnull;
441 : }
442 :
443 : NS_IMETHODIMP
444 0 : nsHTMLTableElement::GetTHead(nsIDOMHTMLTableSectionElement** aValue)
445 : {
446 0 : *aValue = GetTHead().get();
447 :
448 0 : return NS_OK;
449 : }
450 :
451 : NS_IMETHODIMP
452 0 : nsHTMLTableElement::SetTHead(nsIDOMHTMLTableSectionElement* aValue)
453 : {
454 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aValue));
455 0 : NS_ENSURE_TRUE(content, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
456 :
457 0 : if (!content->NodeInfo()->Equals(nsGkAtoms::thead)) {
458 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
459 : }
460 :
461 0 : nsresult rv = DeleteTHead();
462 0 : if (NS_FAILED(rv)) {
463 0 : return rv;
464 : }
465 :
466 0 : if (aValue) {
467 0 : nsCOMPtr<nsIDOMNode> child;
468 0 : rv = GetFirstChild(getter_AddRefs(child));
469 0 : if (NS_FAILED(rv)) {
470 0 : return rv;
471 : }
472 :
473 0 : nsCOMPtr<nsIDOMNode> resultChild;
474 0 : rv = InsertBefore(aValue, child, getter_AddRefs(resultChild));
475 : }
476 :
477 0 : return rv;
478 : }
479 :
480 : NS_IMETHODIMP
481 0 : nsHTMLTableElement::GetTFoot(nsIDOMHTMLTableSectionElement** aValue)
482 : {
483 0 : *aValue = GetTFoot().get();
484 :
485 0 : return NS_OK;
486 : }
487 :
488 : NS_IMETHODIMP
489 0 : nsHTMLTableElement::SetTFoot(nsIDOMHTMLTableSectionElement* aValue)
490 : {
491 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aValue));
492 0 : NS_ENSURE_TRUE(content, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
493 :
494 0 : if (!content->NodeInfo()->Equals(nsGkAtoms::tfoot)) {
495 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
496 : }
497 :
498 0 : nsresult rv = DeleteTFoot();
499 0 : if (NS_SUCCEEDED(rv)) {
500 0 : if (aValue) {
501 0 : nsCOMPtr<nsIDOMNode> resultingChild;
502 0 : AppendChild(aValue, getter_AddRefs(resultingChild));
503 : }
504 : }
505 :
506 0 : return rv;
507 : }
508 :
509 : NS_IMETHODIMP
510 0 : nsHTMLTableElement::GetRows(nsIDOMHTMLCollection** aValue)
511 : {
512 0 : if (!mRows) {
513 0 : mRows = new TableRowsCollection(this);
514 : }
515 :
516 0 : *aValue = mRows;
517 0 : NS_ADDREF(*aValue);
518 :
519 0 : return NS_OK;
520 : }
521 :
522 : NS_IMETHODIMP
523 0 : nsHTMLTableElement::GetTBodies(nsIDOMHTMLCollection** aValue)
524 : {
525 0 : NS_ADDREF(*aValue = TBodies());
526 0 : return NS_OK;
527 : }
528 :
529 : nsContentList*
530 0 : nsHTMLTableElement::TBodies()
531 : {
532 0 : if (!mTBodies) {
533 : // Not using NS_GetContentList because this should not be cached
534 : mTBodies = new nsContentList(this,
535 : kNameSpaceID_XHTML,
536 : nsGkAtoms::tbody,
537 : nsGkAtoms::tbody,
538 0 : false);
539 : }
540 :
541 0 : return mTBodies;
542 : }
543 :
544 : NS_IMETHODIMP
545 0 : nsHTMLTableElement::CreateTHead(nsIDOMHTMLElement** aValue)
546 : {
547 0 : *aValue = nsnull;
548 :
549 0 : nsRefPtr<nsIDOMHTMLTableSectionElement> head = GetTHead();
550 0 : if (head) {
551 : // return the existing thead
552 0 : head.forget(aValue);
553 0 : return NS_OK;
554 : }
555 :
556 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
557 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::thead,
558 0 : getter_AddRefs(nodeInfo));
559 :
560 : nsCOMPtr<nsIContent> newHead =
561 0 : NS_NewHTMLTableSectionElement(nodeInfo.forget());
562 :
563 0 : if (!newHead) {
564 0 : return NS_OK;
565 : }
566 :
567 0 : nsCOMPtr<nsIDOMNode> child;
568 0 : nsresult rv = GetFirstChild(getter_AddRefs(child));
569 0 : NS_ENSURE_SUCCESS(rv, rv);
570 :
571 0 : nsCOMPtr<nsIDOMHTMLElement> newHeadAsDOMElement = do_QueryInterface(newHead);
572 :
573 0 : nsCOMPtr<nsIDOMNode> resultChild;
574 0 : InsertBefore(newHeadAsDOMElement, child, getter_AddRefs(resultChild));
575 0 : newHeadAsDOMElement.forget(aValue);
576 0 : return NS_OK;
577 : }
578 :
579 : NS_IMETHODIMP
580 0 : nsHTMLTableElement::DeleteTHead()
581 : {
582 0 : nsCOMPtr<nsIDOMHTMLTableSectionElement> childToDelete;
583 0 : nsresult rv = GetTHead(getter_AddRefs(childToDelete));
584 :
585 0 : if ((NS_SUCCEEDED(rv)) && childToDelete) {
586 0 : nsCOMPtr<nsIDOMNode> resultingChild;
587 : // mInner does the notification
588 0 : RemoveChild(childToDelete, getter_AddRefs(resultingChild));
589 : }
590 :
591 0 : return NS_OK;
592 : }
593 :
594 : NS_IMETHODIMP
595 0 : nsHTMLTableElement::CreateTFoot(nsIDOMHTMLElement** aValue)
596 : {
597 0 : *aValue = nsnull;
598 :
599 0 : nsRefPtr<nsIDOMHTMLTableSectionElement> foot = GetTFoot();
600 0 : if (foot) {
601 : // return the existing tfoot
602 0 : foot.forget(aValue);
603 0 : return NS_OK;
604 : }
605 : // create a new foot rowgroup
606 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
607 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::tfoot,
608 0 : getter_AddRefs(nodeInfo));
609 :
610 0 : nsCOMPtr<nsIContent> newFoot = NS_NewHTMLTableSectionElement(nodeInfo.forget());
611 :
612 0 : if (!newFoot) {
613 0 : return NS_OK;
614 : }
615 0 : AppendChildTo(newFoot, true);
616 0 : nsCOMPtr<nsIDOMHTMLElement> newFootAsDOMElement = do_QueryInterface(newFoot);
617 0 : newFootAsDOMElement.forget(aValue);
618 0 : return NS_OK;
619 : }
620 :
621 : NS_IMETHODIMP
622 0 : nsHTMLTableElement::DeleteTFoot()
623 : {
624 0 : nsCOMPtr<nsIDOMHTMLTableSectionElement> childToDelete;
625 0 : nsresult rv = GetTFoot(getter_AddRefs(childToDelete));
626 :
627 0 : if ((NS_SUCCEEDED(rv)) && childToDelete) {
628 0 : nsCOMPtr<nsIDOMNode> resultingChild;
629 : // mInner does the notification
630 0 : RemoveChild(childToDelete, getter_AddRefs(resultingChild));
631 : }
632 :
633 0 : return NS_OK;
634 : }
635 :
636 : NS_IMETHODIMP
637 0 : nsHTMLTableElement::CreateCaption(nsIDOMHTMLElement** aValue)
638 : {
639 0 : *aValue = nsnull;
640 :
641 0 : if (nsRefPtr<nsIDOMHTMLTableCaptionElement> caption = GetCaption()) {
642 : // return the existing caption
643 0 : caption.forget(aValue);
644 0 : return NS_OK;
645 : }
646 :
647 : // create a new head rowgroup
648 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
649 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::caption,
650 0 : getter_AddRefs(nodeInfo));
651 :
652 0 : nsCOMPtr<nsIContent> newCaption = NS_NewHTMLTableCaptionElement(nodeInfo.forget());
653 :
654 0 : if (!newCaption) {
655 0 : return NS_OK;
656 : }
657 :
658 0 : AppendChildTo(newCaption, true);
659 : nsCOMPtr<nsIDOMHTMLElement> captionAsDOMElement =
660 0 : do_QueryInterface(newCaption);
661 0 : captionAsDOMElement.forget(aValue);
662 0 : return NS_OK;
663 : }
664 :
665 : NS_IMETHODIMP
666 0 : nsHTMLTableElement::DeleteCaption()
667 : {
668 0 : nsCOMPtr<nsIDOMHTMLTableCaptionElement> childToDelete;
669 0 : nsresult rv = GetCaption(getter_AddRefs(childToDelete));
670 :
671 0 : if ((NS_SUCCEEDED(rv)) && childToDelete) {
672 0 : nsCOMPtr<nsIDOMNode> resultingChild;
673 0 : RemoveChild(childToDelete, getter_AddRefs(resultingChild));
674 : }
675 :
676 0 : return NS_OK;
677 : }
678 :
679 : NS_IMETHODIMP
680 0 : nsHTMLTableElement::InsertRow(PRInt32 aIndex, nsIDOMHTMLElement** aValue)
681 : {
682 : /* get the ref row at aIndex
683 : if there is one,
684 : get its parent
685 : insert the new row just before the ref row
686 : else
687 : get the first row group
688 : insert the new row as its first child
689 : */
690 0 : *aValue = nsnull;
691 :
692 0 : if (aIndex < -1) {
693 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
694 : }
695 :
696 0 : nsCOMPtr<nsIDOMHTMLCollection> rows;
697 0 : GetRows(getter_AddRefs(rows));
698 :
699 : PRUint32 rowCount;
700 0 : rows->GetLength(&rowCount);
701 :
702 0 : if ((PRUint32)aIndex > rowCount && aIndex != -1) {
703 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
704 : }
705 :
706 : // use local variable refIndex so we can remember original aIndex
707 0 : PRUint32 refIndex = (PRUint32)aIndex;
708 :
709 : nsresult rv;
710 0 : if (rowCount > 0) {
711 0 : if (refIndex == rowCount || aIndex == -1) {
712 : // we set refIndex to the last row so we can get the last row's
713 : // parent we then do an AppendChild below if (rowCount<aIndex)
714 :
715 0 : refIndex = rowCount - 1;
716 : }
717 :
718 0 : nsCOMPtr<nsIDOMNode> refRow;
719 0 : rows->Item(refIndex, getter_AddRefs(refRow));
720 :
721 0 : nsCOMPtr<nsIDOMNode> parent;
722 :
723 0 : refRow->GetParentNode(getter_AddRefs(parent));
724 : // create the row
725 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
726 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::tr,
727 0 : getter_AddRefs(nodeInfo));
728 :
729 0 : nsCOMPtr<nsIContent> newRow = NS_NewHTMLTableRowElement(nodeInfo.forget());
730 :
731 0 : if (newRow) {
732 0 : nsCOMPtr<nsIDOMNode> newRowNode(do_QueryInterface(newRow));
733 0 : nsCOMPtr<nsIDOMNode> retChild;
734 :
735 : // If index is -1 or equal to the number of rows, the new row
736 : // is appended.
737 0 : if (aIndex == -1 || PRUint32(aIndex) == rowCount) {
738 0 : rv = parent->AppendChild(newRowNode, getter_AddRefs(retChild));
739 0 : NS_ENSURE_SUCCESS(rv, rv);
740 : }
741 : else
742 : {
743 : // insert the new row before the reference row we found above
744 0 : rv = parent->InsertBefore(newRowNode, refRow,
745 0 : getter_AddRefs(retChild));
746 0 : NS_ENSURE_SUCCESS(rv, rv);
747 : }
748 :
749 0 : if (retChild) {
750 0 : CallQueryInterface(retChild, aValue);
751 : }
752 : }
753 : } else {
754 : // the row count was 0, so
755 : // find the first row group and insert there as first child
756 0 : nsCOMPtr<nsIDOMNode> rowGroup;
757 :
758 0 : for (nsIContent* child = nsINode::GetFirstChild();
759 : child;
760 0 : child = child->GetNextSibling()) {
761 0 : nsINodeInfo *childInfo = child->NodeInfo();
762 0 : nsIAtom *localName = childInfo->NameAtom();
763 0 : if (childInfo->NamespaceID() == kNameSpaceID_XHTML &&
764 : (localName == nsGkAtoms::thead ||
765 : localName == nsGkAtoms::tbody ||
766 : localName == nsGkAtoms::tfoot)) {
767 0 : rowGroup = do_QueryInterface(child);
768 0 : NS_ASSERTION(rowGroup, "HTML node did not QI to nsIDOMNode");
769 0 : break;
770 : }
771 : }
772 :
773 0 : if (!rowGroup) { // need to create a TBODY
774 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
775 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::tbody,
776 0 : getter_AddRefs(nodeInfo));
777 :
778 : nsCOMPtr<nsIContent> newRowGroup =
779 0 : NS_NewHTMLTableSectionElement(nodeInfo.forget());
780 :
781 0 : if (newRowGroup) {
782 0 : rv = AppendChildTo(newRowGroup, true);
783 0 : NS_ENSURE_SUCCESS(rv, rv);
784 :
785 0 : rowGroup = do_QueryInterface(newRowGroup);
786 : }
787 : }
788 :
789 0 : if (rowGroup) {
790 0 : nsCOMPtr<nsINodeInfo> nodeInfo;
791 : nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::tr,
792 0 : getter_AddRefs(nodeInfo));
793 :
794 0 : nsCOMPtr<nsIContent> newRow = NS_NewHTMLTableRowElement(nodeInfo.forget());
795 0 : if (newRow) {
796 0 : nsCOMPtr<nsIDOMNode> firstRow;
797 :
798 : nsCOMPtr<nsIDOMHTMLTableSectionElement> section =
799 0 : do_QueryInterface(rowGroup);
800 :
801 0 : if (section) {
802 0 : nsCOMPtr<nsIDOMHTMLCollection> rows;
803 0 : section->GetRows(getter_AddRefs(rows));
804 0 : if (rows) {
805 0 : rows->Item(0, getter_AddRefs(firstRow));
806 : }
807 : }
808 :
809 0 : nsCOMPtr<nsIDOMNode> retNode, newRowNode(do_QueryInterface(newRow));
810 :
811 0 : rowGroup->InsertBefore(newRowNode, firstRow, getter_AddRefs(retNode));
812 :
813 0 : if (retNode) {
814 0 : CallQueryInterface(retNode, aValue);
815 : }
816 : }
817 : }
818 : }
819 :
820 0 : return NS_OK;
821 : }
822 :
823 : NS_IMETHODIMP
824 0 : nsHTMLTableElement::DeleteRow(PRInt32 aValue)
825 : {
826 0 : if (aValue < -1) {
827 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
828 : }
829 :
830 0 : nsCOMPtr<nsIDOMHTMLCollection> rows;
831 0 : GetRows(getter_AddRefs(rows));
832 :
833 : nsresult rv;
834 : PRUint32 refIndex;
835 0 : if (aValue == -1) {
836 0 : rv = rows->GetLength(&refIndex);
837 0 : NS_ENSURE_SUCCESS(rv, rv);
838 :
839 0 : if (refIndex == 0) {
840 0 : return NS_OK;
841 : }
842 :
843 0 : --refIndex;
844 : }
845 : else {
846 0 : refIndex = (PRUint32)aValue;
847 : }
848 :
849 0 : nsCOMPtr<nsIDOMNode> row;
850 0 : rv = rows->Item(refIndex, getter_AddRefs(row));
851 0 : NS_ENSURE_SUCCESS(rv, rv);
852 :
853 0 : if (!row) {
854 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
855 : }
856 :
857 0 : nsCOMPtr<nsIDOMNode> parent;
858 0 : row->GetParentNode(getter_AddRefs(parent));
859 0 : NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
860 :
861 0 : nsCOMPtr<nsIDOMNode> deleted_row;
862 0 : return parent->RemoveChild(row, getter_AddRefs(deleted_row));
863 : }
864 :
865 : static const nsAttrValue::EnumTable kFrameTable[] = {
866 : { "void", NS_STYLE_TABLE_FRAME_NONE },
867 : { "above", NS_STYLE_TABLE_FRAME_ABOVE },
868 : { "below", NS_STYLE_TABLE_FRAME_BELOW },
869 : { "hsides", NS_STYLE_TABLE_FRAME_HSIDES },
870 : { "lhs", NS_STYLE_TABLE_FRAME_LEFT },
871 : { "rhs", NS_STYLE_TABLE_FRAME_RIGHT },
872 : { "vsides", NS_STYLE_TABLE_FRAME_VSIDES },
873 : { "box", NS_STYLE_TABLE_FRAME_BOX },
874 : { "border", NS_STYLE_TABLE_FRAME_BORDER },
875 : { 0 }
876 : };
877 :
878 : static const nsAttrValue::EnumTable kRulesTable[] = {
879 : { "none", NS_STYLE_TABLE_RULES_NONE },
880 : { "groups", NS_STYLE_TABLE_RULES_GROUPS },
881 : { "rows", NS_STYLE_TABLE_RULES_ROWS },
882 : { "cols", NS_STYLE_TABLE_RULES_COLS },
883 : { "all", NS_STYLE_TABLE_RULES_ALL },
884 : { 0 }
885 : };
886 :
887 : static const nsAttrValue::EnumTable kLayoutTable[] = {
888 : { "auto", NS_STYLE_TABLE_LAYOUT_AUTO },
889 : { "fixed", NS_STYLE_TABLE_LAYOUT_FIXED },
890 : { 0 }
891 : };
892 :
893 :
894 : bool
895 0 : nsHTMLTableElement::ParseAttribute(PRInt32 aNamespaceID,
896 : nsIAtom* aAttribute,
897 : const nsAString& aValue,
898 : nsAttrValue& aResult)
899 : {
900 : /* ignore summary, just a string */
901 0 : if (aNamespaceID == kNameSpaceID_None) {
902 0 : if (aAttribute == nsGkAtoms::cellspacing ||
903 : aAttribute == nsGkAtoms::cellpadding) {
904 0 : return aResult.ParseNonNegativeIntValue(aValue);
905 : }
906 0 : if (aAttribute == nsGkAtoms::cols ||
907 : aAttribute == nsGkAtoms::border) {
908 0 : return aResult.ParseIntWithBounds(aValue, 0);
909 : }
910 0 : if (aAttribute == nsGkAtoms::height) {
911 0 : return aResult.ParseSpecialIntValue(aValue);
912 : }
913 0 : if (aAttribute == nsGkAtoms::width) {
914 0 : if (aResult.ParseSpecialIntValue(aValue)) {
915 : // treat 0 width as auto
916 0 : nsAttrValue::ValueType type = aResult.Type();
917 : return !((type == nsAttrValue::eInteger &&
918 0 : aResult.GetIntegerValue() == 0) ||
919 : (type == nsAttrValue::ePercent &&
920 0 : aResult.GetPercentValue() == 0.0f));
921 : }
922 0 : return false;
923 : }
924 :
925 0 : if (aAttribute == nsGkAtoms::align) {
926 0 : return ParseTableHAlignValue(aValue, aResult);
927 : }
928 0 : if (aAttribute == nsGkAtoms::bgcolor ||
929 : aAttribute == nsGkAtoms::bordercolor) {
930 0 : return aResult.ParseColor(aValue);
931 : }
932 0 : if (aAttribute == nsGkAtoms::frame) {
933 0 : return aResult.ParseEnumValue(aValue, kFrameTable, false);
934 : }
935 0 : if (aAttribute == nsGkAtoms::layout) {
936 0 : return aResult.ParseEnumValue(aValue, kLayoutTable, false);
937 : }
938 0 : if (aAttribute == nsGkAtoms::rules) {
939 0 : return aResult.ParseEnumValue(aValue, kRulesTable, false);
940 : }
941 0 : if (aAttribute == nsGkAtoms::hspace ||
942 : aAttribute == nsGkAtoms::vspace) {
943 0 : return aResult.ParseIntWithBounds(aValue, 0);
944 : }
945 : }
946 :
947 : return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
948 0 : aResult);
949 : }
950 :
951 :
952 :
953 : static void
954 0 : MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
955 : nsRuleData* aData)
956 : {
957 : // XXX Bug 211636: This function is used by a single style rule
958 : // that's used to match two different type of elements -- tables, and
959 : // table cells. (nsHTMLTableCellElement overrides
960 : // WalkContentStyleRules so that this happens.) This violates the
961 : // nsIStyleRule contract, since it's the same style rule object doing
962 : // the mapping in two different ways. It's also incorrect since it's
963 : // testing the display type of the style context rather than checking
964 : // which *element* it's matching (style rules should not stop matching
965 : // when the display type is changed).
966 :
967 0 : nsPresContext* presContext = aData->mPresContext;
968 0 : nsCompatibility mode = presContext->CompatibilityMode();
969 :
970 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TableBorder)) {
971 : // cellspacing
972 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellspacing);
973 0 : nsCSSValue* borderSpacing = aData->ValueForBorderSpacing();
974 0 : if (value && value->Type() == nsAttrValue::eInteger &&
975 0 : borderSpacing->GetUnit() == eCSSUnit_Null) {
976 : borderSpacing->
977 0 : SetFloatValue(float(value->GetIntegerValue()), eCSSUnit_Pixel);
978 : }
979 : }
980 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Table)) {
981 : const nsAttrValue* value;
982 : // layout
983 0 : nsCSSValue* tableLayout = aData->ValueForTableLayout();
984 0 : if (tableLayout->GetUnit() == eCSSUnit_Null) {
985 0 : value = aAttributes->GetAttr(nsGkAtoms::layout);
986 0 : if (value && value->Type() == nsAttrValue::eEnum)
987 0 : tableLayout->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
988 : }
989 : // cols
990 0 : value = aAttributes->GetAttr(nsGkAtoms::cols);
991 0 : if (value) {
992 0 : nsCSSValue* cols = aData->ValueForCols();
993 0 : if (value->Type() == nsAttrValue::eInteger)
994 0 : cols->SetIntValue(value->GetIntegerValue(), eCSSUnit_Integer);
995 : else // COLS had no value, so it refers to all columns
996 0 : cols->SetIntValue(NS_STYLE_TABLE_COLS_ALL, eCSSUnit_Enumerated);
997 : }
998 : }
999 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
1000 : // align; Check for enumerated type (it may be another type if
1001 : // illegal)
1002 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
1003 :
1004 0 : if (value && value->Type() == nsAttrValue::eEnum) {
1005 0 : if (value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_CENTER ||
1006 0 : value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) {
1007 0 : nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
1008 0 : if (marginLeft->GetUnit() == eCSSUnit_Null)
1009 0 : marginLeft->SetAutoValue();
1010 0 : nsCSSValue* marginRight = aData->ValueForMarginRightValue();
1011 0 : if (marginRight->GetUnit() == eCSSUnit_Null)
1012 0 : marginRight->SetAutoValue();
1013 : }
1014 : }
1015 :
1016 : // hspace is mapped into left and right margin,
1017 : // vspace is mapped into top and bottom margins
1018 : // - *** Quirks Mode only ***
1019 0 : if (eCompatibility_NavQuirks == mode) {
1020 0 : value = aAttributes->GetAttr(nsGkAtoms::hspace);
1021 :
1022 0 : if (value && value->Type() == nsAttrValue::eInteger) {
1023 0 : nsCSSValue* marginLeft = aData->ValueForMarginLeftValue();
1024 0 : if (marginLeft->GetUnit() == eCSSUnit_Null)
1025 0 : marginLeft->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1026 0 : nsCSSValue* marginRight = aData->ValueForMarginRightValue();
1027 0 : if (marginRight->GetUnit() == eCSSUnit_Null)
1028 0 : marginRight->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1029 : }
1030 :
1031 0 : value = aAttributes->GetAttr(nsGkAtoms::vspace);
1032 :
1033 0 : if (value && value->Type() == nsAttrValue::eInteger) {
1034 0 : nsCSSValue* marginTop = aData->ValueForMarginTop();
1035 0 : if (marginTop->GetUnit() == eCSSUnit_Null)
1036 0 : marginTop->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1037 0 : nsCSSValue* marginBottom = aData->ValueForMarginBottom();
1038 0 : if (marginBottom->GetUnit() == eCSSUnit_Null)
1039 0 : marginBottom->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1040 : }
1041 : }
1042 : }
1043 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
1044 : // width: value
1045 0 : nsCSSValue* width = aData->ValueForWidth();
1046 0 : if (width->GetUnit() == eCSSUnit_Null) {
1047 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
1048 0 : if (value && value->Type() == nsAttrValue::eInteger)
1049 0 : width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1050 0 : else if (value && value->Type() == nsAttrValue::ePercent)
1051 0 : width->SetPercentValue(value->GetPercentValue());
1052 : }
1053 :
1054 : // height: value
1055 0 : nsCSSValue* height = aData->ValueForHeight();
1056 0 : if (height->GetUnit() == eCSSUnit_Null) {
1057 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
1058 0 : if (value && value->Type() == nsAttrValue::eInteger)
1059 0 : height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
1060 0 : else if (value && value->Type() == nsAttrValue::ePercent)
1061 0 : height->SetPercentValue(value->GetPercentValue());
1062 : }
1063 : }
1064 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)) {
1065 : // bordercolor
1066 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
1067 : nscolor color;
1068 0 : if (value && presContext->UseDocumentColors() &&
1069 0 : value->GetColorValue(color)) {
1070 0 : nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColorValue();
1071 0 : if (borderLeftColor->GetUnit() == eCSSUnit_Null)
1072 0 : borderLeftColor->SetColorValue(color);
1073 0 : nsCSSValue* borderRightColor = aData->ValueForBorderRightColorValue();
1074 0 : if (borderRightColor->GetUnit() == eCSSUnit_Null)
1075 0 : borderRightColor->SetColorValue(color);
1076 0 : nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
1077 0 : if (borderTopColor->GetUnit() == eCSSUnit_Null)
1078 0 : borderTopColor->SetColorValue(color);
1079 0 : nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
1080 0 : if (borderBottomColor->GetUnit() == eCSSUnit_Null)
1081 0 : borderBottomColor->SetColorValue(color);
1082 : }
1083 :
1084 : // border
1085 0 : const nsAttrValue* borderValue = aAttributes->GetAttr(nsGkAtoms::border);
1086 0 : if (borderValue) {
1087 : // border = 1 pixel default
1088 0 : PRInt32 borderThickness = 1;
1089 :
1090 0 : if (borderValue->Type() == nsAttrValue::eInteger)
1091 0 : borderThickness = borderValue->GetIntegerValue();
1092 :
1093 : // by default, set all border sides to the specified width
1094 0 : nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
1095 0 : if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
1096 0 : borderLeftWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
1097 0 : nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
1098 0 : if (borderRightWidth->GetUnit() == eCSSUnit_Null)
1099 0 : borderRightWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
1100 0 : nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
1101 0 : if (borderTopWidth->GetUnit() == eCSSUnit_Null)
1102 0 : borderTopWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
1103 0 : nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
1104 0 : if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
1105 0 : borderBottomWidth->SetFloatValue((float)borderThickness, eCSSUnit_Pixel);
1106 : }
1107 : }
1108 0 : nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
1109 0 : nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
1110 0 : }
1111 :
1112 : NS_IMETHODIMP_(bool)
1113 0 : nsHTMLTableElement::IsAttributeMapped(const nsIAtom* aAttribute) const
1114 : {
1115 : static const MappedAttributeEntry attributes[] = {
1116 : { &nsGkAtoms::layout },
1117 : { &nsGkAtoms::cellpadding },
1118 : { &nsGkAtoms::cellspacing },
1119 : { &nsGkAtoms::cols },
1120 : { &nsGkAtoms::border },
1121 : { &nsGkAtoms::width },
1122 : { &nsGkAtoms::height },
1123 : { &nsGkAtoms::hspace },
1124 : { &nsGkAtoms::vspace },
1125 :
1126 : { &nsGkAtoms::bordercolor },
1127 :
1128 : { &nsGkAtoms::align },
1129 : { nsnull }
1130 : };
1131 :
1132 : static const MappedAttributeEntry* const map[] = {
1133 : attributes,
1134 : sCommonAttributeMap,
1135 : sBackgroundAttributeMap,
1136 : };
1137 :
1138 0 : return FindAttributeDependence(aAttribute, map);
1139 : }
1140 :
1141 : nsMapRuleToAttributesFunc
1142 0 : nsHTMLTableElement::GetAttributeMappingFunction() const
1143 : {
1144 0 : return &MapAttributesIntoRule;
1145 : }
1146 :
1147 : static void
1148 0 : MapInheritedTableAttributesIntoRule(const nsMappedAttributes* aAttributes,
1149 : nsRuleData* aData)
1150 : {
1151 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Padding)) {
1152 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellpadding);
1153 0 : if (value && value->Type() == nsAttrValue::eInteger) {
1154 : // We have cellpadding. This will override our padding values if we
1155 : // don't have any set.
1156 0 : nsCSSValue padVal(float(value->GetIntegerValue()), eCSSUnit_Pixel);
1157 :
1158 0 : nsCSSValue* paddingLeft = aData->ValueForPaddingLeftValue();
1159 0 : if (paddingLeft->GetUnit() == eCSSUnit_Null) {
1160 0 : *paddingLeft = padVal;
1161 : }
1162 :
1163 0 : nsCSSValue* paddingRight = aData->ValueForPaddingRightValue();
1164 0 : if (paddingRight->GetUnit() == eCSSUnit_Null) {
1165 0 : *paddingRight = padVal;
1166 : }
1167 :
1168 0 : nsCSSValue* paddingTop = aData->ValueForPaddingTop();
1169 0 : if (paddingTop->GetUnit() == eCSSUnit_Null) {
1170 0 : *paddingTop = padVal;
1171 : }
1172 :
1173 0 : nsCSSValue* paddingBottom = aData->ValueForPaddingBottom();
1174 0 : if (paddingBottom->GetUnit() == eCSSUnit_Null) {
1175 0 : *paddingBottom = padVal;
1176 : }
1177 : }
1178 : }
1179 0 : }
1180 :
1181 : nsMappedAttributes*
1182 0 : nsHTMLTableElement::GetAttributesMappedForCell()
1183 : {
1184 0 : if (mTableInheritedAttributes) {
1185 0 : if (mTableInheritedAttributes == TABLE_ATTRS_DIRTY)
1186 0 : BuildInheritedAttributes();
1187 0 : if (mTableInheritedAttributes != TABLE_ATTRS_DIRTY)
1188 0 : return mTableInheritedAttributes;
1189 : }
1190 0 : return nsnull;
1191 : }
1192 :
1193 : void
1194 0 : nsHTMLTableElement::BuildInheritedAttributes()
1195 : {
1196 0 : NS_ASSERTION(mTableInheritedAttributes == TABLE_ATTRS_DIRTY,
1197 : "potential leak, plus waste of work");
1198 0 : nsIDocument *document = GetCurrentDoc();
1199 : nsHTMLStyleSheet* sheet = document ?
1200 0 : document->GetAttributeStyleSheet() : nsnull;
1201 0 : nsRefPtr<nsMappedAttributes> newAttrs;
1202 0 : if (sheet) {
1203 0 : const nsAttrValue* value = mAttrsAndChildren.GetAttr(nsGkAtoms::cellpadding);
1204 0 : if (value) {
1205 : nsRefPtr<nsMappedAttributes> modifiableMapped = new
1206 0 : nsMappedAttributes(sheet, MapInheritedTableAttributesIntoRule);
1207 :
1208 0 : if (modifiableMapped) {
1209 0 : nsAttrValue val(*value);
1210 0 : modifiableMapped->SetAndTakeAttr(nsGkAtoms::cellpadding, val);
1211 : }
1212 0 : newAttrs = sheet->UniqueMappedAttributes(modifiableMapped);
1213 0 : NS_ASSERTION(newAttrs, "out of memory, but handling gracefully");
1214 :
1215 0 : if (newAttrs != modifiableMapped) {
1216 : // Reset the stylesheet of modifiableMapped so that it doesn't
1217 : // spend time trying to remove itself from the hash. There is no
1218 : // risk that modifiableMapped is in the hash since we created
1219 : // it ourselves and it didn't come from the stylesheet (in which
1220 : // case it would not have been modifiable).
1221 0 : modifiableMapped->DropStyleSheetReference();
1222 : }
1223 : }
1224 0 : mTableInheritedAttributes = newAttrs;
1225 0 : NS_IF_ADDREF(mTableInheritedAttributes);
1226 : }
1227 0 : }
1228 :
1229 : nsresult
1230 0 : nsHTMLTableElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
1231 : nsIContent* aBindingParent,
1232 : bool aCompileEventHandlers)
1233 : {
1234 0 : ReleaseInheritedAttributes();
1235 : return nsGenericHTMLElement::BindToTree(aDocument, aParent,
1236 : aBindingParent,
1237 0 : aCompileEventHandlers);
1238 : }
1239 :
1240 : void
1241 0 : nsHTMLTableElement::UnbindFromTree(bool aDeep, bool aNullParent)
1242 : {
1243 0 : ReleaseInheritedAttributes();
1244 0 : nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
1245 0 : }
1246 :
1247 : nsresult
1248 0 : nsHTMLTableElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
1249 : const nsAttrValueOrString* aValue,
1250 : bool aNotify)
1251 : {
1252 0 : if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
1253 0 : ReleaseInheritedAttributes();
1254 : }
1255 : return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
1256 0 : aNotify);
1257 : }
1258 :
1259 : nsresult
1260 0 : nsHTMLTableElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
1261 : const nsAttrValue* aValue,
1262 : bool aNotify)
1263 : {
1264 0 : if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
1265 0 : BuildInheritedAttributes();
1266 : }
1267 : return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
1268 0 : aNotify);
1269 4392 : }
|