Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsNameSpaceManager.h"
7 #include "nsGkAtoms.h"
8 #include "nsIDOMElement.h"
9 #include "nsIBoxObject.h"
10 #include "nsTreeColumns.h"
11 #include "nsTreeUtils.h"
12 #include "nsStyleContext.h"
13 #include "nsDOMClassInfoID.h"
14 #include "nsINodeInfo.h"
15 #include "nsContentUtils.h"
16 #include "nsTreeBodyFrame.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/TreeColumnsBinding.h"
20 using namespace mozilla;
22 // Column class that caches all the info about our column.
23 nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent)
24 : mContent(aContent),
25 mColumns(aColumns),
26 mPrevious(nullptr)
27 {
28 NS_ASSERTION(aContent &&
29 aContent->NodeInfo()->Equals(nsGkAtoms::treecol,
30 kNameSpaceID_XUL),
31 "nsTreeColumn's content must be a <xul:treecol>");
33 Invalidate();
34 }
36 nsTreeColumn::~nsTreeColumn()
37 {
38 if (mNext) {
39 mNext->SetPrevious(nullptr);
40 }
41 }
43 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTreeColumn)
45 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTreeColumn)
46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
47 if (tmp->mNext) {
48 tmp->mNext->SetPrevious(nullptr);
49 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNext)
50 }
51 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTreeColumn)
53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNext)
55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
57 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumn)
58 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumn)
60 DOMCI_DATA(TreeColumn, nsTreeColumn)
62 // QueryInterface implementation for nsTreeColumn
63 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumn)
64 NS_INTERFACE_MAP_ENTRY(nsITreeColumn)
65 NS_INTERFACE_MAP_ENTRY(nsISupports)
66 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TreeColumn)
67 if (aIID.Equals(NS_GET_IID(nsTreeColumn))) {
68 AddRef();
69 *aInstancePtr = this;
70 return NS_OK;
71 }
72 else
73 NS_INTERFACE_MAP_END
75 nsIFrame*
76 nsTreeColumn::GetFrame()
77 {
78 NS_ENSURE_TRUE(mContent, nullptr);
80 return mContent->GetPrimaryFrame();
81 }
83 bool
84 nsTreeColumn::IsLastVisible(nsTreeBodyFrame* aBodyFrame)
85 {
86 NS_ASSERTION(GetFrame(), "should have checked for this already");
88 // cyclers are fixed width, don't adjust them
89 if (IsCycler())
90 return false;
92 // we're certainly not the last visible if we're not visible
93 if (GetFrame()->GetRect().width == 0)
94 return false;
96 // try to find a visible successor
97 for (nsTreeColumn *next = GetNext(); next; next = next->GetNext()) {
98 nsIFrame* frame = next->GetFrame();
99 if (frame && frame->GetRect().width > 0)
100 return false;
101 }
102 return true;
103 }
105 nsresult
106 nsTreeColumn::GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult)
107 {
108 nsIFrame* frame = GetFrame();
109 if (!frame) {
110 *aResult = nsRect();
111 return NS_ERROR_FAILURE;
112 }
114 bool isRTL = aBodyFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
115 *aResult = frame->GetRect();
116 aResult->y = aY;
117 aResult->height = aHeight;
118 if (isRTL)
119 aResult->x += aBodyFrame->mAdjustWidth;
120 else if (IsLastVisible(aBodyFrame))
121 aResult->width += aBodyFrame->mAdjustWidth;
122 return NS_OK;
123 }
125 nsresult
126 nsTreeColumn::GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
127 {
128 nsIFrame* frame = GetFrame();
129 if (!frame) {
130 *aResult = 0;
131 return NS_ERROR_FAILURE;
132 }
133 *aResult = frame->GetRect().x;
134 return NS_OK;
135 }
137 nsresult
138 nsTreeColumn::GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
139 {
140 nsIFrame* frame = GetFrame();
141 if (!frame) {
142 *aResult = 0;
143 return NS_ERROR_FAILURE;
144 }
145 *aResult = frame->GetRect().width;
146 if (IsLastVisible(aBodyFrame))
147 *aResult += aBodyFrame->mAdjustWidth;
148 return NS_OK;
149 }
152 NS_IMETHODIMP
153 nsTreeColumn::GetElement(nsIDOMElement** aElement)
154 {
155 if (mContent) {
156 return CallQueryInterface(mContent, aElement);
157 }
158 *aElement = nullptr;
159 return NS_ERROR_FAILURE;
160 }
162 NS_IMETHODIMP
163 nsTreeColumn::GetColumns(nsITreeColumns** aColumns)
164 {
165 NS_IF_ADDREF(*aColumns = mColumns);
166 return NS_OK;
167 }
169 NS_IMETHODIMP
170 nsTreeColumn::GetX(int32_t* aX)
171 {
172 nsIFrame* frame = GetFrame();
173 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
175 *aX = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x);
176 return NS_OK;
177 }
179 NS_IMETHODIMP
180 nsTreeColumn::GetWidth(int32_t* aWidth)
181 {
182 nsIFrame* frame = GetFrame();
183 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
185 *aWidth = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width);
186 return NS_OK;
187 }
189 NS_IMETHODIMP
190 nsTreeColumn::GetId(nsAString& aId)
191 {
192 aId = GetId();
193 return NS_OK;
194 }
196 NS_IMETHODIMP
197 nsTreeColumn::GetIdConst(const char16_t** aIdConst)
198 {
199 *aIdConst = mId.get();
200 return NS_OK;
201 }
203 NS_IMETHODIMP
204 nsTreeColumn::GetAtom(nsIAtom** aAtom)
205 {
206 NS_IF_ADDREF(*aAtom = GetAtom());
207 return NS_OK;
208 }
210 NS_IMETHODIMP
211 nsTreeColumn::GetIndex(int32_t* aIndex)
212 {
213 *aIndex = GetIndex();
214 return NS_OK;
215 }
217 NS_IMETHODIMP
218 nsTreeColumn::GetPrimary(bool* aPrimary)
219 {
220 *aPrimary = IsPrimary();
221 return NS_OK;
222 }
224 NS_IMETHODIMP
225 nsTreeColumn::GetCycler(bool* aCycler)
226 {
227 *aCycler = IsCycler();
228 return NS_OK;
229 }
231 NS_IMETHODIMP
232 nsTreeColumn::GetEditable(bool* aEditable)
233 {
234 *aEditable = IsEditable();
235 return NS_OK;
236 }
238 NS_IMETHODIMP
239 nsTreeColumn::GetSelectable(bool* aSelectable)
240 {
241 *aSelectable = IsSelectable();
242 return NS_OK;
243 }
245 NS_IMETHODIMP
246 nsTreeColumn::GetType(int16_t* aType)
247 {
248 *aType = GetType();
249 return NS_OK;
250 }
252 NS_IMETHODIMP
253 nsTreeColumn::GetNext(nsITreeColumn** _retval)
254 {
255 NS_IF_ADDREF(*_retval = GetNext());
256 return NS_OK;
257 }
259 NS_IMETHODIMP
260 nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
261 {
262 NS_IF_ADDREF(*_retval = GetPrevious());
263 return NS_OK;
264 }
266 NS_IMETHODIMP
267 nsTreeColumn::Invalidate()
268 {
269 nsIFrame* frame = GetFrame();
270 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
272 // Fetch the Id.
273 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
275 // If we have an Id, cache the Id as an atom.
276 if (!mId.IsEmpty()) {
277 mAtom = do_GetAtom(mId);
278 }
280 // Cache our index.
281 nsTreeUtils::GetColumnIndex(mContent, &mIndex);
283 const nsStyleVisibility* vis = frame->StyleVisibility();
285 // Cache our text alignment policy.
286 const nsStyleText* textStyle = frame->StyleText();
288 mTextAlignment = textStyle->mTextAlign;
289 // DEFAULT or END alignment sometimes means RIGHT
290 if ((mTextAlignment == NS_STYLE_TEXT_ALIGN_DEFAULT &&
291 vis->mDirection == NS_STYLE_DIRECTION_RTL) ||
292 (mTextAlignment == NS_STYLE_TEXT_ALIGN_END &&
293 vis->mDirection == NS_STYLE_DIRECTION_LTR)) {
294 mTextAlignment = NS_STYLE_TEXT_ALIGN_RIGHT;
295 } else if (mTextAlignment == NS_STYLE_TEXT_ALIGN_DEFAULT ||
296 mTextAlignment == NS_STYLE_TEXT_ALIGN_END) {
297 mTextAlignment = NS_STYLE_TEXT_ALIGN_LEFT;
298 }
300 // Figure out if we're the primary column (that has to have indentation
301 // and twisties drawn.
302 mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
303 nsGkAtoms::_true, eCaseMatters);
305 // Figure out if we're a cycling column (one that doesn't cause a selection
306 // to happen).
307 mIsCycler = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
308 nsGkAtoms::_true, eCaseMatters);
310 mIsEditable = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
311 nsGkAtoms::_true, eCaseMatters);
313 mIsSelectable = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
314 nsGkAtoms::_false, eCaseMatters);
316 mOverflow = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
317 nsGkAtoms::_true, eCaseMatters);
319 // Figure out our column type. Default type is text.
320 mType = nsITreeColumn::TYPE_TEXT;
321 static nsIContent::AttrValuesArray typestrings[] =
322 {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, nullptr};
323 switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
324 typestrings, eCaseMatters)) {
325 case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
326 case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break;
327 }
329 // Fetch the crop style.
330 mCropStyle = 0;
331 static nsIContent::AttrValuesArray cropstrings[] =
332 {&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr};
333 switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
334 cropstrings, eCaseMatters)) {
335 case 0:
336 mCropStyle = 1;
337 break;
338 case 1:
339 case 2:
340 mCropStyle = 2;
341 break;
342 }
344 return NS_OK;
345 }
348 nsTreeColumns::nsTreeColumns(nsTreeBodyFrame* aTree)
349 : mTree(aTree),
350 mFirstColumn(nullptr)
351 {
352 SetIsDOMBinding();
353 }
355 nsTreeColumns::~nsTreeColumns()
356 {
357 nsTreeColumns::InvalidateColumns();
358 }
360 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsTreeColumns)
362 // QueryInterface implementation for nsTreeColumns
363 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumns)
364 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
365 NS_INTERFACE_MAP_ENTRY(nsITreeColumns)
366 NS_INTERFACE_MAP_ENTRY(nsISupports)
367 NS_INTERFACE_MAP_END
369 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumns)
370 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumns)
372 nsIContent*
373 nsTreeColumns::GetParentObject() const
374 {
375 return mTree ? mTree->GetBaseElement() : nullptr;
376 }
378 /* virtual */ JSObject*
379 nsTreeColumns::WrapObject(JSContext* aCx)
380 {
381 return dom::TreeColumnsBinding::Wrap(aCx, this);
382 }
384 nsITreeBoxObject*
385 nsTreeColumns::GetTree() const
386 {
387 return mTree ? mTree->GetTreeBoxObject() : nullptr;
388 }
390 NS_IMETHODIMP
391 nsTreeColumns::GetTree(nsITreeBoxObject** _retval)
392 {
393 NS_IF_ADDREF(*_retval = GetTree());
394 return NS_OK;
395 }
397 uint32_t
398 nsTreeColumns::Count()
399 {
400 EnsureColumns();
401 uint32_t count = 0;
402 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
403 ++count;
404 }
405 return count;
406 }
408 NS_IMETHODIMP
409 nsTreeColumns::GetCount(int32_t* _retval)
410 {
411 *_retval = Count();
412 return NS_OK;
413 }
415 NS_IMETHODIMP
416 nsTreeColumns::GetLength(int32_t* _retval)
417 {
418 *_retval = Length();
419 return NS_OK;
420 }
422 NS_IMETHODIMP
423 nsTreeColumns::GetFirstColumn(nsITreeColumn** _retval)
424 {
425 NS_IF_ADDREF(*_retval = GetFirstColumn());
426 return NS_OK;
427 }
429 nsTreeColumn*
430 nsTreeColumns::GetLastColumn()
431 {
432 EnsureColumns();
433 nsTreeColumn* currCol = mFirstColumn;
434 while (currCol) {
435 nsTreeColumn* next = currCol->GetNext();
436 if (!next) {
437 return currCol;
438 }
439 currCol = next;
440 }
441 return nullptr;
442 }
444 NS_IMETHODIMP
445 nsTreeColumns::GetLastColumn(nsITreeColumn** _retval)
446 {
447 NS_IF_ADDREF(*_retval = GetLastColumn());
448 return NS_OK;
449 }
451 NS_IMETHODIMP
452 nsTreeColumns::GetPrimaryColumn(nsITreeColumn** _retval)
453 {
454 NS_IF_ADDREF(*_retval = GetPrimaryColumn());
455 return NS_OK;
456 }
458 nsTreeColumn*
459 nsTreeColumns::GetSortedColumn()
460 {
461 EnsureColumns();
462 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
463 if (currCol->mContent &&
464 nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
465 nsGkAtoms::sortDirection)) {
466 return currCol;
467 }
468 }
469 return nullptr;
470 }
472 NS_IMETHODIMP
473 nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval)
474 {
475 NS_IF_ADDREF(*_retval = GetSortedColumn());
476 return NS_OK;
477 }
479 nsTreeColumn*
480 nsTreeColumns::GetKeyColumn()
481 {
482 EnsureColumns();
484 nsTreeColumn* first = nullptr;
485 nsTreeColumn* primary = nullptr;
486 nsTreeColumn* sorted = nullptr;
488 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
489 // Skip hidden columns.
490 if (!currCol->mContent ||
491 currCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
492 nsGkAtoms::_true, eCaseMatters))
493 continue;
495 // Skip non-text column
496 if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
497 continue;
499 if (!first)
500 first = currCol;
502 if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
503 nsGkAtoms::sortDirection)) {
504 // Use sorted column as the key.
505 sorted = currCol;
506 break;
507 }
509 if (currCol->IsPrimary())
510 if (!primary)
511 primary = currCol;
512 }
514 if (sorted)
515 return sorted;
516 if (primary)
517 return primary;
518 return first;
519 }
521 NS_IMETHODIMP
522 nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
523 {
524 NS_IF_ADDREF(*_retval = GetKeyColumn());
525 return NS_OK;
526 }
528 nsTreeColumn*
529 nsTreeColumns::GetColumnFor(dom::Element* aElement)
530 {
531 EnsureColumns();
532 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
533 if (currCol->mContent == aElement) {
534 return currCol;
535 }
536 }
537 return nullptr;
538 }
540 NS_IMETHODIMP
541 nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval)
542 {
543 nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
544 NS_ADDREF(*_retval = GetColumnFor(element));
545 return NS_OK;
546 }
548 nsTreeColumn*
549 nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound)
550 {
551 EnsureColumns();
552 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
553 if (currCol->GetId().Equals(aId)) {
554 aFound = true;
555 return currCol;
556 }
557 }
558 aFound = false;
559 return nullptr;
560 }
562 bool
563 nsTreeColumns::NameIsEnumerable(const nsAString& aName)
564 {
565 return true;
566 }
568 nsTreeColumn*
569 nsTreeColumns::GetNamedColumn(const nsAString& aId)
570 {
571 bool dummy;
572 return NamedGetter(aId, dummy);
573 }
575 NS_IMETHODIMP
576 nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval)
577 {
578 NS_IF_ADDREF(*_retval = GetNamedColumn(aId));
579 return NS_OK;
580 }
582 void
583 nsTreeColumns::GetSupportedNames(unsigned, nsTArray<nsString>& aNames)
584 {
585 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
586 aNames.AppendElement(currCol->GetId());
587 }
588 }
591 nsTreeColumn*
592 nsTreeColumns::IndexedGetter(uint32_t aIndex, bool& aFound)
593 {
594 EnsureColumns();
595 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
596 if (currCol->GetIndex() == static_cast<int32_t>(aIndex)) {
597 aFound = true;
598 return currCol;
599 }
600 }
601 aFound = false;
602 return nullptr;
603 }
605 nsTreeColumn*
606 nsTreeColumns::GetColumnAt(uint32_t aIndex)
607 {
608 bool dummy;
609 return IndexedGetter(aIndex, dummy);
610 }
612 NS_IMETHODIMP
613 nsTreeColumns::GetColumnAt(int32_t aIndex, nsITreeColumn** _retval)
614 {
615 NS_IF_ADDREF(*_retval = GetColumnAt(static_cast<uint32_t>(aIndex)));
616 return NS_OK;
617 }
619 NS_IMETHODIMP
620 nsTreeColumns::InvalidateColumns()
621 {
622 for (nsTreeColumn* currCol = mFirstColumn; currCol;
623 currCol = currCol->GetNext()) {
624 currCol->SetColumns(nullptr);
625 }
626 NS_IF_RELEASE(mFirstColumn);
627 return NS_OK;
628 }
630 NS_IMETHODIMP
631 nsTreeColumns::RestoreNaturalOrder()
632 {
633 if (!mTree)
634 return NS_OK;
636 nsIContent* content = mTree->GetBaseElement();
638 // Strong ref, since we'll be setting attributes
639 nsCOMPtr<nsIContent> colsContent =
640 nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treecols);
641 if (!colsContent)
642 return NS_OK;
644 for (uint32_t i = 0; i < colsContent->GetChildCount(); ++i) {
645 nsCOMPtr<nsIContent> child = colsContent->GetChildAt(i);
646 nsAutoString ordinal;
647 ordinal.AppendInt(i);
648 child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, true);
649 }
651 nsTreeColumns::InvalidateColumns();
653 if (mTree) {
654 mTree->Invalidate();
655 }
656 return NS_OK;
657 }
659 nsTreeColumn*
660 nsTreeColumns::GetPrimaryColumn()
661 {
662 EnsureColumns();
663 for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
664 if (currCol->IsPrimary()) {
665 return currCol;
666 }
667 }
668 return nullptr;
669 }
671 void
672 nsTreeColumns::EnsureColumns()
673 {
674 if (mTree && !mFirstColumn) {
675 nsIContent* treeContent = mTree->GetBaseElement();
676 nsIContent* colsContent =
677 nsTreeUtils::GetDescendantChild(treeContent, nsGkAtoms::treecols);
678 if (!colsContent)
679 return;
681 nsIContent* colContent =
682 nsTreeUtils::GetDescendantChild(colsContent, nsGkAtoms::treecol);
683 if (!colContent)
684 return;
686 nsIFrame* colFrame = colContent->GetPrimaryFrame();
687 if (!colFrame)
688 return;
690 colFrame = colFrame->GetParent();
691 if (!colFrame)
692 return;
694 colFrame = colFrame->GetFirstPrincipalChild();
695 if (!colFrame)
696 return;
698 // Now that we have the first visible column,
699 // we can enumerate the columns in visible order
700 nsTreeColumn* currCol = nullptr;
701 while (colFrame) {
702 nsIContent* colContent = colFrame->GetContent();
704 if (colContent->NodeInfo()->Equals(nsGkAtoms::treecol,
705 kNameSpaceID_XUL)) {
706 // Create a new column structure.
707 nsTreeColumn* col = new nsTreeColumn(this, colContent);
708 if (!col)
709 return;
711 if (currCol) {
712 currCol->SetNext(col);
713 col->SetPrevious(currCol);
714 }
715 else {
716 NS_ADDREF(mFirstColumn = col);
717 }
718 currCol = col;
719 }
721 colFrame = colFrame->GetNextSibling();
722 }
723 }
724 }