Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsContainerFrame.cpp
blob2a5ad8a44772b3141d64ca2dd8dfe841f12fb0c1
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()
51 NS_QUERYFRAME_HEAD(nsContainerFrame)
52 NS_QUERYFRAME_ENTRY(nsContainerFrame)
53 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
55 void
56 nsContainerFrame::Init(nsIContent* aContent,
57 nsContainerFrame* aParent,
58 nsIFrame* aPrevInFlow)
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);
70 void
71 nsContainerFrame::SetInitialChildList(ChildListID aListID,
72 nsFrameList& aChildList)
74 MOZ_ASSERT(mFrames.IsEmpty(),
75 "unexpected second call to SetInitialChildList");
76 MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
77 #ifdef DEBUG
78 nsFrame::VerifyDirtyBitSet(aChildList);
79 #endif
80 mFrames.SetFrames(aChildList);
83 void
84 nsContainerFrame::AppendFrames(ChildListID aListID,
85 nsFrameList& aFrameList)
87 MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
88 "unexpected child list");
90 if (MOZ_UNLIKELY(aFrameList.IsEmpty())) {
91 return;
94 DrainSelfOverflowList(); // ensure the last frame is in mFrames
95 mFrames.AppendFrames(this, aFrameList);
97 if (aListID != kNoReflowPrincipalList) {
98 PresContext()->PresShell()->
99 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
100 NS_FRAME_HAS_DIRTY_CHILDREN);
104 void
105 nsContainerFrame::InsertFrames(ChildListID aListID,
106 nsIFrame* aPrevFrame,
107 nsFrameList& aFrameList)
109 MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
110 "unexpected child list");
111 NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
112 "inserting after sibling frame with different parent");
114 if (MOZ_UNLIKELY(aFrameList.IsEmpty())) {
115 return;
118 DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames
119 mFrames.InsertFrames(this, aPrevFrame, aFrameList);
121 if (aListID != kNoReflowPrincipalList) {
122 PresContext()->PresShell()->
123 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
124 NS_FRAME_HAS_DIRTY_CHILDREN);
128 void
129 nsContainerFrame::RemoveFrame(ChildListID aListID,
130 nsIFrame* aOldFrame)
132 MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
133 "unexpected child list");
135 // Loop and destroy aOldFrame and all of its continuations.
136 // Request a reflow on the parent frames involved unless we were explicitly
137 // told not to (kNoReflowPrincipalList).
138 bool generateReflowCommand = true;
139 if (kNoReflowPrincipalList == aListID) {
140 generateReflowCommand = false;
142 nsIPresShell* shell = PresContext()->PresShell();
143 nsContainerFrame* lastParent = nullptr;
144 while (aOldFrame) {
145 nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
146 nsContainerFrame* parent = aOldFrame->GetParent();
147 // Please note that 'parent' may not actually be where 'aOldFrame' lives.
148 // We really MUST use StealFrame() and nothing else here.
149 // @see nsInlineFrame::StealFrame for details.
150 parent->StealFrame(aOldFrame, true);
151 aOldFrame->Destroy();
152 aOldFrame = oldFrameNextContinuation;
153 if (parent != lastParent && generateReflowCommand) {
154 shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
155 NS_FRAME_HAS_DIRTY_CHILDREN);
156 lastParent = parent;
161 void
162 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
164 if (IsAbsoluteContainer()) {
165 GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
166 MarkAsNotAbsoluteContainingBlock();
170 void
171 nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
172 nsIPresShell* aPresShell,
173 FramePropertyTable* aPropTable,
174 const FramePropertyDescriptor* aProp)
176 // Note that the last frame can be removed through another route and thus
177 // delete the property -- that's why we fetch the property again before
178 // removing each frame rather than fetching it once and iterating the list.
179 while (nsFrameList* frameList =
180 static_cast<nsFrameList*>(aPropTable->Get(this, aProp))) {
181 nsIFrame* frame = frameList->RemoveFirstChild();
182 if (MOZ_LIKELY(frame)) {
183 frame->DestroyFrom(aDestructRoot);
184 } else {
185 aPropTable->Remove(this, aProp);
186 frameList->Delete(aPresShell);
187 return;
192 void
193 nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
195 // Prevent event dispatch during destruction.
196 if (HasView()) {
197 GetView()->SetFrame(nullptr);
200 DestroyAbsoluteFrames(aDestructRoot);
202 // Destroy frames on the principal child list.
203 mFrames.DestroyFramesFrom(aDestructRoot);
205 // Destroy frames on the auxiliary frame lists and delete the lists.
206 nsPresContext* pc = PresContext();
207 nsIPresShell* shell = pc->PresShell();
208 FramePropertyTable* props = pc->PropertyTable();
209 SafelyDestroyFrameListProp(aDestructRoot, shell, props, OverflowProperty());
211 MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers) ||
212 !(props->Get(this, nsContainerFrame::OverflowContainersProperty()) ||
213 props->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())),
214 "this type of frame should't have overflow containers");
216 SafelyDestroyFrameListProp(aDestructRoot, shell, props,
217 OverflowContainersProperty());
218 SafelyDestroyFrameListProp(aDestructRoot, shell, props,
219 ExcessOverflowContainersProperty());
221 nsSplittableFrame::DestroyFrom(aDestructRoot);
224 /////////////////////////////////////////////////////////////////////////////
225 // Child frame enumeration
227 const nsFrameList&
228 nsContainerFrame::GetChildList(ChildListID aListID) const
230 // We only know about the principal child list and the overflow lists.
231 switch (aListID) {
232 case kPrincipalList:
233 return mFrames;
234 case kOverflowList: {
235 nsFrameList* list = GetOverflowFrames();
236 return list ? *list : nsFrameList::EmptyList();
238 case kOverflowContainersList: {
239 nsFrameList* list = GetPropTableFrames(OverflowContainersProperty());
240 return list ? *list : nsFrameList::EmptyList();
242 case kExcessOverflowContainersList: {
243 nsFrameList* list =
244 GetPropTableFrames(ExcessOverflowContainersProperty());
245 return list ? *list : nsFrameList::EmptyList();
247 default:
248 return nsSplittableFrame::GetChildList(aListID);
252 static void AppendIfNonempty(const nsIFrame* aFrame,
253 FramePropertyTable* aPropTable,
254 const FramePropertyDescriptor* aProperty,
255 nsTArray<nsIFrame::ChildList>* aLists,
256 nsIFrame::ChildListID aListID)
258 nsFrameList* list = static_cast<nsFrameList*>(
259 aPropTable->Get(aFrame, aProperty));
260 if (list) {
261 list->AppendIfNonempty(aLists, aListID);
265 void
266 nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
268 mFrames.AppendIfNonempty(aLists, kPrincipalList);
269 FramePropertyTable* propTable = PresContext()->PropertyTable();
270 ::AppendIfNonempty(this, propTable, OverflowProperty(),
271 aLists, kOverflowList);
272 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
273 ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
274 aLists, kOverflowContainersList);
275 ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
276 aLists, kExcessOverflowContainersList);
278 nsSplittableFrame::GetChildLists(aLists);
281 /////////////////////////////////////////////////////////////////////////////
282 // Painting/Events
284 void
285 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
286 const nsRect& aDirtyRect,
287 const nsDisplayListSet& aLists)
289 DisplayBorderBackgroundOutline(aBuilder, aLists);
291 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
294 void
295 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
296 const nsRect& aDirtyRect,
297 const nsDisplayListSet& aLists,
298 uint32_t aFlags)
300 nsIFrame* kid = mFrames.FirstChild();
301 // Put each child's background directly onto the content list
302 nsDisplayListSet set(aLists, aLists.Content());
303 // The children should be in content order
304 while (kid) {
305 BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
306 kid = kid->GetNextSibling();
310 /* virtual */ void
311 nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
313 NS_ASSERTION(NS_SUBTREE_DIRTY(aChild), "child isn't actually dirty");
315 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
318 bool
319 nsContainerFrame::IsLeaf() const
321 return false;
324 nsIFrame::FrameSearchResult
325 nsContainerFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
327 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
328 // Don't allow the caret to stay in an empty (leaf) container frame.
329 return CONTINUE_EMPTY;
332 nsIFrame::FrameSearchResult
333 nsContainerFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
334 bool aRespectClusters)
336 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
337 // Don't allow the caret to stay in an empty (leaf) container frame.
338 return CONTINUE_EMPTY;
341 /////////////////////////////////////////////////////////////////////////////
342 // Helper member functions
344 static nsresult
345 ReparentFrameViewTo(nsIFrame* aFrame,
346 nsViewManager* aViewManager,
347 nsView* aNewParentView,
348 nsView* aOldParentView)
351 // XXX What to do about placeholder views for "position: fixed" elements?
352 // They should be reparented too.
354 // Does aFrame have a view?
355 if (aFrame->HasView()) {
356 #ifdef MOZ_XUL
357 if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
358 // This view must be parented by the root view, don't reparent it.
359 return NS_OK;
361 #endif
362 nsView* view = aFrame->GetView();
363 // Verify that the current parent view is what we think it is
364 //nsView* parentView;
365 //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
367 aViewManager->RemoveChild(view);
369 // The view will remember the Z-order and other attributes that have been set on it.
370 nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
371 aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
372 } else {
373 nsIFrame::ChildListIterator lists(aFrame);
374 for (; !lists.IsDone(); lists.Next()) {
375 // Iterate the child frames, and check each child frame to see if it has
376 // a view
377 nsFrameList::Enumerator childFrames(lists.CurrentList());
378 for (; !childFrames.AtEnd(); childFrames.Next()) {
379 ReparentFrameViewTo(childFrames.get(), aViewManager,
380 aNewParentView, aOldParentView);
385 return NS_OK;
388 void
389 nsContainerFrame::CreateViewForFrame(nsIFrame* aFrame,
390 bool aForce)
392 if (aFrame->HasView()) {
393 return;
396 // If we don't yet have a view, see if we need a view
397 if (!aForce && !aFrame->NeedsView()) {
398 // don't need a view
399 return;
402 nsView* parentView = aFrame->GetParent()->GetClosestView();
403 NS_ASSERTION(parentView, "no parent with view");
405 nsViewManager* viewManager = parentView->GetViewManager();
406 NS_ASSERTION(viewManager, "null view manager");
408 // Create a view
409 nsView* view = viewManager->CreateView(aFrame->GetRect(), parentView);
411 SyncFrameViewProperties(aFrame->PresContext(), aFrame, nullptr, view);
413 nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, aFrame);
414 // we insert this view 'above' the insertBefore view, unless insertBefore is null,
415 // in which case we want to call with aAbove == false to insert at the beginning
416 // in document order
417 viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
419 // REVIEW: Don't create a widget for fixed-pos elements anymore.
420 // ComputeRepaintRegionForCopy will calculate the right area to repaint
421 // when we scroll.
422 // Reparent views on any child frames (or their descendants) to this
423 // view. We can just call ReparentFrameViewTo on this frame because
424 // we know this frame has no view, so it will crawl the children. Also,
425 // we know that any descendants with views must have 'parentView' as their
426 // parent view.
427 ReparentFrameViewTo(aFrame, viewManager, view, parentView);
429 // Remember our view
430 aFrame->SetView(view);
432 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
433 ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
434 aFrame));
438 * Position the view associated with |aKidFrame|, if there is one. A
439 * container frame should call this method after positioning a frame,
440 * but before |Reflow|.
442 void
443 nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
445 nsIFrame* parentFrame = aKidFrame->GetParent();
446 if (!aKidFrame->HasView() || !parentFrame)
447 return;
449 nsView* view = aKidFrame->GetView();
450 nsViewManager* vm = view->GetViewManager();
451 nsPoint pt;
452 nsView* ancestorView = parentFrame->GetClosestView(&pt);
454 if (ancestorView != view->GetParent()) {
455 NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
456 "Allowed only one anonymous view between frames");
457 // parentFrame is responsible for positioning aKidFrame's view
458 // explicitly
459 return;
462 pt += aKidFrame->GetPosition();
463 vm->MoveViewTo(view, pt.x, pt.y);
466 nsresult
467 nsContainerFrame::ReparentFrameView(nsIFrame* aChildFrame,
468 nsIFrame* aOldParentFrame,
469 nsIFrame* aNewParentFrame)
471 NS_PRECONDITION(aChildFrame, "null child frame pointer");
472 NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
473 NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
474 NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
476 // See if either the old parent frame or the new parent frame have a view
477 while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
478 // Walk up both the old parent frame and the new parent frame nodes
479 // stopping when we either find a common parent or views for one
480 // or both of the frames.
482 // This works well in the common case where we push/pull and the old parent
483 // frame and the new parent frame are part of the same flow. They will
484 // typically be the same distance (height wise) from the
485 aOldParentFrame = aOldParentFrame->GetParent();
486 aNewParentFrame = aNewParentFrame->GetParent();
488 // We should never walk all the way to the root frame without finding
489 // a view
490 NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
492 // See if we reached a common ancestor
493 if (aOldParentFrame == aNewParentFrame) {
494 break;
498 // See if we found a common parent frame
499 if (aOldParentFrame == aNewParentFrame) {
500 // We found a common parent and there are no views between the old parent
501 // and the common parent or the new parent frame and the common parent.
502 // Because neither the old parent frame nor the new parent frame have views,
503 // then any child views don't need reparenting
504 return NS_OK;
507 // We found views for one or both of the ancestor frames before we
508 // found a common ancestor.
509 nsView* oldParentView = aOldParentFrame->GetClosestView();
510 nsView* newParentView = aNewParentFrame->GetClosestView();
512 // See if the old parent frame and the new parent frame are in the
513 // same view sub-hierarchy. If they are then we don't have to do
514 // anything
515 if (oldParentView != newParentView) {
516 // They're not so we need to reparent any child views
517 return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
518 oldParentView);
521 return NS_OK;
524 nsresult
525 nsContainerFrame::ReparentFrameViewList(const nsFrameList& aChildFrameList,
526 nsIFrame* aOldParentFrame,
527 nsIFrame* aNewParentFrame)
529 NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
530 NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
531 NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
532 NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
534 // See if either the old parent frame or the new parent frame have a view
535 while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
536 // Walk up both the old parent frame and the new parent frame nodes
537 // stopping when we either find a common parent or views for one
538 // or both of the frames.
540 // This works well in the common case where we push/pull and the old parent
541 // frame and the new parent frame are part of the same flow. They will
542 // typically be the same distance (height wise) from the
543 aOldParentFrame = aOldParentFrame->GetParent();
544 aNewParentFrame = aNewParentFrame->GetParent();
546 // We should never walk all the way to the root frame without finding
547 // a view
548 NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
550 // See if we reached a common ancestor
551 if (aOldParentFrame == aNewParentFrame) {
552 break;
557 // See if we found a common parent frame
558 if (aOldParentFrame == aNewParentFrame) {
559 // We found a common parent and there are no views between the old parent
560 // and the common parent or the new parent frame and the common parent.
561 // Because neither the old parent frame nor the new parent frame have views,
562 // then any child views don't need reparenting
563 return NS_OK;
566 // We found views for one or both of the ancestor frames before we
567 // found a common ancestor.
568 nsView* oldParentView = aOldParentFrame->GetClosestView();
569 nsView* newParentView = aNewParentFrame->GetClosestView();
571 // See if the old parent frame and the new parent frame are in the
572 // same view sub-hierarchy. If they are then we don't have to do
573 // anything
574 if (oldParentView != newParentView) {
575 nsViewManager* viewManager = oldParentView->GetViewManager();
577 // They're not so we need to reparent any child views
578 for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
579 ReparentFrameViewTo(e.get(), viewManager, newParentView, oldParentView);
583 return NS_OK;
586 static nsIWidget*
587 GetPresContextContainerWidget(nsPresContext* aPresContext)
589 nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
590 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
591 if (!baseWindow)
592 return nullptr;
594 nsCOMPtr<nsIWidget> mainWidget;
595 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
596 return mainWidget;
599 static bool
600 IsTopLevelWidget(nsIWidget* aWidget)
602 nsWindowType windowType = aWidget->WindowType();
603 return windowType == eWindowType_toplevel ||
604 windowType == eWindowType_dialog ||
605 windowType == eWindowType_sheet;
606 // popups aren't toplevel so they're not handled here
609 void
610 nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
611 nsIFrame* aFrame,
612 nsView* aView,
613 nsRenderingContext* aRC)
615 #ifdef MOZ_XUL
616 if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
617 return;
619 nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
620 if (!windowWidget || !IsTopLevelWidget(windowWidget))
621 return;
623 nsViewManager* vm = aView->GetViewManager();
624 nsView* rootView = vm->GetRootView();
626 if (aView != rootView)
627 return;
629 Element* rootElement = aPresContext->Document()->GetRootElement();
630 if (!rootElement || !rootElement->IsXUL()) {
631 // Scrollframes use native widgets which don't work well with
632 // translucent windows, at least in Windows XP. So if the document
633 // has a root scrollrame it's useless to try to make it transparent,
634 // we'll just get something broken.
635 // nsCSSFrameConstructor::ConstructRootFrame constructs root
636 // scrollframes whenever the root element is not a XUL element, so
637 // we test for that here. We can't just call
638 // presShell->GetRootScrollFrame() since that might not have
639 // been constructed yet.
640 // We can change this to allow translucent toplevel HTML documents
641 // (e.g. to do something like Dashboard widgets), once we
642 // have broad support for translucent scrolled documents, but be
643 // careful because apparently some Firefox extensions expect
644 // openDialog("something.html") to produce an opaque window
645 // even if the HTML doesn't have a background-color set.
646 return;
649 nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
650 if (!rootFrame)
651 return;
653 nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
654 nsIWidget* viewWidget = aView->GetWidget();
655 viewWidget->SetTransparencyMode(mode);
656 windowWidget->SetWindowShadowStyle(rootFrame->StyleUIReset()->mWindowShadow);
658 if (!aRC)
659 return;
661 nsBoxLayoutState aState(aPresContext, aRC);
662 nsSize minSize = rootFrame->GetMinSize(aState);
663 nsSize maxSize = rootFrame->GetMaxSize(aState);
665 SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
666 #endif
669 void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
670 nsIWidget* aWidget,
671 const nsSize& aMinSize,
672 const nsSize& aMaxSize)
674 nsIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
675 aPresContext->AppUnitsToDevPixels(aMinSize.height));
676 nsIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
677 aPresContext->AppUnitsToDevPixels(aMaxSize.width),
678 aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
679 aPresContext->AppUnitsToDevPixels(aMaxSize.height));
681 // MinSize has a priority over MaxSize
682 if (devMinSize.width > devMaxSize.width)
683 devMaxSize.width = devMinSize.width;
684 if (devMinSize.height > devMaxSize.height)
685 devMaxSize.height = devMinSize.height;
687 widget::SizeConstraints constraints(devMinSize, devMaxSize);
689 // The sizes are in inner window sizes, so convert them into outer window sizes.
690 // Use a size of (200, 200) as only the difference between the inner and outer
691 // size is needed.
692 nsIntSize windowSize = aWidget->ClientToWindowSize(nsIntSize(200, 200));
693 if (constraints.mMinSize.width)
694 constraints.mMinSize.width += windowSize.width - 200;
695 if (constraints.mMinSize.height)
696 constraints.mMinSize.height += windowSize.height - 200;
697 if (constraints.mMaxSize.width != NS_MAXSIZE)
698 constraints.mMaxSize.width += windowSize.width - 200;
699 if (constraints.mMaxSize.height != NS_MAXSIZE)
700 constraints.mMaxSize.height += windowSize.height - 200;
702 aWidget->SetSizeConstraints(constraints);
705 void
706 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
707 nsIFrame* aFrame,
708 nsView* aView,
709 const nsRect& aVisualOverflowArea,
710 uint32_t aFlags)
712 if (!aView) {
713 return;
716 // Make sure the view is sized and positioned correctly
717 if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
718 PositionFrameView(aFrame);
721 if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
722 nsViewManager* vm = aView->GetViewManager();
724 vm->ResizeView(aView, aVisualOverflowArea, true);
728 void
729 nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
730 nsIFrame* aFrame,
731 nsStyleContext* aStyleContext,
732 nsView* aView,
733 uint32_t aFlags)
735 NS_ASSERTION(!aStyleContext || aFrame->StyleContext() == aStyleContext,
736 "Wrong style context for frame?");
738 if (!aView) {
739 return;
742 nsViewManager* vm = aView->GetViewManager();
744 if (nullptr == aStyleContext) {
745 aStyleContext = aFrame->StyleContext();
748 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
749 if (0 == (aFlags & NS_FRAME_NO_VISIBILITY) &&
750 !aFrame->SupportsVisibilityHidden()) {
751 // See if the view should be hidden or visible
752 vm->SetViewVisibility(aView,
753 aStyleContext->StyleVisibility()->IsVisible()
754 ? nsViewVisibility_kShow : nsViewVisibility_kHide);
757 // See if the frame is being relatively positioned or absolutely
758 // positioned
759 bool isPositioned = aFrame->IsPositioned();
761 int32_t zIndex = 0;
762 bool autoZIndex = false;
764 if (!isPositioned) {
765 autoZIndex = true;
766 } else {
767 // Make sure z-index is correct
768 const nsStylePosition* position = aStyleContext->StylePosition();
770 if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
771 zIndex = position->mZIndex.GetIntValue();
772 } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
773 autoZIndex = true;
777 vm->SetViewZIndex(aView, autoZIndex, zIndex);
780 static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
782 if (aCoord.ConvertsToLength()) {
783 return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
785 return aIfNotCoord;
788 void
789 nsContainerFrame::DoInlineIntrinsicISize(nsRenderingContext *aRenderingContext,
790 InlineIntrinsicISizeData *aData,
791 nsLayoutUtils::IntrinsicISizeType aType)
793 if (GetPrevInFlow())
794 return; // Already added.
796 NS_PRECONDITION(aType == nsLayoutUtils::MIN_ISIZE ||
797 aType == nsLayoutUtils::PREF_ISIZE, "bad type");
799 mozilla::css::Side startSide, endSide;
800 if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
801 startSide = NS_SIDE_LEFT;
802 endSide = NS_SIDE_RIGHT;
803 } else {
804 startSide = NS_SIDE_RIGHT;
805 endSide = NS_SIDE_LEFT;
808 const nsStylePadding *stylePadding = StylePadding();
809 const nsStyleBorder *styleBorder = StyleBorder();
810 const nsStyleMargin *styleMargin = StyleMargin();
812 // This goes at the beginning no matter how things are broken and how
813 // messy the bidi situations are, since per CSS2.1 section 8.6
814 // (implemented in bug 328168), the startSide border is always on the
815 // first line.
816 // This frame is a first-in-flow, but it might have a previous bidi
817 // continuation, in which case that continuation should handle the startSide
818 // border.
819 // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
820 // add that to each line. For box-decoration-break:slice clonePBM is zero.
821 nscoord clonePBM = 0; // PBM = PaddingBorderMargin
822 const bool sliceBreak =
823 styleBorder->mBoxDecorationBreak == NS_STYLE_BOX_DECORATION_BREAK_SLICE;
824 if (!GetPrevContinuation()) {
825 nscoord startPBM =
826 // clamp negative calc() to 0
827 std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
828 styleBorder->GetComputedBorderWidth(startSide) +
829 GetCoord(styleMargin->mMargin.Get(startSide), 0);
830 if (MOZ_LIKELY(sliceBreak)) {
831 aData->currentLine += startPBM;
832 } else {
833 clonePBM = startPBM;
837 nscoord endPBM =
838 // clamp negative calc() to 0
839 std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
840 styleBorder->GetComputedBorderWidth(endSide) +
841 GetCoord(styleMargin->mMargin.Get(endSide), 0);
842 if (MOZ_UNLIKELY(!sliceBreak)) {
843 clonePBM += endPBM;
846 const nsLineList_iterator* savedLine = aData->line;
847 nsIFrame* const savedLineContainer = aData->lineContainer;
849 nsContainerFrame *lastInFlow;
850 for (nsContainerFrame *nif = this; nif;
851 nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
852 if (aData->currentLine == 0) {
853 aData->currentLine = clonePBM;
855 for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
856 kid = kid->GetNextSibling()) {
857 if (aType == nsLayoutUtils::MIN_ISIZE)
858 kid->AddInlineMinISize(aRenderingContext,
859 static_cast<InlineMinISizeData*>(aData));
860 else
861 kid->AddInlinePrefISize(aRenderingContext,
862 static_cast<InlinePrefISizeData*>(aData));
865 // After we advance to our next-in-flow, the stored line and line container
866 // may no longer be correct. Just forget them.
867 aData->line = nullptr;
868 aData->lineContainer = nullptr;
870 lastInFlow = nif;
873 aData->line = savedLine;
874 aData->lineContainer = savedLineContainer;
876 // This goes at the end no matter how things are broken and how
877 // messy the bidi situations are, since per CSS2.1 section 8.6
878 // (implemented in bug 328168), the endSide border is always on the
879 // last line.
880 // We reached the last-in-flow, but it might have a next bidi
881 // continuation, in which case that continuation should handle
882 // the endSide border.
883 if (MOZ_LIKELY(!lastInFlow->GetNextContinuation() && sliceBreak)) {
884 aData->currentLine += endPBM;
888 /* virtual */
889 LogicalSize
890 nsContainerFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
891 WritingMode aWM,
892 const LogicalSize& aCBSize,
893 nscoord aAvailableISize,
894 const LogicalSize& aMargin,
895 const LogicalSize& aBorder,
896 const LogicalSize& aPadding,
897 bool aShrinkWrap)
899 LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
900 nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
901 aBorder.ISize(aWM) - aPadding.ISize(aWM);
902 // replaced elements always shrink-wrap
903 if (aShrinkWrap || IsFrameOfType(eReplaced)) {
904 // don't bother setting it if the result won't be used
905 const nsStyleCoord& inlineStyleCoord =
906 aWM.IsVertical() ? StylePosition()->mHeight : StylePosition()->mWidth;
907 if (inlineStyleCoord.GetUnit() == eStyleUnit_Auto) {
908 result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased);
910 } else {
911 result.ISize(aWM) = availBased;
914 if (IsTableCaption()) {
915 // If we're a container for font size inflation, then shrink
916 // wrapping inside of us should not apply font size inflation.
917 AutoMaybeDisableFontInflation an(this);
919 // XXX todo: make this aware of vertical writing modes
920 uint8_t captionSide = StyleTableBorder()->mCaptionSide;
921 if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
922 captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
923 result.ISize(aWM) = GetMinISize(aRenderingContext);
924 } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
925 captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
926 // The outer frame constrains our available width to the width of
927 // the table. Grow if our min-width is bigger than that, but not
928 // larger than the containing block width. (It would really be nice
929 // to transmit that information another way, so we could grow up to
930 // the table's available width, but that's harder.)
931 nscoord min = GetMinISize(aRenderingContext);
932 if (min > aCBSize.ISize(aWM)) {
933 min = aCBSize.ISize(aWM);
935 if (min > result.ISize(aWM)) {
936 result.ISize(aWM) = min;
940 return result;
944 * Invokes the WillReflow() function, positions the frame and its view (if
945 * requested), and then calls Reflow(). If the reflow succeeds and the child
946 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
948 void
949 nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
950 nsPresContext* aPresContext,
951 nsHTMLReflowMetrics& aDesiredSize,
952 const nsHTMLReflowState& aReflowState,
953 nscoord aX,
954 nscoord aY,
955 uint32_t aFlags,
956 nsReflowStatus& aStatus,
957 nsOverflowContinuationTracker* aTracker)
959 NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
961 // Send the WillReflow() notification, and position the child frame
962 // and its view if requested
963 aKidFrame->WillReflow(aPresContext);
965 if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
966 aKidFrame->SetPosition(nsPoint(aX, aY));
969 if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
970 PositionFrameView(aKidFrame);
973 // Reflow the child frame
974 aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
976 // If the child frame is complete, delete any next-in-flows,
977 // but only if the NO_DELETE_NEXT_IN_FLOW flag isn't set.
978 if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
979 !(aFlags & NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD)) {
980 nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
981 if (kidNextInFlow) {
982 // Remove all of the childs next-in-flows. Make sure that we ask
983 // the right parent to do the removal (it's possible that the
984 // parent is not this because we are executing pullup code)
985 nsOverflowContinuationTracker::AutoFinish fini(aTracker, aKidFrame);
986 kidNextInFlow->GetParent()->DeleteNextInFlowChild(kidNextInFlow, true);
993 * Position the views of |aFrame|'s descendants. A container frame
994 * should call this method if it moves a frame after |Reflow|.
996 void
997 nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
999 if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
1000 return;
1003 // Recursively walk aFrame's child frames.
1004 // Process the additional child lists, but skip the popup list as the
1005 // view for popups is managed by the parent. Currently only nsMenuFrame
1006 // and nsPopupSetFrame have a popupList and during layout will adjust the
1007 // view manually to position the popup.
1008 ChildListIterator lists(aFrame);
1009 for (; !lists.IsDone(); lists.Next()) {
1010 if (lists.CurrentID() == kPopupList) {
1011 continue;
1013 nsFrameList::Enumerator childFrames(lists.CurrentList());
1014 for (; !childFrames.AtEnd(); childFrames.Next()) {
1015 // Position the frame's view (if it has one) otherwise recursively
1016 // process its children
1017 nsIFrame* childFrame = childFrames.get();
1018 if (childFrame->HasView()) {
1019 PositionFrameView(childFrame);
1020 } else {
1021 PositionChildViews(childFrame);
1028 * The second half of frame reflow. Does the following:
1029 * - sets the frame's bounds
1030 * - sizes and positions (if requested) the frame's view. If the frame's final
1031 * position differs from the current position and the frame itself does not
1032 * have a view, then any child frames with views are positioned so they stay
1033 * in sync
1034 * - sets the view's visibility, opacity, content transparency, and clip
1035 * - invoked the DidReflow() function
1037 * Flags:
1038 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1039 * case. Also implies NS_FRAME_NO_MOVE_VIEW
1040 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1041 * don't want to automatically sync the frame and view
1042 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1044 void
1045 nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
1046 nsPresContext* aPresContext,
1047 const nsHTMLReflowMetrics& aDesiredSize,
1048 const nsHTMLReflowState* aReflowState,
1049 nscoord aX,
1050 nscoord aY,
1051 uint32_t aFlags)
1053 nsPoint curOrigin = aKidFrame->GetPosition();
1055 if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
1056 aKidFrame->SetRect(nsRect(aX, aY, aDesiredSize.Width(), aDesiredSize.Height()));
1057 } else {
1058 aKidFrame->SetSize(nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
1061 if (aKidFrame->HasView()) {
1062 nsView* view = aKidFrame->GetView();
1063 // Make sure the frame's view is properly sized and positioned and has
1064 // things like opacity correct
1065 SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
1066 aDesiredSize.VisualOverflow(), aFlags);
1069 if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
1070 (curOrigin.x != aX || curOrigin.y != aY)) {
1071 if (!aKidFrame->HasView()) {
1072 // If the frame has moved, then we need to make sure any child views are
1073 // correctly positioned
1074 PositionChildViews(aKidFrame);
1078 aKidFrame->DidReflow(aPresContext, aReflowState, nsDidReflowStatus::FINISHED);
1081 void
1082 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
1083 const nsHTMLReflowState& aReflowState,
1084 nsOverflowAreas& aOverflowRects,
1085 uint32_t aFlags,
1086 nsReflowStatus& aStatus)
1088 NS_PRECONDITION(aPresContext, "null pointer");
1090 nsFrameList* overflowContainers =
1091 GetPropTableFrames(OverflowContainersProperty());
1093 NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
1094 && static_cast<nsContainerFrame*>(GetPrevInFlow())
1095 ->GetPropTableFrames(ExcessOverflowContainersProperty())),
1096 "conflicting overflow containers lists");
1098 if (!overflowContainers) {
1099 // Drain excess from previnflow
1100 nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
1101 if (prev) {
1102 nsFrameList* excessFrames =
1103 prev->RemovePropTableFrames(ExcessOverflowContainersProperty());
1104 if (excessFrames) {
1105 excessFrames->ApplySetParent(this);
1106 nsContainerFrame::ReparentFrameViewList(*excessFrames, prev, this);
1107 overflowContainers = excessFrames;
1108 SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1113 // Our own excess overflow containers from a previous reflow can still be
1114 // present if our next-in-flow hasn't been reflown yet.
1115 nsFrameList* selfExcessOCFrames =
1116 RemovePropTableFrames(ExcessOverflowContainersProperty());
1117 if (selfExcessOCFrames) {
1118 if (overflowContainers) {
1119 overflowContainers->AppendFrames(nullptr, *selfExcessOCFrames);
1120 selfExcessOCFrames->Delete(aPresContext->PresShell());
1121 } else {
1122 overflowContainers = selfExcessOCFrames;
1123 SetPropTableFrames(overflowContainers, OverflowContainersProperty());
1126 if (!overflowContainers) {
1127 return; // nothing to reflow
1130 nsOverflowContinuationTracker tracker(this, false, false);
1131 bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
1133 for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
1134 frame = frame->GetNextSibling()) {
1135 if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1136 // frame's prevInFlow has moved, skip reflowing this frame;
1137 // it will get reflowed once it's been placed
1138 continue;
1140 // If the available vertical height has changed, we need to reflow
1141 // even if the frame isn't dirty.
1142 if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
1143 // Get prev-in-flow
1144 nsIFrame* prevInFlow = frame->GetPrevInFlow();
1145 NS_ASSERTION(prevInFlow,
1146 "overflow container frame must have a prev-in-flow");
1147 NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
1148 "overflow container frame must have overflow container bit set");
1149 nsRect prevRect = prevInFlow->GetRect();
1151 // Initialize reflow params
1152 WritingMode wm = frame->GetWritingMode();
1153 LogicalSize availSpace(wm, LogicalSize(wm, prevRect.Size()).ISize(wm),
1154 aReflowState.AvailableSize(wm).BSize(wm));
1155 nsHTMLReflowMetrics desiredSize(aReflowState);
1156 nsHTMLReflowState frameState(aPresContext, aReflowState,
1157 frame, availSpace);
1158 nsReflowStatus frameStatus;
1160 // Reflow
1161 ReflowChild(frame, aPresContext, desiredSize, frameState,
1162 prevRect.x, 0, aFlags, frameStatus, &tracker);
1163 //XXXfr Do we need to override any shrinkwrap effects here?
1164 // e.g. desiredSize.Width() = prevRect.width;
1165 FinishReflowChild(frame, aPresContext, desiredSize, &frameState,
1166 prevRect.x, 0, aFlags);
1168 // Handle continuations
1169 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
1170 if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
1171 // Abspos frames can't cause their parent to be incomplete,
1172 // only overflow incomplete.
1173 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
1175 else {
1176 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
1177 "overflow container frames can't be incomplete, only overflow-incomplete");
1180 // Acquire a next-in-flow, creating it if necessary
1181 nsIFrame* nif = frame->GetNextInFlow();
1182 if (!nif) {
1183 NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
1184 "Someone forgot a REFLOW_NEXTINFLOW flag");
1185 nif = aPresContext->PresShell()->FrameConstructor()->
1186 CreateContinuingFrame(aPresContext, frame, this);
1188 else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1189 // used to be a normal next-in-flow; steal it from the child list
1190 nsresult rv = nif->GetParent()->StealFrame(nif);
1191 if (NS_FAILED(rv)) {
1192 return;
1196 tracker.Insert(nif, frameStatus);
1198 NS_MergeReflowStatusInto(&aStatus, frameStatus);
1199 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1200 // but we have some unsplittable frames that, when taller than
1201 // availableHeight will push zero-height content into a next-in-flow.
1203 else {
1204 tracker.Skip(frame, aStatus);
1205 if (aReflowState.mFloatManager)
1206 nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
1208 ConsiderChildOverflow(aOverflowRects, frame);
1212 void
1213 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
1214 const nsRect& aDirtyRect,
1215 const nsDisplayListSet& aLists)
1217 nsFrameList* overflowconts = GetPropTableFrames(OverflowContainersProperty());
1218 if (overflowconts) {
1219 for (nsIFrame* frame = overflowconts->FirstChild(); frame;
1220 frame = frame->GetNextSibling()) {
1221 BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
1226 static bool
1227 TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable,
1228 const FramePropertyDescriptor* aProp, nsIFrame* aChildToRemove)
1230 nsFrameList* list = static_cast<nsFrameList*>(aPropTable->Get(aFrame, aProp));
1231 if (list && list->StartRemoveFrame(aChildToRemove)) {
1232 // aChildToRemove *may* have been removed from this list.
1233 if (list->IsEmpty()) {
1234 aPropTable->Remove(aFrame, aProp);
1235 list->Delete(aFrame->PresContext()->PresShell());
1237 return true;
1239 return false;
1242 nsresult
1243 nsContainerFrame::StealFrame(nsIFrame* aChild,
1244 bool aForceNormal)
1246 #ifdef DEBUG
1247 if (!mFrames.ContainsFrame(aChild)) {
1248 nsFrameList* list = GetOverflowFrames();
1249 if (!list || !list->ContainsFrame(aChild)) {
1250 FramePropertyTable* propTable = PresContext()->PropertyTable();
1251 list = static_cast<nsFrameList*>(
1252 propTable->Get(this, OverflowContainersProperty()));
1253 if (!list || !list->ContainsFrame(aChild)) {
1254 list = static_cast<nsFrameList*>(
1255 propTable->Get(this, ExcessOverflowContainersProperty()));
1256 MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child"
1257 " or on a frame list not supported by StealFrame");
1261 #endif
1263 bool removed;
1264 if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
1265 && !aForceNormal) {
1266 FramePropertyTable* propTable = PresContext()->PropertyTable();
1267 // Try removing from the overflow container list.
1268 removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(),
1269 aChild);
1270 if (!removed) {
1271 // It must be in the excess overflow container list.
1272 removed = ::TryRemoveFrame(this, propTable,
1273 ExcessOverflowContainersProperty(),
1274 aChild);
1276 } else {
1277 removed = mFrames.StartRemoveFrame(aChild);
1278 if (!removed) {
1279 // We didn't find the child in our principal child list.
1280 // Maybe it's on the overflow list?
1281 nsFrameList* frameList = GetOverflowFrames();
1282 if (frameList) {
1283 removed = frameList->ContinueRemoveFrame(aChild);
1284 if (frameList->IsEmpty()) {
1285 DestroyOverflowList();
1291 NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
1292 return removed ? NS_OK : NS_ERROR_UNEXPECTED;
1295 nsFrameList
1296 nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
1298 NS_ASSERTION(!aChild ||
1299 !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
1300 "StealFramesAfter doesn't handle overflow containers");
1301 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame, "unexpected call");
1303 if (!aChild) {
1304 nsFrameList copy(mFrames);
1305 mFrames.Clear();
1306 return copy;
1309 for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
1310 iter.Next()) {
1311 if (iter.PrevFrame() == aChild) {
1312 return mFrames.ExtractTail(iter);
1316 // We didn't find the child in the principal child list.
1317 // Maybe it's on the overflow list?
1318 nsFrameList* overflowFrames = GetOverflowFrames();
1319 if (overflowFrames) {
1320 for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
1321 iter.Next()) {
1322 if (iter.PrevFrame() == aChild) {
1323 return overflowFrames->ExtractTail(iter);
1328 NS_ERROR("StealFramesAfter: can't find aChild");
1329 return nsFrameList::EmptyList();
1333 * Create a next-in-flow for aFrame. Will return the newly created
1334 * frame <b>if and only if</b> a new frame is created; otherwise
1335 * nullptr is returned.
1337 nsIFrame*
1338 nsContainerFrame::CreateNextInFlow(nsIFrame* aFrame)
1340 NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame,
1341 "you should have called nsBlockFrame::CreateContinuationFor instead");
1342 NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
1344 nsPresContext* pc = PresContext();
1345 nsIFrame* nextInFlow = aFrame->GetNextInFlow();
1346 if (nullptr == nextInFlow) {
1347 // Create a continuation frame for the child frame and insert it
1348 // into our child list.
1349 nextInFlow = pc->PresShell()->FrameConstructor()->
1350 CreateContinuingFrame(pc, aFrame, this);
1351 mFrames.InsertFrame(nullptr, aFrame, nextInFlow);
1353 NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
1354 ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1355 aFrame, nextInFlow));
1357 return nextInFlow;
1359 return nullptr;
1363 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1364 * pointers
1366 void
1367 nsContainerFrame::DeleteNextInFlowChild(nsIFrame* aNextInFlow,
1368 bool aDeletingEmptyFrames)
1370 #ifdef DEBUG
1371 nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
1372 #endif
1373 NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
1375 // If the next-in-flow has a next-in-flow then delete it, too (and
1376 // delete it first).
1377 // Do this in a loop so we don't overflow the stack for frames
1378 // with very many next-in-flows
1379 nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
1380 if (nextNextInFlow) {
1381 nsAutoTArray<nsIFrame*, 8> frames;
1382 for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
1383 frames.AppendElement(f);
1385 for (int32_t i = frames.Length() - 1; i >= 0; --i) {
1386 nsIFrame* delFrame = frames.ElementAt(i);
1387 delFrame->GetParent()->
1388 DeleteNextInFlowChild(delFrame, aDeletingEmptyFrames);
1392 // Take the next-in-flow out of the parent's child list
1393 DebugOnly<nsresult> rv = StealFrame(aNextInFlow);
1394 NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
1396 #ifdef DEBUG
1397 if (aDeletingEmptyFrames) {
1398 nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
1400 #endif
1402 // Delete the next-in-flow frame and its descendants. This will also
1403 // remove it from its next-in-flow/prev-in-flow chain.
1404 aNextInFlow->Destroy();
1406 NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
1410 * Set the frames on the overflow list
1412 void
1413 nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames)
1415 NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
1417 nsPresContext* pc = PresContext();
1418 nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames);
1420 pc->PropertyTable()->Set(this, OverflowProperty(), newList);
1423 nsFrameList*
1424 nsContainerFrame::GetPropTableFrames(const FramePropertyDescriptor* aProperty) const
1426 FramePropertyTable* propTable = PresContext()->PropertyTable();
1427 return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
1430 nsFrameList*
1431 nsContainerFrame::RemovePropTableFrames(const FramePropertyDescriptor* aProperty)
1433 FramePropertyTable* propTable = PresContext()->PropertyTable();
1434 return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
1437 void
1438 nsContainerFrame::SetPropTableFrames(nsFrameList* aFrameList,
1439 const FramePropertyDescriptor* aProperty)
1441 NS_PRECONDITION(aProperty && aFrameList, "null ptr");
1442 NS_PRECONDITION(
1443 (aProperty != nsContainerFrame::OverflowContainersProperty() &&
1444 aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
1445 IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
1446 "this type of frame can't have overflow containers");
1447 MOZ_ASSERT(!GetPropTableFrames(aProperty));
1448 PresContext()->PropertyTable()->Set(this, aProperty, aFrameList);
1452 * Push aFromChild and its next siblings to the next-in-flow. Change the
1453 * geometric parent of each frame that's pushed. If there is no next-in-flow
1454 * the frames are placed on the overflow list (and the geometric parent is
1455 * left unchanged).
1457 * Updates the next-in-flow's child count. Does <b>not</b> update the
1458 * pusher's child count.
1460 * @param aFromChild the first child frame to push. It is disconnected from
1461 * aPrevSibling
1462 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1463 * an error to push a parent's first child frame
1465 void
1466 nsContainerFrame::PushChildren(nsIFrame* aFromChild,
1467 nsIFrame* aPrevSibling)
1469 NS_PRECONDITION(aFromChild, "null pointer");
1470 NS_PRECONDITION(aPrevSibling, "pushing first child");
1471 NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
1473 // Disconnect aFromChild from its previous sibling
1474 nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
1476 nsContainerFrame* nextInFlow =
1477 static_cast<nsContainerFrame*>(GetNextInFlow());
1478 if (nextInFlow) {
1479 // XXX This is not a very good thing to do. If it gets removed
1480 // then remove the copy of this routine that doesn't do this from
1481 // nsInlineFrame.
1482 // When pushing and pulling frames we need to check for whether any
1483 // views need to be reparented.
1484 for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
1485 nsContainerFrame::ReparentFrameView(f, this, nextInFlow);
1487 nextInFlow->mFrames.InsertFrames(nextInFlow, nullptr, tail);
1489 else {
1490 // Add the frames to our overflow list
1491 SetOverflowFrames(tail);
1496 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1497 * the receiver's overflow list) to the child list.
1499 * Updates this frame's child count and content mapping.
1501 * @return true if any frames were moved and false otherwise
1503 bool
1504 nsContainerFrame::MoveOverflowToChildList()
1506 bool result = false;
1508 // Check for an overflow list with our prev-in-flow
1509 nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
1510 if (nullptr != prevInFlow) {
1511 AutoFrameListPtr prevOverflowFrames(PresContext(),
1512 prevInFlow->StealOverflowFrames());
1513 if (prevOverflowFrames) {
1514 // Tables are special; they can have repeated header/footer
1515 // frames on mFrames at this point.
1516 NS_ASSERTION(mFrames.IsEmpty() || GetType() == nsGkAtoms::tableFrame,
1517 "bad overflow list");
1518 // When pushing and pulling frames we need to check for whether any
1519 // views need to be reparented.
1520 nsContainerFrame::ReparentFrameViewList(*prevOverflowFrames,
1521 prevInFlow, this);
1522 mFrames.AppendFrames(this, *prevOverflowFrames);
1523 result = true;
1527 // It's also possible that we have an overflow list for ourselves.
1528 return DrainSelfOverflowList() || result;
1531 bool
1532 nsContainerFrame::DrainSelfOverflowList()
1534 AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
1535 if (overflowFrames) {
1536 mFrames.AppendFrames(nullptr, *overflowFrames);
1537 return true;
1539 return false;
1542 nsIFrame*
1543 nsContainerFrame::GetNextInFlowChild(ContinuationTraversingState& aState,
1544 bool* aIsInOverflow)
1546 nsContainerFrame*& nextInFlow = aState.mNextInFlow;
1547 while (nextInFlow) {
1548 // See if there is any frame in the container
1549 nsIFrame* frame = nextInFlow->mFrames.FirstChild();
1550 if (frame) {
1551 if (aIsInOverflow) {
1552 *aIsInOverflow = false;
1554 return frame;
1556 // No frames in the principal list, try its overflow list
1557 nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
1558 if (overflowFrames) {
1559 if (aIsInOverflow) {
1560 *aIsInOverflow = true;
1562 return overflowFrames->FirstChild();
1564 nextInFlow = static_cast<nsContainerFrame*>(nextInFlow->GetNextInFlow());
1566 return nullptr;
1569 nsIFrame*
1570 nsContainerFrame::PullNextInFlowChild(ContinuationTraversingState& aState)
1572 bool isInOverflow;
1573 nsIFrame* frame = GetNextInFlowChild(aState, &isInOverflow);
1574 if (frame) {
1575 nsContainerFrame* nextInFlow = aState.mNextInFlow;
1576 if (isInOverflow) {
1577 nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
1578 overflowFrames->RemoveFirstChild();
1579 if (overflowFrames->IsEmpty()) {
1580 nextInFlow->DestroyOverflowList();
1582 } else {
1583 nextInFlow->mFrames.RemoveFirstChild();
1586 // Move the frame to the principal frame list of this container
1587 mFrames.AppendFrame(this, frame);
1588 // AppendFrame has reparented the frame, we need
1589 // to reparent the frame view then.
1590 nsContainerFrame::ReparentFrameView(frame, nextInFlow, this);
1592 return frame;
1595 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsContainerFrame* aFrame,
1596 bool aWalkOOFFrames,
1597 bool aSkipOverflowContainerChildren)
1598 : mOverflowContList(nullptr),
1599 mPrevOverflowCont(nullptr),
1600 mSentry(nullptr),
1601 mParent(aFrame),
1602 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
1603 mWalkOOFFrames(aWalkOOFFrames)
1605 NS_PRECONDITION(aFrame, "null frame pointer");
1606 SetupOverflowContList();
1609 void
1610 nsOverflowContinuationTracker::SetupOverflowContList()
1612 NS_PRECONDITION(mParent, "null frame pointer");
1613 NS_PRECONDITION(!mOverflowContList, "already have list");
1614 nsContainerFrame* nif =
1615 static_cast<nsContainerFrame*>(mParent->GetNextInFlow());
1616 if (nif) {
1617 mOverflowContList = nif->GetPropTableFrames(
1618 nsContainerFrame::OverflowContainersProperty());
1619 if (mOverflowContList) {
1620 mParent = nif;
1621 SetUpListWalker();
1624 if (!mOverflowContList) {
1625 mOverflowContList = mParent->GetPropTableFrames(
1626 nsContainerFrame::ExcessOverflowContainersProperty());
1627 if (mOverflowContList) {
1628 SetUpListWalker();
1634 * Helper function to walk past overflow continuations whose prev-in-flow
1635 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1637 void
1638 nsOverflowContinuationTracker::SetUpListWalker()
1640 NS_ASSERTION(!mSentry && !mPrevOverflowCont,
1641 "forgot to reset mSentry or mPrevOverflowCont");
1642 if (mOverflowContList) {
1643 nsIFrame* cur = mOverflowContList->FirstChild();
1644 if (mSkipOverflowContainerChildren) {
1645 while (cur && (cur->GetPrevInFlow()->GetStateBits()
1646 & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1647 mPrevOverflowCont = cur;
1648 cur = cur->GetNextSibling();
1650 while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1651 == mWalkOOFFrames)) {
1652 mPrevOverflowCont = cur;
1653 cur = cur->GetNextSibling();
1656 if (cur) {
1657 mSentry = cur->GetPrevInFlow();
1663 * Helper function to step forward through the overflow continuations list.
1664 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1665 * as appropriate. May only be called when we have already set up an
1666 * mOverflowContList; mOverflowContList cannot be null.
1668 void
1669 nsOverflowContinuationTracker::StepForward()
1671 NS_PRECONDITION(mOverflowContList, "null list");
1673 // Step forward
1674 if (mPrevOverflowCont) {
1675 mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
1677 else {
1678 mPrevOverflowCont = mOverflowContList->FirstChild();
1681 // Skip over oof or non-oof frames as appropriate
1682 if (mSkipOverflowContainerChildren) {
1683 nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
1684 while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1685 == mWalkOOFFrames)) {
1686 mPrevOverflowCont = cur;
1687 cur = cur->GetNextSibling();
1691 // Set up the sentry
1692 mSentry = (mPrevOverflowCont->GetNextSibling())
1693 ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
1694 : nullptr;
1697 nsresult
1698 nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
1699 nsReflowStatus& aReflowStatus)
1701 NS_PRECONDITION(aOverflowCont, "null frame pointer");
1702 NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
1703 !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
1704 "shouldn't insert frame that doesn't match walker type");
1705 NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
1706 "overflow containers must have a prev-in-flow");
1707 nsresult rv = NS_OK;
1708 bool reparented = false;
1709 nsPresContext* presContext = aOverflowCont->PresContext();
1710 bool addToList = !mSentry || aOverflowCont != mSentry->GetNextInFlow();
1712 // If we have a list and aOverflowCont is already in it then don't try to
1713 // add it again.
1714 if (addToList && aOverflowCont->GetParent() == mParent &&
1715 (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
1716 mOverflowContList && mOverflowContList->ContainsFrame(aOverflowCont)) {
1717 addToList = false;
1718 mPrevOverflowCont = aOverflowCont->GetPrevSibling();
1721 if (addToList) {
1722 if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
1723 // aOverflowCont is in some other overflow container list,
1724 // steal it first
1725 NS_ASSERTION(!(mOverflowContList &&
1726 mOverflowContList->ContainsFrame(aOverflowCont)),
1727 "overflow containers out of order");
1728 rv = aOverflowCont->GetParent()->StealFrame(aOverflowCont);
1729 NS_ENSURE_SUCCESS(rv, rv);
1731 else {
1732 aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
1734 if (!mOverflowContList) {
1735 mOverflowContList = new (presContext->PresShell()) nsFrameList();
1736 mParent->SetPropTableFrames(mOverflowContList,
1737 nsContainerFrame::ExcessOverflowContainersProperty());
1738 SetUpListWalker();
1740 if (aOverflowCont->GetParent() != mParent) {
1741 nsContainerFrame::ReparentFrameView(aOverflowCont,
1742 aOverflowCont->GetParent(),
1743 mParent);
1744 reparented = true;
1747 // If aOverflowCont has a prev/next-in-flow that might be in
1748 // mOverflowContList we need to find it and insert after/before it to
1749 // maintain the order amongst next-in-flows in this list.
1750 nsIFrame* pif = aOverflowCont->GetPrevInFlow();
1751 nsIFrame* nif = aOverflowCont->GetNextInFlow();
1752 if ((pif && pif->GetParent() == mParent && pif != mPrevOverflowCont) ||
1753 (nif && nif->GetParent() == mParent && mPrevOverflowCont)) {
1754 for (nsFrameList::Enumerator e(*mOverflowContList); !e.AtEnd(); e.Next()) {
1755 nsIFrame* f = e.get();
1756 if (f == pif) {
1757 mPrevOverflowCont = pif;
1758 break;
1760 if (f == nif) {
1761 mPrevOverflowCont = f->GetPrevSibling();
1762 break;
1767 mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
1768 aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
1771 // If we need to reflow it, mark it dirty
1772 if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
1773 aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
1775 // It's in our list, just step forward
1776 StepForward();
1777 NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
1778 (mSkipOverflowContainerChildren &&
1779 (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
1780 (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
1781 "OverflowContTracker in unexpected state");
1783 if (addToList) {
1784 // Convert all non-overflow-container continuations of aOverflowCont
1785 // into overflow containers and move them to our overflow
1786 // tracker. This preserves the invariant that the next-continuations
1787 // of an overflow container are also overflow containers.
1788 nsIFrame* f = aOverflowCont->GetNextContinuation();
1789 if (f && (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
1790 (!reparented && f->GetParent() == mParent) ||
1791 (reparented && f->GetParent() != mParent))) {
1792 if (!(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1793 rv = f->GetParent()->StealFrame(f);
1794 NS_ENSURE_SUCCESS(rv, rv);
1796 Insert(f, aReflowStatus);
1799 return rv;
1802 void
1803 nsOverflowContinuationTracker::BeginFinish(nsIFrame* aChild)
1805 NS_PRECONDITION(aChild, "null ptr");
1806 NS_PRECONDITION(aChild->GetNextInFlow(),
1807 "supposed to call Finish *before* deleting next-in-flow!");
1808 for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) {
1809 // We'll update these in EndFinish after the next-in-flows are gone.
1810 if (f == mPrevOverflowCont) {
1811 mSentry = nullptr;
1812 mPrevOverflowCont = nullptr;
1813 break;
1815 if (f == mSentry) {
1816 mSentry = nullptr;
1817 break;
1822 void
1823 nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
1825 if (!mOverflowContList) {
1826 return;
1828 // Forget mOverflowContList if it was deleted.
1829 nsPresContext* pc = aChild->PresContext();
1830 FramePropertyTable* propTable = pc->PropertyTable();
1831 nsFrameList* eoc = static_cast<nsFrameList*>(propTable->Get(mParent,
1832 nsContainerFrame::ExcessOverflowContainersProperty()));
1833 if (eoc != mOverflowContList) {
1834 nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent,
1835 nsContainerFrame::OverflowContainersProperty()));
1836 if (oc != mOverflowContList) {
1837 // mOverflowContList was deleted
1838 mPrevOverflowCont = nullptr;
1839 mSentry = nullptr;
1840 mParent = aChild->GetParent();
1841 mOverflowContList = nullptr;
1842 SetupOverflowContList();
1843 return;
1846 // The list survived, update mSentry if needed.
1847 if (!mSentry) {
1848 if (!mPrevOverflowCont) {
1849 SetUpListWalker();
1850 } else {
1851 mozilla::AutoRestore<nsIFrame*> saved(mPrevOverflowCont);
1852 // step backward to make StepForward() use our current mPrevOverflowCont
1853 mPrevOverflowCont = mPrevOverflowCont->GetPrevSibling();
1854 StepForward();
1859 /////////////////////////////////////////////////////////////////////////////
1860 // Debugging
1862 #ifdef DEBUG_FRAME_DUMP
1863 void
1864 nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
1866 nsCString str;
1867 ListGeneric(str, aPrefix, aFlags);
1869 // Output the children
1870 bool outputOneList = false;
1871 ChildListIterator lists(this);
1872 for (; !lists.IsDone(); lists.Next()) {
1873 if (outputOneList) {
1874 str += aPrefix;
1876 if (lists.CurrentID() != kPrincipalList) {
1877 if (!outputOneList) {
1878 str += "\n";
1879 str += aPrefix;
1881 str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
1882 &GetChildList(lists.CurrentID()));
1884 fprintf_stderr(out, "%s<\n", str.get());
1885 str = "";
1886 nsFrameList::Enumerator childFrames(lists.CurrentList());
1887 for (; !childFrames.AtEnd(); childFrames.Next()) {
1888 nsIFrame* kid = childFrames.get();
1889 // Verify the child frame's parent frame pointer is correct
1890 NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
1892 // Have the child frame list
1893 nsCString pfx(aPrefix);
1894 pfx += " ";
1895 kid->List(out, pfx.get(), aFlags);
1897 fprintf_stderr(out, "%s>\n", aPrefix);
1898 outputOneList = true;
1901 if (!outputOneList) {
1902 fprintf_stderr(out, "%s<>\n", str.get());
1905 #endif