Bug 575870 - Enable the firefox button on xp themed, classic, and aero basic. r=dao...
[mozilla-central.git] / layout / generic / nsContainerFrame.cpp
blobfc62951bc0a688affaef43432ba212656e9f49fc
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
13 * License.
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.
22 * Contributor(s):
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"
49 #include "nsRect.h"
50 #include "nsPoint.h"
51 #include "nsGUIEvent.h"
52 #include "nsStyleConsts.h"
53 #include "nsIView.h"
54 #include "nsHTMLContainerFrame.h"
55 #include "nsFrameManager.h"
56 #include "nsIPresShell.h"
57 #include "nsCOMPtr.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"
66 #include "nsRegion.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"
78 #ifdef NS_DEBUG
79 #undef NOISY
80 #else
81 #undef NOISY
82 #endif
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)
97 NS_IMETHODIMP
98 nsContainerFrame::Init(nsIContent* aContent,
99 nsIFrame* aParent,
100 nsIFrame* aPrevInFlow)
102 nsresult rv = nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
103 if (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);
110 return rv;
113 NS_IMETHODIMP
114 nsContainerFrame::SetInitialChildList(nsIAtom* aListName,
115 nsFrameList& aChildList)
117 nsresult result;
118 if (mFrames.NotEmpty()) {
119 // We already have child frames which means we've already been
120 // initialized
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;
127 } else {
128 #ifdef NS_DEBUG
129 nsFrame::VerifyDirtyBitSet(aChildList);
130 #endif
131 mFrames.SetFrames(aChildList);
132 result = NS_OK;
134 return result;
137 NS_IMETHODIMP
138 nsContainerFrame::AppendFrames(nsIAtom* aListName,
139 nsFrameList& aFrameList)
141 if (nsnull != aListName) {
142 #ifdef IBMBIDI
143 if (aListName != nsGkAtoms::nextBidi)
144 #endif
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.
154 #ifdef IBMBIDI
155 if (nsnull == aListName)
156 #endif
158 PresContext()->PresShell()->
159 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
160 NS_FRAME_HAS_DIRTY_CHILDREN);
163 return NS_OK;
166 NS_IMETHODIMP
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) {
175 #ifdef IBMBIDI
176 if (aListName != nsGkAtoms::nextBidi)
177 #endif
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);
187 #ifdef IBMBIDI
188 if (nsnull == aListName)
189 #endif
191 PresContext()->PresShell()->
192 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
193 NS_FRAME_HAS_DIRTY_CHILDREN);
196 return NS_OK;
199 NS_IMETHODIMP
200 nsContainerFrame::RemoveFrame(nsIAtom* aListName,
201 nsIFrame* aOldFrame)
203 if (nsnull != aListName) {
204 #ifdef IBMBIDI
205 if (nsGkAtoms::nextBidi != aListName)
206 #endif
208 NS_ERROR("unexpected child list");
209 return NS_ERROR_INVALID_ARG;
213 if (aOldFrame) {
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;
219 #ifdef IBMBIDI
220 if (nsGkAtoms::nextBidi == aListName) {
221 generateReflowCommand = PR_FALSE;
223 #endif
224 nsContainerFrame* parent = static_cast<nsContainerFrame*>(aOldFrame->GetParent());
225 while (aOldFrame) {
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
228 // command.
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();
241 } else {
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);
245 break;
247 aOldFrame = oldFrameNextContinuation;
248 if (aOldFrame) {
249 parent = static_cast<nsContainerFrame*>(aOldFrame->GetParent());
253 if (generateReflowCommand) {
254 PresContext()->PresShell()->
255 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
256 NS_FRAME_HAS_DIRTY_CHILDREN);
260 return NS_OK;
263 void
264 nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
266 // Prevent event dispatch during destruction
267 if (HasView()) {
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());
282 if (frameList)
283 frameList->DestroyFrom(aDestructRoot);
285 frameList = RemovePropTableFrames(prescontext,
286 ExcessOverflowContainersProperty());
287 if (frameList)
288 frameList->DestroyFrom(aDestructRoot);
291 // Destroy the frame and remove the flow pointers
292 nsSplittableFrame::DestroyFrom(aDestructRoot);
295 /////////////////////////////////////////////////////////////////////////////
296 // Child frame enumeration
298 nsFrameList
299 nsContainerFrame::GetChildList(nsIAtom* aListName) const
301 // We only know about the unnamed principal child list and the overflow
302 // lists
303 if (nsnull == aListName) {
304 return mFrames;
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
333 nsIAtom*
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;
344 return nsnull;
347 /////////////////////////////////////////////////////////////////////////////
348 // Painting/Events
350 NS_IMETHODIMP
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);
361 nsresult
362 nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
363 const nsRect& aDirtyRect,
364 const nsDisplayListSet& aLists,
365 PRUint32 aFlags)
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
371 while (kid) {
372 nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
373 NS_ENSURE_SUCCESS(rv, rv);
374 kid = kid->GetNextSibling();
376 return NS_OK;
379 /* virtual */ void
380 nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
382 AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
385 PRBool
386 nsContainerFrame::IsLeaf() const
388 return PR_FALSE;
391 PRBool
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.
396 return PR_FALSE;
399 PRBool
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.
404 return PR_FALSE;
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|.
415 void
416 nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
418 nsIFrame* parentFrame = aKidFrame->GetParent();
419 if (!aKidFrame->HasView() || !parentFrame)
420 return;
422 nsIView* view = aKidFrame->GetView();
423 nsIViewManager* vm = view->GetViewManager();
424 nsPoint pt;
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
431 // explicitly
432 return;
435 pt += aKidFrame->GetPosition();
436 vm->MoveViewTo(view, pt.x, pt.y);
439 static nsIWidget*
440 GetPresContextContainerWidget(nsPresContext* aPresContext)
442 nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
443 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
444 if (!baseWindow)
445 return nsnull;
447 nsCOMPtr<nsIWidget> mainWidget;
448 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
449 return mainWidget;
452 static PRBool
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
463 void
464 nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
465 nsIFrame* aFrame,
466 nsIView* aView)
468 #ifdef MOZ_XUL
469 if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
470 return;
472 nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
473 if (!windowWidget || !IsTopLevelWidget(windowWidget))
474 return;
476 nsIViewManager* vm = aView->GetViewManager();
477 nsIView* rootView;
478 vm->GetRootView(rootView);
480 if (aView != rootView)
481 return;
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.
500 return;
503 nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
504 if (!rootFrame)
505 return;
507 nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
508 nsIWidget* viewWidget = aView->GetWidget();
509 viewWidget->SetTransparencyMode(mode);
510 windowWidget->SetWindowShadowStyle(rootFrame->GetStyleUIReset()->mWindowShadow);
511 #endif
514 void
515 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
516 nsIFrame* aFrame,
517 nsIView* aView,
518 const nsRect* aCombinedArea,
519 PRUint32 aFlags)
521 if (!aView) {
522 return;
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);
539 void
540 nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
541 nsIFrame* aFrame,
542 nsStyleContext* aStyleContext,
543 nsIView* aView,
544 PRUint32 aFlags)
546 NS_ASSERTION(!aStyleContext || aFrame->GetStyleContext() == aStyleContext,
547 "Wrong style context for frame?");
549 if (!aView) {
550 return;
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
569 // positioned
570 PRBool isPositioned = aStyleContext->GetStyleDisplay()->IsPositioned();
572 PRInt32 zIndex = 0;
573 PRBool autoZIndex = PR_FALSE;
575 if (!isPositioned) {
576 autoZIndex = PR_TRUE;
577 } else {
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()
595 : aIfNotCoord;
598 void
599 nsContainerFrame::DoInlineIntrinsicWidth(nsIRenderingContext *aRenderingContext,
600 InlineIntrinsicWidthData *aData,
601 nsLayoutUtils::IntrinsicWidthType aType)
603 if (GetPrevInFlow())
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;
613 } else {
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
625 // first line.
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
628 // border.
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));
647 else
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;
657 lastInFlow = nif;
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
666 // last line.
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);
678 /* virtual */ nsSize
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 -
686 aPadding.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);
693 } else {
694 result.width = availBased;
696 return result;
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()
704 nsresult
705 nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
706 nsPresContext* aPresContext,
707 nsHTMLReflowMetrics& aDesiredSize,
708 const nsHTMLReflowState& aReflowState,
709 nscoord aX,
710 nscoord aY,
711 PRUint32 aFlags,
712 nsReflowStatus& aStatus,
713 nsOverflowContinuationTracker* aTracker)
715 NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
717 nsresult result;
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,
738 aStatus);
740 // If the reflow was successful and the child frame is complete, delete any
741 // next-in-flows
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);
753 return result;
758 * Position the views of |aFrame|'s descendants. A container frame
759 * should call this method if it moves a frame after |Reflow|.
761 void
762 nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
764 if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
765 return;
768 nsIAtom* childListName = nsnull;
769 PRInt32 childListIndex = 0;
771 do {
772 // Recursively walk aFrame's child frames
773 nsIFrame* childFrame = aFrame->GetFirstChild(childListName);
774 while (childFrame) {
775 // Position the frame's view (if it has one) otherwise recursively
776 // process its children
777 if (childFrame->HasView()) {
778 PositionFrameView(childFrame);
779 } else {
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.
790 do {
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
802 * in sync
803 * - sets the view's visibility, opacity, content transparency, and clip
804 * - invoked the DidReflow() function
806 * Flags:
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
813 nsresult
814 nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
815 nsPresContext* aPresContext,
816 const nsHTMLReflowState* aReflowState,
817 const nsHTMLReflowMetrics& aDesiredSize,
818 nscoord aX,
819 nscoord aY,
820 PRUint32 aFlags)
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,
833 aFlags);
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);
855 nsresult
856 nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
857 const nsHTMLReflowState& aReflowState,
858 nsRect& aOverflowRect,
859 PRUint32 aFlags,
860 nsReflowStatus& aStatus)
862 NS_PRECONDITION(aPresContext, "null pointer");
863 nsresult rv = NS_OK;
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();
878 if (prev) {
879 nsFrameList* excessFrames =
880 prev->RemovePropTableFrames(aPresContext,
881 ExcessOverflowContainersProperty());
882 if (excessFrames) {
883 excessFrames->ApplySetParent(this);
884 nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, *excessFrames,
885 prev, this);
886 overflowContainers = excessFrames;
887 rv = SetPropTableFrames(aPresContext, overflowContainers,
888 OverflowContainersProperty());
889 if (NS_FAILED(rv)) {
890 excessFrames->DestroyFrames();
891 delete excessFrames;
892 return rv;
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
909 continue;
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)) {
914 // Get prev-in-flow
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,
926 frame, availSpace);
927 nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
929 // Cache old bounds
930 nsRect oldRect = frame->GetRect();
931 nsRect oldOverflow = frame->GetOverflowRect();
933 // Reflow
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);
962 else {
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();
969 if (!nif) {
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.
990 else {
991 tracker.Skip(frame, aStatus);
992 if (aReflowState.mFloatManager)
993 nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
995 ConsiderChildOverflow(aOverflowRect, frame);
998 return NS_OK;
1001 void
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);
1016 nsresult
1017 nsContainerFrame::StealFrame(nsPresContext* aPresContext,
1018 nsIFrame* aChild,
1019 PRBool aForceNormal)
1021 PRBool removed = PR_TRUE;
1022 if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
1023 && !aForceNormal) {
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());
1032 else {
1033 if (!mFrames.RemoveFrameIfPresent(aChild)) {
1034 removed = PR_FALSE;
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();
1038 if (frameList) {
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;
1051 nsFrameList
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");
1059 if (!aChild) {
1060 nsFrameList copy(mFrames);
1061 mFrames.Clear();
1062 return copy;
1065 for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
1066 iter.Next()) {
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();
1077 iter.Next()) {
1078 if (iter.PrevFrame() == aChild) {
1079 return overflowFrames->ExtractTail(iter);
1084 NS_ERROR("StealFramesAfter: can't find aChild");
1085 return nsFrameList::EmptyList();
1088 void
1089 nsContainerFrame::DestroyOverflowList(nsPresContext* aPresContext,
1090 nsIFrame* aDestructRoot)
1092 nsFrameList* list =
1093 RemovePropTableFrames(aPresContext, OverflowProperty());
1094 if (list) {
1095 if (aDestructRoot)
1096 list->DestroyFrom(aDestructRoot);
1097 else
1098 list->Destroy();
1103 * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1104 * pointers
1106 void
1107 nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
1108 nsIFrame* aNextInFlow,
1109 PRBool aDeletingEmptyFrames)
1111 #ifdef DEBUG
1112 nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
1113 #endif
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
1136 #ifdef DEBUG
1137 nsresult rv =
1138 #endif
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
1152 nsresult
1153 nsContainerFrame::SetOverflowFrames(nsPresContext* aPresContext,
1154 const nsFrameList& aOverflowFrames)
1156 NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
1157 nsFrameList* newList = new nsFrameList(aOverflowFrames);
1158 if (!newList) {
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);
1166 return NS_OK;
1169 nsFrameList*
1170 nsContainerFrame::GetPropTableFrames(nsPresContext* aPresContext,
1171 const FramePropertyDescriptor* aProperty) const
1173 FramePropertyTable* propTable = aPresContext->PropertyTable();
1174 return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
1177 nsFrameList*
1178 nsContainerFrame::RemovePropTableFrames(nsPresContext* aPresContext,
1179 const FramePropertyDescriptor* aProperty)
1181 FramePropertyTable* propTable = aPresContext->PropertyTable();
1182 return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
1185 PRBool
1186 nsContainerFrame::RemovePropTableFrame(nsPresContext* aPresContext,
1187 nsIFrame* aFrame,
1188 const FramePropertyDescriptor* aProperty)
1190 nsFrameList* frameList = RemovePropTableFrames(aPresContext, aProperty);
1191 if (!frameList) {
1192 // No such list
1193 return PR_FALSE;
1195 if (!frameList->RemoveFrameIfPresent(aFrame)) {
1196 // Found list, but it doesn't have the frame. Put list back.
1197 SetPropTableFrames(aPresContext, frameList, aProperty);
1198 return PR_FALSE;
1201 if (frameList->IsEmpty()) {
1202 // Removed frame and now list is empty. Delete it.
1203 delete frameList;
1205 else {
1206 // Removed frame, but list not empty. Put it back.
1207 SetPropTableFrames(aPresContext, frameList, aProperty);
1209 return PR_TRUE;
1212 nsresult
1213 nsContainerFrame::SetPropTableFrames(nsPresContext* aPresContext,
1214 nsFrameList* aFrameList,
1215 const FramePropertyDescriptor* aProperty)
1217 NS_PRECONDITION(aPresContext && aProperty && aFrameList, "null ptr");
1218 NS_PRECONDITION(
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);
1224 return NS_OK;
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
1231 * left unchanged).
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
1237 * aPrevSibling
1238 * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1239 * an error to push a parent's first child frame
1241 void
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());
1255 if (nextInFlow) {
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
1258 // nsInlineFrame.
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);
1266 else {
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
1280 PRBool
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,
1298 prevInFlow, this);
1299 mFrames.AppendFrames(this, *prevOverflowFrames);
1300 result = PR_TRUE;
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);
1309 result = PR_TRUE;
1311 return result;
1314 nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext* aPresContext,
1315 nsContainerFrame* aFrame,
1316 PRBool aWalkOOFFrames,
1317 PRBool aSkipOverflowContainerChildren)
1318 : mOverflowContList(nsnull),
1319 mPrevOverflowCont(nsnull),
1320 mSentry(nsnull),
1321 mParent(aFrame),
1322 mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
1323 mWalkOOFFrames(aWalkOOFFrames)
1325 NS_PRECONDITION(aFrame, "null frame pointer");
1326 nsContainerFrame* next = static_cast<nsContainerFrame*>
1327 (aFrame->GetNextInFlow());
1328 if (next) {
1329 mOverflowContList = next->GetPropTableFrames(aPresContext,
1330 nsContainerFrame::OverflowContainersProperty());
1331 if (mOverflowContList) {
1332 mParent = next;
1333 SetUpListWalker();
1336 if (!mOverflowContList) {
1337 mOverflowContList = mParent->GetPropTableFrames(aPresContext,
1338 nsContainerFrame::ExcessOverflowContainersProperty());
1339 if (mOverflowContList) {
1340 SetUpListWalker();
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.
1349 void
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();
1368 if (cur) {
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.
1380 void
1381 nsOverflowContinuationTracker::StepForward()
1383 NS_PRECONDITION(mOverflowContList, "null list");
1385 // Step forward
1386 if (mPrevOverflowCont) {
1387 mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
1389 else {
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()
1406 : nsnull;
1409 nsresult
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,
1426 // steal it first
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);
1434 else {
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);
1443 SetUpListWalker();
1445 if (aOverflowCont->GetParent() != mParent) {
1446 nsHTMLContainerFrame::ReparentFrameView(presContext, aOverflowCont,
1447 aOverflowCont->GetParent(),
1448 mParent);
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
1459 StepForward();
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);
1479 return rv;
1482 void
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;
1497 mSentry = nsnull;
1498 mParent = static_cast<nsContainerFrame*>(f->GetParent());
1499 break;
1501 if (f == mSentry) {
1502 // Step past aChild
1503 nsIFrame* prevOverflowCont = mPrevOverflowCont;
1504 StepForward();
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 /////////////////////////////////////////////////////////////////////////////
1515 // Debugging
1517 #ifdef NS_DEBUG
1518 NS_IMETHODIMP
1519 nsContainerFrame::List(FILE* out, PRInt32 aIndent) const
1521 IndentBy(out, aIndent);
1522 ListTag(out);
1523 #ifdef DEBUG_waterson
1524 fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
1525 #endif
1526 if (HasView()) {
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());
1539 if (IBsibling) {
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);
1547 if (0 != mState) {
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();
1559 if (pseudoTag) {
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;
1570 do {
1571 nsIFrame* kid = GetFirstChild(listName);
1572 if (nsnull != kid) {
1573 if (outputOneList) {
1574 IndentBy(out, aIndent);
1576 outputOneList = PR_TRUE;
1577 nsAutoString tmp;
1578 if (nsnull != listName) {
1579 listName->ToString(tmp);
1580 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
1582 fputs("<\n", 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);
1592 fputs(">\n", out);
1594 listName = GetAdditionalChildListName(listIndex++);
1595 } while(nsnull != listName);
1597 if (!outputOneList) {
1598 fputs("<>\n", out);
1601 return NS_OK;
1603 #endif