Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 /* base class #1 for rendering objects that have child lists */
8 #include "nsContainerFrame.h"
10 #include "nsAbsoluteContainingBlock.h"
11 #include "nsIDocument.h"
12 #include "nsPresContext.h"
13 #include "nsStyleContext.h"
14 #include "nsRect.h"
15 #include "nsPoint.h"
16 #include "nsStyleConsts.h"
17 #include "nsView.h"
18 #include "nsIPresShell.h"
19 #include "nsCOMPtr.h"
20 #include "nsGkAtoms.h"
21 #include "nsViewManager.h"
22 #include "nsIWidget.h"
23 #include "nsCSSRendering.h"
24 #include "nsError.h"
25 #include "nsDisplayList.h"
26 #include "nsIBaseWindow.h"
27 #include "nsBoxLayoutState.h"
28 #include "nsCSSFrameConstructor.h"
29 #include "nsBlockFrame.h"
30 #include "mozilla/AutoRestore.h"
31 #include "nsIFrameInlines.h"
32 #include "nsPrintfCString.h"
33 #include <algorithm>
35 #ifdef DEBUG
36 #undef NOISY
37 #else
38 #undef NOISY
39 #endif
41 using namespace mozilla;
42 using namespace mozilla::dom;
43 using namespace mozilla::layout;
45 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame)
47 nsContainerFrame::~nsContainerFrame()
48 {
49 }
51 NS_QUERYFRAME_HEAD(nsContainerFrame)
52 NS_QUERYFRAME_ENTRY(nsContainerFrame)
53 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
55 void
56 nsContainerFrame::Init(nsIContent* aContent,
57 nsIFrame* aParent,
58 nsIFrame* aPrevInFlow)
59 {
60 nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
61 if (aPrevInFlow) {
62 // Make sure we copy bits from our prev-in-flow that will affect
63 // us. A continuation for a container frame needs to know if it
64 // has a child with a view so that we'll properly reposition it.
65 if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
66 AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
67 }
68 }
70 nsresult
71 nsContainerFrame::SetInitialChildList(ChildListID aListID,
72 nsFrameList& aChildList)
73 {
74 nsresult result;
75 if (mFrames.NotEmpty()) {
76 // We already have child frames which means we've already been
77 // initialized
78 NS_NOTREACHED("unexpected second call to SetInitialChildList");
79 result = NS_ERROR_UNEXPECTED;
80 } else if (aListID != kPrincipalList) {
81 // All we know about is the principal child list.
82 NS_NOTREACHED("unknown frame list");
83 result = NS_ERROR_INVALID_ARG;
84 } else {
85 #ifdef DEBUG
86 nsFrame::VerifyDirtyBitSet(aChildList);
87 #endif
88 mFrames.SetFrames(aChildList);
89 result = NS_OK;
90 }
91 return result;
92 }
94 nsresult
95 nsContainerFrame::AppendFrames(ChildListID aListID,
96 nsFrameList& aFrameList)
97 {
98 if (aListID != kPrincipalList) {
99 if (aListID != kNoReflowPrincipalList)
100 {
101 NS_ERROR("unexpected child list");
102 return NS_ERROR_INVALID_ARG;
103 }
104 }
105 if (aFrameList.NotEmpty()) {
106 mFrames.AppendFrames(this, aFrameList);
108 // Ask the parent frame to reflow me.
109 if (aListID == kPrincipalList)
110 {
111 PresContext()->PresShell()->
112 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
113 NS_FRAME_HAS_DIRTY_CHILDREN);
114 }
115 }
116 return NS_OK;
117 }
119 nsresult
120 nsContainerFrame::InsertFrames(ChildListID aListID,
121 nsIFrame* aPrevFrame,
122 nsFrameList& aFrameList)
123 {
124 NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
125 "inserting after sibling frame with different parent");
127 if (aListID != kPrincipalList) {
128 if (aListID != kNoReflowPrincipalList)
129 {
130 NS_ERROR("unexpected child list");
131 return NS_ERROR_INVALID_ARG;
132 }
133 }
134 if (aFrameList.NotEmpty()) {
135 // Insert frames after aPrevFrame
136 mFrames.InsertFrames(this, aPrevFrame, aFrameList);
138 if (aListID == kPrincipalList)
139 {
140 PresContext()->PresShell()->
141 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
142 NS_FRAME_HAS_DIRTY_CHILDREN);
143 }
144 }
145 return NS_OK;
146 }
148 nsresult
149 nsContainerFrame::RemoveFrame(ChildListID aListID,
150 nsIFrame* aOldFrame)
151 {
152 if (aListID != kPrincipalList) {
153 if (kNoReflowPrincipalList != aListID)
154 {
155 NS_ERROR("unexpected child list");
156 return NS_ERROR_INVALID_ARG;
157 }
158 }
160 // Loop and destroy aOldFrame and all of its continuations.
161 // Request a reflow on the parent frames involved unless we were explicitly
162 // told not to (kNoReflowPrincipalList).
163 bool generateReflowCommand = true;
164 if (kNoReflowPrincipalList == aListID) {
165 generateReflowCommand = false;
166 }
167 nsIPresShell* shell = PresContext()->PresShell();
168 nsContainerFrame* lastParent = nullptr;
169 while (aOldFrame) {
170 //XXXfr probably should use StealFrame here. I'm not sure if we need to
171 // check the overflow lists atm, but we'll need a prescontext lookup
172 // for overflow containers once we can split abspos elements with
173 // inline containing blocks.
174 nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
175 nsContainerFrame* parent =
176 static_cast<nsContainerFrame*>(aOldFrame->GetParent());
177 parent->StealFrame(aOldFrame, true);
178 aOldFrame->Destroy();
179 aOldFrame = oldFrameNextContinuation;
180 if (parent != lastParent && generateReflowCommand) {
181 shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
182 NS_FRAME_HAS_DIRTY_CHILDREN);
183 lastParent = parent;
184 }
185 }
186 return NS_OK;
187 }
189 void
190 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
191 {
192 if (IsAbsoluteContainer()) {
193 GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
194 MarkAsNotAbsoluteContainingBlock();
195 }
196 }
198 void
199 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
200 nsIPresShell* aPresShell,
201 FramePropertyTable* aPropTable,
202 const FramePropertyDescriptor* aProp)
203 {
204 // Note that the last frame can be removed through another route and thus
205 // delete the property -- that's why we fetch the property again before
206 // removing each frame rather than fetching it once and iterating the list.
207 while (nsFrameList* frameList =
208 static_cast<nsFrameList*>(aPropTable->Get(this, aProp))) {
209 nsIFrame* frame = frameList->RemoveFirstChild();
210 if (MOZ_LIKELY(frame)) {
211 frame->DestroyFrom(aDestructRoot);
212 } else {
213 aPropTable->Remove(this, aProp);
214 frameList->Delete(aPresShell);
215 return;
216 }
217 }
218 }
220 void
221 nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
222 {
223 // Prevent event dispatch during destruction.
224 if (HasView()) {
225 GetView()->SetFrame(nullptr);
226 }
228 DestroyAbsoluteFrames(aDestructRoot);
230 // Destroy frames on the principal child list.
231 mFrames.DestroyFramesFrom(aDestructRoot);
233 // Destroy frames on the auxiliary frame lists and delete the lists.
234 nsPresContext* pc = PresContext();
235 nsIPresShell* shell = pc->PresShell();
236 FramePropertyTable* props = pc->PropertyTable();
237 SafelyDestroyFrameListProp(aDestructRoot, shell, props, OverflowProperty());
239 MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers) ||
240 !(props->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
241 props->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
242 "this type of frame should't have overflow containers");
244 SafelyDestroyFrameListProp(aDestructRoot, shell, props,
245 OverflowContainersProperty());
246 SafelyDestroyFrameListProp(aDestructRoot, shell, props,
247 ExcessOverflowContainersProperty());
249 nsSplittableFrame::DestroyFrom(aDestructRoot);
250 }
252 /////////////////////////////////////////////////////////////////////////////
253 // Child frame enumeration
255 const nsFrameList&
256 nsContainerFrame::GetChildList(ChildListID aListID) const
257 {
258 // We only know about the principal child list and the overflow lists.
259 switch (aListID) {
260 case kPrincipalList:
261 return mFrames;
262 case kOverflowList: {
263 nsFrameList* list = GetOverflowFrames();
264 return list ? *list : nsFrameList::EmptyList();
265 }
266 case kOverflowContainersList: {
267 nsFrameList* list = GetPropTableFrames(OverflowContainersProperty());
268 return list ? *list : nsFrameList::EmptyList();
269 }
270 case kExcessOverflowContainersList: {
271 nsFrameList* list =
272 GetPropTableFrames(ExcessOverflowContainersProperty());
273 return list ? *list : nsFrameList::EmptyList();
274 }
275 default:
276 return nsSplittableFrame::GetChildList(aListID);
277 }
278 }
280 static void AppendIfNonempty(const nsIFrame* aFrame,
281 FramePropertyTable* aPropTable,
282 const FramePropertyDescriptor* aProperty,
283 nsTArray<nsIFrame::ChildList>* aLists,
284 nsIFrame::ChildListID aListID)
285 {
286 nsFrameList* list = static_cast<nsFrameList*>(
287 aPropTable->Get(aFrame, aProperty));
288 if (list) {
289 list->AppendIfNonempty(aLists, aListID);
290 }
291 }
293 void
294 nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
295 {
296 mFrames.AppendIfNonempty(aLists, kPrincipalList);
297 FramePropertyTable* propTable = PresContext()->PropertyTable();
298 ::AppendIfNonempty(this, propTable, OverflowProperty(),
299 aLists, kOverflowList);
300 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
301 ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
302 aLists, kOverflowContainersList);
303 ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
304 aLists, kExcessOverflowContainersList);
305 }
306 nsSplittableFrame::GetChildLists(aLists);
307 }
309 /////////////////////////////////////////////////////////////////////////////
310 // Painting/Events
312 void
313 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
314 const nsRect& aDirtyRect,
315 const nsDisplayListSet& aLists)
316 {
317 DisplayBorderBackgroundOutline(aBuilder, aLists);
319 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
320 }
322 void
323 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
324 const nsRect& aDirtyRect,
325 const nsDisplayListSet& aLists,
326 uint32_t aFlags)
327 {
328 nsIFrame* kid = mFrames.FirstChild();
329 // Put each child's background directly onto the content list
330 nsDisplayListSet set(aLists, aLists.Content());
331 // The children should be in content order
332 while (kid) {
333 BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
334 kid = kid->GetNextSibling();
335 }
336 }
338 /* virtual */ void
339 nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
340 {
341 NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
343 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
344 }
346 bool
347 nsContainerFrame::IsLeaf() const
348 {
349 return false;
350 }
352 nsIFrame::FrameSearchResult
353 nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
354 {
355 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
356 // Don't allow the caret to stay in an empty (leaf) container frame.
357 return CONTINUE_EMPTY;
358 }
360 nsIFrame::FrameSearchResult
361 nsContainerFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
362 bool aRespectClusters)
363 {
364 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
365 // Don't allow the caret to stay in an empty (leaf) container frame.
366 return CONTINUE_EMPTY;
367 }
369 /////////////////////////////////////////////////////////////////////////////
370 // Helper member functions
372 static nsresult
373 ReparentFrameViewTo(nsIFrame* aFrame,
374 nsViewManager* aViewManager,
375 nsView* aNewParentView,
376 nsView* aOldParentView)
377 {
379 // XXX What to do about placeholder views for "position: fixed" elements?
380 // They should be reparented too.
382 // Does aFrame have a view?
383 if (aFrame->HasView()) {
384 #ifdef MOZ_XUL
385 if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
386 // This view must be parented by the root view, don't reparent it.
387 return NS_OK;
388 }
389 #endif
390 nsView* view = aFrame->GetView();
391 // Verify that the current parent view is what we think it is
392 //nsView* parentView;
393 //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
395 aViewManager->RemoveChild(view);
397 // The view will remember the Z-order and other attributes that have been set on it.
398 nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
399 aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
400 } else {
401 nsIFrame::ChildListIterator lists(aFrame);
402 for (; !lists.IsDone(); lists.Next()) {
403 // Iterate the child frames, and check each child frame to see if it has
404 // a view
405 nsFrameList::Enumerator childFrames(lists.CurrentList());
406 for (; !childFrames.AtEnd(); childFrames.Next()) {
407 ReparentFrameViewTo(childFrames.get(), aViewManager,
408 aNewParentView, aOldParentView);
409 }
410 }
411 }
413 return NS_OK;
414 }
416 void
417 nsContainerFrame::CreateViewForFrame(nsIFrame* aFrame,
418 bool aForce)
419 {
420 if (aFrame->HasView()) {
421 return;
422 }
424 // If we don't yet have a view, see if we need a view
425 if (!aForce && !aFrame->NeedsView()) {
426 // don't need a view
427 return;
428 }
430 nsView* parentView = aFrame->GetParent()->GetClosestView();
431 NS_ASSERTION(parentView, "no parent with view");
433 nsViewManager* viewManager = parentView->GetViewManager();
434 NS_ASSERTION(viewManager, "null view manager");
436 // Create a view
437 nsView* view = viewManager->CreateView(aFrame->GetRect(), parentView);
439 SyncFrameViewProperties(aFrame->PresContext(), aFrame, nullptr, view);
441 nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, aFrame);
442 // we insert this view 'above' the insertBefore view, unless insertBefore is null,
443 // in which case we want to call with aAbove == false to insert at the beginning
444 // in document order
445 viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
447 // REVIEW: Don't create a widget for fixed-pos elements anymore.
448 // ComputeRepaintRegionForCopy will calculate the right area to repaint
449 // when we scroll.
450 // Reparent views on any child frames (or their descendants) to this
451 // view. We can just call ReparentFrameViewTo on this frame because
452 // we know this frame has no view, so it will crawl the children. Also,
453 // we know that any descendants with views must have 'parentView' as their
454 // parent view.
455 ReparentFrameViewTo(aFrame, viewManager, view, parentView);
457 // Remember our view
458 aFrame->SetView(view);
460 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
461 ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
462 aFrame));
463 }
465 /**
466 * Position the view associated with |aKidFrame|, if there is one. A
467 * container frame should call this method after positioning a frame,
468 * but before |Reflow|.
469 */
470 void
471 nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
472 {
473 nsIFrame* parentFrame = aKidFrame->GetParent();
474 if (!aKidFrame->HasView() || !parentFrame)
475 return;
477 nsView* view = aKidFrame->GetView();
478 nsViewManager* vm = view->GetViewManager();
479 nsPoint pt;
480 nsView* ancestorView = parentFrame->GetClosestView(&pt);
482 if (ancestorView != view->GetParent()) {
483 NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
484 "Allowed only one anonymous view between frames");
485 // parentFrame is responsible for positioning aKidFrame's view
486 // explicitly
487 return;
488 }
490 pt += aKidFrame->GetPosition();
491 vm->MoveViewTo(view, pt.x, pt.y);
492 }
494 nsresult
495 nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
496 nsIFrame* aOldParentFrame,
497 nsIFrame* aNewParentFrame)
498 {
499 NS_PRECONDITION(aChildFrame, "null child frame pointer");
500 NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
501 NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
502 NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
504 // See if either the old parent frame or the new parent frame have a view
505 while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
506 // Walk up both the old parent frame and the new parent frame nodes
507 // stopping when we either find a common parent or views for one
508 // or both of the frames.
509 //
510 // This works well in the common case where we push/pull and the old parent
511 // frame and the new parent frame are part of the same flow. They will
512 // typically be the same distance (height wise) from the
513 aOldParentFrame = aOldParentFrame->GetParent();
514 aNewParentFrame = aNewParentFrame->GetParent();
516 // We should never walk all the way to the root frame without finding
517 // a view
518 NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
520 // See if we reached a common ancestor
521 if (aOldParentFrame == aNewParentFrame) {
522 break;
523 }
524 }
526 // See if we found a common parent frame
527 if (aOldParentFrame == aNewParentFrame) {
528 // We found a common parent and there are no views between the old parent
529 // and the common parent or the new parent frame and the common parent.
530 // Because neither the old parent frame nor the new parent frame have views,
531 // then any child views don't need reparenting
532 return NS_OK;
533 }
535 // We found views for one or both of the ancestor frames before we
536 // found a common ancestor.
537 nsView* oldParentView = aOldParentFrame->GetClosestView();
538 nsView* newParentView = aNewParentFrame->GetClosestView();
540 // See if the old parent frame and the new parent frame are in the
541 // same view sub-hierarchy. If they are then we don't have to do
542 // anything
543 if (oldParentView != newParentView) {
544 // They're not so we need to reparent any child views
545 return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
546 oldParentView);
547 }
549 return NS_OK;
550 }
552 nsresult
553 nsContainerFrame::ReparentFrameViewList(const nsFrameList& aChildFrameList,
554 nsIFrame* aOldParentFrame,
555 nsIFrame* aNewParentFrame)
556 {
557 NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
558 NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
559 NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
560 NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
562 // See if either the old parent frame or the new parent frame have a view
563 while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
564 // Walk up both the old parent frame and the new parent frame nodes
565 // stopping when we either find a common parent or views for one
566 // or both of the frames.
567 //
568 // This works well in the common case where we push/pull and the old parent
569 // frame and the new parent frame are part of the same flow. They will
570 // typically be the same distance (height wise) from the
571 aOldParentFrame = aOldParentFrame->GetParent();
572 aNewParentFrame = aNewParentFrame->GetParent();
574 // We should never walk all the way to the root frame without finding
575 // a view
576 NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
578 // See if we reached a common ancestor
579 if (aOldParentFrame == aNewParentFrame) {
580 break;
581 }
582 }
585 // See if we found a common parent frame
586 if (aOldParentFrame == aNewParentFrame) {
587 // We found a common parent and there are no views between the old parent
588 // and the common parent or the new parent frame and the common parent.
589 // Because neither the old parent frame nor the new parent frame have views,
590 // then any child views don't need reparenting
591 return NS_OK;
592 }
594 // We found views for one or both of the ancestor frames before we
595 // found a common ancestor.
596 nsView* oldParentView = aOldParentFrame->GetClosestView();
597 nsView* newParentView = aNewParentFrame->GetClosestView();
599 // See if the old parent frame and the new parent frame are in the
600 // same view sub-hierarchy. If they are then we don't have to do
601 // anything
602 if (oldParentView != newParentView) {
603 nsViewManager* viewManager = oldParentView->GetViewManager();
605 // They're not so we need to reparent any child views
606 for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
607 ReparentFrameViewTo(e.get(), viewManager, newParentView, oldParentView);
608 }
609 }
611 return NS_OK;
612 }
614 static nsIWidget*
615 GetPresContextContainerWidget(nsPresContext* aPresContext)
616 {
617 nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
618 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
619 if (!baseWindow)
620 return nullptr;
622 nsCOMPtr<nsIWidget> mainWidget;
623 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
624 return mainWidget;
625 }
627 static bool
628 IsTopLevelWidget(nsIWidget* aWidget)
629 {
630 nsWindowType windowType = aWidget->WindowType();
631 return windowType == eWindowType_toplevel ||
632 windowType == eWindowType_dialog ||
633 windowType == eWindowType_sheet;
634 // popups aren't toplevel so they're not handled here
635 }
637 void
638 nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
639 nsIFrame* aFrame,
640 nsView* aView,
641 nsRenderingContext* aRC)
642 {
643 #ifdef MOZ_XUL
644 if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
645 return;
647 nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
648 if (!windowWidget || !IsTopLevelWidget(windowWidget))
649 return;
651 nsViewManager* vm = aView->GetViewManager();
652 nsView* rootView = vm->GetRootView();
654 if (aView != rootView)
655 return;
657 Element* rootElement = aPresContext->Document()->GetRootElement();
658 if (!rootElement || !rootElement->IsXUL()) {
659 // Scrollframes use native widgets which don't work well with
660 // translucent windows, at least in Windows XP. So if the document
661 // has a root scrollrame it's useless to try to make it transparent,
662 // we'll just get something broken.
663 // nsCSSFrameConstructor::ConstructRootFrame constructs root
664 // scrollframes whenever the root element is not a XUL element, so
665 // we test for that here. We can't just call
666 // presShell->GetRootScrollFrame() since that might not have
667 // been constructed yet.
668 // We can change this to allow translucent toplevel HTML documents
669 // (e.g. to do something like Dashboard widgets), once we
670 // have broad support for translucent scrolled documents, but be
671 // careful because apparently some Firefox extensions expect
672 // openDialog("something.html") to produce an opaque window
673 // even if the HTML doesn't have a background-color set.
674 return;
675 }
677 nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
678 if (!rootFrame)
679 return;
681 nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
682 nsIWidget* viewWidget = aView->GetWidget();
683 viewWidget->SetTransparencyMode(mode);
684 windowWidget->SetWindowShadowStyle(rootFrame->StyleUIReset()->mWindowShadow);
686 if (!aRC)
687 return;
689 nsBoxLayoutState aState(aPresContext, aRC);
690 nsSize minSize = rootFrame->GetMinSize(aState);
691 nsSize maxSize = rootFrame->GetMaxSize(aState);
693 SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
694 #endif
695 }
697 void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
698 nsIWidget* aWidget,
699 const nsSize& aMinSize,
700 const nsSize& aMaxSize)
701 {
702 nsIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
703 aPresContext->AppUnitsToDevPixels(aMinSize.height));
704 nsIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
705 aPresContext->AppUnitsToDevPixels(aMaxSize.width),
706 aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
707 aPresContext->AppUnitsToDevPixels(aMaxSize.height));
708 widget::SizeConstraints constraints(devMinSize, devMaxSize);
710 // The sizes are in inner window sizes, so convert them into outer window sizes.
711 // Use a size of (200, 200) as only the difference between the inner and outer
712 // size is needed.
713 nsIntSize windowSize = aWidget->ClientToWindowSize(nsIntSize(200, 200));
714 if (constraints.mMinSize.width)
715 constraints.mMinSize.width += windowSize.width - 200;
716 if (constraints.mMinSize.height)
717 constraints.mMinSize.height += windowSize.height - 200;
718 if (constraints.mMaxSize.width != NS_MAXSIZE)
719 constraints.mMaxSize.width += windowSize.width - 200;
720 if (constraints.mMaxSize.height != NS_MAXSIZE)
721 constraints.mMaxSize.height += windowSize.height - 200;
723 aWidget->SetSizeConstraints(constraints);
724 }
726 void
727 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
728 nsIFrame* aFrame,
729 nsView* aView,
730 const nsRect& aVisualOverflowArea,
731 uint32_t aFlags)
732 {
733 if (!aView) {
734 return;
735 }
737 // Make sure the view is sized and positioned correctly
738 if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
739 PositionFrameView(aFrame);
740 }
742 if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
743 nsViewManager* vm = aView->GetViewManager();
745 vm->ResizeView(aView, aVisualOverflowArea, true);
746 }
747 }
749 void
750 nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
751 nsIFrame* aFrame,
752 nsStyleContext* aStyleContext,
753 nsView* aView,
754 uint32_t aFlags)
755 {
756 NS_ASSERTION(!aStyleContext || aFrame->StyleContext() == aStyleContext,
757 "Wrong style context for frame?");
759 if (!aView) {
760 return;
761 }
763 nsViewManager* vm = aView->GetViewManager();
765 if (nullptr == aStyleContext) {
766 aStyleContext = aFrame->StyleContext();
767 }
769 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
770 if (0 == (aFlags & NS_FRAME_NO_VISIBILITY) &&
771 !aFrame->SupportsVisibilityHidden()) {
772 // See if the view should be hidden or visible
773 vm->SetViewVisibility(aView,
774 aStyleContext->StyleVisibility()->IsVisible()
775 ? nsViewVisibility_kShow : nsViewVisibility_kHide);
776 }
778 // See if the frame is being relatively positioned or absolutely
779 // positioned
780 bool isPositioned = aFrame->IsPositioned();
782 int32_t zIndex = 0;
783 bool autoZIndex = false;
785 if (!isPositioned) {
786 autoZIndex = true;
787 } else {
788 // Make sure z-index is correct
789 const nsStylePosition* position = aStyleContext->StylePosition();
791 if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
792 zIndex = position->mZIndex.GetIntValue();
793 } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
794 autoZIndex = true;
795 }
796 }
798 vm->SetViewZIndex(aView, autoZIndex, zIndex);
799 }
801 static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
802 {
803 if (aCoord.ConvertsToLength()) {
804 return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
805 }
806 return aIfNotCoord;
807 }
809 void
810 nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
811 InlineIntrinsicWidthData *aData,
812 nsLayoutUtils::IntrinsicWidthType aType)
813 {
814 if (GetPrevInFlow())
815 return; // Already added.
817 NS_PRECONDITION(aType == nsLayoutUtils::MIN_WIDTH ||
818 aType == nsLayoutUtils::PREF_WIDTH, "bad type");
820 mozilla::css::Side startSide, endSide;
821 if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
822 startSide = NS_SIDE_LEFT;
823 endSide = NS_SIDE_RIGHT;
824 } else {
825 startSide = NS_SIDE_RIGHT;
826 endSide = NS_SIDE_LEFT;
827 }
829 const nsStylePadding *stylePadding = StylePadding();
830 const nsStyleBorder *styleBorder = StyleBorder();
831 const nsStyleMargin *styleMargin = StyleMargin();
833 // This goes at the beginning no matter how things are broken and how
834 // messy the bidi situations are, since per CSS2.1 section 8.6
835 // (implemented in bug 328168), the startSide border is always on the
836 // first line.
837 // This frame is a first-in-flow, but it might have a previous bidi
838 // continuation, in which case that continuation should handle the startSide
839 // border.
840 if (!GetPrevContinuation()) {
841 aData->currentLine +=
842 // clamp negative calc() to 0
843 std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
844 styleBorder->GetComputedBorderWidth(startSide) +
845 GetCoord(styleMargin->mMargin.Get(startSide), 0);
846 }
848 const nsLineList_iterator* savedLine = aData->line;
849 nsIFrame* const savedLineContainer = aData->lineContainer;
851 nsContainerFrame *lastInFlow;
852 for (nsContainerFrame *nif = this; nif;
853 nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
854 for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
855 kid = kid->GetNextSibling()) {
856 if (aType == nsLayoutUtils::MIN_WIDTH)
857 kid->AddInlineMinWidth(aRenderingContext,
858 static_cast<InlineMinWidthData*>(aData));
859 else
860 kid->AddInlinePrefWidth(aRenderingContext,
861 static_cast<InlinePrefWidthData*>(aData));
862 }
864 // After we advance to our next-in-flow, the stored line and line container
865 // may no longer be correct. Just forget them.
866 aData->line = nullptr;
867 aData->lineContainer = nullptr;
869 lastInFlow = nif;
870 }
872 aData->line = savedLine;
873 aData->lineContainer = savedLineContainer;
875 // This goes at the end no matter how things are broken and how
876 // messy the bidi situations are, since per CSS2.1 section 8.6
877 // (implemented in bug 328168), the endSide border is always on the
878 // last line.
879 // We reached the last-in-flow, but it might have a next bidi
880 // continuation, in which case that continuation should handle
881 // the endSide border.
882 if (!lastInFlow->GetNextContinuation()) {
883 aData->currentLine +=
884 // clamp negative calc() to 0
885 std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
886 styleBorder->GetComputedBorderWidth(endSide) +
887 GetCoord(styleMargin->mMargin.Get(endSide), 0);
888 }
889 }
891 /* virtual */ nsSize
892 nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
893 nsSize aCBSize, nscoord aAvailableWidth,
894 nsSize aMargin, nsSize aBorder,
895 nsSize aPadding, bool aShrinkWrap)
896 {
897 nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
898 nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
899 aPadding.width;
900 // replaced elements always shrink-wrap
901 if (aShrinkWrap || IsFrameOfType(eReplaced)) {
902 // don't bother setting it if the result won't be used
903 if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
904 result.width = ShrinkWidthToFit(aRenderingContext, availBased);
905 }
906 } else {
907 result.width = availBased;
908 }
909 return result;
910 }
912 /**
913 * Invokes the WillReflow() function, positions the frame and its view (if
914 * requested), and then calls Reflow(). If the reflow succeeds and the child
915 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
916 */
917 nsresult
918 nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
919 nsPresContext* aPresContext,
920 nsHTMLReflowMetrics& aDesiredSize,
921 const nsHTMLReflowState& aReflowState,
922 nscoord aX,
923 nscoord aY,
924 uint32_t aFlags,
925 nsReflowStatus& aStatus,
926 nsOverflowContinuationTracker* aTracker)
927 {
928 NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
930 nsresult result;
932 // Send the WillReflow() notification, and position the child frame
933 // and its view if requested
934 aKidFrame->WillReflow(aPresContext);
936 if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
937 aKidFrame->SetPosition(nsPoint(aX, aY));
938 }
940 if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
941 PositionFrameView(aKidFrame);
942 }
944 // Reflow the child frame
945 result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
946 aStatus);
948 // If the reflow was successful and the child frame is complete, delete any
949 // next-in-flows, but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
950 if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
951 !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
952 nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
953 if (kidNextInFlow) {
954 // Remove all of the childs next-in-flows. Make sure that we ask
955 // the right parent to do the removal (it's possible that the
956 // parent is not this because we are executing pullup code)
957 nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
958 static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
959 ->DeleteNextInFlowChild(kidNextInFlow, true);
960 }
961 }
962 return result;
963 }
966 /**
967 * Position the views of |aFrame|'s descendants. A container frame
968 * should call this method if it moves a frame after |Reflow|.
969 */
970 void
971 nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
972 {
973 if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
974 return;
975 }
977 // Recursively walk aFrame's child frames.
978 // Process the additional child lists, but skip the popup list as the
979 // view for popups is managed by the parent. Currently only nsMenuFrame
980 // and nsPopupSetFrame have a popupList and during layout will adjust the
981 // view manually to position the popup.
982 ChildListIterator lists(aFrame);
983 for (; !lists.IsDone(); lists.Next()) {
984 if (lists.CurrentID() == kPopupList) {
985 continue;
986 }
987 nsFrameList::Enumerator childFrames(lists.CurrentList());
988 for (; !childFrames.AtEnd(); childFrames.Next()) {
989 // Position the frame's view (if it has one) otherwise recursively
990 // process its children
991 nsIFrame* childFrame = childFrames.get();
992 if (childFrame->HasView()) {
993 PositionFrameView(childFrame);
994 } else {
995 PositionChildViews(childFrame);
996 }
997 }
998 }
999 }
1001 /**
1002 * The second half of frame reflow. Does the following:
1003 * - sets the frame's bounds
1004 * - sizes and positions (if requested) the frame's view. If the frame's final
1005 * position differs from the current position and the frame itself does not
1006 * have a view, then any child frames with views are positioned so they stay
1007 * in sync
1008 * - sets the view's visibility, opacity, content transparency, and clip
1009 * - invoked the DidReflow() function
1010 *
1011 * Flags:
1012 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1013 * case. Also implies NS_FRAME_NO_MOVE_VIEW
1014 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1015 * don't want to automatically sync the frame and view
1016 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1017 */
1018 nsresult
1019 nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
1020 nsPresContext* aPresContext,
1021 const nsHTMLReflowMetrics& aDesiredSize,
1022 const nsHTMLReflowState* aReflowState,
1023 nscoord aX,
1024 nscoord aY,
1025 uint32_t aFlags)
1026 {
1027 nsPoint curOrigin = aKidFrame->GetPosition();
1029 if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
1030 aKidFrame->SetRect(nsRect(aX, aY, aDesiredSize.Width(), aDesiredSize.Height()));
1031 } else {
1032 aKidFrame->SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
1033 }
1035 if (aKidFrame->HasView()) {
1036 nsView* view = aKidFrame->GetView();
1037 // Make sure the frame's view is properly sized and positioned and has
1038 // things like opacity correct
1039 SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
1040 aDesiredSize.VisualOverflow(), aFlags);
1041 }
1043 if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
1044 (curOrigin.x != aX || curOrigin.y != aY)) {
1045 if (!aKidFrame->HasView()) {
1046 // If the frame has moved, then we need to make sure any child views are
1047 // correctly positioned
1048 PositionChildViews(aKidFrame);
1049 }
1050 }
1052 return aKidFrame->DidReflow(aPresContext, aReflowState, nsDidReflowStatus::FINISHED);
1053 }
1055 nsresult
1056 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
1057 const nsHTMLReflowState& aReflowState,
1058 nsOverflowAreas& aOverflowRects,
1059 uint32_t aFlags,
1060 nsReflowStatus& aStatus)
1061 {
1062 NS_PRECONDITION(aPresContext, "null pointer");
1063 nsresult rv = NS_OK;
1065 nsFrameList* overflowContainers =
1066 GetPropTableFrames(OverflowContainersProperty());
1068 NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
1069 && static_cast<nsContainerFrame*>(GetPrevInFlow())
1070 ->GetPropTableFrames(ExcessOverflowContainersProperty())),
1071 "conflicting overflow containers lists");
1073 if (!overflowContainers) {
1074 // Drain excess from previnflow
1075 nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
1076 if (prev) {
1077 nsFrameList* excessFrames =
1078 prev->RemovePropTableFrames(ExcessOverflowContainersProperty());
1079 if (excessFrames) {
1080 excessFrames->ApplySetParent(this);
1081 nsContainerFrame::ReparentFrameViewList(*excessFrames, prev, this);
1082 overflowContainers = excessFrames;
1083 SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1084 }
1085 }
1086 }
1088 // Our own excess overflow containers from a previous reflow can still be
1089 // present if our next-in-flow hasn't been reflown yet.
1090 nsFrameList* selfExcessOCFrames =
1091 RemovePropTableFrames(ExcessOverflowContainersProperty());
1092 if (selfExcessOCFrames) {
1093 if (overflowContainers) {
1094 overflowContainers->AppendFrames(nullptr, *selfExcessOCFrames);
1095 selfExcessOCFrames->Delete(aPresContext->PresShell());
1096 } else {
1097 overflowContainers = selfExcessOCFrames;
1098 SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1099 }
1100 }
1101 if (!overflowContainers) {
1102 return NS_OK; // nothing to reflow
1103 }
1105 nsOverflowContinuationTracker tracker(this, false, false);
1106 bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
1108 for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
1109 frame = frame->GetNextSibling()) {
1110 if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1111 // frame's prevInFlow has moved, skip reflowing this frame;
1112 // it will get reflowed once it's been placed
1113 continue;
1114 }
1115 // If the available vertical height has changed, we need to reflow
1116 // even if the frame isn't dirty.
1117 if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
1118 // Get prev-in-flow
1119 nsIFrame* prevInFlow = frame->GetPrevInFlow();
1120 NS_ASSERTION(prevInFlow,
1121 "overflow container frame must have a prev-in-flow");
1122 NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
1123 "overflow container frame must have overflow container bit set");
1124 nsRect prevRect = prevInFlow->GetRect();
1126 // Initialize reflow params
1127 nsSize availSpace(prevRect.width, aReflowState.AvailableHeight());
1128 nsHTMLReflowMetrics desiredSize(aReflowState);
1129 nsHTMLReflowState frameState(aPresContext, aReflowState,
1130 frame, availSpace);
1131 nsReflowStatus frameStatus;
1133 // Reflow
1134 rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
1135 prevRect.x, 0, aFlags, frameStatus, &tracker);
1136 NS_ENSURE_SUCCESS(rv, rv);
1137 //XXXfr Do we need to override any shrinkwrap effects here?
1138 // e.g. desiredSize.Width() = prevRect.width;
1139 rv = FinishReflowChild(frame, aPresContext, desiredSize, &frameState,
1140 prevRect.x, 0, aFlags);
1141 NS_ENSURE_SUCCESS(rv, rv);
1143 // Handle continuations
1144 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
1145 if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
1146 // Abspos frames can't cause their parent to be incomplete,
1147 // only overflow incomplete.
1148 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
1149 }
1150 else {
1151 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
1152 "overflow container frames can't be incomplete, only overflow-incomplete");
1153 }
1155 // Acquire a next-in-flow, creating it if necessary
1156 nsIFrame* nif = frame->GetNextInFlow();
1157 if (!nif) {
1158 NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
1159 "Someone forgot a REFLOW_NEXTINFLOW flag");
1160 nif = aPresContext->PresShell()->FrameConstructor()->
1161 CreateContinuingFrame(aPresContext, frame, this);
1162 }
1163 else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1164 // used to be a normal next-in-flow; steal it from the child list
1165 rv = static_cast<nsContainerFrame*>(nif->GetParent())
1166 ->StealFrame(nif);
1167 NS_ENSURE_SUCCESS(rv, rv);
1168 }
1170 tracker.Insert(nif, frameStatus);
1171 }
1172 NS_MergeReflowStatusInto(&aStatus, frameStatus);
1173 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1174 // but we have some unsplittable frames that, when taller than
1175 // availableHeight will push zero-height content into a next-in-flow.
1176 }
1177 else {
1178 tracker.Skip(frame, aStatus);
1179 if (aReflowState.mFloatManager)
1180 nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
1181 }
1182 ConsiderChildOverflow(aOverflowRects, frame);
1183 }
1185 return NS_OK;
1186 }
1188 void
1189 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
1190 const nsRect& aDirtyRect,
1191 const nsDisplayListSet& aLists)
1192 {
1193 nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty());
1194 if (overflowconts) {
1195 for (nsIFrame* frame = overflowconts->FirstChild(); frame;
1196 frame = frame->GetNextSibling()) {
1197 BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
1198 }
1199 }
1200 }
1202 static bool
1203 TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable,
1204 const FramePropertyDescriptor* aProp, nsIFrame* aChildToRemove)
1205 {
1206 nsFrameList* list = static_cast<nsFrameList*>(aPropTable->Get(aFrame, aProp));
1207 if (list && list->StartRemoveFrame(aChildToRemove)) {
1208 // aChildToRemove *may* have been removed from this list.
1209 if (list->IsEmpty()) {
1210 aPropTable->Remove(aFrame, aProp);
1211 list->Delete(aFrame->PresContext()->PresShell());
1212 }
1213 return true;
1214 }
1215 return false;
1216 }
1218 nsresult
1219 nsContainerFrame::StealFrame(nsIFrame* aChild,
1220 bool aForceNormal)
1221 {
1222 #ifdef DEBUG
1223 if (!mFrames.ContainsFrame(aChild)) {
1224 nsFrameList* list = GetOverflowFrames();
1225 if (!list || !list->ContainsFrame(aChild)) {
1226 FramePropertyTable* propTable = PresContext()->PropertyTable();
1227 list = static_cast<nsFrameList*>(
1228 propTable->Get(this, OverflowContainersProperty()));
1229 if (!list || !list->ContainsFrame(aChild)) {
1230 list = static_cast<nsFrameList*>(
1231 propTable->Get(this, ExcessOverflowContainersProperty()));
1232 MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child"
1233 " or on a frame list not supported by StealFrame");
1234 }
1235 }
1236 }
1237 #endif
1239 bool removed;
1240 if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
1241 && !aForceNormal) {
1242 FramePropertyTable* propTable = PresContext()->PropertyTable();
1243 // Try removing from the overflow container list.
1244 removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(),
1245 aChild);
1246 if (!removed) {
1247 // It must be in the excess overflow container list.
1248 removed = ::TryRemoveFrame(this, propTable,
1249 ExcessOverflowContainersProperty(),
1250 aChild);
1251 }
1252 } else {
1253 removed = mFrames.StartRemoveFrame(aChild);
1254 if (!removed) {
1255 // We didn't find the child in our principal child list.
1256 // Maybe it's on the overflow list?
1257 nsFrameList* frameList = GetOverflowFrames();
1258 if (frameList) {
1259 removed = frameList->ContinueRemoveFrame(aChild);
1260 if (frameList->IsEmpty()) {
1261 DestroyOverflowList();
1262 }
1263 }
1264 }
1265 }
1267 NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
1268 return removed ? NS_OK : NS_ERROR_UNEXPECTED;
1269 }
1271 nsFrameList
1272 nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
1273 {
1274 NS_ASSERTION(!aChild ||
1275 !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
1276 "StealFramesAfter doesn't handle overflow containers");
1277 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame, "unexpected call");
1279 if (!aChild) {
1280 nsFrameList copy(mFrames);
1281 mFrames.Clear();
1282 return copy;
1283 }
1285 for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
1286 iter.Next()) {
1287 if (iter.PrevFrame() == aChild) {
1288 return mFrames.ExtractTail(iter);
1289 }
1290 }
1292 // We didn't find the child in the principal child list.
1293 // Maybe it's on the overflow list?
1294 nsFrameList* overflowFrames = GetOverflowFrames();
1295 if (overflowFrames) {
1296 for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
1297 iter.Next()) {
1298 if (iter.PrevFrame() == aChild) {
1299 return overflowFrames->ExtractTail(iter);
1300 }
1301 }
1302 }
1304 NS_ERROR("StealFramesAfter: can't find aChild");
1305 return nsFrameList::EmptyList();
1306 }
1308 /*
1309 * Create a next-in-flow for aFrame. Will return the newly created
1310 * frame in aNextInFlowResult <b>if and only if</b> a new frame is
1311 * created; otherwise nullptr is returned in aNextInFlowResult.
1312 */
1313 nsresult
1314 nsContainerFrame::CreateNextInFlow(nsIFrame* aFrame,
1315 nsIFrame*& aNextInFlowResult)
1316 {
1317 NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame,
1318 "you should have called nsBlockFrame::CreateContinuationFor instead");
1319 NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
1321 nsPresContext* pc = PresContext();
1322 aNextInFlowResult = nullptr;
1324 nsIFrame* nextInFlow = aFrame->GetNextInFlow();
1325 if (nullptr == nextInFlow) {
1326 // Create a continuation frame for the child frame and insert it
1327 // into our child list.
1328 nextInFlow = pc->PresShell()->FrameConstructor()->
1329 CreateContinuingFrame(pc, aFrame, this);
1330 mFrames.InsertFrame(nullptr, aFrame, nextInFlow);
1332 NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
1333 ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1334 aFrame, nextInFlow));
1336 aNextInFlowResult = nextInFlow;
1337 }
1338 return NS_OK;
1339 }
1341 /**
1342 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1343 * pointers
1344 */
1345 void
1346 nsContainerFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
1347 bool aDeletingEmptyFrames)
1348 {
1349 #ifdef DEBUG
1350 nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
1351 #endif
1352 NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
1354 // If the next-in-flow has a next-in-flow then delete it, too (and
1355 // delete it first).
1356 // Do this in a loop so we don't overflow the stack for frames
1357 // with very many next-in-flows
1358 nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
1359 if (nextNextInFlow) {
1360 nsAutoTArray<nsIFrame*, 8> frames;
1361 for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
1362 frames.AppendElement(f);
1363 }
1364 for (int32_t i = frames.Length() - 1; i >= 0; --i) {
1365 nsIFrame* delFrame = frames.ElementAt(i);
1366 static_cast<nsContainerFrame*>(delFrame->GetParent())
1367 ->DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
1368 }
1369 }
1371 // Take the next-in-flow out of the parent's child list
1372 DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
1373 NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
1375 #ifdef DEBUG
1376 if (aDeletingEmptyFrames) {
1377 nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
1378 }
1379 #endif
1381 // Delete the next-in-flow frame and its descendants. This will also
1382 // remove it from its next-in-flow/prev-in-flow chain.
1383 aNextInFlow->Destroy();
1385 NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
1386 }
1388 /**
1389 * Set the frames on the overflow list
1390 */
1391 void
1392 nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames)
1393 {
1394 NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
1396 nsPresContext* pc = PresContext();
1397 nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames);
1399 pc->PropertyTable()->Set(this, OverflowProperty(), newList);
1400 }
1402 nsFrameList*
1403 nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor* aProperty) const
1404 {
1405 FramePropertyTable* propTable = PresContext()->PropertyTable();
1406 return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
1407 }
1409 nsFrameList*
1410 nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor* aProperty)
1411 {
1412 FramePropertyTable* propTable = PresContext()->PropertyTable();
1413 return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
1414 }
1416 void
1417 nsContainerFrame::SetPropTableFrames(nsFrameList* aFrameList,
1418 const FramePropertyDescriptor* aProperty)
1419 {
1420 NS_PRECONDITION(aProperty && aFrameList, "null ptr");
1421 NS_PRECONDITION(
1422 (aProperty != nsContainerFrame::OverflowContainersProperty() &&
1423 aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
1424 IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
1425 "this type of frame can't have overflow containers");
1426 MOZ_ASSERT(!GetPropTableFrames(aProperty));
1427 PresContext()->PropertyTable()->Set(this, aProperty, aFrameList);
1428 }
1430 /**
1431 * Push aFromChild and its next siblings to the next-in-flow. Change the
1432 * geometric parent of each frame that's pushed. If there is no next-in-flow
1433 * the frames are placed on the overflow list (and the geometric parent is
1434 * left unchanged).
1435 *
1436 * Updates the next-in-flow's child count. Does <b>not</b> update the
1437 * pusher's child count.
1438 *
1439 * @param aFromChild the first child frame to push. It is disconnected from
1440 * aPrevSibling
1441 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1442 * an error to push a parent's first child frame
1443 */
1444 void
1445 nsContainerFrame::PushChildren(nsIFrame* aFromChild,
1446 nsIFrame* aPrevSibling)
1447 {
1448 NS_PRECONDITION(aFromChild, "null pointer");
1449 NS_PRECONDITION(aPrevSibling, "pushing first child");
1450 NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
1452 // Disconnect aFromChild from its previous sibling
1453 nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
1455 nsContainerFrame* nextInFlow =
1456 static_cast<nsContainerFrame*>(GetNextInFlow());
1457 if (nextInFlow) {
1458 // XXX This is not a very good thing to do. If it gets removed
1459 // then remove the copy of this routine that doesn't do this from
1460 // nsInlineFrame.
1461 // When pushing and pulling frames we need to check for whether any
1462 // views need to be reparented.
1463 for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
1464 nsContainerFrame::ReparentFrameView(f, this, nextInFlow);
1465 }
1466 nextInFlow->mFrames.InsertFrames(nextInFlow, nullptr, tail);
1467 }
1468 else {
1469 // Add the frames to our overflow list
1470 SetOverflowFrames(tail);
1471 }
1472 }
1474 /**
1475 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1476 * the receiver's overflow list) to the child list.
1477 *
1478 * Updates this frame's child count and content mapping.
1479 *
1480 * @return true if any frames were moved and false otherwise
1481 */
1482 bool
1483 nsContainerFrame::MoveOverflowToChildList()
1484 {
1485 bool result = false;
1487 // Check for an overflow list with our prev-in-flow
1488 nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
1489 if (nullptr != prevInFlow) {
1490 AutoFrameListPtr prevOverflowFrames(PresContext(),
1491 prevInFlow->StealOverflowFrames());
1492 if (prevOverflowFrames) {
1493 // Tables are special; they can have repeated header/footer
1494 // frames on mFrames at this point.
1495 NS_ASSERTION(mFrames.IsEmpty() || GetType() == nsGkAtoms::tableFrame,
1496 "bad overflow list");
1497 // When pushing and pulling frames we need to check for whether any
1498 // views need to be reparented.
1499 nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
1500 prevInFlow, this);
1501 mFrames.AppendFrames(this, *prevOverflowFrames);
1502 result = true;
1503 }
1504 }
1506 // It's also possible that we have an overflow list for ourselves.
1507 return DrainSelfOverflowList() || result;
1508 }
1510 bool
1511 nsContainerFrame::DrainSelfOverflowList()
1512 {
1513 AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
1514 if (overflowFrames) {
1515 NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
1516 mFrames.AppendFrames(nullptr, *overflowFrames);
1517 return true;
1518 }
1519 return false;
1520 }
1522 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame* aFrame,
1523 bool aWalkOOFFrames,
1524 bool aSkipOverflowContainerChildren)
1525 : mOverflowContList(nullptr),
1526 mPrevOverflowCont(nullptr),
1527 mSentry(nullptr),
1528 mParent(aFrame),
1529 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
1530 mWalkOOFFrames(aWalkOOFFrames)
1531 {
1532 NS_PRECONDITION(aFrame, "null frame pointer");
1533 SetupOverflowContList();
1534 }
1536 void
1537 nsOverflowContinuationTracker::SetupOverflowContList()
1538 {
1539 NS_PRECONDITION(mParent, "null frame pointer");
1540 NS_PRECONDITION(!mOverflowContList, "already have list");
1541 nsContainerFrame* nif =
1542 static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
1543 if (nif) {
1544 mOverflowContList = nif->GetPropTableFrames(
1545 nsContainerFrame::OverflowContainersProperty());
1546 if (mOverflowContList) {
1547 mParent = nif;
1548 SetUpListWalker();
1549 }
1550 }
1551 if (!mOverflowContList) {
1552 mOverflowContList = mParent->GetPropTableFrames(
1553 nsContainerFrame::ExcessOverflowContainersProperty());
1554 if (mOverflowContList) {
1555 SetUpListWalker();
1556 }
1557 }
1558 }
1560 /**
1561 * Helper function to walk past overflow continuations whose prev-in-flow
1562 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1563 */
1564 void
1565 nsOverflowContinuationTracker::SetUpListWalker()
1566 {
1567 NS_ASSERTION(!mSentry && !mPrevOverflowCont,
1568 "forgot to reset mSentry or mPrevOverflowCont");
1569 if (mOverflowContList) {
1570 nsIFrame* cur = mOverflowContList->FirstChild();
1571 if (mSkipOverflowContainerChildren) {
1572 while (cur && (cur->GetPrevInFlow()->GetStateBits()
1573 & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1574 mPrevOverflowCont = cur;
1575 cur = cur->GetNextSibling();
1576 }
1577 while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1578 == mWalkOOFFrames)) {
1579 mPrevOverflowCont = cur;
1580 cur = cur->GetNextSibling();
1581 }
1582 }
1583 if (cur) {
1584 mSentry = cur->GetPrevInFlow();
1585 }
1586 }
1587 }
1589 /**
1590 * Helper function to step forward through the overflow continuations list.
1591 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1592 * as appropriate. May only be called when we have already set up an
1593 * mOverflowContList; mOverflowContList cannot be null.
1594 */
1595 void
1596 nsOverflowContinuationTracker::StepForward()
1597 {
1598 NS_PRECONDITION(mOverflowContList, "null list");
1600 // Step forward
1601 if (mPrevOverflowCont) {
1602 mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
1603 }
1604 else {
1605 mPrevOverflowCont = mOverflowContList->FirstChild();
1606 }
1608 // Skip over oof or non-oof frames as appropriate
1609 if (mSkipOverflowContainerChildren) {
1610 nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
1611 while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1612 == mWalkOOFFrames)) {
1613 mPrevOverflowCont = cur;
1614 cur = cur->GetNextSibling();
1615 }
1616 }
1618 // Set up the sentry
1619 mSentry = (mPrevOverflowCont->GetNextSibling())
1620 ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
1621 : nullptr;
1622 }
1624 nsresult
1625 nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
1626 nsReflowStatus& aReflowStatus)
1627 {
1628 NS_PRECONDITION(aOverflowCont, "null frame pointer");
1629 NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
1630 !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
1631 "shouldn't insert frame that doesn't match walker type");
1632 NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
1633 "overflow containers must have a prev-in-flow");
1634 nsresult rv = NS_OK;
1635 bool reparented = false;
1636 nsPresContext* presContext = aOverflowCont->PresContext();
1637 bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
1639 // If we have a list and aOverflowCont is already in it then don't try to
1640 // add it again.
1641 if (addToList && aOverflowCont->GetParent() == mParent &&
1642 (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
1643 mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
1644 addToList = false;
1645 mPrevOverflowCont = aOverflowCont->GetPrevSibling();
1646 }
1648 if (addToList) {
1649 if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
1650 // aOverflowCont is in some other overflow container list,
1651 // steal it first
1652 NS_ASSERTION(!(mOverflowContList &&
1653 mOverflowContList->ContainsFrame(aOverflowCont)),
1654 "overflow containers out of order");
1655 rv = static_cast<nsContainerFrame*>(aOverflowCont->GetParent())
1656 ->StealFrame(aOverflowCont);
1657 NS_ENSURE_SUCCESS(rv, rv);
1658 }
1659 else {
1660 aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
1661 }
1662 if (!mOverflowContList) {
1663 mOverflowContList = new (presContext->PresShell()) nsFrameList();
1664 mParent->SetPropTableFrames(mOverflowContList,
1665 nsContainerFrame::ExcessOverflowContainersProperty());
1666 SetUpListWalker();
1667 }
1668 if (aOverflowCont->GetParent() != mParent) {
1669 nsContainerFrame::ReparentFrameView(aOverflowCont,
1670 aOverflowCont->GetParent(),
1671 mParent);
1672 reparented = true;
1673 }
1675 // If aOverflowCont has a prev/next-in-flow that might be in
1676 // mOverflowContList we need to find it and insert after/before it to
1677 // maintain the order amongst next-in-flows in this list.
1678 nsIFrame* pif = aOverflowCont->GetPrevInFlow();
1679 nsIFrame* nif = aOverflowCont->GetNextInFlow();
1680 if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
1681 (nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
1682 for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
1683 nsIFrame* f = e.get();
1684 if (f == pif) {
1685 mPrevOverflowCont = pif;
1686 break;
1687 }
1688 if (f == nif) {
1689 mPrevOverflowCont = f->GetPrevSibling();
1690 break;
1691 }
1692 }
1693 }
1695 mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
1696 aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
1697 }
1699 // If we need to reflow it, mark it dirty
1700 if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
1701 aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
1703 // It's in our list, just step forward
1704 StepForward();
1705 NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
1706 (mSkipOverflowContainerChildren &&
1707 (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
1708 (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
1709 "OverflowContTracker in unexpected state");
1711 if (addToList) {
1712 // Convert all non-overflow-container continuations of aOverflowCont
1713 // into overflow containers and move them to our overflow
1714 // tracker. This preserves the invariant that the next-continuations
1715 // of an overflow container are also overflow containers.
1716 nsIFrame* f = aOverflowCont->GetNextContinuation();
1717 if (f && (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
1718 (!reparented && f->GetParent() == mParent) ||
1719 (reparented && f->GetParent() != mParent))) {
1720 if (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1721 nsContainerFrame* parent = static_cast<nsContainerFrame*>(f->GetParent());
1722 rv = parent->StealFrame(f);
1723 NS_ENSURE_SUCCESS(rv, rv);
1724 }
1725 Insert(f, aReflowStatus);
1726 }
1727 }
1728 return rv;
1729 }
1731 void
1732 nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
1733 {
1734 NS_PRECONDITION(aChild, "null ptr");
1735 NS_PRECONDITION(aChild->GetNextInFlow(),
1736 "supposed to call Finish *before* deleting next-in-flow!");
1737 for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
1738 // We'll update these in EndFinish after the next-in-flows are gone.
1739 if (f == mPrevOverflowCont) {
1740 mSentry = nullptr;
1741 mPrevOverflowCont = nullptr;
1742 break;
1743 }
1744 if (f == mSentry) {
1745 mSentry = nullptr;
1746 break;
1747 }
1748 }
1749 }
1751 void
1752 nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
1753 {
1754 if (!mOverflowContList) {
1755 return;
1756 }
1757 // Forget mOverflowContList if it was deleted.
1758 nsPresContext* pc = aChild->PresContext();
1759 FramePropertyTable* propTable = pc->PropertyTable();
1760 nsFrameList* eoc = static_cast<nsFrameList*>(propTable->Get(mParent,
1761 nsContainerFrame::ExcessOverflowContainersProperty()));
1762 if (eoc != mOverflowContList) {
1763 nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent,
1764 nsContainerFrame::OverflowContainersProperty()));
1765 if (oc != mOverflowContList) {
1766 // mOverflowContList was deleted
1767 mPrevOverflowCont = nullptr;
1768 mSentry = nullptr;
1769 mParent = static_cast<nsContainerFrame*>(aChild->GetParent());
1770 mOverflowContList = nullptr;
1771 SetupOverflowContList();
1772 return;
1773 }
1774 }
1775 // The list survived, update mSentry if needed.
1776 if (!mSentry) {
1777 if (!mPrevOverflowCont) {
1778 SetUpListWalker();
1779 } else {
1780 mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
1781 // step backward to make StepForward() use our current mPrevOverflowCont
1782 mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
1783 StepForward();
1784 }
1785 }
1786 }
1788 /////////////////////////////////////////////////////////////////////////////
1789 // Debugging
1791 #ifdef DEBUG_FRAME_DUMP
1792 void
1793 nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
1794 {
1795 nsCString str;
1796 ListGeneric(str, aPrefix, aFlags);
1798 // Output the children
1799 bool outputOneList = false;
1800 ChildListIterator lists(this);
1801 for (; !lists.IsDone(); lists.Next()) {
1802 if (outputOneList) {
1803 str += aPrefix;
1804 }
1805 if (lists.CurrentID() != kPrincipalList) {
1806 if (!outputOneList) {
1807 str += "\n";
1808 str += aPrefix;
1809 }
1810 str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
1811 &GetChildList(lists.CurrentID()));
1812 }
1813 fprintf_stderr(out, "%s<\n", str.get());
1814 str = "";
1815 nsFrameList::Enumerator childFrames(lists.CurrentList());
1816 for (; !childFrames.AtEnd(); childFrames.Next()) {
1817 nsIFrame* kid = childFrames.get();
1818 // Verify the child frame's parent frame pointer is correct
1819 NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
1821 // Have the child frame list
1822 nsCString pfx(aPrefix);
1823 pfx += " ";
1824 kid->List(out, pfx.get(), aFlags);
1825 }
1826 fprintf_stderr(out, "%s>\n", aPrefix);
1827 outputOneList = true;
1828 }
1830 if (!outputOneList) {
1831 fprintf_stderr(out, "%s<>\n", str.get());
1832 }
1833 }
1834 #endif