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 77152 bbb68899df56fe3296ba9d9ee93e97f49af69b66
parent 77151 5c0d46747250439b8987d5740149e7014c4a3fa2
child 77153 de17763f5ba71293a5193266f815151047466eb5
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, dbaron
bugs653649
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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();