1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Pierre Phaneuf <pp@ludusdesign.com>
24 * Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 /* base class #1 for rendering objects that have child lists */
42 #include "nsContainerFrame.h"
43 #include "nsHTMLContainerFrame.h"
44 #include "nsIContent.h"
45 #include "nsIDocument.h"
46 #include "nsPresContext.h"
47 #include "nsIRenderingContext.h"
48 #include "nsStyleContext.h"
51 #include "nsGUIEvent.h"
52 #include "nsStyleConsts.h"
54 #include "nsHTMLContainerFrame.h"
55 #include "nsFrameManager.h"
56 #include "nsIPresShell.h"
58 #include "nsGkAtoms.h"
59 #include "nsCSSAnonBoxes.h"
60 #include "nsIViewManager.h"
61 #include "nsIWidget.h"
62 #include "nsGfxCIID.h"
63 #include "nsIServiceManager.h"
64 #include "nsCSSRendering.h"
65 #include "nsTransform2D.h"
67 #include "nsLayoutErrors.h"
68 #include "nsDisplayList.h"
69 #include "nsContentErrors.h"
70 #include "nsIEventStateManager.h"
71 #include "nsListControlFrame.h"
72 #include "nsIBaseWindow.h"
73 #include "nsThemeConstants.h"
74 #include "nsCSSFrameConstructor.h"
75 #include "nsThemeConstants.h"
76 #include "mozilla/dom/Element.h"
84 using namespace mozilla
;
85 using namespace mozilla::dom
;
87 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame
)
89 nsContainerFrame::~nsContainerFrame()
93 NS_QUERYFRAME_HEAD(nsContainerFrame
)
94 NS_QUERYFRAME_ENTRY(nsContainerFrame
)
95 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame
)
98 nsContainerFrame::Init(nsIContent
* aContent
,
100 nsIFrame
* aPrevInFlow
)
102 nsresult rv
= nsSplittableFrame::Init(aContent
, aParent
, aPrevInFlow
);
104 // Make sure we copy bits from our prev-in-flow that will affect
105 // us. A continuation for a container frame needs to know if it
106 // has a child with a view so that we'll properly reposition it.
107 if (aPrevInFlow
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)
108 AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW
);
114 nsContainerFrame::SetInitialChildList(nsIAtom
* aListName
,
115 nsFrameList
& aChildList
)
118 if (mFrames
.NotEmpty()) {
119 // We already have child frames which means we've already been
121 NS_NOTREACHED("unexpected second call to SetInitialChildList");
122 result
= NS_ERROR_UNEXPECTED
;
123 } else if (aListName
) {
124 // All we know about is the unnamed principal child list
125 NS_NOTREACHED("unknown frame list");
126 result
= NS_ERROR_INVALID_ARG
;
129 nsFrame::VerifyDirtyBitSet(aChildList
);
131 mFrames
.SetFrames(aChildList
);
138 nsContainerFrame::AppendFrames(nsIAtom
* aListName
,
139 nsFrameList
& aFrameList
)
141 if (nsnull
!= aListName
) {
143 if (aListName
!= nsGkAtoms::nextBidi
)
146 NS_ERROR("unexpected child list");
147 return NS_ERROR_INVALID_ARG
;
150 if (aFrameList
.NotEmpty()) {
151 mFrames
.AppendFrames(this, aFrameList
);
153 // Ask the parent frame to reflow me.
155 if (nsnull
== aListName
)
158 PresContext()->PresShell()->
159 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
160 NS_FRAME_HAS_DIRTY_CHILDREN
);
167 nsContainerFrame::InsertFrames(nsIAtom
* aListName
,
168 nsIFrame
* aPrevFrame
,
169 nsFrameList
& aFrameList
)
171 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
172 "inserting after sibling frame with different parent");
174 if (nsnull
!= aListName
) {
176 if (aListName
!= nsGkAtoms::nextBidi
)
179 NS_ERROR("unexpected child list");
180 return NS_ERROR_INVALID_ARG
;
183 if (aFrameList
.NotEmpty()) {
184 // Insert frames after aPrevFrame
185 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
188 if (nsnull
== aListName
)
191 PresContext()->PresShell()->
192 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
193 NS_FRAME_HAS_DIRTY_CHILDREN
);
200 nsContainerFrame::RemoveFrame(nsIAtom
* aListName
,
203 if (nsnull
!= aListName
) {
205 if (nsGkAtoms::nextBidi
!= aListName
)
208 NS_ERROR("unexpected child list");
209 return NS_ERROR_INVALID_ARG
;
214 // Loop and destroy the frame and all of its continuations.
215 // If the frame we are removing is a brFrame, we need a reflow so
216 // the line the brFrame was on can attempt to pull up any frames
217 // that can fit from lines below it.
218 PRBool generateReflowCommand
= PR_TRUE
;
220 if (nsGkAtoms::nextBidi
== aListName
) {
221 generateReflowCommand
= PR_FALSE
;
224 nsContainerFrame
* parent
= static_cast<nsContainerFrame
*>(aOldFrame
->GetParent());
226 // When the parent is an inline frame we have a simple task - just
227 // remove the frame from its parents list and generate a reflow
229 nsIFrame
* oldFrameNextContinuation
= aOldFrame
->GetNextContinuation();
230 //XXXfr probably should use StealFrame here. I'm not sure if we need to
231 // check the overflow lists atm, but we'll need a prescontext lookup
232 // for overflow containers once we can split abspos elements with
233 // inline containing blocks.
234 if (parent
== this) {
235 if (!parent
->mFrames
.DestroyFrameIfPresent(aOldFrame
)) {
236 // Try to remove it from our overflow list, if we have one.
237 // The simplest way is to reuse StealFrame.
238 StealFrame(PresContext(), aOldFrame
, PR_TRUE
);
239 aOldFrame
->Destroy();
242 // This recursive call takes care of all continuations after aOldFrame,
243 // so we don't need to loop anymore.
244 parent
->RemoveFrame(nsnull
, aOldFrame
);
247 aOldFrame
= oldFrameNextContinuation
;
249 parent
= static_cast<nsContainerFrame
*>(aOldFrame
->GetParent());
253 if (generateReflowCommand
) {
254 PresContext()->PresShell()->
255 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
256 NS_FRAME_HAS_DIRTY_CHILDREN
);
264 nsContainerFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
266 // Prevent event dispatch during destruction
268 GetView()->SetClientData(nsnull
);
271 // Delete the primary child list
272 mFrames
.DestroyFramesFrom(aDestructRoot
);
274 // Destroy auxiliary frame lists
275 nsPresContext
* prescontext
= PresContext();
277 DestroyOverflowList(prescontext
, aDestructRoot
);
279 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
280 nsFrameList
* frameList
=
281 RemovePropTableFrames(prescontext
, OverflowContainersProperty());
283 frameList
->DestroyFrom(aDestructRoot
);
285 frameList
= RemovePropTableFrames(prescontext
,
286 ExcessOverflowContainersProperty());
288 frameList
->DestroyFrom(aDestructRoot
);
291 // Destroy the frame and remove the flow pointers
292 nsSplittableFrame::DestroyFrom(aDestructRoot
);
295 /////////////////////////////////////////////////////////////////////////////
296 // Child frame enumeration
299 nsContainerFrame::GetChildList(nsIAtom
* aListName
) const
301 // We only know about the unnamed principal child list and the overflow
303 if (nsnull
== aListName
) {
307 if (nsGkAtoms::overflowList
== aListName
) {
308 nsFrameList
* frameList
= GetOverflowFrames();
309 return frameList
? *frameList
: nsFrameList::EmptyList();
312 if (nsGkAtoms::overflowContainersList
== aListName
) {
313 nsFrameList
* list
= GetPropTableFrames(PresContext(),
314 OverflowContainersProperty());
315 return list
? *list
: nsFrameList::EmptyList();
318 if (nsGkAtoms::excessOverflowContainersList
== aListName
) {
319 nsFrameList
* list
= GetPropTableFrames(PresContext(),
320 ExcessOverflowContainersProperty());
321 return list
? *list
: nsFrameList::EmptyList();
324 return nsFrameList::EmptyList();
327 #define NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX 0
328 #define NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX 1
329 #define NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX 2
330 // If adding/removing lists, don't forget to update count in .h file
334 nsContainerFrame::GetAdditionalChildListName(PRInt32 aIndex
) const
336 if (NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX
== aIndex
)
337 return nsGkAtoms::overflowList
;
338 else if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
339 if (NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX
== aIndex
)
340 return nsGkAtoms::overflowContainersList
;
341 else if (NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX
== aIndex
)
342 return nsGkAtoms::excessOverflowContainersList
;
347 /////////////////////////////////////////////////////////////////////////////
351 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
352 const nsRect
& aDirtyRect
,
353 const nsDisplayListSet
& aLists
)
355 nsresult rv
= DisplayBorderBackgroundOutline(aBuilder
, aLists
);
356 NS_ENSURE_SUCCESS(rv
, rv
);
358 return BuildDisplayListForNonBlockChildren(aBuilder
, aDirtyRect
, aLists
);
362 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
363 const nsRect
& aDirtyRect
,
364 const nsDisplayListSet
& aLists
,
367 nsIFrame
* kid
= mFrames
.FirstChild();
368 // Put each child's background directly onto the content list
369 nsDisplayListSet
set(aLists
, aLists
.Content());
370 // The children should be in content order
372 nsresult rv
= BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, aFlags
);
373 NS_ENSURE_SUCCESS(rv
, rv
);
374 kid
= kid
->GetNextSibling();
380 nsContainerFrame::ChildIsDirty(nsIFrame
* aChild
)
382 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
386 nsContainerFrame::IsLeaf() const
392 nsContainerFrame::PeekOffsetNoAmount(PRBool aForward
, PRInt32
* aOffset
)
394 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
395 // Don't allow the caret to stay in an empty (leaf) container frame.
400 nsContainerFrame::PeekOffsetCharacter(PRBool aForward
, PRInt32
* aOffset
)
402 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
403 // Don't allow the caret to stay in an empty (leaf) container frame.
407 /////////////////////////////////////////////////////////////////////////////
408 // Helper member functions
411 * Position the view associated with |aKidFrame|, if there is one. A
412 * container frame should call this method after positioning a frame,
413 * but before |Reflow|.
416 nsContainerFrame::PositionFrameView(nsIFrame
* aKidFrame
)
418 nsIFrame
* parentFrame
= aKidFrame
->GetParent();
419 if (!aKidFrame
->HasView() || !parentFrame
)
422 nsIView
* view
= aKidFrame
->GetView();
423 nsIViewManager
* vm
= view
->GetViewManager();
425 nsIView
* ancestorView
= parentFrame
->GetClosestView(&pt
);
427 if (ancestorView
!= view
->GetParent()) {
428 NS_ASSERTION(ancestorView
== view
->GetParent()->GetParent(),
429 "Allowed only one anonymous view between frames");
430 // parentFrame is responsible for positioning aKidFrame's view
435 pt
+= aKidFrame
->GetPosition();
436 vm
->MoveViewTo(view
, pt
.x
, pt
.y
);
440 GetPresContextContainerWidget(nsPresContext
* aPresContext
)
442 nsCOMPtr
<nsISupports
> container
= aPresContext
->Document()->GetContainer();
443 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(container
);
447 nsCOMPtr
<nsIWidget
> mainWidget
;
448 baseWindow
->GetMainWidget(getter_AddRefs(mainWidget
));
453 IsTopLevelWidget(nsIWidget
* aWidget
)
455 nsWindowType windowType
;
456 aWidget
->GetWindowType(windowType
);
457 return windowType
== eWindowType_toplevel
||
458 windowType
== eWindowType_dialog
||
459 windowType
== eWindowType_sheet
;
460 // popups aren't toplevel so they're not handled here
464 nsContainerFrame::SyncWindowProperties(nsPresContext
* aPresContext
,
469 if (!aView
|| !nsCSSRendering::IsCanvasFrame(aFrame
) || !aView
->HasWidget())
472 nsIWidget
* windowWidget
= GetPresContextContainerWidget(aPresContext
);
473 if (!windowWidget
|| !IsTopLevelWidget(windowWidget
))
476 nsIViewManager
* vm
= aView
->GetViewManager();
478 vm
->GetRootView(rootView
);
480 if (aView
!= rootView
)
483 Element
* rootElement
= aPresContext
->Document()->GetRootElement();
484 if (!rootElement
|| !rootElement
->IsXUL()) {
485 // Scrollframes use native widgets which don't work well with
486 // translucent windows, at least in Windows XP. So if the document
487 // has a root scrollrame it's useless to try to make it transparent,
488 // we'll just get something broken.
489 // nsCSSFrameConstructor::ConstructRootFrame constructs root
490 // scrollframes whenever the root element is not a XUL element, so
491 // we test for that here. We can't just call
492 // presShell->GetRootScrollFrame() since that might not have
493 // been constructed yet.
494 // We can change this to allow translucent toplevel HTML documents
495 // (e.g. to do something like Dashboard widgets), once we
496 // have broad support for translucent scrolled documents, but be
497 // careful because apparently some Firefox extensions expect
498 // openDialog("something.html") to produce an opaque window
499 // even if the HTML doesn't have a background-color set.
503 nsIFrame
*rootFrame
= aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
507 nsTransparencyMode mode
= nsLayoutUtils::GetFrameTransparency(aFrame
, rootFrame
);
508 nsIWidget
* viewWidget
= aView
->GetWidget();
509 viewWidget
->SetTransparencyMode(mode
);
510 windowWidget
->SetWindowShadowStyle(rootFrame
->GetStyleUIReset()->mWindowShadow
);
515 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
518 const nsRect
* aCombinedArea
,
525 NS_ASSERTION(aCombinedArea
, "Combined area must be passed in now");
527 // Make sure the view is sized and positioned correctly
528 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
529 PositionFrameView(aFrame
);
532 if (0 == (aFlags
& NS_FRAME_NO_SIZE_VIEW
)) {
533 nsIViewManager
* vm
= aView
->GetViewManager();
535 vm
->ResizeView(aView
, *aCombinedArea
, PR_TRUE
);
540 nsContainerFrame::SyncFrameViewProperties(nsPresContext
* aPresContext
,
542 nsStyleContext
* aStyleContext
,
546 NS_ASSERTION(!aStyleContext
|| aFrame
->GetStyleContext() == aStyleContext
,
547 "Wrong style context for frame?");
553 nsIViewManager
* vm
= aView
->GetViewManager();
555 if (nsnull
== aStyleContext
) {
556 aStyleContext
= aFrame
->GetStyleContext();
559 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
560 if (0 == (aFlags
& NS_FRAME_NO_VISIBILITY
) &&
561 !aFrame
->SupportsVisibilityHidden()) {
562 // See if the view should be hidden or visible
563 vm
->SetViewVisibility(aView
,
564 aStyleContext
->GetStyleVisibility()->IsVisible()
565 ? nsViewVisibility_kShow
: nsViewVisibility_kHide
);
568 // See if the frame is being relatively positioned or absolutely
570 PRBool isPositioned
= aStyleContext
->GetStyleDisplay()->IsPositioned();
573 PRBool autoZIndex
= PR_FALSE
;
576 autoZIndex
= PR_TRUE
;
578 // Make sure z-index is correct
579 const nsStylePosition
* position
= aStyleContext
->GetStylePosition();
581 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
) {
582 zIndex
= position
->mZIndex
.GetIntValue();
583 } else if (position
->mZIndex
.GetUnit() == eStyleUnit_Auto
) {
584 autoZIndex
= PR_TRUE
;
588 vm
->SetViewZIndex(aView
, autoZIndex
, zIndex
, isPositioned
);
591 static nscoord
GetCoord(const nsStyleCoord
& aCoord
, nscoord aIfNotCoord
)
593 return aCoord
.GetUnit() == eStyleUnit_Coord
594 ? aCoord
.GetCoordValue()
599 nsContainerFrame::DoInlineIntrinsicWidth(nsIRenderingContext
*aRenderingContext
,
600 InlineIntrinsicWidthData
*aData
,
601 nsLayoutUtils::IntrinsicWidthType aType
)
604 return; // Already added.
606 NS_PRECONDITION(aType
== nsLayoutUtils::MIN_WIDTH
||
607 aType
== nsLayoutUtils::PREF_WIDTH
, "bad type");
609 mozilla::css::Side startSide
, endSide
;
610 if (GetStyleVisibility()->mDirection
== NS_STYLE_DIRECTION_LTR
) {
611 startSide
= NS_SIDE_LEFT
;
612 endSide
= NS_SIDE_RIGHT
;
614 startSide
= NS_SIDE_RIGHT
;
615 endSide
= NS_SIDE_LEFT
;
618 const nsStylePadding
*stylePadding
= GetStylePadding();
619 const nsStyleBorder
*styleBorder
= GetStyleBorder();
620 const nsStyleMargin
*styleMargin
= GetStyleMargin();
622 // This goes at the beginning no matter how things are broken and how
623 // messy the bidi situations are, since per CSS2.1 section 8.6
624 // (implemented in bug 328168), the startSide border is always on the
626 // This frame is a first-in-flow, but it might have a previous bidi
627 // continuation, in which case that continuation should handle the startSide
629 if (!GetPrevContinuation()) {
630 aData
->currentLine
+=
631 GetCoord(stylePadding
->mPadding
.Get(startSide
), 0) +
632 styleBorder
->GetActualBorderWidth(startSide
) +
633 GetCoord(styleMargin
->mMargin
.Get(startSide
), 0);
636 const nsLineList_iterator
* savedLine
= aData
->line
;
637 nsIFrame
* const savedLineContainer
= aData
->lineContainer
;
639 nsContainerFrame
*lastInFlow
;
640 for (nsContainerFrame
*nif
= this; nif
;
641 nif
= static_cast<nsContainerFrame
*>(nif
->GetNextInFlow())) {
642 for (nsIFrame
*kid
= nif
->mFrames
.FirstChild(); kid
;
643 kid
= kid
->GetNextSibling()) {
644 if (aType
== nsLayoutUtils::MIN_WIDTH
)
645 kid
->AddInlineMinWidth(aRenderingContext
,
646 static_cast<InlineMinWidthData
*>(aData
));
648 kid
->AddInlinePrefWidth(aRenderingContext
,
649 static_cast<InlinePrefWidthData
*>(aData
));
652 // After we advance to our next-in-flow, the stored line and line container
653 // may no longer be correct. Just forget them.
654 aData
->line
= nsnull
;
655 aData
->lineContainer
= nsnull
;
660 aData
->line
= savedLine
;
661 aData
->lineContainer
= savedLineContainer
;
663 // This goes at the end no matter how things are broken and how
664 // messy the bidi situations are, since per CSS2.1 section 8.6
665 // (implemented in bug 328168), the endSide border is always on the
667 // We reached the last-in-flow, but it might have a next bidi
668 // continuation, in which case that continuation should handle
669 // the endSide border.
670 if (!lastInFlow
->GetNextContinuation()) {
671 aData
->currentLine
+=
672 GetCoord(stylePadding
->mPadding
.Get(endSide
), 0) +
673 styleBorder
->GetActualBorderWidth(endSide
) +
674 GetCoord(styleMargin
->mMargin
.Get(endSide
), 0);
679 nsContainerFrame::ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
680 nsSize aCBSize
, nscoord aAvailableWidth
,
681 nsSize aMargin
, nsSize aBorder
,
682 nsSize aPadding
, PRBool aShrinkWrap
)
684 nsSize
result(0xdeadbeef, NS_UNCONSTRAINEDSIZE
);
685 nscoord availBased
= aAvailableWidth
- aMargin
.width
- aBorder
.width
-
687 // replaced elements always shrink-wrap
688 if (aShrinkWrap
|| IsFrameOfType(eReplaced
)) {
689 // don't bother setting it if the result won't be used
690 if (GetStylePosition()->mWidth
.GetUnit() == eStyleUnit_Auto
) {
691 result
.width
= ShrinkWidthToFit(aRenderingContext
, availBased
);
694 result
.width
= availBased
;
700 * Invokes the WillReflow() function, positions the frame and its view (if
701 * requested), and then calls Reflow(). If the reflow succeeds and the child
702 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
705 nsContainerFrame::ReflowChild(nsIFrame
* aKidFrame
,
706 nsPresContext
* aPresContext
,
707 nsHTMLReflowMetrics
& aDesiredSize
,
708 const nsHTMLReflowState
& aReflowState
,
712 nsReflowStatus
& aStatus
,
713 nsOverflowContinuationTracker
* aTracker
)
715 NS_PRECONDITION(aReflowState
.frame
== aKidFrame
, "bad reflow state");
719 // Send the WillReflow() notification, and position the child frame
720 // and its view if requested
721 aKidFrame
->WillReflow(aPresContext
);
723 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
724 if ((aFlags
& NS_FRAME_INVALIDATE_ON_MOVE
) &&
725 !(aKidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) &&
726 aKidFrame
->GetPosition() != nsPoint(aX
, aY
)) {
727 aKidFrame
->InvalidateOverflowRect();
729 aKidFrame
->SetPosition(nsPoint(aX
, aY
));
732 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
733 PositionFrameView(aKidFrame
);
736 // Reflow the child frame
737 result
= aKidFrame
->Reflow(aPresContext
, aDesiredSize
, aReflowState
,
740 // If the reflow was successful and the child frame is complete, delete any
742 if (NS_SUCCEEDED(result
) && NS_FRAME_IS_FULLY_COMPLETE(aStatus
)) {
743 nsIFrame
* kidNextInFlow
= aKidFrame
->GetNextInFlow();
744 if (nsnull
!= kidNextInFlow
) {
745 // Remove all of the childs next-in-flows. Make sure that we ask
746 // the right parent to do the removal (it's possible that the
747 // parent is not this because we are executing pullup code)
748 if (aTracker
) aTracker
->Finish(aKidFrame
);
749 static_cast<nsContainerFrame
*>(kidNextInFlow
->GetParent())
750 ->DeleteNextInFlowChild(aPresContext
, kidNextInFlow
, PR_TRUE
);
758 * Position the views of |aFrame|'s descendants. A container frame
759 * should call this method if it moves a frame after |Reflow|.
762 nsContainerFrame::PositionChildViews(nsIFrame
* aFrame
)
764 if (!(aFrame
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)) {
768 nsIAtom
* childListName
= nsnull
;
769 PRInt32 childListIndex
= 0;
772 // Recursively walk aFrame's child frames
773 nsIFrame
* childFrame
= aFrame
->GetFirstChild(childListName
);
775 // Position the frame's view (if it has one) otherwise recursively
776 // process its children
777 if (childFrame
->HasView()) {
778 PositionFrameView(childFrame
);
780 PositionChildViews(childFrame
);
783 // Get the next sibling child frame
784 childFrame
= childFrame
->GetNextSibling();
787 // also process the additional child lists, but skip the popup list as the
788 // view for popups is managed by the parent. Currently only nsMenuFrame
789 // has a popupList and during layout will call nsMenuPopupFrame::AdjustView.
791 childListName
= aFrame
->GetAdditionalChildListName(childListIndex
++);
792 } while (childListName
== nsGkAtoms::popupList
);
793 } while (childListName
);
797 * The second half of frame reflow. Does the following:
798 * - sets the frame's bounds
799 * - sizes and positions (if requested) the frame's view. If the frame's final
800 * position differs from the current position and the frame itself does not
801 * have a view, then any child frames with views are positioned so they stay
803 * - sets the view's visibility, opacity, content transparency, and clip
804 * - invoked the DidReflow() function
807 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
808 * case. Also implies NS_FRAME_NO_MOVE_VIEW
809 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
810 * don't want to automatically sync the frame and view
811 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
814 nsContainerFrame::FinishReflowChild(nsIFrame
* aKidFrame
,
815 nsPresContext
* aPresContext
,
816 const nsHTMLReflowState
* aReflowState
,
817 const nsHTMLReflowMetrics
& aDesiredSize
,
822 nsPoint curOrigin
= aKidFrame
->GetPosition();
823 nsRect
bounds(aX
, aY
, aDesiredSize
.width
, aDesiredSize
.height
);
825 aKidFrame
->SetRect(bounds
);
827 if (aKidFrame
->HasView()) {
828 nsIView
* view
= aKidFrame
->GetView();
829 // Make sure the frame's view is properly sized and positioned and has
830 // things like opacity correct
831 SyncFrameViewAfterReflow(aPresContext
, aKidFrame
, view
,
832 &aDesiredSize
.mOverflowArea
,
836 if (!(aFlags
& NS_FRAME_NO_MOVE_VIEW
) &&
837 (curOrigin
.x
!= aX
|| curOrigin
.y
!= aY
)) {
838 if (!aKidFrame
->HasView()) {
839 // If the frame has moved, then we need to make sure any child views are
840 // correctly positioned
841 PositionChildViews(aKidFrame
);
844 // We also need to redraw everything associated with the frame
845 // because if the frame's Reflow issued any invalidates, then they
846 // will be at the wrong offset ... note that this includes
847 // invalidates issued against the frame's children, so we need to
848 // invalidate the overflow area too.
849 aKidFrame
->Invalidate(aDesiredSize
.mOverflowArea
);
852 return aKidFrame
->DidReflow(aPresContext
, aReflowState
, NS_FRAME_REFLOW_FINISHED
);
856 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
857 const nsHTMLReflowState
& aReflowState
,
858 nsRect
& aOverflowRect
,
860 nsReflowStatus
& aStatus
)
862 NS_PRECONDITION(aPresContext
, "null pointer");
865 nsFrameList
* overflowContainers
=
866 GetPropTableFrames(aPresContext
,
867 OverflowContainersProperty());
869 NS_ASSERTION(!(overflowContainers
&& GetPrevInFlow()
870 && static_cast<nsContainerFrame
*>(GetPrevInFlow())
871 ->GetPropTableFrames(aPresContext
,
872 ExcessOverflowContainersProperty())),
873 "conflicting overflow containers lists");
875 if (!overflowContainers
) {
876 // Drain excess from previnflow
877 nsContainerFrame
* prev
= (nsContainerFrame
*) GetPrevInFlow();
879 nsFrameList
* excessFrames
=
880 prev
->RemovePropTableFrames(aPresContext
,
881 ExcessOverflowContainersProperty());
883 excessFrames
->ApplySetParent(this);
884 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
, *excessFrames
,
886 overflowContainers
= excessFrames
;
887 rv
= SetPropTableFrames(aPresContext
, overflowContainers
,
888 OverflowContainersProperty());
890 excessFrames
->DestroyFrames();
898 if (!overflowContainers
)
899 return NS_OK
; // nothing to reflow
901 nsOverflowContinuationTracker
tracker(aPresContext
, this, PR_FALSE
, PR_FALSE
);
902 PRBool shouldReflowAllKids
= aReflowState
.ShouldReflowAllKids();
904 for (nsIFrame
* frame
= overflowContainers
->FirstChild(); frame
;
905 frame
= frame
->GetNextSibling()) {
906 if (frame
->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
907 // frame's prevInFlow has moved, skip reflowing this frame;
908 // it will get reflowed once it's been placed
911 // If the available vertical height has changed, we need to reflow
912 // even if the frame isn't dirty.
913 if (shouldReflowAllKids
|| NS_SUBTREE_DIRTY(frame
)) {
915 nsIFrame
* prevInFlow
= frame
->GetPrevInFlow();
916 NS_ASSERTION(prevInFlow
,
917 "overflow container frame must have a prev-in-flow");
918 NS_ASSERTION(frame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
,
919 "overflow container frame must have overflow container bit set");
920 nsRect prevRect
= prevInFlow
->GetRect();
922 // Initialize reflow params
923 nsSize
availSpace(prevRect
.width
, aReflowState
.availableHeight
);
924 nsHTMLReflowMetrics desiredSize
;
925 nsHTMLReflowState
frameState(aPresContext
, aReflowState
,
927 nsReflowStatus frameStatus
= NS_FRAME_COMPLETE
;
930 nsRect oldRect
= frame
->GetRect();
931 nsRect oldOverflow
= frame
->GetOverflowRect();
934 rv
= ReflowChild(frame
, aPresContext
, desiredSize
, frameState
,
935 prevRect
.x
, 0, aFlags
, frameStatus
, &tracker
);
936 NS_ENSURE_SUCCESS(rv
, rv
);
937 //XXXfr Do we need to override any shrinkwrap effects here?
938 // e.g. desiredSize.width = prevRect.width;
939 rv
= FinishReflowChild(frame
, aPresContext
, &frameState
, desiredSize
,
940 prevRect
.x
, 0, aFlags
);
941 NS_ENSURE_SUCCESS(rv
, rv
);
943 // Invalidate if there was a position or size change
944 nsRect rect
= frame
->GetRect();
945 if (rect
!= oldRect
) {
946 nsRect dirtyRect
= oldOverflow
;
947 dirtyRect
.MoveBy(oldRect
.x
, oldRect
.y
);
948 Invalidate(dirtyRect
);
950 dirtyRect
= frame
->GetOverflowRect();
951 dirtyRect
.MoveBy(rect
.x
, rect
.y
);
952 Invalidate(dirtyRect
);
955 // Handle continuations
956 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus
)) {
957 if (frame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
958 // Abspos frames can't cause their parent to be incomplete,
959 // only overflow incomplete.
960 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus
);
963 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus
),
964 "overflow container frames can't be incomplete, only overflow-incomplete");
967 // Acquire a next-in-flow, creating it if necessary
968 nsIFrame
* nif
= frame
->GetNextInFlow();
970 NS_ASSERTION(frameStatus
& NS_FRAME_REFLOW_NEXTINFLOW
,
971 "Someone forgot a REFLOW_NEXTINFLOW flag");
972 rv
= aPresContext
->PresShell()->FrameConstructor()->
973 CreateContinuingFrame(aPresContext
, frame
, this, &nif
);
974 NS_ENSURE_SUCCESS(rv
, rv
);
976 else if (!(nif
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
977 // used to be a normal next-in-flow; steal it from the child list
978 rv
= static_cast<nsContainerFrame
*>(nif
->GetParent())
979 ->StealFrame(aPresContext
, nif
);
980 NS_ENSURE_SUCCESS(rv
, rv
);
983 tracker
.Insert(nif
, frameStatus
);
985 NS_MergeReflowStatusInto(&aStatus
, frameStatus
);
986 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
987 // but we have some unsplittable frames that, when taller than
988 // availableHeight will push zero-height content into a next-in-flow.
991 tracker
.Skip(frame
, aStatus
);
992 if (aReflowState
.mFloatManager
)
993 nsBlockFrame::RecoverFloatsFor(frame
, *aReflowState
.mFloatManager
);
995 ConsiderChildOverflow(aOverflowRect
, frame
);
1002 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
1003 const nsRect
& aDirtyRect
,
1004 const nsDisplayListSet
& aLists
)
1006 nsFrameList
* overflowconts
=
1007 GetPropTableFrames(PresContext(), OverflowContainersProperty());
1008 if (overflowconts
) {
1009 for (nsIFrame
* frame
= overflowconts
->FirstChild(); frame
;
1010 frame
= frame
->GetNextSibling()) {
1011 BuildDisplayListForChild(aBuilder
, frame
, aDirtyRect
, aLists
);
1017 nsContainerFrame::StealFrame(nsPresContext
* aPresContext
,
1019 PRBool aForceNormal
)
1021 PRBool removed
= PR_TRUE
;
1022 if ((aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)
1024 // Try removing from the overflow container list
1025 if (!RemovePropTableFrame(aPresContext
, aChild
,
1026 OverflowContainersProperty())) {
1027 // It must be in the excess overflow container list
1028 removed
= RemovePropTableFrame(aPresContext
, aChild
,
1029 ExcessOverflowContainersProperty());
1033 if (!mFrames
.RemoveFrameIfPresent(aChild
)) {
1035 // We didn't find the child in the parent's principal child list.
1036 // Maybe it's on the overflow list?
1037 nsFrameList
* frameList
= GetOverflowFrames();
1039 removed
= frameList
->RemoveFrameIfPresent(aChild
);
1040 if (frameList
->IsEmpty()) {
1041 DestroyOverflowList(aPresContext
, nsnull
);
1047 NS_POSTCONDITION(removed
, "StealFrame: can't find aChild");
1048 return removed
? NS_OK
: NS_ERROR_UNEXPECTED
;
1052 nsContainerFrame::StealFramesAfter(nsIFrame
* aChild
)
1054 NS_ASSERTION(!aChild
||
1055 !(aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
),
1056 "StealFramesAfter doesn't handle overflow containers");
1057 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame
, "unexpected call");
1060 nsFrameList
copy(mFrames
);
1065 for (nsFrameList::FrameLinkEnumerator
iter(mFrames
); !iter
.AtEnd();
1067 if (iter
.PrevFrame() == aChild
) {
1068 return mFrames
.ExtractTail(iter
);
1072 // We didn't find the child in the principal child list.
1073 // Maybe it's on the overflow list?
1074 nsFrameList
* overflowFrames
= GetOverflowFrames();
1075 if (overflowFrames
) {
1076 for (nsFrameList::FrameLinkEnumerator
iter(*overflowFrames
); !iter
.AtEnd();
1078 if (iter
.PrevFrame() == aChild
) {
1079 return overflowFrames
->ExtractTail(iter
);
1084 NS_ERROR("StealFramesAfter: can't find aChild");
1085 return nsFrameList::EmptyList();
1089 nsContainerFrame::DestroyOverflowList(nsPresContext
* aPresContext
,
1090 nsIFrame
* aDestructRoot
)
1093 RemovePropTableFrames(aPresContext
, OverflowProperty());
1096 list
->DestroyFrom(aDestructRoot
);
1103 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1107 nsContainerFrame::DeleteNextInFlowChild(nsPresContext
* aPresContext
,
1108 nsIFrame
* aNextInFlow
,
1109 PRBool aDeletingEmptyFrames
)
1112 nsIFrame
* prevInFlow
= aNextInFlow
->GetPrevInFlow();
1114 NS_PRECONDITION(prevInFlow
, "bad prev-in-flow");
1116 // If the next-in-flow has a next-in-flow then delete it, too (and
1117 // delete it first).
1118 // Do this in a loop so we don't overflow the stack for frames
1119 // with very many next-in-flows
1120 nsIFrame
* nextNextInFlow
= aNextInFlow
->GetNextInFlow();
1121 if (nextNextInFlow
) {
1122 nsAutoTArray
<nsIFrame
*, 8> frames
;
1123 for (nsIFrame
* f
= nextNextInFlow
; f
; f
= f
->GetNextInFlow()) {
1124 frames
.AppendElement(f
);
1126 for (PRInt32 i
= frames
.Length() - 1; i
>= 0; --i
) {
1127 nsIFrame
* delFrame
= frames
.ElementAt(i
);
1128 static_cast<nsContainerFrame
*>(delFrame
->GetParent())
1129 ->DeleteNextInFlowChild(aPresContext
, delFrame
, aDeletingEmptyFrames
);
1133 aNextInFlow
->InvalidateOverflowRect();
1135 // Take the next-in-flow out of the parent's child list
1139 StealFrame(aPresContext
, aNextInFlow
);
1140 NS_ASSERTION(NS_SUCCEEDED(rv
), "StealFrame failure");
1142 // Delete the next-in-flow frame and its descendants. This will also
1143 // remove it from its next-in-flow/prev-in-flow chain.
1144 aNextInFlow
->Destroy();
1146 NS_POSTCONDITION(!prevInFlow
->GetNextInFlow(), "non null next-in-flow");
1150 * Set the frames on the overflow list
1153 nsContainerFrame::SetOverflowFrames(nsPresContext
* aPresContext
,
1154 const nsFrameList
& aOverflowFrames
)
1156 NS_PRECONDITION(aOverflowFrames
.NotEmpty(), "Shouldn't be called");
1157 nsFrameList
* newList
= new nsFrameList(aOverflowFrames
);
1159 // XXXbz should really destroy the frames here, but callers are holding
1160 // pointers to them.... We should switch all callers to framelists, then
1161 // audit and do that.
1162 return NS_ERROR_OUT_OF_MEMORY
;
1165 aPresContext
->PropertyTable()->Set(this, OverflowProperty(), newList
);
1170 nsContainerFrame::GetPropTableFrames(nsPresContext
* aPresContext
,
1171 const FramePropertyDescriptor
* aProperty
) const
1173 FramePropertyTable
* propTable
= aPresContext
->PropertyTable();
1174 return static_cast<nsFrameList
*>(propTable
->Get(this, aProperty
));
1178 nsContainerFrame::RemovePropTableFrames(nsPresContext
* aPresContext
,
1179 const FramePropertyDescriptor
* aProperty
)
1181 FramePropertyTable
* propTable
= aPresContext
->PropertyTable();
1182 return static_cast<nsFrameList
*>(propTable
->Remove(this, aProperty
));
1186 nsContainerFrame::RemovePropTableFrame(nsPresContext
* aPresContext
,
1188 const FramePropertyDescriptor
* aProperty
)
1190 nsFrameList
* frameList
= RemovePropTableFrames(aPresContext
, aProperty
);
1195 if (!frameList
->RemoveFrameIfPresent(aFrame
)) {
1196 // Found list, but it doesn't have the frame. Put list back.
1197 SetPropTableFrames(aPresContext
, frameList
, aProperty
);
1201 if (frameList
->IsEmpty()) {
1202 // Removed frame and now list is empty. Delete it.
1206 // Removed frame, but list not empty. Put it back.
1207 SetPropTableFrames(aPresContext
, frameList
, aProperty
);
1213 nsContainerFrame::SetPropTableFrames(nsPresContext
* aPresContext
,
1214 nsFrameList
* aFrameList
,
1215 const FramePropertyDescriptor
* aProperty
)
1217 NS_PRECONDITION(aPresContext
&& aProperty
&& aFrameList
, "null ptr");
1219 (aProperty
!= nsContainerFrame::OverflowContainersProperty() &&
1220 aProperty
!= nsContainerFrame::ExcessOverflowContainersProperty()) ||
1221 IsFrameOfType(nsIFrame::eCanContainOverflowContainers
),
1222 "this type of frame can't have overflow containers");
1223 aPresContext
->PropertyTable()->Set(this, aProperty
, aFrameList
);
1228 * Push aFromChild and its next siblings to the next-in-flow. Change the
1229 * geometric parent of each frame that's pushed. If there is no next-in-flow
1230 * the frames are placed on the overflow list (and the geometric parent is
1233 * Updates the next-in-flow's child count. Does <b>not</b> update the
1234 * pusher's child count.
1236 * @param aFromChild the first child frame to push. It is disconnected from
1238 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1239 * an error to push a parent's first child frame
1242 nsContainerFrame::PushChildren(nsPresContext
* aPresContext
,
1243 nsIFrame
* aFromChild
,
1244 nsIFrame
* aPrevSibling
)
1246 NS_PRECONDITION(aFromChild
, "null pointer");
1247 NS_PRECONDITION(aPrevSibling
, "pushing first child");
1248 NS_PRECONDITION(aPrevSibling
->GetNextSibling() == aFromChild
, "bad prev sibling");
1250 // Disconnect aFromChild from its previous sibling
1251 nsFrameList tail
= mFrames
.RemoveFramesAfter(aPrevSibling
);
1253 nsContainerFrame
* nextInFlow
=
1254 static_cast<nsContainerFrame
*>(GetNextInFlow());
1256 // XXX This is not a very good thing to do. If it gets removed
1257 // then remove the copy of this routine that doesn't do this from
1259 // When pushing and pulling frames we need to check for whether any
1260 // views need to be reparented.
1261 for (nsIFrame
* f
= aFromChild
; f
; f
= f
->GetNextSibling()) {
1262 nsHTMLContainerFrame::ReparentFrameView(aPresContext
, f
, this, nextInFlow
);
1264 nextInFlow
->mFrames
.InsertFrames(nextInFlow
, nsnull
, tail
);
1267 // Add the frames to our overflow list
1268 SetOverflowFrames(aPresContext
, tail
);
1273 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1274 * the receiver's overflow list) to the child list.
1276 * Updates this frame's child count and content mapping.
1278 * @return PR_TRUE if any frames were moved and PR_FALSE otherwise
1281 nsContainerFrame::MoveOverflowToChildList(nsPresContext
* aPresContext
)
1283 PRBool result
= PR_FALSE
;
1285 // Check for an overflow list with our prev-in-flow
1286 nsContainerFrame
* prevInFlow
= (nsContainerFrame
*)GetPrevInFlow();
1287 if (nsnull
!= prevInFlow
) {
1288 nsAutoPtr
<nsFrameList
> prevOverflowFrames(prevInFlow
->StealOverflowFrames());
1289 if (prevOverflowFrames
) {
1290 // Tables are special; they can have repeated header/footer
1291 // frames on mFrames at this point.
1292 NS_ASSERTION(mFrames
.IsEmpty() || GetType() == nsGkAtoms::tableFrame
,
1293 "bad overflow list");
1294 // When pushing and pulling frames we need to check for whether any
1295 // views need to be reparented.
1296 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
,
1297 *prevOverflowFrames
,
1299 mFrames
.AppendFrames(this, *prevOverflowFrames
);
1304 // It's also possible that we have an overflow list for ourselves
1305 nsAutoPtr
<nsFrameList
> overflowFrames(StealOverflowFrames());
1306 if (overflowFrames
) {
1307 NS_ASSERTION(mFrames
.NotEmpty(), "overflow list w/o frames");
1308 mFrames
.AppendFrames(nsnull
, *overflowFrames
);
1314 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext
* aPresContext
,
1315 nsContainerFrame
* aFrame
,
1316 PRBool aWalkOOFFrames
,
1317 PRBool aSkipOverflowContainerChildren
)
1318 : mOverflowContList(nsnull
),
1319 mPrevOverflowCont(nsnull
),
1322 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren
),
1323 mWalkOOFFrames(aWalkOOFFrames
)
1325 NS_PRECONDITION(aFrame
, "null frame pointer");
1326 nsContainerFrame
* next
= static_cast<nsContainerFrame
*>
1327 (aFrame
->GetNextInFlow());
1329 mOverflowContList
= next
->GetPropTableFrames(aPresContext
,
1330 nsContainerFrame::OverflowContainersProperty());
1331 if (mOverflowContList
) {
1336 if (!mOverflowContList
) {
1337 mOverflowContList
= mParent
->GetPropTableFrames(aPresContext
,
1338 nsContainerFrame::ExcessOverflowContainersProperty());
1339 if (mOverflowContList
) {
1346 * Helper function to walk past overflow continuations whose prev-in-flow
1347 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1350 nsOverflowContinuationTracker::SetUpListWalker()
1352 NS_ASSERTION(!mSentry
&& !mPrevOverflowCont
,
1353 "forgot to reset mSentry or mPrevOverflowCont");
1354 if (mOverflowContList
) {
1355 nsIFrame
* cur
= mOverflowContList
->FirstChild();
1356 if (mSkipOverflowContainerChildren
) {
1357 while (cur
&& (cur
->GetPrevInFlow()->GetStateBits()
1358 & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1359 mPrevOverflowCont
= cur
;
1360 cur
= cur
->GetNextSibling();
1362 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1363 == mWalkOOFFrames
)) {
1364 mPrevOverflowCont
= cur
;
1365 cur
= cur
->GetNextSibling();
1369 mSentry
= cur
->GetPrevInFlow();
1375 * Helper function to step forward through the overflow continuations list.
1376 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1377 * as appropriate. May only be called when we have already set up an
1378 * mOverflowContList; mOverflowContList cannot be null.
1381 nsOverflowContinuationTracker::StepForward()
1383 NS_PRECONDITION(mOverflowContList
, "null list");
1386 if (mPrevOverflowCont
) {
1387 mPrevOverflowCont
= mPrevOverflowCont
->GetNextSibling();
1390 mPrevOverflowCont
= mOverflowContList
->FirstChild();
1393 // Skip over oof or non-oof frames as appropriate
1394 if (mSkipOverflowContainerChildren
) {
1395 nsIFrame
* cur
= mPrevOverflowCont
->GetNextSibling();
1396 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1397 == mWalkOOFFrames
)) {
1398 mPrevOverflowCont
= cur
;
1399 cur
= cur
->GetNextSibling();
1403 // Set up the sentry
1404 mSentry
= (mPrevOverflowCont
->GetNextSibling())
1405 ? mPrevOverflowCont
->GetNextSibling()->GetPrevInFlow()
1410 nsOverflowContinuationTracker::Insert(nsIFrame
* aOverflowCont
,
1411 nsReflowStatus
& aReflowStatus
)
1413 NS_PRECONDITION(aOverflowCont
, "null frame pointer");
1414 NS_PRECONDITION(!mSkipOverflowContainerChildren
|| mWalkOOFFrames
==
1415 !!(aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
),
1416 "shouldn't insert frame that doesn't match walker type");
1417 NS_PRECONDITION(aOverflowCont
->GetPrevInFlow(),
1418 "overflow containers must have a prev-in-flow");
1419 nsresult rv
= NS_OK
;
1420 PRBool convertedToOverflowContainer
= PR_FALSE
;
1421 nsPresContext
* presContext
= aOverflowCont
->PresContext();
1422 if (!mSentry
|| aOverflowCont
!= mSentry
->GetNextInFlow()) {
1423 // Not in our list, so we need to add it
1424 if (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) {
1425 // aOverflowCont is in some other overflow container list,
1427 NS_ASSERTION(!(mOverflowContList
&&
1428 mOverflowContList
->ContainsFrame(aOverflowCont
)),
1429 "overflow containers out of order");
1430 rv
= static_cast<nsContainerFrame
*>(aOverflowCont
->GetParent())
1431 ->StealFrame(presContext
, aOverflowCont
);
1432 NS_ENSURE_SUCCESS(rv
, rv
);
1435 aOverflowCont
->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
);
1436 convertedToOverflowContainer
= PR_TRUE
;
1438 if (!mOverflowContList
) {
1439 mOverflowContList
= new nsFrameList();
1440 rv
= mParent
->SetPropTableFrames(presContext
, mOverflowContList
,
1441 nsContainerFrame::ExcessOverflowContainersProperty());
1442 NS_ENSURE_SUCCESS(rv
, rv
);
1445 if (aOverflowCont
->GetParent() != mParent
) {
1446 nsHTMLContainerFrame::ReparentFrameView(presContext
, aOverflowCont
,
1447 aOverflowCont
->GetParent(),
1450 mOverflowContList
->InsertFrame(mParent
, mPrevOverflowCont
, aOverflowCont
);
1451 aReflowStatus
|= NS_FRAME_REFLOW_NEXTINFLOW
;
1454 // If we need to reflow it, mark it dirty
1455 if (aReflowStatus
& NS_FRAME_REFLOW_NEXTINFLOW
)
1456 aOverflowCont
->AddStateBits(NS_FRAME_IS_DIRTY
);
1458 // It's in our list, just step forward
1460 NS_ASSERTION(mPrevOverflowCont
== aOverflowCont
||
1461 (mSkipOverflowContainerChildren
&&
1462 (mPrevOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) !=
1463 (aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)),
1464 "OverflowContTracker in unexpected state");
1466 if (convertedToOverflowContainer
) {
1467 // Convert all non-overflow-container continuations of aOverflowCont
1468 // into overflow containers and move them to our overflow
1469 // tracker. This preserves the invariant that the next-continuations
1470 // of an overflow container are also overflow containers.
1471 nsIFrame
* f
= aOverflowCont
->GetNextContinuation();
1472 if (f
&& !(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1473 nsContainerFrame
* parent
= static_cast<nsContainerFrame
*>(f
->GetParent());
1474 rv
= parent
->StealFrame(presContext
, f
);
1475 NS_ENSURE_SUCCESS(rv
, rv
);
1476 Insert(f
, aReflowStatus
);
1483 nsOverflowContinuationTracker::Finish(nsIFrame
* aChild
)
1485 NS_PRECONDITION(aChild
, "null ptr");
1486 NS_PRECONDITION(aChild
->GetNextInFlow(),
1487 "supposed to call Finish *before* deleting next-in-flow!");
1489 for (nsIFrame
* f
= aChild
; f
; f
= f
->GetNextInFlow()) {
1490 // Make sure we drop all references if the only frame
1491 // in the overflow containers list is about to be destroyed
1492 if (mOverflowContList
&&
1493 mOverflowContList
->FirstChild() == f
->GetNextInFlow() &&
1494 !f
->GetNextInFlow()->GetNextSibling()) {
1495 mOverflowContList
= nsnull
;
1496 mPrevOverflowCont
= nsnull
;
1498 mParent
= static_cast<nsContainerFrame
*>(f
->GetParent());
1503 nsIFrame
* prevOverflowCont
= mPrevOverflowCont
;
1505 if (mPrevOverflowCont
== f
->GetNextInFlow()) {
1506 // Pull mPrevOverflowChild back to aChild's prevSibling:
1507 // aChild will be removed from our list by our caller
1508 mPrevOverflowCont
= prevOverflowCont
;
1514 /////////////////////////////////////////////////////////////////////////////
1519 nsContainerFrame::List(FILE* out
, PRInt32 aIndent
) const
1521 IndentBy(out
, aIndent
);
1523 #ifdef DEBUG_waterson
1524 fprintf(out
, " [parent=%p]", static_cast<void*>(mParent
));
1527 fprintf(out
, " [view=%p]", static_cast<void*>(GetView()));
1529 if (GetNextSibling()) {
1530 fprintf(out
, " next=%p", static_cast<void*>(GetNextSibling()));
1532 if (nsnull
!= GetPrevContinuation()) {
1533 fprintf(out
, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
1535 if (nsnull
!= GetNextContinuation()) {
1536 fprintf(out
, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
1538 void* IBsibling
= Properties().Get(IBSplitSpecialSibling());
1540 fprintf(out
, " IBSplitSpecialSibling=%p", IBsibling
);
1542 void* IBprevsibling
= Properties().Get(IBSplitSpecialPrevSibling());
1543 if (IBprevsibling
) {
1544 fprintf(out
, " IBSplitSpecialPrevSibling=%p", IBprevsibling
);
1546 fprintf(out
, " {%d,%d,%d,%d}", mRect
.x
, mRect
.y
, mRect
.width
, mRect
.height
);
1548 fprintf(out
, " [state=%016llx]", mState
);
1550 fprintf(out
, " [content=%p]", static_cast<void*>(mContent
));
1551 nsContainerFrame
* f
= const_cast<nsContainerFrame
*>(this);
1552 if (f
->HasOverflowRect()) {
1553 nsRect overflowArea
= f
->GetOverflowRect();
1554 fprintf(out
, " [overflow=%d,%d,%d,%d]", overflowArea
.x
, overflowArea
.y
,
1555 overflowArea
.width
, overflowArea
.height
);
1557 fprintf(out
, " [sc=%p]", static_cast<void*>(mStyleContext
));
1558 nsIAtom
* pseudoTag
= mStyleContext
->GetPseudo();
1560 nsAutoString atomString
;
1561 pseudoTag
->ToString(atomString
);
1562 fprintf(out
, " pst=%s",
1563 NS_LossyConvertUTF16toASCII(atomString
).get());
1566 // Output the children
1567 nsIAtom
* listName
= nsnull
;
1568 PRInt32 listIndex
= 0;
1569 PRBool outputOneList
= PR_FALSE
;
1571 nsIFrame
* kid
= GetFirstChild(listName
);
1572 if (nsnull
!= kid
) {
1573 if (outputOneList
) {
1574 IndentBy(out
, aIndent
);
1576 outputOneList
= PR_TRUE
;
1578 if (nsnull
!= listName
) {
1579 listName
->ToString(tmp
);
1580 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
1583 while (nsnull
!= kid
) {
1584 // Verify the child frame's parent frame pointer is correct
1585 NS_ASSERTION(kid
->GetParent() == (nsIFrame
*)this, "bad parent frame pointer");
1587 // Have the child frame list
1588 kid
->List(out
, aIndent
+ 1);
1589 kid
= kid
->GetNextSibling();
1591 IndentBy(out
, aIndent
);
1594 listName
= GetAdditionalChildListName(listIndex
++);
1595 } while(nsnull
!= listName
);
1597 if (!outputOneList
) {