Bug 653649 - New way of getting child lists from frames. (part 2/5) r=roc sr=dbaron
authorMats Palmgren <matspal@gmail.com>
Wed, 24 Aug 2011 22:54:29 +0200
changeset 75841 bbb68899df56fe3296ba9d9ee93e97f49af69b66
parent 75840 5c0d46747250439b8987d5740149e7014c4a3fa2
child 75842 de17763f5ba71293a5193266f815151047466eb5
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersroc, dbaron
bugs653649
milestone9.0a1
Bug 653649 - New way of getting child lists from frames. (part 2/5) r=roc sr=dbaron Implement GetChildList(ChildListID) and GetChildLists(nsTArray<ChildList>*) for various frame classes. Remove GetAdditionalChildListName(PRInt32) methods and associated macros and list index constants.
layout/forms/nsComboboxControlFrame.cpp
layout/generic/nsAbsoluteContainingBlock.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsIFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsViewportFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableOuterFrame.cpp
layout/xul/base/src/nsMenuFrame.cpp
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1232,24 +1232,30 @@ nsComboboxControlFrame::DestroyFrom(nsIF
 
   // Cleanup frames in popup child list
   mPopupFrames.DestroyFramesFrom(aDestructRoot);
   nsContentUtils::DestroyAnonymousContent(&mDisplayContent);
   nsContentUtils::DestroyAnonymousContent(&mButtonContent);
   nsBlockFrame::DestroyFrom(aDestructRoot);
 }
 
-
 nsFrameList
-nsComboboxControlFrame::GetChildList(nsIAtom* aListName) const
+nsComboboxControlFrame::GetChildList(ChildListID aListID) const
 {
-  if (nsGkAtoms::selectPopupList == aListName) {
+  if (kSelectPopupList == aListID) {
     return mPopupFrames;
   }
-  return nsBlockFrame::GetChildList(aListName);
+  return nsBlockFrame::GetChildList(aListID);
+}
+
+void
+nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const
+{
+  nsBlockFrame::GetChildLists(aLists);
+  mPopupFrames.AppendIfNonempty(aLists, kSelectPopupList);
 }
 
 NS_IMETHODIMP
 nsComboboxControlFrame::SetInitialChildList(nsIAtom*        aListName,
                                             nsFrameList&    aChildList)
 {
   nsresult rv = NS_OK;
   if (nsGkAtoms::selectPopupList == aListName) {
@@ -1264,35 +1270,16 @@ nsComboboxControlFrame::SetInitialChildL
       }
     }
     NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
     rv = nsBlockFrame::SetInitialChildList(aListName, aChildList);
   }
   return rv;
 }
 
-#define NS_COMBO_FRAME_POPUP_LIST_INDEX   (NS_BLOCK_LIST_COUNT)
-
-nsIAtom*
-nsComboboxControlFrame::GetAdditionalChildListName(PRInt32 aIndex) const
-{
-   // Maintain a separate child list for the dropdown list (i.e. popup listbox)
-   // This is necessary because we don't want the listbox to be included in the layout
-   // of the combox's children because it would take up space, when it is suppose to
-   // be floating above the display.
-  if (aIndex < NS_BLOCK_LIST_COUNT) {
-    return nsBlockFrame::GetAdditionalChildListName(aIndex);
-  }
-  
-  if (NS_COMBO_FRAME_POPUP_LIST_INDEX == aIndex) {
-    return nsGkAtoms::selectPopupList;
-  }
-  return nsnull;
-}
-
 //----------------------------------------------------------------------
   //nsIRollupListener
 //----------------------------------------------------------------------
 NS_IMETHODIMP 
 nsComboboxControlFrame::Rollup(PRUint32 aCount,
                                nsIContent** aLastRolledUp)
 {
   if (aLastRolledUp)
--- a/layout/generic/nsAbsoluteContainingBlock.h
+++ b/layout/generic/nsAbsoluteContainingBlock.h
@@ -80,16 +80,22 @@ public:
                  "should either represent position:fixed or absolute content");
   }
 
 #ifdef DEBUG
   nsIAtom* GetChildListName() const { return mChildListName; }
 #endif
 
   const nsFrameList& GetChildList() const { return mAbsoluteFrames; }
+  void AppendChildList(nsTArray<nsIFrame::ChildList>* aLists,
+                       ChildListID aListID) const
+  {
+    NS_ASSERTION(aListID == GetChildListID(), "wrong list ID");
+    GetChildList().AppendIfNonempty(aLists, aListID);
+  }
 
   nsresult SetInitialChildList(nsIFrame*       aDelegatingFrame,
                                nsIAtom*        aListName,
                                nsFrameList&    aChildList);
   nsresult AppendFrames(nsIFrame*      aDelegatingFrame,
                         nsIAtom*       aListName,
                         nsFrameList&   aFrameList);
   nsresult InsertFrames(nsIFrame*      aDelegatingFrame,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -577,76 +577,72 @@ nsBlockFrame::GetCaretBaseline() const
       CalcLineHeight(GetStyleContext(), contentRect.height)) +
     bp.top;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
 
 nsFrameList
-nsBlockFrame::GetChildList(nsIAtom* aListName) const
+nsBlockFrame::GetChildList(ChildListID aListID) const
 {
-  if (nsGkAtoms::absoluteList == aListName) {
-    return mAbsoluteContainer.GetChildList();
-  }
-  else if (nsnull == aListName) {
-    return mFrames;
-  }
-  else if (aListName == nsGkAtoms::overflowList) {
-    // XXXbz once we start using nsFrameList for our overflow list, we
-    // could switch GetChildList to returning a |const nsFrameList&|.
-    nsLineList* overflowLines = GetOverflowLines();
-    return overflowLines ? nsFrameList(overflowLines->front()->mFirstChild,
-                                       overflowLines->back()->LastChild())
-                         : nsFrameList::EmptyList();
-  }
-  else if (aListName == nsGkAtoms::overflowOutOfFlowList) {
-    const nsFrameList* list = GetOverflowOutOfFlows();
-    return list ? *list : nsFrameList::EmptyList();
-  }
-  else if (aListName == nsGkAtoms::pushedFloatsList) {
-    const nsFrameList* list = GetPushedFloats();
-    return list ? *list : nsFrameList::EmptyList();
-  }
-  else if (aListName == nsGkAtoms::floatList) {
-    return mFloats;
-  }
-  else if (aListName == nsGkAtoms::bulletList) {
-    return HaveOutsideBullet() ? nsFrameList(mBullet, mBullet)
-                               : nsFrameList::EmptyList();
-  }
-  return nsContainerFrame::GetChildList(aListName);
-}
-
-#define NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX  (NS_CONTAINER_LIST_COUNT_INCL_OC + 0)
-#define NS_BLOCK_FRAME_FLOAT_LIST_INDEX         (NS_CONTAINER_LIST_COUNT_INCL_OC + 1)
-#define NS_BLOCK_FRAME_BULLET_LIST_INDEX        (NS_CONTAINER_LIST_COUNT_INCL_OC + 2)
-#define NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX      (NS_CONTAINER_LIST_COUNT_INCL_OC + 3)
-#define NS_BLOCK_FRAME_PUSHED_FLOATS_LIST_INDEX (NS_CONTAINER_LIST_COUNT_INCL_OC + 4)
-// If adding/removing lists, don't forget to update the count in nsBlockFrame.h
-
-nsIAtom*
-nsBlockFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+  switch (aListID) {
+    case kPrincipalList:
+      return mFrames;
+    case kOverflowList: {
+      // XXXbz once we start using nsFrameList for our overflow list, we
+      // could switch GetChildList to returning a |const nsFrameList&|.
+      nsLineList* overflowLines = GetOverflowLines();
+      return overflowLines ? nsFrameList(overflowLines->front()->mFirstChild,
+                                         overflowLines->back()->LastChild())
+                           : nsFrameList::EmptyList();
+    }
+    case kAbsoluteList:
+      return mAbsoluteContainer.GetChildList();
+    case kFloatList:
+      return mFloats;
+    case kOverflowOutOfFlowList: {
+      const nsFrameList* list = GetOverflowOutOfFlows();
+      return list ? *list : nsFrameList::EmptyList();
+    }
+    case kPushedFloatsList: {
+      const nsFrameList* list = GetPushedFloats();
+      return list ? *list : nsFrameList::EmptyList();
+    }
+    case kBulletList:
+      return HaveOutsideBullet() ? nsFrameList(mBullet, mBullet)
+                                 : nsFrameList::EmptyList();
+    default:
+      return nsContainerFrame::GetChildList(aListID);
+  }
+}
+
+void
+nsBlockFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
-  if (aIndex < NS_CONTAINER_LIST_COUNT_INCL_OC)
-    return nsContainerFrame::GetAdditionalChildListName(aIndex);
-
-  switch (aIndex) {
-  case NS_BLOCK_FRAME_FLOAT_LIST_INDEX:
-    return nsGkAtoms::floatList;
-  case NS_BLOCK_FRAME_BULLET_LIST_INDEX:
-    return nsGkAtoms::bulletList;
-  case NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX:
-    return nsGkAtoms::overflowOutOfFlowList;
-  case NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX:
-    return nsGkAtoms::absoluteList;
-  case NS_BLOCK_FRAME_PUSHED_FLOATS_LIST_INDEX:
-    return nsGkAtoms::pushedFloatsList;
-  default:
-    return nsnull;
+  nsContainerFrame::GetChildLists(aLists);
+  nsLineList* overflowLines = GetOverflowLines();
+  if (overflowLines && overflowLines->front()->mFirstChild) {
+    nsFrameList overflowList(overflowLines->front()->mFirstChild,
+                             overflowLines->back()->LastChild());
+    overflowList.AppendIfNonempty(aLists, kOverflowList);
+  }
+  const nsFrameList* list = GetOverflowOutOfFlows();
+  if (list) {
+    list->AppendIfNonempty(aLists, kOverflowOutOfFlowList);
+  }
+  mFloats.AppendIfNonempty(aLists, kFloatList);
+  if (HaveOutsideBullet()) {
+    nsFrameList bullet(mBullet, mBullet);
+    bullet.AppendIfNonempty(aLists, kBulletList);
+  }
+  mAbsoluteContainer.AppendChildList(aLists, kAbsoluteList);
+  list = GetPushedFloats();
+  if (list) {
+    list->AppendIfNonempty(aLists, kPushedFloatsList);
   }
 }
 
 /* virtual */ PRBool
 nsBlockFrame::IsContainingBlock() const
 {
   // The block wrappers we use to wrap blocks inside inlines aren't
   // described in the CSS spec.  We need to make them not be containing
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -222,22 +222,29 @@ nsCanvasFrame::GetAdditionalChildListNam
 {
   if (CANVAS_ABS_POS_CHILD_LIST == aIndex)
     return nsGkAtoms::absoluteList;
 
   return nsHTMLContainerFrame::GetAdditionalChildListName(aIndex);
 }
 
 nsFrameList
-nsCanvasFrame::GetChildList(nsIAtom* aListName) const
+nsCanvasFrame::GetChildList(ChildListID aListID) const
 {
-  if (nsGkAtoms::absoluteList == aListName)
+  if (kAbsoluteList == aListID)
     return mAbsoluteContainer.GetChildList();
 
-  return nsHTMLContainerFrame::GetChildList(aListName);
+  return nsHTMLContainerFrame::GetChildList(aListID);
+}
+
+void
+nsCanvasFrame::GetChildLists(nsTArray<ChildList>* aLists) const
+{
+  nsHTMLContainerFrame::GetChildLists(aLists);
+  mAbsoluteContainer.AppendChildList(aLists, kAbsoluteList);
 }
 
 nsRect nsCanvasFrame::CanvasArea() const
 {
   // Not clear which overflow rect we want here, but it probably doesn't
   // matter.
   nsRect result(GetVisualOverflowRect());
 
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -79,18 +79,18 @@ public:
   NS_IMETHOD AppendFrames(nsIAtom*        aListName,
                           nsFrameList&    aFrameList);
   NS_IMETHOD InsertFrames(nsIAtom*        aListName,
                           nsIFrame*       aPrevFrame,
                           nsFrameList&    aFrameList);
   NS_IMETHOD RemoveFrame(nsIAtom*        aListName,
                          nsIFrame*       aOldFrame);
 
-  virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
-  virtual nsFrameList GetChildList(nsIAtom* aListName) const;
+  virtual nsFrameList GetChildList(ChildListID aListID) const;
+  virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus);
   virtual PRBool IsContainingBlock() const { return PR_TRUE; }
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -289,62 +289,67 @@ nsContainerFrame::DestroyFrom(nsIFrame* 
   // Destroy the frame and remove the flow pointers
   nsSplittableFrame::DestroyFrom(aDestructRoot);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
 
 nsFrameList
-nsContainerFrame::GetChildList(nsIAtom* aListName) const
+nsContainerFrame::GetChildList(ChildListID aListID) const
 {
-  // We only know about the unnamed principal child list and the overflow
-  // lists
-  if (nsnull == aListName) {
-    return mFrames;
-  }
-
-  if (nsGkAtoms::overflowList == aListName) {
-    nsFrameList* frameList = GetOverflowFrames();
-    return frameList ? *frameList : nsFrameList::EmptyList();
+  // We only know about the principal child list and the overflow lists.
+  switch (aListID) {
+    case kPrincipalList:
+      return mFrames;
+    case kOverflowList: {
+      nsFrameList* list = GetOverflowFrames();
+      return list ? *list : nsFrameList::EmptyList();
+    }
+    case kOverflowContainersList: {
+      nsFrameList* list =
+        GetPropTableFrames(PresContext(), OverflowContainersProperty());
+      return list ? *list : nsFrameList::EmptyList();
+    }
+    case kExcessOverflowContainersList: {
+      nsFrameList* list =
+        GetPropTableFrames(PresContext(), ExcessOverflowContainersProperty());
+      return list ? *list : nsFrameList::EmptyList();
+    }
+    default:
+      return nsSplittableFrame::GetChildList(aListID);
   }
-
-  if (nsGkAtoms::overflowContainersList == aListName) {
-    nsFrameList* list = GetPropTableFrames(PresContext(),
-                                           OverflowContainersProperty());
-    return list ? *list : nsFrameList::EmptyList();
-  }
-
-  if (nsGkAtoms::excessOverflowContainersList == aListName) {
-    nsFrameList* list = GetPropTableFrames(PresContext(),
-                                           ExcessOverflowContainersProperty());
-    return list ? *list : nsFrameList::EmptyList();
-  }
-
-  return nsFrameList::EmptyList();
 }
 
-#define NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX                   0
-#define NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX        1
-#define NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX 2
-// If adding/removing lists, don't forget to update count in .h file
-
-
-nsIAtom*
-nsContainerFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+static void AppendIfNonempty(const nsIFrame* aFrame,
+                            FramePropertyTable* aPropTable,
+                            const FramePropertyDescriptor* aProperty,
+                            nsTArray<nsIFrame::ChildList>* aLists,
+                            nsIFrame::ChildListID aListID)
 {
-  if (NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX == aIndex)
-    return nsGkAtoms::overflowList;
-  else if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
-    if (NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX == aIndex)
-      return nsGkAtoms::overflowContainersList;
-    else if (NS_CONTAINER_FRAME_EXCESS_OVERFLOW_CONTAINERS_LIST_INDEX == aIndex)
-      return nsGkAtoms::excessOverflowContainersList;
+  nsFrameList* list = static_cast<nsFrameList*>(
+    aPropTable->Get(aFrame, aProperty));
+  if (list) {
+    list->AppendIfNonempty(aLists, aListID);
   }
-  return nsnull;
+}
+
+void
+nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
+{
+  mFrames.AppendIfNonempty(aLists, kPrincipalList);
+  FramePropertyTable* propTable = PresContext()->PropertyTable();
+  ::AppendIfNonempty(this, propTable, OverflowProperty(),
+                     aLists, kOverflowList);
+  if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
+    ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
+                       aLists, kOverflowContainersList);
+    ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
+                       aLists, kExcessOverflowContainersList);
+  }
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Painting/Events
 
 NS_IMETHODIMP
 nsContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                    const nsRect&           aDirtyRect,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -586,16 +586,38 @@ nsFrame::DidSetStyleContext(nsStyleConte
   // does not contain any characters that would activate the Unicode
   // bidi algorithm, we need to call |SetBidiEnabled| on the pres
   // context before reflow starts.  See bug 115921.
   if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     PresContext()->SetBidiEnabled();
   }
 }
 
+// MSVC fails with link error "one or more multiply defined symbols found",
+// gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
+// etc if they are not defined.
+#ifndef _MSC_VER
+// static nsIFrame constants; initialized in the header file.
+const nsIFrame::ChildListID nsIFrame::kPrincipalList;
+const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
+const nsIFrame::ChildListID nsIFrame::kBulletList;
+const nsIFrame::ChildListID nsIFrame::kCaptionList;
+const nsIFrame::ChildListID nsIFrame::kColGroupList;
+const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
+const nsIFrame::ChildListID nsIFrame::kFixedList;
+const nsIFrame::ChildListID nsIFrame::kFloatList;
+const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
+const nsIFrame::ChildListID nsIFrame::kOverflowList;
+const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
+const nsIFrame::ChildListID nsIFrame::kPopupList;
+const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
+const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
+const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
+#endif
+
 /* virtual */ nsMargin
 nsIFrame::GetUsedMargin() const
 {
   nsMargin margin(0, 0, 0, 0);
   if ((mState & NS_FRAME_FIRST_REFLOW) &&
       !(mState & NS_FRAME_IN_REFLOW))
     return margin;
 
@@ -913,31 +935,16 @@ nsFrame::GetBaseline() const
 {
   NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
                "frame must not be dirty");
   // Default to the bottom margin edge, per CSS2.1's definition of the
   // 'baseline' value of 'vertical-align'.
   return mRect.height + GetUsedMargin().bottom;
 }
 
-// Child frame enumeration
-
-nsIAtom*
-nsFrame::GetAdditionalChildListName(PRInt32 aIndex) const
-{
-  NS_PRECONDITION(aIndex >= 0, "invalid index number");
-  return nsnull;
-}
-
-nsFrameList
-nsFrame::GetChildList(nsIAtom* aListName) const
-{
-  return nsFrameList::EmptyList();
-}
-
 static nsIFrame*
 GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
 {
   nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
   if (capturingContent) {
     nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
     return activeFrame ? activeFrame : aFrame;
   }
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -186,17 +186,21 @@ public:
                           nsIFrame*       aOldFrame);
   virtual void DestroyFrom(nsIFrame* aDestructRoot);
   virtual nsStyleContext* GetAdditionalStyleContext(PRInt32 aIndex) const;
   virtual void SetAdditionalStyleContext(PRInt32 aIndex,
                                          nsStyleContext* aStyleContext);
   virtual void SetParent(nsIFrame* aParent);
   virtual nscoord GetBaseline() const;
   virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
-  virtual nsFrameList GetChildList(nsIAtom* aListName) const;
+  virtual nsFrameList GetChildList(ChildListID aListID) const {
+    return nsFrameList::EmptyList();
+  }
+  virtual void GetChildLists(nsTArray<ChildList>* aLists) const {}
+
   NS_IMETHOD  HandleEvent(nsPresContext* aPresContext, 
                           nsGUIEvent*     aEvent,
                           nsEventStatus*  aEventStatus);
   NS_IMETHOD  GetContentForEvent(nsPresContext* aPresContext,
                                  nsEvent* aEvent,
                                  nsIContent** aContent);
   NS_IMETHOD  GetCursor(const nsPoint&    aPoint,
                         nsIFrame::Cursor& aCursor);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -55,16 +55,17 @@
 #include "nsEvent.h"
 #include "nsStyleStruct.h"
 #include "nsStyleContext.h"
 #include "nsIContent.h"
 #include "nsHTMLReflowMetrics.h"
 #include "gfxMatrix.h"
 #include "nsFrameList.h"
 #include "nsAlgorithm.h"
+#include "mozilla/layout/FrameChildList.h"
 #include "FramePropertyTable.h"
 
 /**
  * New rules of reflow:
  * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in order
  *    (no separate pass over the tree)
  * 2. it's the parent frame's responsibility to size/position the child's view (not
  *    the child frame's responsibility as it is today) during reflow (and before
@@ -520,16 +521,21 @@ typedef PRBool nsDidReflowStatus;
  * restrict yourself to calling virtual methods, which won't hurt you as badly.
  */
 class nsIFrame : public nsQueryFrame
 {
 public:
   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
   typedef mozilla::FrameProperties FrameProperties;
   typedef mozilla::layers::Layer Layer;
+  typedef mozilla::layout::FrameChildList ChildList;
+  typedef mozilla::layout::FrameChildListID ChildListID;
+  typedef mozilla::layout::FrameChildListIDs ChildListIDs;
+  typedef mozilla::layout::FrameChildListIterator ChildListIterator;
+  typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator;
 
   NS_DECL_QUERYFRAME_TARGET(nsIFrame)
 
   nsPresContext* PresContext() const {
     return GetStyleContext()->GetRuleNode()->GetPresContext();
   }
 
   /**
@@ -1013,48 +1019,59 @@ public:
    * which return a baseline from GetBaseline which is not useful for
    * caret positioning.
    */
   virtual nscoord GetCaretBaseline() const {
     return GetBaseline();
   }
 
   /**
-   * Used to iterate the list of additional child list names. Returns the atom
-   * name for the additional child list at the specified 0-based index, or a
-   * NULL pointer if there are no more named child lists.
-   *
-   * Note that the list is only the additional named child lists and does not
-   * include the unnamed principal child list.
-   */
-  virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const = 0;
-
-  /**
    * Get the specified child list.
    *
-   * @param   aListName the name of the child list. A NULL pointer for the atom
-   *            name means the unnamed principal child list
-   * @return  the child list.  If this is an unknown list name, an empty list
-   *            will be returned.
-   * @see     #GetAdditionalListName()
+   * @param   aListID identifies the requested child list.
+   * @return  the child list.  If the requested list is unsupported by this
+   *          frame type, an empty list will be returned.
    */
   // XXXbz if all our frame storage were actually backed by nsFrameList, we
   // could make this return a const reference...  nsBlockFrame is the only real
   // culprit here.  Make sure to assign the return value of this function into
   // a |const nsFrameList&|, not an nsFrameList.
-  virtual nsFrameList GetChildList(nsIAtom* aListName) const = 0;
+  virtual nsFrameList GetChildList(ChildListID aListID) const = 0;
+  nsFrameList PrincipalChildList() { return GetChildList(kPrincipalList); }
+  virtual void GetChildLists(nsTArray<ChildList>* aLists) const = 0;
   // XXXbz this method should go away
-  nsIFrame* GetFirstChild(nsIAtom* aListName) const {
-    return GetChildList(aListName).FirstChild();
+  nsIFrame* GetFirstChild(ChildListID aListID) const {
+    return GetChildList(aListID).FirstChild();
   }
   // XXXmats this method should also go away then
-  nsIFrame* GetLastChild(nsIAtom* aListName) const {
-    return GetChildList(aListName).LastChild();
+  nsIFrame* GetLastChild(ChildListID aListID) const {
+    return GetChildList(aListID).LastChild();
+  }
+  nsIFrame* GetFirstPrincipalChild() const {
+    return GetFirstChild(kPrincipalList);
   }
 
+  // The individual concrete child lists.
+  static const ChildListID kPrincipalList = mozilla::layout::kPrincipalList;
+  static const ChildListID kAbsoluteList = mozilla::layout::kAbsoluteList;
+  static const ChildListID kBulletList = mozilla::layout::kBulletList;
+  static const ChildListID kCaptionList = mozilla::layout::kCaptionList;
+  static const ChildListID kColGroupList = mozilla::layout::kColGroupList;
+  static const ChildListID kExcessOverflowContainersList = mozilla::layout::kExcessOverflowContainersList;
+  static const ChildListID kFixedList = mozilla::layout::kFixedList;
+  static const ChildListID kFloatList = mozilla::layout::kFloatList;
+  static const ChildListID kOverflowContainersList = mozilla::layout::kOverflowContainersList;
+  static const ChildListID kOverflowList = mozilla::layout::kOverflowList;
+  static const ChildListID kOverflowOutOfFlowList = mozilla::layout::kOverflowOutOfFlowList;
+  static const ChildListID kPopupList = mozilla::layout::kPopupList;
+  static const ChildListID kPushedFloatsList = mozilla::layout::kPushedFloatsList;
+  static const ChildListID kSelectPopupList = mozilla::layout::kSelectPopupList;
+  // A special alias for kPrincipalList that do not request reflow.
+  static const ChildListID kNoReflowPrincipalList = mozilla::layout::kNoReflowPrincipalList;
+
   /**
    * Child frames are linked together in a doubly-linked list
    */
   nsIFrame* GetNextSibling() const { return mNextSibling; }
   void SetNextSibling(nsIFrame* aNextSibling) {
     NS_ASSERTION(this != aNextSibling, "Creating a circular frame list, this is very bad.");
     if (mNextSibling && mNextSibling->GetPrevSibling() == this) {
       mNextSibling->mPrevSibling = nsnull;
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -1202,32 +1202,30 @@ nsPositionedInlineFrame::BuildDisplayLis
                                           const nsRect&           aDirtyRect,
                                           const nsDisplayListSet& aLists)
 {
   aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetChildList(),
 				     aDirtyRect);
   return nsHTMLContainerFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
 }
 
-nsIAtom*
-nsPositionedInlineFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+nsFrameList
+nsPositionedInlineFrame::GetChildList(ChildListID aListID) const
 {
-  if (0 == aIndex) {
-    return nsGkAtoms::absoluteList;
-  }
-  return nsnull;
+  if (kAbsoluteList == aListID)
+    return mAbsoluteContainer.GetChildList();
+
+  return nsInlineFrame::GetChildList(aListID);
 }
 
-nsFrameList
-nsPositionedInlineFrame::GetChildList(nsIAtom* aListName) const
+void
+nsPositionedInlineFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
-  if (nsGkAtoms::absoluteList == aListName)
-    return mAbsoluteContainer.GetChildList();
-
-  return nsInlineFrame::GetChildList(aListName);
+  nsInlineFrame::GetChildLists(aLists);
+  mAbsoluteContainer.AppendChildList(aLists, kAbsoluteList);
 }
 
 nsIAtom*
 nsPositionedInlineFrame::GetType() const
 {
   return nsGkAtoms::positionedInlineFrame;
 }
 
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -165,35 +165,30 @@ ViewportFrame::RemoveFrame(nsIAtom*     
   else {
     NS_ASSERTION(!aListName, "unexpected child list");
     rv = nsContainerFrame::RemoveFrame(aListName, aOldFrame);
   }
 
   return rv;
 }
 
-nsIAtom*
-ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+nsFrameList
+ViewportFrame::GetChildList(ChildListID aListID) const
 {
-  NS_PRECONDITION(aIndex >= 0, "illegal index");
+  if (kFixedList == aListID)
+    return mFixedContainer.GetChildList();
 
-  if (0 == aIndex) {
-    return nsGkAtoms::fixedList;
-  }
-
-  return nsnull;
+  return nsContainerFrame::GetChildList(aListID);
 }
 
-nsFrameList
-ViewportFrame::GetChildList(nsIAtom* aListName) const
+void
+ViewportFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
-  if (nsGkAtoms::fixedList == aListName)
-    return mFixedContainer.GetChildList();
-
-  return nsContainerFrame::GetChildList(aListName);
+  nsContainerFrame::GetChildLists(aLists);
+  mFixedContainer.AppendChildList(aLists, kFixedList);
 }
 
 /* virtual */ nscoord
 ViewportFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
   if (mFrames.IsEmpty())
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1062,36 +1062,29 @@ nsTableFrame::InsertRowGroups(const nsFr
   Dump(PR_TRUE, PR_TRUE, PR_TRUE);
 #endif
 }
 
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
 
-nsFrameList
-nsTableFrame::GetChildList(nsIAtom* aListName) const
-{
-  if (aListName == nsGkAtoms::colGroupList) {
+nsTableFrame::GetChildList(ChildListID aListID) const
+{
+  if (aListID == kColGroupList) {
     return mColGroups;
   }
-
-  return nsHTMLContainerFrame::GetChildList(aListName);
-}
-
-nsIAtom*
-nsTableFrame::GetAdditionalChildListName(PRInt32 aIndex) const
-{
-  if (aIndex == NS_TABLE_FRAME_COLGROUP_LIST_INDEX) {
-    return nsGkAtoms::colGroupList;
-  }
-  if (aIndex == NS_TABLE_FRAME_OVERFLOW_LIST_INDEX) {
-    return nsGkAtoms::overflowList;
-  }
-  return nsnull;
+  return nsHTMLContainerFrame::GetChildList(aListID);
+}
+
+void
+nsTableFrame::GetChildLists(nsTArray<ChildList>* aLists) const
+{
+  nsHTMLContainerFrame::GetChildLists(aLists);
+  mColGroups.AppendIfNonempty(aLists, kColGroupList);
 }
 
 nsRect
 nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder) {
   return mFrame->GetVisualOverflowRect() + ToReferenceFrame();
 }
 
 PRBool
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -214,34 +214,33 @@ nsTableOuterFrame::IsContainingBlock() c
 void
 nsTableOuterFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   mCaptionFrames.DestroyFramesFrom(aDestructRoot);
   nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 nsFrameList
-nsTableOuterFrame::GetChildList(nsIAtom* aListName) const
+nsTableOuterFrame::GetChildList(ChildListID aListID) const
 {
-  if (nsGkAtoms::captionList == aListName) {
-    return mCaptionFrames;
+  switch (aListID) {
+    case kPrincipalList:
+      return mFrames;
+    case kCaptionList:
+      return mCaptionFrames;
+    default:
+      return nsFrameList::EmptyList();
   }
-  if (!aListName) {
-    return mFrames;
-  }
-  return nsFrameList::EmptyList();
 }
 
-nsIAtom*
-nsTableOuterFrame::GetAdditionalChildListName(PRInt32 aIndex) const
+void
+nsTableOuterFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
-  if (aIndex == NS_TABLE_FRAME_CAPTION_LIST_INDEX) {
-    return nsGkAtoms::captionList;
-  }
-  return nsnull;
+  mFrames.AppendIfNonempty(aLists, kPrincipalList);
+  mCaptionFrames.AppendIfNonempty(aLists, kCaptionList);
 }
 
 NS_IMETHODIMP 
 nsTableOuterFrame::SetInitialChildList(nsIAtom*        aListName,
                                        nsFrameList&    aChildList)
 {
   if (nsGkAtoms::captionList == aListName) {
     // the frame constructor already checked for table-caption display type
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -296,25 +296,31 @@ nsMenuFrame::Init(nsIContent*      aCont
 
   BuildAcceleratorText(PR_FALSE);
   nsIReflowCallback* cb = new nsASyncMenuInitialization(this);
   NS_ENSURE_TRUE(cb, NS_ERROR_OUT_OF_MEMORY);
   PresContext()->PresShell()->PostReflowCallback(cb);
   return rv;
 }
 
-// The following methods are all overridden to ensure that the menupopup frame
-// is placed in the appropriate list.
 nsFrameList
-nsMenuFrame::GetChildList(nsIAtom* aListName) const
+nsMenuFrame::GetChildList(ChildListID aListID) const
 {
-  if (nsGkAtoms::popupList == aListName) {
+  if (kPopupList == aListID) {
     return nsFrameList(mPopupFrame, mPopupFrame);
   }
-  return nsBoxFrame::GetChildList(aListName);
+  return nsBoxFrame::GetChildList(aListID);
+}
+
+void
+nsMenuFrame::GetChildLists(nsTArray<ChildList>* aLists) const
+{
+  nsBoxFrame::GetChildLists(aLists);
+  nsFrameList popupList(mPopupFrame, mPopupFrame);
+  popupList.AppendIfNonempty(aLists, kPopupList);
 }
 
 void
 nsMenuFrame::SetPopupFrame(nsFrameList& aFrameList)
 {
   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
     if (e.get()->GetType() == nsGkAtoms::menuPopupFrame) {
       // Remove this frame from the list and set it as mPopupFrame
@@ -330,25 +336,16 @@ nsMenuFrame::SetInitialChildList(nsIAtom
                                  nsFrameList&    aChildList)
 {
   NS_ASSERTION(!mPopupFrame, "already have a popup frame set");
   if (!aListName || aListName == nsGkAtoms::popupList)
     SetPopupFrame(aChildList);
   return nsBoxFrame::SetInitialChildList(aListName, aChildList);
 }
 
-nsIAtom*
-nsMenuFrame::GetAdditionalChildListName(PRInt32 aIndex) const
-{
-  if (NS_MENU_POPUP_LIST_INDEX == aIndex) {
-    return nsGkAtoms::popupList;
-  }
-  return nsnull;
-}
-
 void
 nsMenuFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   // Kill our timer if one is active. This is not strictly necessary as
   // the pointer to this frame will be cleared from the mediator, but
   // this is done for added safety.
   if (mOpenTimer) {
     mOpenTimer->Cancel();