Back to index

lightning-sunbird  0.9+nobinonly
nsContainerFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsContainerFrame.h"
00039 #include "nsIContent.h"
00040 #include "nsIDocument.h"
00041 #include "nsPresContext.h"
00042 #include "nsIRenderingContext.h"
00043 #include "nsStyleContext.h"
00044 #include "nsRect.h"
00045 #include "nsPoint.h"
00046 #include "nsGUIEvent.h"
00047 #include "nsStyleConsts.h"
00048 #include "nsIView.h"
00049 #include "nsIScrollableView.h"
00050 #include "nsVoidArray.h"
00051 #include "nsHTMLContainerFrame.h"
00052 #include "nsFrameManager.h"
00053 #include "nsIPresShell.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsLayoutAtoms.h"
00056 #include "nsCSSAnonBoxes.h"
00057 #include "nsIViewManager.h"
00058 #include "nsIWidget.h"
00059 #include "nsGfxCIID.h"
00060 #include "nsIServiceManager.h"
00061 #include "nsCSSRendering.h"
00062 #include "nsTransform2D.h"
00063 #include "nsRegion.h"
00064 #include "nsLayoutErrors.h"
00065 
00066 #ifdef NS_DEBUG
00067 #undef NOISY
00068 #else
00069 #undef NOISY
00070 #endif
00071 
00072 nsContainerFrame::nsContainerFrame()
00073 {
00074 }
00075 
00076 nsContainerFrame::~nsContainerFrame()
00077 {
00078 }
00079 
00080 NS_IMETHODIMP
00081 nsContainerFrame::Init(nsPresContext*  aPresContext,
00082                        nsIContent*      aContent,
00083                        nsIFrame*        aParent,
00084                        nsStyleContext*  aContext,
00085                        nsIFrame*        aPrevInFlow)
00086 {
00087   nsresult rv;
00088   rv = nsSplittableFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
00089   if (aPrevInFlow) {
00090     // Make sure we copy bits from our prev-in-flow that will affect
00091     // us. A continuation for a container frame needs to know if it
00092     // has a child with a view so that we'll properly reposition it.
00093     if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
00094       AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
00095   }
00096   return rv;
00097 }
00098 
00099 NS_IMETHODIMP
00100 nsContainerFrame::SetInitialChildList(nsPresContext* aPresContext,
00101                                       nsIAtom*        aListName,
00102                                       nsIFrame*       aChildList)
00103 {
00104   nsresult  result;
00105   if (!mFrames.IsEmpty()) {
00106     // We already have child frames which means we've already been
00107     // initialized
00108     NS_NOTREACHED("unexpected second call to SetInitialChildList");
00109     result = NS_ERROR_UNEXPECTED;
00110   } else if (aListName) {
00111     // All we know about is the unnamed principal child list
00112     NS_NOTREACHED("unknown frame list");
00113     result = NS_ERROR_INVALID_ARG;
00114   } else {
00115 #ifdef NS_DEBUG
00116     nsFrame::VerifyDirtyBitSet(aChildList);
00117 #endif
00118     mFrames.SetFrames(aChildList);
00119     result = NS_OK;
00120   }
00121   return result;
00122 }
00123 
00124 static void
00125 CleanupGeneratedContentIn(nsIContent* aRealContent, nsIFrame* aRoot) {
00126   nsIAtom* frameList = nsnull;
00127   PRInt32 listIndex = 0;
00128   do {
00129     nsIFrame* child = aRoot->GetFirstChild(frameList);
00130     while (child) {
00131       nsIContent* content = child->GetContent();
00132       if (content && content != aRealContent) {
00133         content->UnbindFromTree();
00134       }
00135       ::CleanupGeneratedContentIn(aRealContent, child);
00136       child = child->GetNextSibling();
00137     }
00138     frameList = aRoot->GetAdditionalChildListName(listIndex++);
00139   } while (frameList);
00140 }
00141 
00142 NS_IMETHODIMP
00143 nsContainerFrame::Destroy(nsPresContext* aPresContext)
00144 {
00145   // Prevent event dispatch during destruction
00146   if (HasView()) {
00147     GetView()->SetClientData(nsnull);
00148   }
00149 
00150   if (mState & NS_FRAME_GENERATED_CONTENT) {
00151     nsIAtom* type = GetType();
00152     if (type == nsLayoutAtoms::inlineFrame ||
00153         type== nsLayoutAtoms::blockFrame) {
00154       // Make sure all the content nodes for the generated content inside
00155       // this frame know it's going away.
00156       // XXXbz would this be better done via a global structure in
00157       // nsCSSFrameConstructor that could key off of
00158       // GeneratedContentFrameRemoved or something?  The problem is that
00159       // our kids are gone by the time that's called.
00160       ::CleanupGeneratedContentIn(mContent, this);
00161     }
00162   }
00163   
00164   // Delete the primary child list
00165   mFrames.DestroyFrames(aPresContext);
00166   
00167   // Destroy overflow frames now
00168   nsFrameList overflowFrames(GetOverflowFrames(aPresContext, PR_TRUE));
00169   overflowFrames.DestroyFrames(aPresContext);
00170 
00171   // Destroy the frame and remove the flow pointers
00172   return nsSplittableFrame::Destroy(aPresContext);
00173 }
00174 
00176 // Child frame enumeration
00177 
00178 nsIFrame*
00179 nsContainerFrame::GetFirstChild(nsIAtom* aListName) const
00180 {
00181   // We only know about the unnamed principal child list and the overflow
00182   // list
00183   if (nsnull == aListName) {
00184     return mFrames.FirstChild();
00185   } else if (nsLayoutAtoms::overflowList == aListName) {
00186     return GetOverflowFrames(GetPresContext(), PR_FALSE);
00187   } else {
00188     return nsnull;
00189   }
00190 }
00191 
00192 nsIAtom*
00193 nsContainerFrame::GetAdditionalChildListName(PRInt32 aIndex) const
00194 {
00195   if (aIndex == 0) {
00196     return nsLayoutAtoms::overflowList;
00197   } else {
00198     return nsnull;
00199   }
00200 }
00201 
00203 // Painting/Events
00204 
00205 NS_IMETHODIMP
00206 nsContainerFrame::Paint(nsPresContext*      aPresContext,
00207                         nsIRenderingContext& aRenderingContext,
00208                         const nsRect&        aDirtyRect,
00209                         nsFramePaintLayer    aWhichLayer,
00210                         PRUint32             aFlags)
00211 {
00212   PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags);
00213   return NS_OK;
00214 }
00215 
00216 // Paint the children of a container, assuming nothing about the
00217 // childrens spatial arrangement. Given relative positioning, negative
00218 // margins, etc, that's probably a good thing.
00219 //
00220 // Note: aDirtyRect is in our coordinate system (and of course, child
00221 // rect's are also in our coordinate system)
00222 void
00223 nsContainerFrame::PaintChildren(nsPresContext*      aPresContext,
00224                                 nsIRenderingContext& aRenderingContext,
00225                                 const nsRect&        aDirtyRect,
00226                                 nsFramePaintLayer    aWhichLayer,
00227                                 PRUint32             aFlags)
00228 {
00229   nsIFrame* kid = mFrames.FirstChild();
00230   while (kid) {
00231     PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid, aWhichLayer, aFlags);
00232     kid = kid->GetNextSibling();
00233   }
00234 }
00235 
00236 // Paint one child frame
00237 void
00238 nsContainerFrame::PaintChild(nsPresContext*      aPresContext,
00239                              nsIRenderingContext& aRenderingContext,
00240                              const nsRect&        aDirtyRect,
00241                              nsIFrame*            aFrame,
00242                              nsFramePaintLayer    aWhichLayer,
00243                              PRUint32             aFlags)
00244 {
00245   NS_ASSERTION(aFrame, "no frame to paint!");
00246   if (!aFrame->HasView()) {
00247     nsRect kidRect = aFrame->GetRect();
00248 
00249     // Compute the constrained damage area; set the overlap flag to
00250     // PR_TRUE if any portion of the child frame intersects the
00251     // dirty rect.
00252     nsRect damageArea;
00253     PRBool overlap;
00254     if (NS_FRAME_OUTSIDE_CHILDREN & aFrame->GetStateBits()) {
00255       // If the child frame has children that leak out of our box
00256       // then we don't constrain the damageArea to just the childs
00257       // bounding rect.
00258       damageArea = aDirtyRect;
00259       overlap = PR_TRUE;
00260     }
00261     else {
00262       // Compute the intersection of the dirty rect and the childs
00263       // rect (both are in our coordinate space). This limits the
00264       // damageArea to just the portion that intersects the childs
00265       // rect.
00266       overlap = damageArea.IntersectRect(aDirtyRect, kidRect);
00267 #ifdef NS_DEBUG
00268       if (!overlap && (0 == kidRect.width) && (0 == kidRect.height)) {
00269         overlap = PR_TRUE;
00270       }
00271 #endif
00272     }
00273 
00274     if (overlap) {
00275       // Translate damage area into the kids coordinate
00276       // system. Translate rendering context into the kids
00277       // coordinate system.
00278       damageArea.x -= kidRect.x;
00279       damageArea.y -= kidRect.y;
00280 
00281       {
00282         nsIRenderingContext::AutoPushTranslation
00283           translate(&aRenderingContext, kidRect.x, kidRect.y);
00284   
00285         // Paint the kid
00286         aFrame->Paint(aPresContext, aRenderingContext, damageArea, aWhichLayer, aFlags);
00287       }
00288 
00289 #ifdef NS_DEBUG
00290       // Draw a border around the child
00291       if (nsIFrameDebug::GetShowFrameBorders() && !kidRect.IsEmpty()) {
00292         aRenderingContext.SetColor(NS_RGB(255,0,0));
00293         aRenderingContext.DrawRect(kidRect);
00294       }
00295 #endif
00296     }
00297   }
00298 }
00299 
00300 NS_IMETHODIMP
00301 nsContainerFrame::GetFrameForPoint(const nsPoint& aPoint, 
00302                                    nsFramePaintLayer aWhichLayer,
00303                                    nsIFrame**     aFrame)
00304 {
00305   return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND), aFrame);
00306 }
00307 
00308 nsresult
00309 nsContainerFrame::GetFrameForPointUsing(const nsPoint& aPoint,
00310                                         nsIAtom*       aList,
00311                                         nsFramePaintLayer aWhichLayer,
00312                                         PRBool         aConsiderSelf,
00313                                         nsIFrame**     aFrame)
00314 {
00315   nsIFrame *hit;
00316   nsPoint tmp;
00317 
00318   PRBool inThisFrame = mRect.Contains(aPoint);
00319 
00320   if (! ((mState & NS_FRAME_OUTSIDE_CHILDREN) || inThisFrame ) ) {
00321     return NS_ERROR_FAILURE;
00322   }
00323 
00324   nsIFrame* kid = GetFirstChild(aList);
00325   *aFrame = nsnull;
00326   tmp.MoveTo(aPoint.x - mRect.x, aPoint.y - mRect.y);
00327 
00328   nsPoint originOffset;
00329   nsIView *view = nsnull;
00330   nsresult rv = GetOriginToViewOffset(originOffset, &view);
00331 
00332   if (NS_SUCCEEDED(rv) && view)
00333     tmp += originOffset;
00334 
00335   while (kid) {
00336     if (aWhichLayer == NS_FRAME_PAINT_LAYER_ALL) {
00337       // Check all layers on this kid before moving on to the next one
00338       rv = kid->GetFrameForPoint(tmp, NS_FRAME_PAINT_LAYER_FOREGROUND, &hit);
00339       if (NS_FAILED(rv) || !hit) {
00340         rv = kid->GetFrameForPoint(tmp, NS_FRAME_PAINT_LAYER_FLOATS, &hit);
00341         if (NS_FAILED(rv) || !hit) {
00342           rv = kid->GetFrameForPoint(tmp, NS_FRAME_PAINT_LAYER_BACKGROUND, &hit);
00343         }
00344       }
00345     } else {
00346       rv = kid->GetFrameForPoint(tmp, aWhichLayer, &hit);
00347     }
00348 
00349     if (NS_SUCCEEDED(rv) && hit) {
00350       *aFrame = hit;
00351     }
00352     kid = kid->GetNextSibling();
00353   }
00354 
00355   if (*aFrame) {
00356     return NS_OK;
00357   }
00358 
00359   if ( inThisFrame && aConsiderSelf ) {
00360     if (GetStyleVisibility()->IsVisible()) {
00361       *aFrame = this;
00362       return NS_OK;
00363     }
00364   }
00365 
00366   return NS_ERROR_FAILURE;
00367 }
00368 
00369 NS_IMETHODIMP
00370 nsContainerFrame::ReplaceFrame(nsIAtom*        aListName,
00371                                nsIFrame*       aOldFrame,
00372                                nsIFrame*       aNewFrame)
00373 {
00374   nsIFrame* prevFrame;
00375   nsresult  rv;
00376 
00377   // Get the old frame's previous sibling frame
00378   nsFrameList frames(GetFirstChild(aListName));
00379   NS_ASSERTION(frames.ContainsFrame(aOldFrame), "frame is not a valid child frame");
00380   prevFrame = frames.GetPrevSiblingFor(aOldFrame);
00381 
00382   // Default implementation treats it like two separate operations
00383   rv = RemoveFrame(aListName, aOldFrame);
00384   if (NS_SUCCEEDED(rv)) {
00385     rv = InsertFrames(aListName, prevFrame, aNewFrame);
00386   }
00387 
00388   return rv;
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
00393 {
00394   // The container frame always generates a reflow command
00395   // targeted at its child
00396   // Note that even if this flag is already set, we still need to reflow the
00397   // child because the frame may have more than one child
00398   mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
00399 
00400   aPresShell->AppendReflowCommand(aChild, eReflowType_ReflowDirty, nsnull);
00401 
00402   return NS_OK;
00403 }
00404 
00405 PRBool
00406 nsContainerFrame::IsLeaf() const
00407 {
00408   return PR_FALSE;
00409 }
00410 
00412 // Helper member functions
00413 
00419 void
00420 nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
00421 {
00422   nsIFrame* parentFrame = aKidFrame->GetParent();
00423   if (!aKidFrame->HasView() || !parentFrame)
00424     return;
00425 
00426   nsIView* view = aKidFrame->GetView();
00427   nsIViewManager* vm = view->GetViewManager();
00428   nsPoint pt;
00429   nsIView* ancestorView = parentFrame->GetClosestView(&pt);
00430 
00431   if (ancestorView != view->GetParent()) {
00432     NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
00433                  "Allowed only one anonymous view between frames");
00434     // parentFrame is responsible for positioning aKidFrame's view
00435     // explicitly
00436     return;
00437   }
00438 
00439   pt += aKidFrame->GetPosition();
00440   vm->MoveViewTo(view, pt.x, pt.y);
00441 }
00442 
00443 static PRBool
00444 NonZeroStyleCoord(const nsStyleCoord& aCoord) {
00445   switch (aCoord.GetUnit()) {
00446   case eStyleUnit_Percent:
00447     return aCoord.GetPercentValue() > 0;
00448   case eStyleUnit_Coord:
00449     return aCoord.GetCoordValue() > 0;
00450   case eStyleUnit_Null:
00451     return PR_FALSE;
00452   default:
00453     return PR_TRUE;
00454   }
00455 }
00456 
00457 static PRBool
00458 HasNonZeroBorderRadius(nsStyleContext* aStyleContext) {
00459   const nsStyleBorder* border = aStyleContext->GetStyleBorder();
00460 
00461   nsStyleCoord coord;
00462   border->mBorderRadius.GetTop(coord);
00463   if (NonZeroStyleCoord(coord)) return PR_TRUE;    
00464   border->mBorderRadius.GetRight(coord);
00465   if (NonZeroStyleCoord(coord)) return PR_TRUE;    
00466   border->mBorderRadius.GetBottom(coord);
00467   if (NonZeroStyleCoord(coord)) return PR_TRUE;    
00468   border->mBorderRadius.GetLeft(coord);
00469   if (NonZeroStyleCoord(coord)) return PR_TRUE;    
00470 
00471   return PR_FALSE;
00472 }
00473 
00474 static void
00475 SyncFrameViewGeometryDependentProperties(nsPresContext*  aPresContext,
00476                                          nsIFrame*        aFrame,
00477                                          nsStyleContext*  aStyleContext,
00478                                          nsIView*         aView,
00479                                          PRUint32         aFlags)
00480 {
00481   nsIViewManager* vm = aView->GetViewManager();
00482 
00483   PRBool isCanvas;
00484   const nsStyleBackground* bg;
00485   PRBool hasBG =
00486     nsCSSRendering::FindBackground(aPresContext, aFrame, &bg, &isCanvas);
00487 
00488   // background-attachment: fixed is not really geometry dependent, but
00489   // we set it here because it's cheap to do so
00490   PRBool fixedBackground = hasBG && bg->HasFixedBackground();
00491   // If the frame has a fixed background attachment, then indicate that the
00492   // view's contents should be repainted and not bitblt'd
00493   vm->SetViewBitBltEnabled(aView, !fixedBackground);
00494 
00495   const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
00496   // If the frame has a solid background color, 'background-clip:border',
00497   // and it's a kind of frame that paints its background, and rounded borders aren't
00498   // clipping the background, then it's opaque.
00499   // If the frame has a native theme appearance then its background
00500   // color is actually not relevant.
00501   PRBool  viewHasTransparentContent =
00502     !(hasBG && !(bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) &&
00503       !display->mAppearance && bg->mBackgroundClip == NS_STYLE_BG_CLIP_BORDER &&
00504       aFrame->CanPaintBackground() &&
00505       !HasNonZeroBorderRadius(aStyleContext));
00506 
00507   PRBool drawnOnUniformField = PR_FALSE;
00508   if (aStyleContext->GetPseudoType() == nsCSSAnonBoxes::scrolledContent) {
00509     // If the nsGfxScrollFrame draws a solid unclipped background
00510     // color, and nothing else, then tell the view system that we're
00511     // drawn on a uniform field. Note that it's OK if the background
00512     // is clipped to the padding area, since the scrollport is within
00513     // the borders.
00514     nsIFrame* scrollFrame = aFrame->GetParent();
00515     while (scrollFrame->GetStyleContext()->GetPseudoType()
00516            == nsCSSAnonBoxes::scrolledContent) {
00517       scrollFrame = scrollFrame->GetParent();
00518     }
00519     PRBool scrollFrameIsCanvas;
00520     const nsStyleBackground* scrollFrameBG;
00521     PRBool scrollFrameHasBG =
00522       nsCSSRendering::FindBackground(aPresContext, scrollFrame, &scrollFrameBG,
00523                                      &scrollFrameIsCanvas);
00524     const nsStyleDisplay* bgDisplay = scrollFrame->GetStyleDisplay();
00525     drawnOnUniformField = scrollFrameHasBG &&
00526       !(scrollFrameBG->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT) &&
00527       (scrollFrameBG->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE) &&
00528       !HasNonZeroBorderRadius(scrollFrame->GetStyleContext()) &&
00529       !(bgDisplay->IsAbsolutelyPositioned()
00530         && (bgDisplay->mClipFlags & NS_STYLE_CLIP_RECT));
00531   }
00532   aView->SetHasUniformBackground(drawnOnUniformField);
00533 
00534   if (isCanvas) {
00535     nsIView* rootView;
00536     vm->GetRootView(rootView);
00537     nsIView* rootParent = rootView->GetParent();
00538     if (!rootParent) {
00539       // We're the root of a view manager hierarchy. We will have to
00540       // paint something. NOTE: this can be overridden below.
00541       viewHasTransparentContent = PR_FALSE;
00542     }
00543 
00544     nsIDocument *doc = aPresContext->PresShell()->GetDocument();
00545     if (doc) {
00546       nsIContent *rootElem = doc->GetRootContent();
00547       if (!doc->GetParentDocument() &&
00548           (nsCOMPtr<nsISupports>(doc->GetContainer())) &&
00549           rootElem && rootElem->IsContentOfType(nsIContent::eXUL)) {
00550         // we're XUL at the root of the document hierarchy. Try to make our
00551         // window translucent.
00552         // don't proceed unless this is the root view
00553         // (sometimes the non-root-view is a canvas)
00554         if (aView->HasWidget() && aView == rootView) {
00555           viewHasTransparentContent = hasBG && (bg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT);
00556           aView->GetWidget()->SetWindowTranslucency(viewHasTransparentContent);
00557         }
00558       }
00559     }
00560   }
00561   // XXX we should also set widget transparency for XUL popups
00562 
00563   nsFrameState kidState = aFrame->GetStateBits();
00564   PRBool isBlockLevel =
00565     display->IsBlockLevel() || (kidState & NS_FRAME_OUT_OF_FLOW);
00566   
00567   if (!viewHasTransparentContent) {
00568     const nsStyleVisibility* vis = aStyleContext->GetStyleVisibility();
00569     if (// If we're showing the view but the frame is hidden, then the
00570         // view is transparent
00571         (nsViewVisibility_kShow == aView->GetVisibility() &&
00572          NS_STYLE_VISIBILITY_HIDDEN == vis->mVisible)) {
00573       viewHasTransparentContent = PR_TRUE;
00574     } else {
00575       PRBool isScrolledContent = aView->GetParent() &&
00576         aView->GetParent()->ToScrollableView();
00577       // If we have overflowing kids and we're not clipped by a parent
00578       // scrolling view, then the view must be transparent.
00579       if (!isScrolledContent && (kidState & NS_FRAME_OUTSIDE_CHILDREN)) {
00580         viewHasTransparentContent = PR_TRUE;
00581       }
00582     }
00583   }
00584 
00585   // If the frame has visible content that overflows the content area, then we
00586   // need the view marked as having transparent content
00587 
00588   // There are two types of clipping:
00589   // - 'clip' which only applies to absolutely positioned elements, and is
00590   //    relative to the element's border edge. 'clip' applies to the entire
00591   //    element
00592   // - 'overflow:-moz-hidden-unscrollable' which only applies to
00593   //    block-level elements and replaced elements. Note
00594   //    that out-of-flow frames like floated or absolutely positioned
00595   //    frames are block-level, but we can't rely on the 'display' value
00596   //    being set correctly in the style context...
00597   PRBool hasClip = display->IsAbsolutelyPositioned() && (display->mClipFlags & NS_STYLE_CLIP_RECT);
00598   PRBool hasOverflowClip = isBlockLevel && (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP);
00599   if (hasClip || hasOverflowClip) {
00600     nsSize frameSize = aFrame->GetSize();
00601     nsRect  clipRect;
00602 
00603     if (hasClip) {
00604       // Start with the 'auto' values and then factor in user specified values
00605       clipRect.SetRect(0, 0, frameSize.width, frameSize.height);
00606 
00607       if (display->mClipFlags & NS_STYLE_CLIP_RECT) {
00608         if (0 == (NS_STYLE_CLIP_TOP_AUTO & display->mClipFlags)) {
00609           clipRect.y = display->mClip.y;
00610         }
00611         if (0 == (NS_STYLE_CLIP_LEFT_AUTO & display->mClipFlags)) {
00612           clipRect.x = display->mClip.x;
00613         }
00614         if (0 == (NS_STYLE_CLIP_RIGHT_AUTO & display->mClipFlags)) {
00615           clipRect.width = display->mClip.width;
00616         }
00617         if (0 == (NS_STYLE_CLIP_BOTTOM_AUTO & display->mClipFlags)) {
00618           clipRect.height = display->mClip.height;
00619         }
00620       }
00621     }
00622 
00623     if (hasOverflowClip) {
00624       const nsStyleBorder* borderStyle = aStyleContext->GetStyleBorder();
00625       const nsStylePadding* paddingStyle = aStyleContext->GetStylePadding();
00626 
00627       nsMargin padding;
00628       nsRect overflowClipRect(0, 0, frameSize.width, frameSize.height);
00629       overflowClipRect.Deflate(borderStyle->GetBorder());
00630       // XXX We need to handle percentage padding
00631       if (paddingStyle->GetPadding(padding)) {
00632         overflowClipRect.Deflate(padding);
00633       }
00634 #ifdef DEBUG
00635       else {
00636         NS_WARNING("Percentage padding and CLIP overflow don't mix");
00637       }
00638 #endif
00639 
00640       if (hasClip) {
00641         // If both 'clip' and 'overflow-clip' apply then use the intersection
00642         // of the two
00643         clipRect.IntersectRect(clipRect, overflowClipRect);
00644       } else {
00645         clipRect = overflowClipRect;
00646       }
00647     }
00648   
00649     nsRect newSize = aView->GetBounds();
00650     newSize -= aView->GetPosition();
00651 
00652     // If part of the view is being clipped out, then mark it transparent
00653     if (clipRect.y > newSize.y
00654         || clipRect.x > newSize.x
00655         || clipRect.XMost() < newSize.XMost()
00656         || clipRect.YMost() < newSize.YMost()) {
00657       viewHasTransparentContent = PR_TRUE;
00658     }
00659 
00660     // Set clipping of child views.
00661     nsRegion region(clipRect);
00662     vm->SetViewChildClipRegion(aView, &region);
00663   } else {
00664     // Remove clipping of child views.
00665     vm->SetViewChildClipRegion(aView, nsnull);
00666   }
00667 
00668   vm->SetViewContentTransparency(aView, viewHasTransparentContent);
00669 }
00670 
00671 void
00672 nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
00673                                            nsIFrame*       aFrame,
00674                                            nsIView*        aView,
00675                                            const nsRect*   aCombinedArea,
00676                                            PRUint32        aFlags)
00677 {
00678   if (!aView) {
00679     return;
00680   }
00681 
00682   // Make sure the view is sized and positioned correctly
00683   if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
00684     PositionFrameView(aFrame);
00685   }
00686 
00687   if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
00688     nsIViewManager* vm = aView->GetViewManager();
00689 
00690     // If the frame has child frames that stick outside the content
00691     // area, then size the view large enough to include those child
00692     // frames
00693     NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) ||
00694                  aCombinedArea,
00695                  "resizing view for frame with overflow to the wrong size");
00696     if ((aFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) && aCombinedArea) {
00697       vm->ResizeView(aView, *aCombinedArea, PR_TRUE);
00698     } else {
00699       nsSize frameSize = aFrame->GetSize();
00700       nsRect newSize(0, 0, frameSize.width, frameSize.height);
00701       vm->ResizeView(aView, newSize, PR_TRUE);
00702     }
00703 
00704     // Even if the size hasn't changed, we need to sync up the
00705     // geometry dependent properties, because (kidState &
00706     // NS_FRAME_OUTSIDE_CHILDREN) might have changed, and we can't
00707     // detect whether it has or not. Likewise, whether the view size
00708     // has changed or not, we may need to change the transparency
00709     // state even if there is no clip.
00710     nsStyleContext* savedStyleContext = aFrame->GetStyleContext();
00711     SyncFrameViewGeometryDependentProperties(aPresContext, aFrame, savedStyleContext, aView, aFlags);
00712   }
00713 }
00714 
00715 void
00716 nsContainerFrame::SyncFrameViewAfterSizeChange(nsPresContext*  aPresContext,
00717                                                nsIFrame*        aFrame,
00718                                                nsStyleContext*  aStyleContext,
00719                                                nsIView*         aView,
00720                                                PRUint32         aFlags)
00721 {
00722   NS_ASSERTION(!aStyleContext || aFrame->GetStyleContext() == aStyleContext,
00723                "Wrong style context for frame?");
00724 
00725   if (!aView) {
00726     return;
00727   }
00728   
00729   if (nsnull == aStyleContext) {
00730     aStyleContext = aFrame->GetStyleContext();
00731   }
00732 
00733   SyncFrameViewGeometryDependentProperties(aPresContext, aFrame, aStyleContext, aView, aFlags);
00734 }
00735 
00736 void
00737 nsContainerFrame::SyncFrameViewProperties(nsPresContext*  aPresContext,
00738                                           nsIFrame*        aFrame,
00739                                           nsStyleContext*  aStyleContext,
00740                                           nsIView*         aView,
00741                                           PRUint32         aFlags)
00742 {
00743   NS_ASSERTION(!aStyleContext || aFrame->GetStyleContext() == aStyleContext,
00744                "Wrong style context for frame?");
00745 
00746   if (!aView) {
00747     return;
00748   }
00749 
00750   nsIViewManager* vm = aView->GetViewManager();
00751 
00752   if (nsnull == aStyleContext) {
00753     aStyleContext = aFrame->GetStyleContext();
00754   }
00755     
00756   const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
00757 
00758   // Set the view's opacity
00759   vm->SetViewOpacity(aView, display->mOpacity);
00760 
00761   // Make sure visibility is correct
00762   if (0 == (aFlags & NS_FRAME_NO_VISIBILITY)) {
00763     // See if the view should be hidden or visible
00764     PRBool  viewIsVisible = PR_TRUE;
00765 
00766     if (!aStyleContext->GetStyleVisibility()->IsVisible() &&
00767         !aFrame->SupportsVisibilityHidden()) {
00768       // If it's a scrollable frame that can't hide its scrollbars,
00769       // hide the view. This means that child elements can't override
00770       // their parent's visibility, but it's not practical to leave it
00771       // visible in all cases because the scrollbars will be showing
00772       // XXXldb Does the view system really enforce this correctly?
00773       viewIsVisible = PR_FALSE;
00774     } else {
00775       // if the view is for a popup, don't show the view if the popup is closed
00776       nsIWidget* widget = aView->GetWidget();
00777       if (widget) {
00778         nsWindowType windowType;
00779         widget->GetWindowType(windowType);
00780         if (windowType == eWindowType_popup) {
00781           widget->IsVisible(viewIsVisible);
00782         }
00783       }
00784     }
00785 
00786     vm->SetViewVisibility(aView, viewIsVisible ? nsViewVisibility_kShow :
00787                           nsViewVisibility_kHide);
00788   }
00789 
00790   // See if the frame is being relatively positioned or absolutely
00791   // positioned
00792   PRBool isPositioned = display->IsPositioned();
00793 
00794   PRInt32 zIndex = 0;
00795   PRBool  autoZIndex = PR_FALSE;
00796 
00797   if (!isPositioned) {
00798     autoZIndex = PR_TRUE;
00799   } else {
00800     // Make sure z-index is correct
00801     const nsStylePosition* position = aStyleContext->GetStylePosition();
00802 
00803     if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
00804       zIndex = position->mZIndex.GetIntValue();
00805     } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
00806       autoZIndex = PR_TRUE;
00807     }
00808   }
00809 
00810   vm->SetViewZIndex(aView, autoZIndex, zIndex, isPositioned);
00811 
00812   SyncFrameViewGeometryDependentProperties(aPresContext, aFrame, aStyleContext, aView, aFlags);
00813 }
00814 
00815 PRBool
00816 nsContainerFrame::FrameNeedsView(nsIFrame* aFrame)
00817 {
00818   if (aFrame->NeedsView()) {
00819     return PR_TRUE;
00820   }
00821 
00822   nsStyleContext* sc = aFrame->GetStyleContext();
00823   const nsStyleDisplay* display = sc->GetStyleDisplay();
00824   if (display->mOpacity != 1.0f) {
00825     return PR_TRUE;
00826   }
00827 
00828   // See if the frame has a fixed background attachment
00829   const nsStyleBackground *color;
00830   PRBool isCanvas;
00831   PRBool hasBackground = 
00832     nsCSSRendering::FindBackground(aFrame->GetPresContext(),
00833                                    aFrame, &color, &isCanvas);
00834   if (hasBackground && color->HasFixedBackground()) {
00835     return PR_TRUE;
00836   }
00837     
00838   if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
00839     return PR_TRUE;
00840   } else if (display->IsAbsolutelyPositioned()) {
00841     return PR_TRUE;
00842   } 
00843 
00844   if (sc->GetPseudoType() == nsCSSAnonBoxes::scrolledContent) {
00845     return PR_TRUE;
00846   }
00847 
00848   // See if the frame is block-level and has 'overflow' set to
00849   // '-moz-hidden-unscrollable'. If so, then we need to give it a view
00850   // so clipping of any child views works correctly. Note that if it's
00851   // floated it is also block-level, but we can't trust that the style
00852   // context 'display' value is set correctly.
00853   if ((display->IsBlockLevel() || display->IsFloating()) &&
00854       (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)) {
00855     // XXX Check for the frame being a block frame and only force a view
00856     // in that case, because adding a view for box frames seems to cause
00857     // problems for XUL...
00858     nsIAtom* frameType = aFrame->GetType();
00859     if ((frameType == nsLayoutAtoms::blockFrame) ||
00860         (frameType == nsLayoutAtoms::areaFrame)) {
00861       return PR_TRUE;
00862     }
00863   }
00864 
00865   return PR_FALSE;
00866 }
00867 
00873 nsresult
00874 nsContainerFrame::ReflowChild(nsIFrame*                aKidFrame,
00875                               nsPresContext*           aPresContext,
00876                               nsHTMLReflowMetrics&     aDesiredSize,
00877                               const nsHTMLReflowState& aReflowState,
00878                               nscoord                  aX,
00879                               nscoord                  aY,
00880                               PRUint32                 aFlags,
00881                               nsReflowStatus&          aStatus)
00882 {
00883   NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
00884 
00885   nsresult  result;
00886 
00887 #ifdef DEBUG
00888 #ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
00889   if (aDesiredSize.mComputeMEW) {
00890     aDesiredSize.mMaxElementWidth = nscoord(0xdeadbeef);
00891   }
00892 #endif
00893 #endif
00894 
00895   // Send the WillReflow() notification, and position the child frame
00896   // and its view if requested
00897   aKidFrame->WillReflow(aPresContext);
00898 
00899   if (0 == (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
00900     aKidFrame->SetPosition(nsPoint(aX, aY));
00901   }
00902 
00903   if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
00904     PositionFrameView(aKidFrame);
00905   }
00906 
00907   // Reflow the child frame
00908   result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
00909                              aStatus);
00910 
00911 #ifdef DEBUG
00912 #ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
00913   if (aDesiredSize.mComputeMEW &&
00914       (nscoord(0xdeadbeef) == aDesiredSize.mMaxElementWidth)) {
00915     printf("nsContainerFrame: ");
00916     nsFrame::ListTag(stdout, aKidFrame);
00917     printf(" didn't set max-element-width!\n");
00918   }
00919 #endif
00920 #endif
00921 
00922   // If the reflow was successful and the child frame is complete, delete any
00923   // next-in-flows
00924   if (NS_SUCCEEDED(result) && NS_FRAME_IS_COMPLETE(aStatus)) {
00925     nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
00926     if (nsnull != kidNextInFlow) {
00927       // Remove all of the childs next-in-flows. Make sure that we ask
00928       // the right parent to do the removal (it's possible that the
00929       // parent is not this because we are executing pullup code)
00930       NS_STATIC_CAST(nsContainerFrame*, kidNextInFlow->GetParent())
00931         ->DeleteNextInFlowChild(aPresContext, kidNextInFlow);
00932     }
00933   }
00934   return result;
00935 }
00936 
00937 
00942 void
00943 nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
00944 {
00945   if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
00946     return;
00947   }
00948 
00949   nsIAtom*  childListName = nsnull;
00950   PRInt32   childListIndex = 0;
00951 
00952   do {
00953     // Recursively walk aFrame's child frames
00954     nsIFrame* childFrame = aFrame->GetFirstChild(childListName);
00955     while (childFrame) {
00956       // Position the frame's view (if it has one) otherwise recursively
00957       // process its children
00958       if (childFrame->HasView()) {
00959         PositionFrameView(childFrame);
00960       } else {
00961         PositionChildViews(childFrame);
00962       }
00963 
00964       // Get the next sibling child frame
00965       childFrame = childFrame->GetNextSibling();
00966     }
00967 
00968     childListName = aFrame->GetAdditionalChildListName(childListIndex++);
00969   } while (childListName);
00970 }
00971 
00989 nsresult
00990 nsContainerFrame::FinishReflowChild(nsIFrame*                 aKidFrame,
00991                                     nsPresContext*            aPresContext,
00992                                     const nsHTMLReflowState*  aReflowState,
00993                                     nsHTMLReflowMetrics&      aDesiredSize,
00994                                     nscoord                   aX,
00995                                     nscoord                   aY,
00996                                     PRUint32                  aFlags)
00997 {
00998   nsPoint curOrigin = aKidFrame->GetPosition();
00999   nsRect  bounds(aX, aY, aDesiredSize.width, aDesiredSize.height);
01000 
01001   aKidFrame->SetRect(bounds);
01002 
01003   if (aKidFrame->HasView()) {
01004     nsIView* view = aKidFrame->GetView();
01005     // Make sure the frame's view is properly sized and positioned and has
01006     // things like opacity correct
01007     SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
01008                              &aDesiredSize.mOverflowArea,
01009                              aFlags);
01010   }
01011 
01012   if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
01013       (curOrigin.x != aX || curOrigin.y != aY)) {
01014     if (!aKidFrame->HasView()) {
01015       // If the frame has moved, then we need to make sure any child views are
01016       // correctly positioned
01017       PositionChildViews(aKidFrame);
01018     }
01019 
01020     // We also need to redraw everything associated with the frame
01021     // because if the frame's Reflow issued any invalidates, then they
01022     // will be at the wrong offset ... note that this includes
01023     // invalidates issued against the frame's children, so we need to
01024     // invalidate the overflow area too.
01025     aKidFrame->Invalidate(aDesiredSize.mOverflowArea);
01026   }
01027   
01028   return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED);
01029 }
01030 
01035 void
01036 nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
01037                                         nsIFrame*       aNextInFlow)
01038 {
01039   nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
01040   NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
01041   NS_PRECONDITION(mFrames.ContainsFrame(aNextInFlow), "bad geometric parent");
01042 
01043   // If the next-in-flow has a next-in-flow then delete it, too (and
01044   // delete it first).
01045   // Do this in a loop so we don't overflow the stack for frames
01046   // with very many next-in-flows
01047   nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
01048   if (nextNextInFlow) {
01049     nsAutoVoidArray frames;
01050     for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
01051       frames.AppendElement(f);
01052     }
01053     for (PRInt32 i = frames.Count() - 1; i >= 0; --i) {
01054       nsIFrame* delFrame = NS_STATIC_CAST(nsIFrame*, frames.ElementAt(i));
01055       NS_STATIC_CAST(nsContainerFrame*, delFrame->GetParent())
01056         ->DeleteNextInFlowChild(aPresContext, delFrame);
01057     }
01058   }
01059 
01060 #ifdef IBMBIDI
01061   if ((prevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) &&
01062       (NS_STATIC_CAST(nsIFrame*,
01063                       aPresContext->PropertyTable()->GetProperty(prevInFlow, nsLayoutAtoms::nextBidi)) ==
01064        aNextInFlow)) {
01065     return;
01066   }
01067 #endif // IBMBIDI
01068 
01069   // Disconnect the next-in-flow from the flow list
01070   nsSplittableFrame::BreakFromPrevFlow(aNextInFlow);
01071 
01072   // Take the next-in-flow out of the parent's child list
01073   PRBool result = mFrames.RemoveFrame(aNextInFlow);
01074   if (!result) {
01075     // We didn't find the child in the parent's principal child list.
01076     // Maybe it's on the overflow list?
01077     nsFrameList overflowFrames(GetOverflowFrames(aPresContext, PR_TRUE));
01078 
01079     if (overflowFrames.IsEmpty() || !overflowFrames.RemoveFrame(aNextInFlow)) {
01080       NS_ASSERTION(result, "failed to remove frame");
01081     }
01082 
01083     // Set the overflow property again
01084     if (overflowFrames.NotEmpty()) {
01085       SetOverflowFrames(aPresContext, overflowFrames.FirstChild());
01086     }
01087   }
01088 
01089   // Delete the next-in-flow frame and its descendants.
01090   aNextInFlow->Destroy(aPresContext);
01091 
01092   NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
01093 }
01094 
01095 nsIFrame*
01096 nsContainerFrame::GetOverflowFrames(nsPresContext* aPresContext,
01097                                     PRBool          aRemoveProperty) const
01098 {
01099   nsPropertyTable *propTable = aPresContext->PropertyTable();
01100   if (aRemoveProperty) {
01101     return (nsIFrame*) propTable->UnsetProperty(this,
01102                                               nsLayoutAtoms::overflowProperty);
01103   }
01104 
01105   return (nsIFrame*) propTable->GetProperty(this,
01106                                             nsLayoutAtoms::overflowProperty);
01107 }
01108 
01109 // Destructor function for the overflow frame property
01110 static void
01111 DestroyOverflowFrames(void*           aFrame,
01112                       nsIAtom*        aPropertyName,
01113                       void*           aPropertyValue,
01114                       void*           aDtorData)
01115 {
01116   if (aPropertyValue) {
01117     nsFrameList frames((nsIFrame*)aPropertyValue);
01118 
01119     frames.DestroyFrames(NS_STATIC_CAST(nsPresContext*, aDtorData));
01120   }
01121 }
01122 
01123 nsresult
01124 nsContainerFrame::SetOverflowFrames(nsPresContext* aPresContext,
01125                                     nsIFrame*       aOverflowFrames)
01126 {
01127   nsresult rv =
01128     aPresContext->PropertyTable()->SetProperty(this,
01129                                                nsLayoutAtoms::overflowProperty,
01130                                                aOverflowFrames,
01131                                                DestroyOverflowFrames,
01132                                                aPresContext);
01133 
01134   // Verify that we didn't overwrite an existing overflow list
01135   NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing overflow list");
01136 
01137   return rv;
01138 }
01139 
01154 void
01155 nsContainerFrame::PushChildren(nsPresContext* aPresContext,
01156                                nsIFrame*       aFromChild,
01157                                nsIFrame*       aPrevSibling)
01158 {
01159   NS_PRECONDITION(nsnull != aFromChild, "null pointer");
01160   NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child");
01161   NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
01162 
01163   // Disconnect aFromChild from its previous sibling
01164   aPrevSibling->SetNextSibling(nsnull);
01165 
01166   if (nsnull != mNextInFlow) {
01167     // XXX This is not a very good thing to do. If it gets removed
01168     // then remove the copy of this routine that doesn't do this from
01169     // nsInlineFrame.
01170     nsContainerFrame* nextInFlow = (nsContainerFrame*)mNextInFlow;
01171     // When pushing and pulling frames we need to check for whether any
01172     // views need to be reparented.
01173     for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
01174       nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, this, mNextInFlow);
01175     }
01176     nextInFlow->mFrames.InsertFrames(mNextInFlow, nsnull, aFromChild);
01177   }
01178   else {
01179     // Add the frames to our overflow list
01180     SetOverflowFrames(aPresContext, aFromChild);
01181   }
01182 }
01183 
01192 PRBool
01193 nsContainerFrame::MoveOverflowToChildList(nsPresContext* aPresContext)
01194 {
01195   PRBool result = PR_FALSE;
01196 
01197   // Check for an overflow list with our prev-in-flow
01198   nsContainerFrame* prevInFlow = (nsContainerFrame*)mPrevInFlow;
01199   if (nsnull != prevInFlow) {
01200     nsIFrame* prevOverflowFrames = prevInFlow->GetOverflowFrames(aPresContext,
01201                                                                  PR_TRUE);
01202     if (prevOverflowFrames) {
01203       NS_ASSERTION(mFrames.IsEmpty(), "bad overflow list");
01204       // When pushing and pulling frames we need to check for whether any
01205       // views need to be reparented.
01206       for (nsIFrame* f = prevOverflowFrames; f; f = f->GetNextSibling()) {
01207         nsHTMLContainerFrame::ReparentFrameView(aPresContext, f, prevInFlow, this);
01208       }
01209       mFrames.InsertFrames(this, nsnull, prevOverflowFrames);
01210       result = PR_TRUE;
01211     }
01212   }
01213 
01214   // It's also possible that we have an overflow list for ourselves
01215   nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE);
01216   if (overflowFrames) {
01217     NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
01218     mFrames.AppendFrames(nsnull, overflowFrames);
01219     result = PR_TRUE;
01220   }
01221   return result;
01222 }
01223 
01225 // Debugging
01226 
01227 #ifdef NS_DEBUG
01228 NS_IMETHODIMP
01229 nsContainerFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
01230 {
01231   IndentBy(out, aIndent);
01232   ListTag(out);
01233 #ifdef DEBUG_waterson
01234   fprintf(out, " [parent=%p]", NS_STATIC_CAST(void*, mParent));
01235 #endif
01236   if (HasView()) {
01237     fprintf(out, " [view=%p]", NS_STATIC_CAST(void*, GetView()));
01238   }
01239   if (nsnull != mNextSibling) {
01240     fprintf(out, " next=%p", NS_STATIC_CAST(void*, mNextSibling));
01241   }
01242   if (nsnull != mPrevInFlow) {
01243     fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, mPrevInFlow));
01244   }
01245   if (nsnull != mNextInFlow) {
01246     fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, mNextInFlow));
01247   }
01248   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
01249   if (0 != mState) {
01250     fprintf(out, " [state=%08x]", mState);
01251   }
01252   fprintf(out, " [content=%p]", NS_STATIC_CAST(void*, mContent));
01253   nsContainerFrame* f = NS_CONST_CAST(nsContainerFrame*, this);
01254   nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE);
01255   if (overflowArea) {
01256     fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea->x, overflowArea->y,
01257             overflowArea->width, overflowArea->height);
01258   }
01259   fprintf(out, " [sc=%p]", NS_STATIC_CAST(void*, mStyleContext));
01260   nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
01261   if (pseudoTag) {
01262     nsAutoString atomString;
01263     pseudoTag->ToString(atomString);
01264     fprintf(out, " pst=%s",
01265             NS_LossyConvertUCS2toASCII(atomString).get());
01266   }
01267 
01268   // Output the children
01269   nsIAtom* listName = nsnull;
01270   PRInt32 listIndex = 0;
01271   PRBool outputOneList = PR_FALSE;
01272   do {
01273     nsIFrame* kid = GetFirstChild(listName);
01274     if (nsnull != kid) {
01275       if (outputOneList) {
01276         IndentBy(out, aIndent);
01277       }
01278       outputOneList = PR_TRUE;
01279       nsAutoString tmp;
01280       if (nsnull != listName) {
01281         listName->ToString(tmp);
01282         fputs(NS_LossyConvertUCS2toASCII(tmp).get(), out);
01283       }
01284       fputs("<\n", out);
01285       while (nsnull != kid) {
01286         // Verify the child frame's parent frame pointer is correct
01287         NS_ASSERTION(kid->GetParent() == (nsIFrame*)this, "bad parent frame pointer");
01288 
01289         // Have the child frame list
01290         nsIFrameDebug*  frameDebug;
01291         if (NS_SUCCEEDED(kid->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
01292           frameDebug->List(aPresContext, out, aIndent + 1);
01293         }
01294         kid = kid->GetNextSibling();
01295       }
01296       IndentBy(out, aIndent);
01297       fputs(">\n", out);
01298     }
01299     listName = GetAdditionalChildListName(listIndex++);
01300   } while(nsnull != listName);
01301 
01302   if (!outputOneList) {
01303     fputs("<>\n", out);
01304   }
01305 
01306   return NS_OK;
01307 }
01308 #endif