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"
83 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame
)
85 nsContainerFrame::~nsContainerFrame()
89 NS_QUERYFRAME_HEAD(nsContainerFrame
)
90 NS_QUERYFRAME_ENTRY(nsContainerFrame
)
91 NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame
)
94 nsContainerFrame::Init(nsIContent
* aContent
,
96 nsIFrame
* aPrevInFlow
)
98 nsresult rv
= nsSplittableFrame::Init(aContent
, aParent
, aPrevInFlow
);
100 // Make sure we copy bits from our prev-in-flow that will affect
101 // us. A continuation for a container frame needs to know if it
102 // has a child with a view so that we'll properly reposition it.
103 if (aPrevInFlow
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)
104 AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW
);
110 nsContainerFrame::SetInitialChildList(nsIAtom
* aListName
,
111 nsFrameList
& aChildList
)
114 if (mFrames
.NotEmpty()) {
115 // We already have child frames which means we've already been
117 NS_NOTREACHED("unexpected second call to SetInitialChildList");
118 result
= NS_ERROR_UNEXPECTED
;
119 } else if (aListName
) {
120 // All we know about is the unnamed principal child list
121 NS_NOTREACHED("unknown frame list");
122 result
= NS_ERROR_INVALID_ARG
;
125 nsFrame::VerifyDirtyBitSet(aChildList
);
127 mFrames
.SetFrames(aChildList
);
134 nsContainerFrame::AppendFrames(nsIAtom
* aListName
,
135 nsFrameList
& aFrameList
)
137 if (nsnull
!= aListName
) {
139 if (aListName
!= nsGkAtoms::nextBidi
)
142 NS_ERROR("unexpected child list");
143 return NS_ERROR_INVALID_ARG
;
146 if (aFrameList
.NotEmpty()) {
147 mFrames
.AppendFrames(this, aFrameList
);
149 // Ask the parent frame to reflow me.
151 if (nsnull
== aListName
)
154 PresContext()->PresShell()->
155 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
156 NS_FRAME_HAS_DIRTY_CHILDREN
);
163 nsContainerFrame::InsertFrames(nsIAtom
* aListName
,
164 nsIFrame
* aPrevFrame
,
165 nsFrameList
& aFrameList
)
167 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
168 "inserting after sibling frame with different parent");
170 if (nsnull
!= aListName
) {
172 if (aListName
!= nsGkAtoms::nextBidi
)
175 NS_ERROR("unexpected child list");
176 return NS_ERROR_INVALID_ARG
;
179 if (aFrameList
.NotEmpty()) {
180 // Insert frames after aPrevFrame
181 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
184 if (nsnull
== aListName
)
187 PresContext()->PresShell()->
188 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
189 NS_FRAME_HAS_DIRTY_CHILDREN
);
196 nsContainerFrame::RemoveFrame(nsIAtom
* aListName
,
199 if (nsnull
!= aListName
) {
201 if (nsGkAtoms::nextBidi
!= aListName
)
204 NS_ERROR("unexpected child list");
205 return NS_ERROR_INVALID_ARG
;
210 // Loop and destroy the frame and all of its continuations.
211 // If the frame we are removing is a brFrame, we need a reflow so
212 // the line the brFrame was on can attempt to pull up any frames
213 // that can fit from lines below it.
214 PRBool generateReflowCommand
= PR_TRUE
;
216 if (nsGkAtoms::nextBidi
== aListName
) {
217 generateReflowCommand
= PR_FALSE
;
220 nsContainerFrame
* parent
= static_cast<nsContainerFrame
*>(aOldFrame
->GetParent());
222 // When the parent is an inline frame we have a simple task - just
223 // remove the frame from its parents list and generate a reflow
225 nsIFrame
* oldFrameNextContinuation
= aOldFrame
->GetNextContinuation();
226 //XXXfr probably should use StealFrame here. I'm not sure if we need to
227 // check the overflow lists atm, but we'll need a prescontext lookup
228 // for overflow containers once we can split abspos elements with
229 // inline containing blocks.
230 if (parent
== this) {
231 if (!parent
->mFrames
.DestroyFrameIfPresent(aOldFrame
)) {
232 // Try to remove it from our overflow list, if we have one.
233 // The simplest way is to reuse StealFrame.
234 StealFrame(PresContext(), aOldFrame
, PR_TRUE
);
235 aOldFrame
->Destroy();
238 // This recursive call takes care of all continuations after aOldFrame,
239 // so we don't need to loop anymore.
240 parent
->RemoveFrame(nsnull
, aOldFrame
);
243 aOldFrame
= oldFrameNextContinuation
;
245 parent
= static_cast<nsContainerFrame
*>(aOldFrame
->GetParent());
249 if (generateReflowCommand
) {
250 PresContext()->PresShell()->
251 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
252 NS_FRAME_HAS_DIRTY_CHILDREN
);
260 nsContainerFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
262 // Prevent event dispatch during destruction
264 GetView()->SetClientData(nsnull
);
267 // Delete the primary child list
268 mFrames
.DestroyFramesFrom(aDestructRoot
);
270 // Destroy auxiliary frame lists
271 nsPresContext
* prescontext
= PresContext();
273 DestroyOverflowList(prescontext
, aDestructRoot
);
275 if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
276 nsFrameList
* frameList
= RemovePropTableFrames(prescontext
,
277 nsGkAtoms::overflowContainersProperty
);
279 frameList
->DestroyFrom(aDestructRoot
);
281 frameList
= RemovePropTableFrames(prescontext
,
282 nsGkAtoms::excessOverflowContainersProperty
);
284 frameList
->DestroyFrom(aDestructRoot
);
287 if (IsGeneratedContentFrame()) {
288 // Make sure all the content nodes for the generated content inside
289 // this frame know it's going away.
290 // See also nsCSSFrameConstructor::CreateGeneratedContentFrame which
291 // created this frame.
292 nsCOMArray
<nsIContent
>* generatedContent
=
293 static_cast<nsCOMArray
<nsIContent
>*>(
294 UnsetProperty(nsGkAtoms::generatedContent
));
296 if (generatedContent
) {
297 for (int i
= generatedContent
->Count() - 1; i
>= 0; --i
) {
298 nsIContent
* content
= generatedContent
->ObjectAt(i
);
299 // Tell the ESM that this content is going away now, so it'll update
300 // its hover content, etc.
301 PresContext()->EventStateManager()->
302 ContentRemoved(content
->GetCurrentDoc(), content
);
303 content
->UnbindFromTree();
305 delete generatedContent
;
309 // Destroy the frame and remove the flow pointers
310 nsSplittableFrame::DestroyFrom(aDestructRoot
);
313 /////////////////////////////////////////////////////////////////////////////
314 // Child frame enumeration
317 nsContainerFrame::GetChildList(nsIAtom
* aListName
) const
319 // We only know about the unnamed principal child list and the overflow
321 if (nsnull
== aListName
) {
325 if (nsGkAtoms::overflowList
== aListName
) {
326 nsFrameList
* frameList
= GetOverflowFrames();
327 return frameList
? *frameList
: nsFrameList::EmptyList();
330 if (nsGkAtoms::overflowContainersList
== aListName
) {
331 nsFrameList
* list
= GetPropTableFrames(PresContext(),
332 nsGkAtoms::overflowContainersProperty
);
333 return list
? *list
: nsFrameList::EmptyList();
336 if (nsGkAtoms::excessOverflowContainersList
== aListName
) {
337 nsFrameList
* list
= GetPropTableFrames(PresContext(),
338 nsGkAtoms::excessOverflowContainersProperty
);
339 return list
? *list
: nsFrameList::EmptyList();
342 return nsFrameList::EmptyList();
345 #define NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX 0
346 #define NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX 1
347 #define NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX 2
348 // If adding/removing lists, don't forget to update count in .h file
352 nsContainerFrame::GetAdditionalChildListName(PRInt32 aIndex
) const
354 if (NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX
== aIndex
)
355 return nsGkAtoms::overflowList
;
356 else if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers
)) {
357 if (NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX
== aIndex
)
358 return nsGkAtoms::overflowContainersList
;
359 else if (NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX
== aIndex
)
360 return nsGkAtoms::excessOverflowContainersList
;
365 /////////////////////////////////////////////////////////////////////////////
369 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
370 const nsRect
& aDirtyRect
,
371 const nsDisplayListSet
& aLists
)
373 nsresult rv
= DisplayBorderBackgroundOutline(aBuilder
, aLists
);
374 NS_ENSURE_SUCCESS(rv
, rv
);
376 return BuildDisplayListForNonBlockChildren(aBuilder
, aDirtyRect
, aLists
);
380 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
381 const nsRect
& aDirtyRect
,
382 const nsDisplayListSet
& aLists
,
385 nsIFrame
* kid
= mFrames
.FirstChild();
386 // Put each child's background directly onto the content list
387 nsDisplayListSet
set(aLists
, aLists
.Content());
388 // The children should be in content order
390 nsresult rv
= BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, aFlags
);
391 NS_ENSURE_SUCCESS(rv
, rv
);
392 kid
= kid
->GetNextSibling();
398 nsContainerFrame::ChildIsDirty(nsIFrame
* aChild
)
400 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN
);
404 nsContainerFrame::IsLeaf() const
410 nsContainerFrame::PeekOffsetNoAmount(PRBool aForward
, PRInt32
* aOffset
)
412 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
413 // Don't allow the caret to stay in an empty (leaf) container frame.
418 nsContainerFrame::PeekOffsetCharacter(PRBool aForward
, PRInt32
* aOffset
)
420 NS_ASSERTION (aOffset
&& *aOffset
<= 1, "aOffset out of range");
421 // Don't allow the caret to stay in an empty (leaf) container frame.
425 /////////////////////////////////////////////////////////////////////////////
426 // Helper member functions
429 * Position the view associated with |aKidFrame|, if there is one. A
430 * container frame should call this method after positioning a frame,
431 * but before |Reflow|.
434 nsContainerFrame::PositionFrameView(nsIFrame
* aKidFrame
)
436 nsIFrame
* parentFrame
= aKidFrame
->GetParent();
437 if (!aKidFrame
->HasView() || !parentFrame
)
440 nsIView
* view
= aKidFrame
->GetView();
441 nsIViewManager
* vm
= view
->GetViewManager();
443 nsIView
* ancestorView
= parentFrame
->GetClosestView(&pt
);
445 if (ancestorView
!= view
->GetParent()) {
446 NS_ASSERTION(ancestorView
== view
->GetParent()->GetParent(),
447 "Allowed only one anonymous view between frames");
448 // parentFrame is responsible for positioning aKidFrame's view
453 pt
+= aKidFrame
->GetPosition();
454 vm
->MoveViewTo(view
, pt
.x
, pt
.y
);
458 GetPresContextContainerWidget(nsPresContext
* aPresContext
)
460 nsCOMPtr
<nsISupports
> container
= aPresContext
->Document()->GetContainer();
461 nsCOMPtr
<nsIBaseWindow
> baseWindow
= do_QueryInterface(container
);
465 nsCOMPtr
<nsIWidget
> mainWidget
;
466 baseWindow
->GetMainWidget(getter_AddRefs(mainWidget
));
471 IsTopLevelWidget(nsIWidget
* aWidget
)
473 nsWindowType windowType
;
474 aWidget
->GetWindowType(windowType
);
475 return windowType
== eWindowType_toplevel
||
476 windowType
== eWindowType_dialog
||
477 windowType
== eWindowType_sheet
;
478 // popups aren't toplevel so they're not handled here
482 nsContainerFrame::SyncWindowProperties(nsPresContext
* aPresContext
,
487 if (!aView
|| !nsCSSRendering::IsCanvasFrame(aFrame
) || !aView
->HasWidget())
490 nsIWidget
* windowWidget
= GetPresContextContainerWidget(aPresContext
);
491 if (!windowWidget
|| !IsTopLevelWidget(windowWidget
))
494 nsIViewManager
* vm
= aView
->GetViewManager();
496 vm
->GetRootView(rootView
);
498 if (aView
!= rootView
)
501 nsIContent
* rootContent
= aPresContext
->Document()->GetRootContent();
502 if (!rootContent
|| !rootContent
->IsXUL()) {
503 // Scrollframes use native widgets which don't work well with
504 // translucent windows, at least in Windows XP. So if the document
505 // has a root scrollrame it's useless to try to make it transparent,
506 // we'll just get something broken.
507 // nsCSSFrameConstructor::ConstructRootFrame constructs root
508 // scrollframes whenever the root element is not a XUL element, so
509 // we test for that here. We can't just call
510 // presShell->GetRootScrollFrame() since that might not have
511 // been constructed yet.
512 // We can change this to allow translucent toplevel HTML documents
513 // (e.g. to do something like Dashboard widgets), once we
514 // have broad support for translucent scrolled documents, but be
515 // careful because apparently some Firefox extensions expect
516 // openDialog("something.html") to produce an opaque window
517 // even if the HTML doesn't have a background-color set.
521 nsIFrame
*rootFrame
= aPresContext
->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
525 nsTransparencyMode mode
= nsLayoutUtils::GetFrameTransparency(aFrame
, rootFrame
);
526 nsIWidget
* viewWidget
= aView
->GetWidget();
527 viewWidget
->SetTransparencyMode(mode
);
528 windowWidget
->SetWindowShadowStyle(rootFrame
->GetStyleUIReset()->mWindowShadow
);
533 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
536 const nsRect
* aCombinedArea
,
543 NS_ASSERTION(aCombinedArea
, "Combined area must be passed in now");
545 // Make sure the view is sized and positioned correctly
546 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
547 PositionFrameView(aFrame
);
550 if (0 == (aFlags
& NS_FRAME_NO_SIZE_VIEW
)) {
551 nsIViewManager
* vm
= aView
->GetViewManager();
553 vm
->ResizeView(aView
, *aCombinedArea
, PR_TRUE
);
558 nsContainerFrame::SyncFrameViewProperties(nsPresContext
* aPresContext
,
560 nsStyleContext
* aStyleContext
,
564 NS_ASSERTION(!aStyleContext
|| aFrame
->GetStyleContext() == aStyleContext
,
565 "Wrong style context for frame?");
571 nsIViewManager
* vm
= aView
->GetViewManager();
573 /* If this frame has a -moz-transform property, tell it to invalidate on a scroll
574 * rather than doing a BitBlt.
576 if (aFrame
->GetStyleDisplay()->HasTransform())
577 aView
->SetInvalidateFrameOnScroll();
579 if (nsnull
== aStyleContext
) {
580 aStyleContext
= aFrame
->GetStyleContext();
583 // Make sure visibility is correct. This only affects nsSubdocumentFrame.
584 if (0 == (aFlags
& NS_FRAME_NO_VISIBILITY
) &&
585 !aFrame
->SupportsVisibilityHidden()) {
586 // See if the view should be hidden or visible
587 vm
->SetViewVisibility(aView
,
588 aStyleContext
->GetStyleVisibility()->IsVisible()
589 ? nsViewVisibility_kShow
: nsViewVisibility_kHide
);
592 // See if the frame is being relatively positioned or absolutely
594 PRBool isPositioned
= aStyleContext
->GetStyleDisplay()->IsPositioned();
597 PRBool autoZIndex
= PR_FALSE
;
600 autoZIndex
= PR_TRUE
;
602 // Make sure z-index is correct
603 const nsStylePosition
* position
= aStyleContext
->GetStylePosition();
605 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
) {
606 zIndex
= position
->mZIndex
.GetIntValue();
607 } else if (position
->mZIndex
.GetUnit() == eStyleUnit_Auto
) {
608 autoZIndex
= PR_TRUE
;
612 vm
->SetViewZIndex(aView
, autoZIndex
, zIndex
, isPositioned
);
616 nsContainerFrame::FrameNeedsView(nsIFrame
* aFrame
)
618 // XXX Check needed because frame construction can't properly figure out when
619 // a frame is the child of a scrollframe
620 if (aFrame
->GetStyleContext()->GetPseudo() ==
621 nsCSSAnonBoxes::scrolledContent
) {
624 return aFrame
->NeedsView() || aFrame
->GetStyleDisplay()->HasTransform();
627 static nscoord
GetCoord(const nsStyleCoord
& aCoord
, nscoord aIfNotCoord
)
629 return aCoord
.GetUnit() == eStyleUnit_Coord
630 ? aCoord
.GetCoordValue()
635 nsContainerFrame::DoInlineIntrinsicWidth(nsIRenderingContext
*aRenderingContext
,
636 InlineIntrinsicWidthData
*aData
,
637 nsLayoutUtils::IntrinsicWidthType aType
)
640 return; // Already added.
642 NS_PRECONDITION(aType
== nsLayoutUtils::MIN_WIDTH
||
643 aType
== nsLayoutUtils::PREF_WIDTH
, "bad type");
645 PRUint8 startSide
, endSide
;
646 if (GetStyleVisibility()->mDirection
== NS_STYLE_DIRECTION_LTR
) {
647 startSide
= NS_SIDE_LEFT
;
648 endSide
= NS_SIDE_RIGHT
;
650 startSide
= NS_SIDE_RIGHT
;
651 endSide
= NS_SIDE_LEFT
;
654 const nsStylePadding
*stylePadding
= GetStylePadding();
655 const nsStyleBorder
*styleBorder
= GetStyleBorder();
656 const nsStyleMargin
*styleMargin
= GetStyleMargin();
658 // This goes at the beginning no matter how things are broken and how
659 // messy the bidi situations are, since per CSS2.1 section 8.6
660 // (implemented in bug 328168), the startSide border is always on the
662 // This frame is a first-in-flow, but it might have a previous bidi
663 // continuation, in which case that continuation should handle the startSide
665 if (!GetPrevContinuation()) {
666 aData
->currentLine
+=
667 GetCoord(stylePadding
->mPadding
.Get(startSide
), 0) +
668 styleBorder
->GetActualBorderWidth(startSide
) +
669 GetCoord(styleMargin
->mMargin
.Get(startSide
), 0);
672 const nsLineList_iterator
* savedLine
= aData
->line
;
673 nsIFrame
* const savedLineContainer
= aData
->lineContainer
;
675 nsContainerFrame
*lastInFlow
;
676 for (nsContainerFrame
*nif
= this; nif
;
677 nif
= static_cast<nsContainerFrame
*>(nif
->GetNextInFlow())) {
678 for (nsIFrame
*kid
= nif
->mFrames
.FirstChild(); kid
;
679 kid
= kid
->GetNextSibling()) {
680 if (aType
== nsLayoutUtils::MIN_WIDTH
)
681 kid
->AddInlineMinWidth(aRenderingContext
,
682 static_cast<InlineMinWidthData
*>(aData
));
684 kid
->AddInlinePrefWidth(aRenderingContext
,
685 static_cast<InlinePrefWidthData
*>(aData
));
688 // After we advance to our next-in-flow, the stored line and line container
689 // may no longer be correct. Just forget them.
690 aData
->line
= nsnull
;
691 aData
->lineContainer
= nsnull
;
696 aData
->line
= savedLine
;
697 aData
->lineContainer
= savedLineContainer
;
699 // This goes at the end no matter how things are broken and how
700 // messy the bidi situations are, since per CSS2.1 section 8.6
701 // (implemented in bug 328168), the endSide border is always on the
703 // We reached the last-in-flow, but it might have a next bidi
704 // continuation, in which case that continuation should handle
705 // the endSide border.
706 if (!lastInFlow
->GetNextContinuation()) {
707 aData
->currentLine
+=
708 GetCoord(stylePadding
->mPadding
.Get(endSide
), 0) +
709 styleBorder
->GetActualBorderWidth(endSide
) +
710 GetCoord(styleMargin
->mMargin
.Get(endSide
), 0);
715 nsContainerFrame::ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
716 nsSize aCBSize
, nscoord aAvailableWidth
,
717 nsSize aMargin
, nsSize aBorder
,
718 nsSize aPadding
, PRBool aShrinkWrap
)
720 nsSize
result(0xdeadbeef, NS_UNCONSTRAINEDSIZE
);
721 nscoord availBased
= aAvailableWidth
- aMargin
.width
- aBorder
.width
-
723 // replaced elements always shrink-wrap
724 if (aShrinkWrap
|| IsFrameOfType(eReplaced
)) {
725 // don't bother setting it if the result won't be used
726 if (GetStylePosition()->mWidth
.GetUnit() == eStyleUnit_Auto
) {
727 result
.width
= ShrinkWidthToFit(aRenderingContext
, availBased
);
730 result
.width
= availBased
;
736 * Invokes the WillReflow() function, positions the frame and its view (if
737 * requested), and then calls Reflow(). If the reflow succeeds and the child
738 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
741 nsContainerFrame::ReflowChild(nsIFrame
* aKidFrame
,
742 nsPresContext
* aPresContext
,
743 nsHTMLReflowMetrics
& aDesiredSize
,
744 const nsHTMLReflowState
& aReflowState
,
748 nsReflowStatus
& aStatus
,
749 nsOverflowContinuationTracker
* aTracker
)
751 NS_PRECONDITION(aReflowState
.frame
== aKidFrame
, "bad reflow state");
755 // Send the WillReflow() notification, and position the child frame
756 // and its view if requested
757 aKidFrame
->WillReflow(aPresContext
);
759 if (NS_FRAME_NO_MOVE_FRAME
!= (aFlags
& NS_FRAME_NO_MOVE_FRAME
)) {
760 if ((aFlags
& NS_FRAME_INVALIDATE_ON_MOVE
) &&
761 !(aKidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) &&
762 aKidFrame
->GetPosition() != nsPoint(aX
, aY
)) {
763 aKidFrame
->InvalidateOverflowRect();
765 aKidFrame
->SetPosition(nsPoint(aX
, aY
));
768 if (0 == (aFlags
& NS_FRAME_NO_MOVE_VIEW
)) {
769 PositionFrameView(aKidFrame
);
772 // Reflow the child frame
773 result
= aKidFrame
->Reflow(aPresContext
, aDesiredSize
, aReflowState
,
776 // If the reflow was successful and the child frame is complete, delete any
778 if (NS_SUCCEEDED(result
) && NS_FRAME_IS_FULLY_COMPLETE(aStatus
)) {
779 nsIFrame
* kidNextInFlow
= aKidFrame
->GetNextInFlow();
780 if (nsnull
!= kidNextInFlow
) {
781 // Remove all of the childs next-in-flows. Make sure that we ask
782 // the right parent to do the removal (it's possible that the
783 // parent is not this because we are executing pullup code)
784 if (aTracker
) aTracker
->Finish(aKidFrame
);
785 static_cast<nsContainerFrame
*>(kidNextInFlow
->GetParent())
786 ->DeleteNextInFlowChild(aPresContext
, kidNextInFlow
, PR_TRUE
);
794 * Position the views of |aFrame|'s descendants. A container frame
795 * should call this method if it moves a frame after |Reflow|.
798 nsContainerFrame::PositionChildViews(nsIFrame
* aFrame
)
800 if (!(aFrame
->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW
)) {
804 nsIAtom
* childListName
= nsnull
;
805 PRInt32 childListIndex
= 0;
808 // Recursively walk aFrame's child frames
809 nsIFrame
* childFrame
= aFrame
->GetFirstChild(childListName
);
811 // Position the frame's view (if it has one) otherwise recursively
812 // process its children
813 if (childFrame
->HasView()) {
814 PositionFrameView(childFrame
);
816 PositionChildViews(childFrame
);
819 // Get the next sibling child frame
820 childFrame
= childFrame
->GetNextSibling();
823 // also process the additional child lists, but skip the popup list as the
824 // view for popups is managed by the parent. Currently only nsMenuFrame
825 // has a popupList and during layout will call nsMenuPopupFrame::AdjustView.
827 childListName
= aFrame
->GetAdditionalChildListName(childListIndex
++);
828 } while (childListName
== nsGkAtoms::popupList
);
829 } while (childListName
);
833 * The second half of frame reflow. Does the following:
834 * - sets the frame's bounds
835 * - sizes and positions (if requested) the frame's view. If the frame's final
836 * position differs from the current position and the frame itself does not
837 * have a view, then any child frames with views are positioned so they stay
839 * - sets the view's visibility, opacity, content transparency, and clip
840 * - invoked the DidReflow() function
843 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
844 * case. Also implies NS_FRAME_NO_MOVE_VIEW
845 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
846 * don't want to automatically sync the frame and view
847 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
850 nsContainerFrame::FinishReflowChild(nsIFrame
* aKidFrame
,
851 nsPresContext
* aPresContext
,
852 const nsHTMLReflowState
* aReflowState
,
853 const nsHTMLReflowMetrics
& aDesiredSize
,
858 nsPoint curOrigin
= aKidFrame
->GetPosition();
859 nsRect
bounds(aX
, aY
, aDesiredSize
.width
, aDesiredSize
.height
);
861 aKidFrame
->SetRect(bounds
);
863 if (aKidFrame
->HasView()) {
864 nsIView
* view
= aKidFrame
->GetView();
865 // Make sure the frame's view is properly sized and positioned and has
866 // things like opacity correct
867 SyncFrameViewAfterReflow(aPresContext
, aKidFrame
, view
,
868 &aDesiredSize
.mOverflowArea
,
872 if (!(aFlags
& NS_FRAME_NO_MOVE_VIEW
) &&
873 (curOrigin
.x
!= aX
|| curOrigin
.y
!= aY
)) {
874 if (!aKidFrame
->HasView()) {
875 // If the frame has moved, then we need to make sure any child views are
876 // correctly positioned
877 PositionChildViews(aKidFrame
);
880 // We also need to redraw everything associated with the frame
881 // because if the frame's Reflow issued any invalidates, then they
882 // will be at the wrong offset ... note that this includes
883 // invalidates issued against the frame's children, so we need to
884 // invalidate the overflow area too.
885 aKidFrame
->Invalidate(aDesiredSize
.mOverflowArea
);
888 return aKidFrame
->DidReflow(aPresContext
, aReflowState
, NS_FRAME_REFLOW_FINISHED
);
892 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
893 const nsHTMLReflowState
& aReflowState
,
894 nsRect
& aOverflowRect
,
896 nsReflowStatus
& aStatus
)
898 NS_PRECONDITION(aPresContext
, "null pointer");
901 nsFrameList
* overflowContainers
=
902 GetPropTableFrames(aPresContext
,
903 nsGkAtoms::overflowContainersProperty
);
905 NS_ASSERTION(!(overflowContainers
&& GetPrevInFlow()
906 && static_cast<nsContainerFrame
*>(GetPrevInFlow())
907 ->GetPropTableFrames(aPresContext
,
908 nsGkAtoms::excessOverflowContainersProperty
)),
909 "conflicting overflow containers lists");
911 if (!overflowContainers
) {
912 // Drain excess from previnflow
913 nsContainerFrame
* prev
= (nsContainerFrame
*) GetPrevInFlow();
915 nsFrameList
* excessFrames
=
916 prev
->RemovePropTableFrames(aPresContext
,
917 nsGkAtoms::excessOverflowContainersProperty
);
919 excessFrames
->ApplySetParent(this);
920 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
, *excessFrames
,
922 overflowContainers
= excessFrames
;
923 rv
= SetPropTableFrames(aPresContext
, overflowContainers
,
924 nsGkAtoms::overflowContainersProperty
);
926 excessFrames
->DestroyFrames();
934 if (!overflowContainers
)
935 return NS_OK
; // nothing to reflow
937 nsOverflowContinuationTracker
tracker(aPresContext
, this, PR_FALSE
, PR_FALSE
);
938 for (nsIFrame
* frame
= overflowContainers
->FirstChild(); frame
;
939 frame
= frame
->GetNextSibling()) {
940 if (frame
->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
941 // frame's prevInFlow has moved, skip reflowing this frame;
942 // it will get reflowed once it's been placed
945 if (NS_SUBTREE_DIRTY(frame
)) {
947 nsIFrame
* prevInFlow
= frame
->GetPrevInFlow();
948 NS_ASSERTION(prevInFlow
,
949 "overflow container frame must have a prev-in-flow");
950 NS_ASSERTION(frame
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
,
951 "overflow container frame must have overflow container bit set");
952 nsRect prevRect
= prevInFlow
->GetRect();
954 // Initialize reflow params
955 nsSize
availSpace(prevRect
.width
, aReflowState
.availableHeight
);
956 nsHTMLReflowMetrics desiredSize
;
957 nsHTMLReflowState
frameState(aPresContext
, aReflowState
,
959 nsReflowStatus frameStatus
= NS_FRAME_COMPLETE
;
962 nsRect oldRect
= frame
->GetRect();
963 nsRect oldOverflow
= frame
->GetOverflowRect();
966 rv
= ReflowChild(frame
, aPresContext
, desiredSize
, frameState
,
967 prevRect
.x
, 0, aFlags
, frameStatus
, &tracker
);
968 NS_ENSURE_SUCCESS(rv
, rv
);
969 //XXXfr Do we need to override any shrinkwrap effects here?
970 // e.g. desiredSize.width = prevRect.width;
971 rv
= FinishReflowChild(frame
, aPresContext
, &frameState
, desiredSize
,
972 prevRect
.x
, 0, aFlags
);
973 NS_ENSURE_SUCCESS(rv
, rv
);
975 // Invalidate if there was a position or size change
976 nsRect rect
= frame
->GetRect();
977 if (rect
!= oldRect
) {
978 nsRect dirtyRect
= oldOverflow
;
979 dirtyRect
.MoveBy(oldRect
.x
, oldRect
.y
);
980 Invalidate(dirtyRect
);
982 dirtyRect
= frame
->GetOverflowRect();
983 dirtyRect
.MoveBy(rect
.x
, rect
.y
);
984 Invalidate(dirtyRect
);
987 // Handle continuations
988 if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus
)) {
989 if (frame
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
990 // Abspos frames can't cause their parent to be incomplete,
991 // only overflow incomplete.
992 NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus
);
995 NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus
),
996 "overflow container frames can't be incomplete, only overflow-incomplete");
999 // Acquire a next-in-flow, creating it if necessary
1000 nsIFrame
* nif
= frame
->GetNextInFlow();
1002 NS_ASSERTION(frameStatus
& NS_FRAME_REFLOW_NEXTINFLOW
,
1003 "Someone forgot a REFLOW_NEXTINFLOW flag");
1004 rv
= aPresContext
->PresShell()->FrameConstructor()->
1005 CreateContinuingFrame(aPresContext
, frame
, this, &nif
);
1006 NS_ENSURE_SUCCESS(rv
, rv
);
1008 else if (!(nif
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1009 // used to be a normal next-in-flow; steal it from the child list
1010 rv
= static_cast<nsContainerFrame
*>(nif
->GetParent())
1011 ->StealFrame(aPresContext
, nif
);
1012 NS_ENSURE_SUCCESS(rv
, rv
);
1015 tracker
.Insert(nif
, frameStatus
);
1017 NS_MergeReflowStatusInto(&aStatus
, frameStatus
);
1018 // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1019 // but we have some unsplittable frames that, when taller than
1020 // availableHeight will push zero-height content into a next-in-flow.
1023 tracker
.Skip(frame
, aStatus
);
1024 if (aReflowState
.mFloatManager
)
1025 nsBlockFrame::RecoverFloatsFor(frame
, *aReflowState
.mFloatManager
);
1027 ConsiderChildOverflow(aOverflowRect
, frame
);
1034 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
1035 const nsRect
& aDirtyRect
,
1036 const nsDisplayListSet
& aLists
)
1038 nsFrameList
* overflowconts
= GetPropTableFrames(PresContext(),
1039 nsGkAtoms::overflowContainersProperty
);
1040 if (overflowconts
) {
1041 for (nsIFrame
* frame
= overflowconts
->FirstChild(); frame
;
1042 frame
= frame
->GetNextSibling()) {
1043 BuildDisplayListForChild(aBuilder
, frame
, aDirtyRect
, aLists
);
1049 nsContainerFrame::StealFrame(nsPresContext
* aPresContext
,
1051 PRBool aForceNormal
)
1053 PRBool removed
= PR_TRUE
;
1054 if ((aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)
1056 // Try removing from the overflow container list
1057 if (!RemovePropTableFrame(aPresContext
, aChild
,
1058 nsGkAtoms::overflowContainersProperty
)) {
1059 // It must be in the excess overflow container list
1060 removed
= RemovePropTableFrame(aPresContext
, aChild
,
1061 nsGkAtoms::excessOverflowContainersProperty
);
1065 if (!mFrames
.RemoveFrameIfPresent(aChild
)) {
1067 // We didn't find the child in the parent's principal child list.
1068 // Maybe it's on the overflow list?
1069 nsFrameList
* frameList
= GetOverflowFrames();
1071 removed
= frameList
->RemoveFrameIfPresent(aChild
);
1072 if (frameList
->IsEmpty()) {
1073 DestroyOverflowList(aPresContext
);
1079 NS_POSTCONDITION(removed
, "StealFrame: can't find aChild");
1080 return removed
? NS_OK
: NS_ERROR_UNEXPECTED
;
1084 nsContainerFrame::StealFramesAfter(nsIFrame
* aChild
)
1086 NS_ASSERTION(!aChild
||
1087 !(aChild
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
),
1088 "StealFramesAfter doesn't handle overflow containers");
1089 NS_ASSERTION(GetType() != nsGkAtoms::blockFrame
, "unexpected call");
1092 nsFrameList
copy(mFrames
);
1097 for (nsFrameList::FrameLinkEnumerator
iter(mFrames
); !iter
.AtEnd();
1099 if (iter
.PrevFrame() == aChild
) {
1100 return mFrames
.ExtractTail(iter
);
1104 // We didn't find the child in the principal child list.
1105 // Maybe it's on the overflow list?
1106 nsFrameList
* overflowFrames
= GetOverflowFrames();
1107 if (overflowFrames
) {
1108 for (nsFrameList::FrameLinkEnumerator
iter(*overflowFrames
); !iter
.AtEnd();
1110 if (iter
.PrevFrame() == aChild
) {
1111 return overflowFrames
->ExtractTail(iter
);
1116 NS_ERROR("StealFramesAfter: can't find aChild");
1117 return nsFrameList::EmptyList();
1121 nsContainerFrame::DestroyOverflowList(nsPresContext
* aPresContext
,
1122 nsIFrame
* aDestructRoot
)
1125 RemovePropTableFrames(aPresContext
, nsGkAtoms::overflowProperty
);
1127 list
->DestroyFrom(aDestructRoot
);
1131 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1135 nsContainerFrame::DeleteNextInFlowChild(nsPresContext
* aPresContext
,
1136 nsIFrame
* aNextInFlow
,
1137 PRBool aDeletingEmptyFrames
)
1140 nsIFrame
* prevInFlow
= aNextInFlow
->GetPrevInFlow();
1142 NS_PRECONDITION(prevInFlow
, "bad prev-in-flow");
1144 // If the next-in-flow has a next-in-flow then delete it, too (and
1145 // delete it first).
1146 // Do this in a loop so we don't overflow the stack for frames
1147 // with very many next-in-flows
1148 nsIFrame
* nextNextInFlow
= aNextInFlow
->GetNextInFlow();
1149 if (nextNextInFlow
) {
1150 nsAutoTArray
<nsIFrame
*, 8> frames
;
1151 for (nsIFrame
* f
= nextNextInFlow
; f
; f
= f
->GetNextInFlow()) {
1152 frames
.AppendElement(f
);
1154 for (PRInt32 i
= frames
.Length() - 1; i
>= 0; --i
) {
1155 nsIFrame
* delFrame
= frames
.ElementAt(i
);
1156 static_cast<nsContainerFrame
*>(delFrame
->GetParent())
1157 ->DeleteNextInFlowChild(aPresContext
, delFrame
, aDeletingEmptyFrames
);
1161 aNextInFlow
->Invalidate(aNextInFlow
->GetOverflowRect());
1163 // Take the next-in-flow out of the parent's child list
1167 StealFrame(aPresContext
, aNextInFlow
);
1168 NS_ASSERTION(NS_SUCCEEDED(rv
), "StealFrame failure");
1170 // Delete the next-in-flow frame and its descendants. This will also
1171 // remove it from its next-in-flow/prev-in-flow chain.
1172 aNextInFlow
->Destroy();
1174 NS_POSTCONDITION(!prevInFlow
->GetNextInFlow(), "non null next-in-flow");
1177 // Destructor function for the proptable-stored framelists
1179 DestroyFrameList(void* aFrame
,
1180 nsIAtom
* aPropertyName
,
1181 void* aPropertyValue
,
1185 static_cast<nsFrameList
*>(aPropertyValue
)->Destroy();
1189 * Set the frames on the overflow list
1192 nsContainerFrame::SetOverflowFrames(nsPresContext
* aPresContext
,
1193 const nsFrameList
& aOverflowFrames
)
1195 NS_PRECONDITION(aOverflowFrames
.NotEmpty(), "Shouldn't be called");
1196 nsFrameList
* newList
= new nsFrameList(aOverflowFrames
);
1198 // XXXbz should really destroy the frames here, but callers are holding
1199 // pointers to them.... We should switch all callers to framelists, then
1200 // audit and do that.
1201 return NS_ERROR_OUT_OF_MEMORY
;
1205 aPresContext
->PropertyTable()->SetProperty(this,
1206 nsGkAtoms::overflowProperty
,
1210 if (NS_FAILED(rv
)) {
1214 // Verify that we didn't overwrite an existing overflow list
1215 NS_ASSERTION(rv
!= NS_PROPTABLE_PROP_OVERWRITTEN
, "existing overflow list");
1221 nsContainerFrame::GetPropTableFrames(nsPresContext
* aPresContext
,
1222 nsIAtom
* aPropID
) const
1224 nsPropertyTable
* propTable
= aPresContext
->PropertyTable();
1225 return static_cast<nsFrameList
*>(propTable
->GetProperty(this, aPropID
));
1229 nsContainerFrame::RemovePropTableFrames(nsPresContext
* aPresContext
,
1230 nsIAtom
* aPropID
) const
1232 nsPropertyTable
* propTable
= aPresContext
->PropertyTable();
1233 return static_cast<nsFrameList
*>(propTable
->UnsetProperty(this, aPropID
));
1237 nsContainerFrame::RemovePropTableFrame(nsPresContext
* aPresContext
,
1239 nsIAtom
* aPropID
) const
1241 nsFrameList
* frameList
= RemovePropTableFrames(aPresContext
, aPropID
);
1246 if (!frameList
->RemoveFrameIfPresent(aFrame
)) {
1247 // Found list, but it doesn't have the frame. Put list back.
1248 SetPropTableFrames(aPresContext
, frameList
, aPropID
);
1252 if (frameList
->IsEmpty()) {
1253 // Removed frame and now list is empty. Delete it.
1257 // Removed frame, but list not empty. Put it back.
1258 SetPropTableFrames(aPresContext
, frameList
, aPropID
);
1264 nsContainerFrame::SetPropTableFrames(nsPresContext
* aPresContext
,
1265 nsFrameList
* aFrameList
,
1266 nsIAtom
* aPropID
) const
1268 NS_PRECONDITION(aPresContext
&& aPropID
&& aFrameList
, "null ptr");
1269 nsresult rv
= aPresContext
->PropertyTable()->SetProperty(this, aPropID
,
1270 aFrameList
, DestroyFrameList
, nsnull
);
1271 NS_ASSERTION(rv
!= NS_PROPTABLE_PROP_OVERWRITTEN
, "existing framelist");
1276 * Push aFromChild and its next siblings to the next-in-flow. Change the
1277 * geometric parent of each frame that's pushed. If there is no next-in-flow
1278 * the frames are placed on the overflow list (and the geometric parent is
1281 * Updates the next-in-flow's child count. Does <b>not</b> update the
1282 * pusher's child count.
1284 * @param aFromChild the first child frame to push. It is disconnected from
1286 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1287 * an error to push a parent's first child frame
1290 nsContainerFrame::PushChildren(nsPresContext
* aPresContext
,
1291 nsIFrame
* aFromChild
,
1292 nsIFrame
* aPrevSibling
)
1294 NS_PRECONDITION(aFromChild
, "null pointer");
1295 NS_PRECONDITION(aPrevSibling
, "pushing first child");
1296 NS_PRECONDITION(aPrevSibling
->GetNextSibling() == aFromChild
, "bad prev sibling");
1298 // Disconnect aFromChild from its previous sibling
1299 nsFrameList tail
= mFrames
.RemoveFramesAfter(aPrevSibling
);
1301 nsContainerFrame
* nextInFlow
=
1302 static_cast<nsContainerFrame
*>(GetNextInFlow());
1304 // XXX This is not a very good thing to do. If it gets removed
1305 // then remove the copy of this routine that doesn't do this from
1307 // When pushing and pulling frames we need to check for whether any
1308 // views need to be reparented.
1309 for (nsIFrame
* f
= aFromChild
; f
; f
= f
->GetNextSibling()) {
1310 nsHTMLContainerFrame::ReparentFrameView(aPresContext
, f
, this, nextInFlow
);
1312 nextInFlow
->mFrames
.InsertFrames(nextInFlow
, nsnull
, tail
);
1315 // Add the frames to our overflow list
1316 SetOverflowFrames(aPresContext
, tail
);
1321 * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1322 * the receiver's overflow list) to the child list.
1324 * Updates this frame's child count and content mapping.
1326 * @return PR_TRUE if any frames were moved and PR_FALSE otherwise
1329 nsContainerFrame::MoveOverflowToChildList(nsPresContext
* aPresContext
)
1331 PRBool result
= PR_FALSE
;
1333 // Check for an overflow list with our prev-in-flow
1334 nsContainerFrame
* prevInFlow
= (nsContainerFrame
*)GetPrevInFlow();
1335 if (nsnull
!= prevInFlow
) {
1336 nsAutoPtr
<nsFrameList
> prevOverflowFrames(prevInFlow
->StealOverflowFrames());
1337 if (prevOverflowFrames
) {
1338 // Tables are special; they can have repeated header/footer
1339 // frames on mFrames at this point.
1340 NS_ASSERTION(mFrames
.IsEmpty() || GetType() == nsGkAtoms::tableFrame
,
1341 "bad overflow list");
1342 // When pushing and pulling frames we need to check for whether any
1343 // views need to be reparented.
1344 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext
,
1345 *prevOverflowFrames
,
1347 mFrames
.AppendFrames(this, *prevOverflowFrames
);
1352 // It's also possible that we have an overflow list for ourselves
1353 nsAutoPtr
<nsFrameList
> overflowFrames(StealOverflowFrames());
1354 if (overflowFrames
) {
1355 NS_ASSERTION(mFrames
.NotEmpty(), "overflow list w/o frames");
1356 mFrames
.AppendFrames(nsnull
, *overflowFrames
);
1362 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext
* aPresContext
,
1363 nsContainerFrame
* aFrame
,
1364 PRBool aWalkOOFFrames
,
1365 PRBool aSkipOverflowContainerChildren
)
1366 : mOverflowContList(nsnull
),
1367 mPrevOverflowCont(nsnull
),
1370 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren
),
1371 mWalkOOFFrames(aWalkOOFFrames
)
1373 NS_PRECONDITION(aFrame
, "null frame pointer");
1374 nsContainerFrame
* next
= static_cast<nsContainerFrame
*>
1375 (aFrame
->GetNextInFlow());
1378 next
->GetPropTableFrames(aPresContext
,
1379 nsGkAtoms::overflowContainersProperty
);
1380 if (mOverflowContList
) {
1385 if (!mOverflowContList
) {
1387 mParent
->GetPropTableFrames(aPresContext
,
1388 nsGkAtoms::excessOverflowContainersProperty
);
1389 if (mOverflowContList
) {
1396 * Helper function to walk past overflow continuations whose prev-in-flow
1397 * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1400 nsOverflowContinuationTracker::SetUpListWalker()
1402 NS_ASSERTION(!mSentry
&& !mPrevOverflowCont
,
1403 "forgot to reset mSentry or mPrevOverflowCont");
1404 if (mOverflowContList
) {
1405 nsIFrame
* cur
= mOverflowContList
->FirstChild();
1406 if (mSkipOverflowContainerChildren
) {
1407 while (cur
&& (cur
->GetPrevInFlow()->GetStateBits()
1408 & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1409 mPrevOverflowCont
= cur
;
1410 cur
= cur
->GetNextSibling();
1412 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1413 == mWalkOOFFrames
)) {
1414 mPrevOverflowCont
= cur
;
1415 cur
= cur
->GetNextSibling();
1419 mSentry
= cur
->GetPrevInFlow();
1425 * Helper function to step forward through the overflow continuations list.
1426 * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1427 * as appropriate. May only be called when we have already set up an
1428 * mOverflowContList; mOverflowContList cannot be null.
1431 nsOverflowContinuationTracker::StepForward()
1433 NS_PRECONDITION(mOverflowContList
, "null list");
1436 if (mPrevOverflowCont
) {
1437 mPrevOverflowCont
= mPrevOverflowCont
->GetNextSibling();
1440 mPrevOverflowCont
= mOverflowContList
->FirstChild();
1443 // Skip over oof or non-oof frames as appropriate
1444 if (mSkipOverflowContainerChildren
) {
1445 nsIFrame
* cur
= mPrevOverflowCont
->GetNextSibling();
1446 while (cur
&& (!(cur
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)
1447 == mWalkOOFFrames
)) {
1448 mPrevOverflowCont
= cur
;
1449 cur
= cur
->GetNextSibling();
1453 // Set up the sentry
1454 mSentry
= (mPrevOverflowCont
->GetNextSibling())
1455 ? mPrevOverflowCont
->GetNextSibling()->GetPrevInFlow()
1460 nsOverflowContinuationTracker::Insert(nsIFrame
* aOverflowCont
,
1461 nsReflowStatus
& aReflowStatus
)
1463 NS_PRECONDITION(aOverflowCont
, "null frame pointer");
1464 NS_PRECONDITION(!mSkipOverflowContainerChildren
|| mWalkOOFFrames
==
1465 !!(aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
),
1466 "shouldn't insert frame that doesn't match walker type");
1467 NS_PRECONDITION(aOverflowCont
->GetPrevInFlow(),
1468 "overflow containers must have a prev-in-flow");
1469 nsresult rv
= NS_OK
;
1470 PRBool convertedToOverflowContainer
= PR_FALSE
;
1471 nsPresContext
* presContext
= aOverflowCont
->PresContext();
1472 if (!mSentry
|| aOverflowCont
!= mSentry
->GetNextInFlow()) {
1473 // Not in our list, so we need to add it
1474 if (aOverflowCont
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
) {
1475 // aOverflowCont is in some other overflow container list,
1477 NS_ASSERTION(!(mOverflowContList
&&
1478 mOverflowContList
->ContainsFrame(aOverflowCont
)),
1479 "overflow containers out of order");
1480 rv
= static_cast<nsContainerFrame
*>(aOverflowCont
->GetParent())
1481 ->StealFrame(presContext
, aOverflowCont
);
1482 NS_ENSURE_SUCCESS(rv
, rv
);
1485 aOverflowCont
->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
);
1486 convertedToOverflowContainer
= PR_TRUE
;
1488 if (!mOverflowContList
) {
1489 mOverflowContList
= new nsFrameList();
1490 rv
= mParent
->SetPropTableFrames(presContext
,
1491 mOverflowContList
, nsGkAtoms::excessOverflowContainersProperty
);
1492 NS_ENSURE_SUCCESS(rv
, rv
);
1495 if (aOverflowCont
->GetParent() != mParent
) {
1496 nsHTMLContainerFrame::ReparentFrameView(presContext
, aOverflowCont
,
1497 aOverflowCont
->GetParent(),
1500 mOverflowContList
->InsertFrame(mParent
, mPrevOverflowCont
, aOverflowCont
);
1501 aReflowStatus
|= NS_FRAME_REFLOW_NEXTINFLOW
;
1504 // If we need to reflow it, mark it dirty
1505 if (aReflowStatus
& NS_FRAME_REFLOW_NEXTINFLOW
)
1506 aOverflowCont
->AddStateBits(NS_FRAME_IS_DIRTY
);
1508 // It's in our list, just step forward
1510 NS_ASSERTION(mPrevOverflowCont
== aOverflowCont
||
1511 (mSkipOverflowContainerChildren
&&
1512 (mPrevOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) !=
1513 (aOverflowCont
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
)),
1514 "OverflowContTracker in unexpected state");
1516 if (convertedToOverflowContainer
) {
1517 // Convert all non-overflow-container continuations of aOverflowCont
1518 // into overflow containers and move them to our overflow
1519 // tracker. This preserves the invariant that the next-continuations
1520 // of an overflow container are also overflow containers.
1521 nsIFrame
* f
= aOverflowCont
->GetNextContinuation();
1522 if (f
&& !(f
->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER
)) {
1523 nsContainerFrame
* parent
= static_cast<nsContainerFrame
*>(f
->GetParent());
1524 rv
= parent
->StealFrame(presContext
, f
);
1525 NS_ENSURE_SUCCESS(rv
, rv
);
1526 Insert(f
, aReflowStatus
);
1533 nsOverflowContinuationTracker::Finish(nsIFrame
* aChild
)
1535 NS_PRECONDITION(aChild
, "null ptr");
1536 NS_PRECONDITION(aChild
->GetNextInFlow(),
1537 "supposed to call Finish *before* deleting next-in-flow!");
1539 for (nsIFrame
* f
= aChild
; f
; f
= f
->GetNextInFlow()) {
1541 // Make sure we drop all references if this was the only frame
1542 // in the overflow containers list
1543 if (mOverflowContList
->FirstChild() == f
->GetNextInFlow()
1544 && !f
->GetNextInFlow()->GetNextSibling()) {
1545 mOverflowContList
= nsnull
;
1546 mPrevOverflowCont
= nsnull
;
1548 mParent
= static_cast<nsContainerFrame
*>(f
->GetParent());
1553 nsIFrame
* prevOverflowCont
= mPrevOverflowCont
;
1555 if (mPrevOverflowCont
== f
->GetNextInFlow()) {
1556 // Pull mPrevOverflowChild back to aChild's prevSibling:
1557 // aChild will be removed from our list by our caller
1558 mPrevOverflowCont
= prevOverflowCont
;
1565 /////////////////////////////////////////////////////////////////////////////
1570 nsContainerFrame::List(FILE* out
, PRInt32 aIndent
) const
1572 IndentBy(out
, aIndent
);
1574 #ifdef DEBUG_waterson
1575 fprintf(out
, " [parent=%p]", static_cast<void*>(mParent
));
1578 fprintf(out
, " [view=%p]", static_cast<void*>(GetView()));
1580 if (GetNextSibling()) {
1581 fprintf(out
, " next=%p", static_cast<void*>(GetNextSibling()));
1583 if (nsnull
!= GetPrevContinuation()) {
1584 fprintf(out
, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
1586 if (nsnull
!= GetNextContinuation()) {
1587 fprintf(out
, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
1589 void* IBsibling
= GetProperty(nsGkAtoms::IBSplitSpecialSibling
);
1591 fprintf(out
, " IBSplitSpecialSibling=%p", IBsibling
);
1593 void* IBprevsibling
= GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling
);
1594 if (IBprevsibling
) {
1595 fprintf(out
, " IBSplitSpecialPrevSibling=%p", IBprevsibling
);
1597 fprintf(out
, " {%d,%d,%d,%d}", mRect
.x
, mRect
.y
, mRect
.width
, mRect
.height
);
1599 fprintf(out
, " [state=%08x]", mState
);
1601 fprintf(out
, " [content=%p]", static_cast<void*>(mContent
));
1602 nsContainerFrame
* f
= const_cast<nsContainerFrame
*>(this);
1603 if (f
->HasOverflowRect()) {
1604 nsRect overflowArea
= f
->GetOverflowRect();
1605 fprintf(out
, " [overflow=%d,%d,%d,%d]", overflowArea
.x
, overflowArea
.y
,
1606 overflowArea
.width
, overflowArea
.height
);
1608 fprintf(out
, " [sc=%p]", static_cast<void*>(mStyleContext
));
1609 nsIAtom
* pseudoTag
= mStyleContext
->GetPseudo();
1611 nsAutoString atomString
;
1612 pseudoTag
->ToString(atomString
);
1613 fprintf(out
, " pst=%s",
1614 NS_LossyConvertUTF16toASCII(atomString
).get());
1617 // Output the children
1618 nsIAtom
* listName
= nsnull
;
1619 PRInt32 listIndex
= 0;
1620 PRBool outputOneList
= PR_FALSE
;
1622 nsIFrame
* kid
= GetFirstChild(listName
);
1623 if (nsnull
!= kid
) {
1624 if (outputOneList
) {
1625 IndentBy(out
, aIndent
);
1627 outputOneList
= PR_TRUE
;
1629 if (nsnull
!= listName
) {
1630 listName
->ToString(tmp
);
1631 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
1634 while (nsnull
!= kid
) {
1635 // Verify the child frame's parent frame pointer is correct
1636 NS_ASSERTION(kid
->GetParent() == (nsIFrame
*)this, "bad parent frame pointer");
1638 // Have the child frame list
1639 kid
->List(out
, aIndent
+ 1);
1640 kid
= kid
->GetNextSibling();
1642 IndentBy(out
, aIndent
);
1645 listName
= GetAdditionalChildListName(listIndex
++);
1646 } while(nsnull
!= listName
);
1648 if (!outputOneList
) {