Bug 983434 part 2: Store FlexLines and FlexItems in MFBT LinkedLists instead of nsTArrays. r=mats
☠☠ backed out by e158b7448622 ☠ ☠
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 18 Mar 2014 06:09:41 +0800
changeset 173971 c5dc2de8d2246c2a35efa9564b9919e63c8e5c6f
parent 173970 850dd9773e9dad258d94e6a71beac2cc225f8352
child 173972 5854254a309dafd0e4fb3fb197d9e8c04072a9f1
push id26438
push userphilringnalda@gmail.com
push dateTue, 18 Mar 2014 05:39:07 +0000
treeherderautoland@89275f0ae29f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs983434
milestone31.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 983434 part 2: Store FlexLines and FlexItems in MFBT LinkedLists instead of nsTArrays. r=mats
layout/generic/nsFlexContainerFrame.cpp
layout/generic/nsFlexContainerFrame.h
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -13,16 +13,17 @@
 #include "nsDisplayList.h"
 #include "nsIFrameInlines.h"
 #include "nsLayoutUtils.h"
 #include "nsPlaceholderFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "prlog.h"
 #include <algorithm>
+#include "mozilla/LinkedList.h"
 
 using namespace mozilla::css;
 using namespace mozilla::layout;
 
 // Convenience typedefs for helper classes that we forward-declare in .h file
 // (so that nsFlexContainerFrame methods can use them as parameters):
 typedef nsFlexContainerFrame::FlexItem FlexItem;
 typedef nsFlexContainerFrame::FlexLine FlexLine;
@@ -272,20 +273,23 @@ public:
       nsSize(aCrossSize, aMainSize);
   }
 
 private:
   AxisOrientationType mMainAxis;
   AxisOrientationType mCrossAxis;
 };
 
-// Represents a flex item.
-// Includes the various pieces of input that the Flexbox Layout Algorithm uses
-// to resolve a flexible width.
-class nsFlexContainerFrame::FlexItem {
+/**
+ * Represents a flex item.
+ * Includes the various pieces of input that the Flexbox Layout Algorithm uses
+ * to resolve a flexible width.
+ */
+class nsFlexContainerFrame::FlexItem : public LinkedListElement<FlexItem>
+{
 public:
   // Normal constructor:
   FlexItem(nsIFrame* aChildFrame,
            float aFlexGrow, float aFlexShrink, nscoord aMainBaseSize,
            nscoord aMainMinSize, nscoord aMainMaxSize,
            nscoord aCrossMinSize, nscoord aCrossMaxSize,
            nsMargin aMargin, nsMargin aBorderPadding,
            const FlexboxAxisTracker& aAxisTracker);
@@ -557,37 +561,77 @@ protected:
   bool mIsStretched; // See IsStretched() documentation
   bool mIsStrut;     // Is this item a "strut" left behind by an element
                      // with visibility:collapse?
   uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
                       // swapped out for parent"s "align-items" value,
                       // in our constructor).
 };
 
-// Represents a single flex line in a flex container.
-// Manages an array of the FlexItems that are in the line.
-class nsFlexContainerFrame::FlexLine {
+/**
+ * Represents a single flex line in a flex container.
+ * Manages a linked list of the FlexItems that are in the line.
+ */
+class nsFlexContainerFrame::FlexLine : public LinkedListElement<FlexLine>
+{
 public:
   FlexLine()
-  : mTotalInnerHypotheticalMainSize(0),
+  : mNumItems(0),
+    mTotalInnerHypotheticalMainSize(0),
     mTotalOuterHypotheticalMainSize(0),
     mLineCrossSize(0),
     mBaselineOffsetFromCrossStart(nscoord_MIN)
   {}
 
   // Returns the sum of our FlexItems' outer hypothetical main sizes.
   // ("outer" = margin-box, and "hypothetical" = before flexing)
   nscoord GetTotalOuterHypotheticalMainSize() const {
     return mTotalOuterHypotheticalMainSize;
   }
 
-  // Adds a new FlexItem's hypothetical main sizes to our totals.
-  // (Should only be called when a FlexItem is being appended to this line.)
-  void AddToMainSizeTotals(nscoord aItemInnerHypotheticalMainSize,
-                           nscoord aItemOuterHypotheticalMainSize) {
+  // Accessors for our FlexItems & information about them:
+  FlexItem* GetFirstItem()
+  {
+    MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
+               "mNumItems bookkeeping is off");
+    return mItems.getFirst();
+  }
+
+  const FlexItem* GetFirstItem() const
+  {
+    MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
+               "mNumItems bookkeeping is off");
+    return mItems.getFirst();
+  }
+
+  bool IsEmpty() const
+  {
+    MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
+               "mNumItems bookkeeping is off");
+    return mItems.isEmpty();
+  }
+
+  uint32_t NumItems() const
+  {
+    MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
+               "mNumItems bookkeeping is off");
+    return mNumItems;
+  }
+
+  // Adds the given FlexItem to our list of items, and adds its hypothetical
+  // outer & inner main sizes to our totals. Use this method instead of
+  // directly modifying the item list, so that our bookkeeping remains correct.
+  // XXXdholbert Bug 983427 will extend this to let the caller choose whether
+  // the new FlexItem goes at the front or the back of the list.
+  void AddItem(FlexItem* aItem,
+               nscoord aItemInnerHypotheticalMainSize,
+               nscoord aItemOuterHypotheticalMainSize)
+  {
+    mItems.insertBack(aItem);
+    mNumItems++;
     mTotalInnerHypotheticalMainSize += aItemInnerHypotheticalMainSize;
     mTotalOuterHypotheticalMainSize += aItemOuterHypotheticalMainSize;
   }
 
   // Computes the cross-size and baseline position of this FlexLine, based on
   // its FlexItems.
   void ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker);
 
@@ -614,22 +658,31 @@ public:
 
   void PositionItemsInMainAxis(uint8_t aJustifyContent,
                                nscoord aContentBoxMainSize,
                                const FlexboxAxisTracker& aAxisTracker);
 
   void PositionItemsInCrossAxis(nscoord aLineStartPosition,
                                 const FlexboxAxisTracker& aAxisTracker);
 
-  nsTArray<FlexItem> mItems; // Array of the flex items in this flex line.
-
+  friend class AutoFlexLineListClearer; // (needs access to mItems)
+ 
 private:
   // Helper for ResolveFlexibleLengths():
   void FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
                                        bool aIsFinalIteration);
+
+  LinkedList<FlexItem> mItems; // Linked list of this line's flex items.
+
+  uint32_t mNumItems; // Number of FlexItems in this line (in |mItems|).
+                      // (Shouldn't change after GenerateFlexLines finishes
+                      // with this line -- at least, not until we add support
+                      // for splitting lines across continuations. Then we can
+                      // update this count carefully.)
+
   nscoord mTotalInnerHypotheticalMainSize;
   nscoord mTotalOuterHypotheticalMainSize;
   nscoord mLineCrossSize;
   nscoord mBaselineOffsetFromCrossStart;
 };
 
 // Information about a strut left behind by a FlexItem that's been collapsed
 // using "visibility:collapse".
@@ -640,33 +693,33 @@ struct nsFlexContainerFrame::StrutInfo {
   {
   }
 
   uint32_t mItemIdx;      // Index in the child list.
   nscoord mStrutCrossSize; // The cross-size of this strut.
 };
 
 static void
-BuildStrutInfoFromCollapsedItems(nsTArray<FlexLine>& aLines,
+BuildStrutInfoFromCollapsedItems(const FlexLine* aFirstLine,
                                  nsTArray<StrutInfo>& aStruts)
 {
+  MOZ_ASSERT(aFirstLine, "null first line pointer");
   MOZ_ASSERT(aStruts.IsEmpty(),
              "We should only build up StrutInfo once per reflow, so "
              "aStruts should be empty when this is called");
 
   uint32_t itemIdxInContainer = 0;
-  for (uint32_t lineIdx = 0; lineIdx < aLines.Length(); lineIdx++) {
-    FlexLine& line = aLines[lineIdx];
-    for (uint32_t i = 0; i < line.mItems.Length(); ++i) {
-      FlexItem& item = line.mItems[i];
+  for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
+    for (const FlexItem* item = line->GetFirstItem(); item;
+         item = item->getNext()) {
       if (NS_STYLE_VISIBILITY_COLLAPSE ==
-          item.Frame()->StyleVisibility()->mVisible) {
+          item->Frame()->StyleVisibility()->mVisible) {
         // Note the cross size of the line as the item's strut size.
         aStruts.AppendElement(StrutInfo(itemIdxInContainer,
-                                        line.GetLineCrossSize()));
+                                        line->GetLineCrossSize()));
       }
       itemIdxInContainer++;
     }
   }
 }
 
 // Helper-function to find the first non-anonymous-box descendent of aFrame.
 static nsIFrame*
@@ -823,17 +876,17 @@ IsOrderLEQ(nsIFrame* aFrame1,
 
 bool
 nsFlexContainerFrame::IsHorizontal()
 {
   const FlexboxAxisTracker axisTracker(this);
   return IsAxisHorizontal(axisTracker.GetMainAxis());
 }
 
-FlexItem
+FlexItem*
 nsFlexContainerFrame::GenerateFlexItemForChild(
   nsPresContext* aPresContext,
   nsIFrame*      aChildFrame,
   const nsHTMLReflowState& aParentReflowState,
   const FlexboxAxisTracker& aAxisTracker)
 {
   // Create temporary reflow state just for sizing -- to get hypothetical
   // main-size and the computed values of min / max main-size property.
@@ -915,29 +968,29 @@ nsFlexContainerFrame::GenerateFlexItemFo
       mainMaxSize = std::max(mainMaxSize, widgetMainMinSize);
 
       crossMinSize = std::max(crossMinSize, widgetCrossMinSize);
       crossMaxSize = std::max(crossMaxSize, widgetCrossMinSize);
     }
   }
 
   // Construct the flex item!
-  FlexItem item(aChildFrame,
-                flexGrow, flexShrink, flexBaseSize,
-                mainMinSize, mainMaxSize,
-                crossMinSize, crossMaxSize,
-                childRS.ComputedPhysicalMargin(),
-                childRS.ComputedPhysicalBorderPadding(),
-                aAxisTracker);
+  FlexItem* item = new FlexItem(aChildFrame,
+                                flexGrow, flexShrink, flexBaseSize,
+                                mainMinSize, mainMaxSize,
+                                crossMinSize, crossMaxSize,
+                                childRS.ComputedPhysicalMargin(),
+                                childRS.ComputedPhysicalBorderPadding(),
+                                aAxisTracker);
 
   // If we're inflexible, we can just freeze to our hypothetical main-size
   // up-front. Similarly, if we're a fixed-size widget, we only have one
   // valid size, so we freeze to keep ourselves from flexing.
   if (isFixedSizeWidget || (flexGrow == 0.0f && flexShrink == 0.0f)) {
-    item.Freeze();
+    item->Freeze();
   }
 
   return item;
 }
 
 nsresult
 nsFlexContainerFrame::
   ResolveFlexItemMaxContentSizing(nsPresContext* aPresContext,
@@ -1255,17 +1308,17 @@ protected:
 };
 
 // Tracks our position in the main axis, when we're laying out flex items.
 // The "0" position represents the main-start edge of the flex container's
 // content-box.
 class MOZ_STACK_CLASS MainAxisPositionTracker : public PositionTracker {
 public:
   MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
-                          const nsTArray<FlexItem>& aItems,
+                          const FlexLine* aLine,
                           uint8_t aJustifyContent,
                           nscoord aContentBoxMainSize);
 
   ~MainAxisPositionTracker() {
     MOZ_ASSERT(mNumPackingSpacesRemaining == 0,
                "miscounted the number of packing spaces");
     MOZ_ASSERT(mNumAutoMarginsInMainAxis == 0,
                "miscounted the number of auto margins");
@@ -1286,17 +1339,17 @@ private:
 };
 
 // Utility class for managing our position along the cross axis along
 // the whole flex container (at a higher level than a single line).
 // The "0" position represents the cross-start edge of the flex container's
 // content-box.
 class MOZ_STACK_CLASS CrossAxisPositionTracker : public PositionTracker {
 public:
-  CrossAxisPositionTracker(nsTArray<FlexLine>& aLines,
+  CrossAxisPositionTracker(FlexLine* aFirstLine,
                            uint8_t aAlignContent,
                            nscoord aContentBoxCrossSize,
                            bool aIsCrossSizeDefinite,
                            const FlexboxAxisTracker& aAxisTracker);
 
   // Advances past the packing space (if any) between two flex lines
   void TraversePackingSpace();
 
@@ -1492,58 +1545,57 @@ FlexLine::FreezeOrRestoreEachFlexibleSiz
   if (aTotalViolation == 0) {
     freezeType = eFreezeEverything;
   } else if (aTotalViolation > 0) {
     freezeType = eFreezeMinViolations;
   } else { // aTotalViolation < 0
     freezeType = eFreezeMaxViolations;
   }
 
-  for (uint32_t i = 0; i < mItems.Length(); i++) {
-    FlexItem& item = mItems[i];
-    MOZ_ASSERT(!item.HadMinViolation() || !item.HadMaxViolation(),
+  for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+    MOZ_ASSERT(!item->HadMinViolation() || !item->HadMaxViolation(),
                "Can have either min or max violation, but not both");
 
-    if (!item.IsFrozen()) {
+    if (!item->IsFrozen()) {
       if (eFreezeEverything == freezeType ||
-          (eFreezeMinViolations == freezeType && item.HadMinViolation()) ||
-          (eFreezeMaxViolations == freezeType && item.HadMaxViolation())) {
-
-        MOZ_ASSERT(item.GetMainSize() >= item.GetMainMinSize(),
+          (eFreezeMinViolations == freezeType && item->HadMinViolation()) ||
+          (eFreezeMaxViolations == freezeType && item->HadMaxViolation())) {
+
+        MOZ_ASSERT(item->GetMainSize() >= item->GetMainMinSize(),
                    "Freezing item at a size below its minimum");
-        MOZ_ASSERT(item.GetMainSize() <= item.GetMainMaxSize(),
+        MOZ_ASSERT(item->GetMainSize() <= item->GetMainMaxSize(),
                    "Freezing item at a size above its maximum");
 
-        item.Freeze();
+        item->Freeze();
       } else if (MOZ_UNLIKELY(aIsFinalIteration)) {
         // XXXdholbert If & when bug 765861 is fixed, we should upgrade this
         // assertion to be fatal except in documents with enormous lengths.
         NS_ERROR("Final iteration still has unfrozen items, this shouldn't"
                  " happen unless there was nscoord under/overflow.");
-        item.Freeze();
+        item->Freeze();
       } // else, we'll reset this item's main size to its flex base size on the
         // next iteration of this algorithm.
 
       // Clear this item's violation(s), now that we've dealt with them
-      item.ClearViolationFlags();
+      item->ClearViolationFlags();
     }
   }
 }
 
 // Implementation of flexbox spec's "resolve the flexible lengths" algorithm.
 // NOTE: aTotalFreeSpace should already have the flex items' margin, border,
 // & padding values subtracted out, so that all we need to do is distribute the
 // remaining free space among content-box sizes.  (The spec deals with
 // margin-box sizes, but we can have fewer values in play & a simpler algorithm
 // if we subtract margin/border/padding up front.)
 void
 FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
 {
   PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG, ("ResolveFlexibleLengths\n"));
-  if (mItems.IsEmpty()) {
+  if (IsEmpty()) {
     return;
   }
 
   // Subtract space occupied by our items' margins/borders/padding, so we can
   // just be dealing with the space available for our flex items' content
   // boxes.
   nscoord spaceReservedForMarginBorderPadding =
     mTotalOuterHypotheticalMainSize - mTotalInnerHypotheticalMainSize;
@@ -1551,34 +1603,33 @@ FlexLine::ResolveFlexibleLengths(nscoord
   nscoord spaceAvailableForFlexItemsContentBoxes =
     aFlexContainerMainSize - spaceReservedForMarginBorderPadding;
 
   // Determine whether we're going to be growing or shrinking items.
   const bool isUsingFlexGrow =
     (mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
 
   // NOTE: I claim that this chunk of the algorithm (the looping part) needs to
-  // run the loop at MOST aItems.Length() times.  This claim should hold up
+  // run the loop at MOST mNumItems times.  This claim should hold up
   // because we'll freeze at least one item on each loop iteration, and once
   // we've run out of items to freeze, there's nothing left to do.  However,
   // in most cases, we'll break out of this loop long before we hit that many
   // iterations.
   for (uint32_t iterationCounter = 0;
-       iterationCounter < mItems.Length(); iterationCounter++) {
+       iterationCounter < mNumItems; iterationCounter++) {
     // Set every not-yet-frozen item's used main size to its
     // flex base size, and subtract all the used main sizes from our
     // total amount of space to determine the 'available free space'
     // (positive or negative) to be distributed among our flexible items.
     nscoord availableFreeSpace = spaceAvailableForFlexItemsContentBoxes;
-    for (uint32_t i = 0; i < mItems.Length(); i++) {
-      FlexItem& item = mItems[i];
-      if (!item.IsFrozen()) {
-        item.SetMainSize(item.GetFlexBaseSize());
+    for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+      if (!item->IsFrozen()) {
+        item->SetMainSize(item->GetFlexBaseSize());
       }
-      availableFreeSpace -= item.GetMainSize();
+      availableFreeSpace -= item->GetMainSize();
     }
 
     PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG,
            (" available free space = %d\n", availableFreeSpace));
 
     // If sign of free space matches the type of flexing that we're doing, give
     // each flexible item a portion of availableFreeSpace.
     if ((availableFreeSpace > 0 && isUsingFlexGrow) ||
@@ -1596,28 +1647,27 @@ FlexLine::ResolveFlexibleLengths(nscoord
       // maximum representable float (overflowing to infinity), then we can't
       // sensibly divide out proportional shares anymore. In that case, we
       // simply treat the flex item(s) with the largest flex weights as if
       // their weights were infinite (dwarfing all the others), and we
       // distribute all of the available space among them.
       float runningFlexWeightSum = 0.0f;
       float largestFlexWeight = 0.0f;
       uint32_t numItemsWithLargestFlexWeight = 0;
-      for (uint32_t i = 0; i < mItems.Length(); i++) {
-        FlexItem& item = mItems[i];
-        float curFlexWeight = item.GetFlexWeightToUse(isUsingFlexGrow);
+      for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+        float curFlexWeight = item->GetFlexWeightToUse(isUsingFlexGrow);
         MOZ_ASSERT(curFlexWeight >= 0.0f, "weights are non-negative");
 
         runningFlexWeightSum += curFlexWeight;
         if (NS_finite(runningFlexWeightSum)) {
           if (curFlexWeight == 0.0f) {
-            item.SetShareOfFlexWeightSoFar(0.0f);
+            item->SetShareOfFlexWeightSoFar(0.0f);
           } else {
-            item.SetShareOfFlexWeightSoFar(curFlexWeight /
-                                           runningFlexWeightSum);
+            item->SetShareOfFlexWeightSoFar(curFlexWeight /
+                                            runningFlexWeightSum);
           }
         } // else, the sum of weights overflows to infinity, in which
           // case we don't bother with "SetShareOfFlexWeightSoFar" since
           // we know we won't use it. (instead, we'll just give every
           // item with the largest flex weight an equal share of space.)
 
         // Update our largest-flex-weight tracking vars
         if (curFlexWeight > largestFlexWeight) {
@@ -1626,124 +1676,126 @@ FlexLine::ResolveFlexibleLengths(nscoord
         } else if (curFlexWeight == largestFlexWeight) {
           numItemsWithLargestFlexWeight++;
         }
       }
 
       if (runningFlexWeightSum != 0.0f) { // no distribution if no flexibility
         PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG,
                (" Distributing available space:"));
-        for (uint32_t i = mItems.Length() - 1; i < mItems.Length(); --i) {
-          FlexItem& item = mItems[i];
-
-          if (!item.IsFrozen()) {
+        // NOTE: It's important that we traverse our items in *reverse* order
+        // here, for correct width distribution according to the items'
+        // "ShareOfFlexWeightSoFar" progressively-calculated values.
+        for (FlexItem* item = mItems.getLast(); item;
+             item = item->getPrevious()) {
+
+          if (!item->IsFrozen()) {
             // To avoid rounding issues, we compute the change in size for this
             // item, and then subtract it from the remaining available space.
             nscoord sizeDelta = 0;
             if (NS_finite(runningFlexWeightSum)) {
               float myShareOfRemainingSpace =
-                item.GetShareOfFlexWeightSoFar();
+                item->GetShareOfFlexWeightSoFar();
 
               MOZ_ASSERT(myShareOfRemainingSpace >= 0.0f &&
                          myShareOfRemainingSpace <= 1.0f,
                          "my share should be nonnegative fractional amount");
 
               if (myShareOfRemainingSpace == 1.0f) {
                 // (We special-case 1.0f to avoid float error from converting
                 // availableFreeSpace from integer*1.0f --> float --> integer)
                 sizeDelta = availableFreeSpace;
               } else if (myShareOfRemainingSpace > 0.0f) {
                 sizeDelta = NSToCoordRound(availableFreeSpace *
                                            myShareOfRemainingSpace);
               }
-            } else if (item.GetFlexWeightToUse(isUsingFlexGrow) ==
+            } else if (item->GetFlexWeightToUse(isUsingFlexGrow) ==
                        largestFlexWeight) {
               // Total flexibility is infinite, so we're just distributing
               // the available space equally among the items that are tied for
               // having the largest weight (and this is one of those items).
               sizeDelta =
                 NSToCoordRound(availableFreeSpace /
                                float(numItemsWithLargestFlexWeight));
               numItemsWithLargestFlexWeight--;
             }
 
             availableFreeSpace -= sizeDelta;
 
-            item.SetMainSize(item.GetMainSize() + sizeDelta);
+            item->SetMainSize(item->GetMainSize() + sizeDelta);
             PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG,
-                   ("  child %d receives %d, for a total of %d\n",
-                    i, sizeDelta, item.GetMainSize()));
+                   ("  child %p receives %d, for a total of %d\n",
+                    item, sizeDelta, item->GetMainSize()));
           }
         }
       }
     }
 
     // Fix min/max violations:
     nscoord totalViolation = 0; // keeps track of adjustments for min/max
     PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG,
            (" Checking for violations:"));
 
-    for (uint32_t i = 0; i < mItems.Length(); i++) {
-      FlexItem& item = mItems[i];
-      if (!item.IsFrozen()) {
-        if (item.GetMainSize() < item.GetMainMinSize()) {
+    for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+      if (!item->IsFrozen()) {
+        if (item->GetMainSize() < item->GetMainMinSize()) {
           // min violation
-          totalViolation += item.GetMainMinSize() - item.GetMainSize();
-          item.SetMainSize(item.GetMainMinSize());
-          item.SetHadMinViolation();
-        } else if (item.GetMainSize() > item.GetMainMaxSize()) {
+          totalViolation += item->GetMainMinSize() - item->GetMainSize();
+          item->SetMainSize(item->GetMainMinSize());
+          item->SetHadMinViolation();
+        } else if (item->GetMainSize() > item->GetMainMaxSize()) {
           // max violation
-          totalViolation += item.GetMainMaxSize() - item.GetMainSize();
-          item.SetMainSize(item.GetMainMaxSize());
-          item.SetHadMaxViolation();
+          totalViolation += item->GetMainMaxSize() - item->GetMainSize();
+          item->SetMainSize(item->GetMainMaxSize());
+          item->SetHadMaxViolation();
         }
       }
     }
 
     FreezeOrRestoreEachFlexibleSize(totalViolation,
-                                    iterationCounter + 1 == mItems.Length());
+                                    iterationCounter + 1 == mNumItems);
 
     PR_LOG(GetFlexContainerLog(), PR_LOG_DEBUG,
            (" Total violation: %d\n", totalViolation));
 
     if (totalViolation == 0) {
       break;
     }
   }
 
   // Post-condition: all lengths should've been frozen.
 #ifdef DEBUG
-  for (uint32_t i = 0; i < mItems.Length(); ++i) {
-    MOZ_ASSERT(mItems[i].IsFrozen(),
+  for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+    MOZ_ASSERT(item->IsFrozen(),
                "All flexible lengths should've been resolved");
   }
 #endif // DEBUG
 }
 
 MainAxisPositionTracker::
   MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
-                          const nsTArray<FlexItem>& aItems,
+                          const FlexLine* aLine,
                           uint8_t aJustifyContent,
                           nscoord aContentBoxMainSize)
   : PositionTracker(aAxisTracker.GetMainAxis()),
     mPackingSpaceRemaining(aContentBoxMainSize), // we chip away at this below
     mNumAutoMarginsInMainAxis(0),
     mNumPackingSpacesRemaining(0),
     mJustifyContent(aJustifyContent)
 {
   // mPackingSpaceRemaining is initialized to the container's main size.  Now
   // we'll subtract out the main sizes of our flex items, so that it ends up
   // with the *actual* amount of packing space.
-  for (uint32_t i = 0; i < aItems.Length(); i++) {
-    const FlexItem& item = aItems[i];
+  for (const FlexItem* item = aLine->GetFirstItem(); item;
+       item = item->getNext()) {
     nscoord itemMarginBoxMainSize =
-      item.GetMainSize() +
-      item.GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetMainAxis());
+      item->GetMainSize() +
+      item->GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetMainAxis());
     mPackingSpaceRemaining -= itemMarginBoxMainSize;
-    mNumAutoMarginsInMainAxis += item.GetNumAutoMarginsInAxis(mAxis);
+    mNumAutoMarginsInMainAxis += item->GetNumAutoMarginsInAxis(mAxis);
   }
 
   if (mPackingSpaceRemaining <= 0) {
     // No available packing space to use for resolving auto margins.
     mNumAutoMarginsInMainAxis = 0;
   }
 
   // If packing space is negative, 'space-between' behaves like 'flex-start',
@@ -1756,17 +1808,17 @@ MainAxisPositionTracker::
       mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_CENTER;
     }
   }
 
   // Figure out how much space we'll set aside for auto margins or
   // packing spaces, and advance past any leading packing-space.
   if (mNumAutoMarginsInMainAxis == 0 &&
       mPackingSpaceRemaining != 0 &&
-      !aItems.IsEmpty()) {
+      !aLine->IsEmpty()) {
     switch (mJustifyContent) {
       case NS_STYLE_JUSTIFY_CONTENT_FLEX_START:
         // All packing space should go at the end --> nothing to do here.
         break;
       case NS_STYLE_JUSTIFY_CONTENT_FLEX_END:
         // All packing space goes at the beginning
         mPosition += mPackingSpaceRemaining;
         break;
@@ -1774,26 +1826,26 @@ MainAxisPositionTracker::
         // Half the packing space goes at the beginning
         mPosition += mPackingSpaceRemaining / 2;
         break;
       case NS_STYLE_JUSTIFY_CONTENT_SPACE_BETWEEN:
         MOZ_ASSERT(mPackingSpaceRemaining >= 0,
                    "negative packing space should make us use 'flex-start' "
                    "instead of 'space-between'");
         // 1 packing space between each flex item, no packing space at ends.
-        mNumPackingSpacesRemaining = aItems.Length() - 1;
+        mNumPackingSpacesRemaining = aLine->NumItems() - 1;
         break;
       case NS_STYLE_JUSTIFY_CONTENT_SPACE_AROUND:
         MOZ_ASSERT(mPackingSpaceRemaining >= 0,
                    "negative packing space should make us use 'center' "
                    "instead of 'space-around'");
         // 1 packing space between each flex item, plus half a packing space
         // at beginning & end.  So our number of full packing-spaces is equal
         // to the number of flex items.
-        mNumPackingSpacesRemaining = aItems.Length();
+        mNumPackingSpacesRemaining = aLine->NumItems();
         if (mNumPackingSpacesRemaining > 0) {
           // The edges (start/end) share one full packing space
           nscoord totalEdgePackingSpace =
             mPackingSpaceRemaining / mNumPackingSpacesRemaining;
 
           // ...and we'll use half of that right now, at the start
           mPosition += totalEdgePackingSpace / 2;
           // ...but we need to subtract all of it right away, so that we won't
@@ -1857,52 +1909,54 @@ MainAxisPositionTracker::TraversePacking
 
     mPosition += curPackingSpace;
     mNumPackingSpacesRemaining--;
     mPackingSpaceRemaining -= curPackingSpace;
   }
 }
 
 CrossAxisPositionTracker::
-  CrossAxisPositionTracker(nsTArray<FlexLine>& aLines,
+  CrossAxisPositionTracker(FlexLine* aFirstLine,
                            uint8_t aAlignContent,
                            nscoord aContentBoxCrossSize,
                            bool aIsCrossSizeDefinite,
                            const FlexboxAxisTracker& aAxisTracker)
   : PositionTracker(aAxisTracker.GetCrossAxis()),
     mPackingSpaceRemaining(0),
     mNumPackingSpacesRemaining(0),
     mAlignContent(aAlignContent)
 {
-  MOZ_ASSERT(!aLines.IsEmpty(), "We should have at least 1 line");
-
-  if (aIsCrossSizeDefinite && aLines.Length() == 1) {
+  MOZ_ASSERT(aFirstLine, "null first line pointer");
+
+  if (aIsCrossSizeDefinite && !aFirstLine->getNext()) {
     // "If the flex container has only a single line (even if it's a
     // multi-line flex container) and has a definite cross size, the cross
     // size of the flex line is the flex container's inner cross size."
     // SOURCE: http://dev.w3.org/csswg/css-flexbox/#algo-line-break
     // NOTE: This means (by definition) that there's no packing space, which
     // means we don't need to be concerned with "align-conent" at all and we
     // can return early. This is handy, because this is the usual case (for
     // single-line flexbox).
-    aLines[0].SetLineCrossSize(aContentBoxCrossSize);
+    aFirstLine->SetLineCrossSize(aContentBoxCrossSize);
     return;
   }
 
   // NOTE: The rest of this function should essentially match
   // MainAxisPositionTracker's constructor, though with FlexLines instead of
   // FlexItems, and with the additional value "stretch" (and of course with
   // cross sizes instead of main sizes.)
 
   // Figure out how much packing space we have (container's cross size minus
-  // all the lines' cross sizes)
+  // all the lines' cross sizes).  Also, share this loop to count how many
+  // lines we have. (We need that count in some cases below.)
   mPackingSpaceRemaining = aContentBoxCrossSize;
-  for (uint32_t i = 0; i < aLines.Length(); i++) {
-    const FlexLine& line = aLines[i];
-    mPackingSpaceRemaining -= line.GetLineCrossSize();
+  uint32_t numLines = 0;
+  for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
+    mPackingSpaceRemaining -= line->GetLineCrossSize();
+    numLines++;
   }
 
   // If packing space is negative, 'space-between' and 'stretch' behave like
   // 'flex-start', and 'space-around' behaves like 'center'. In those cases,
   // it's simplest to just pretend we have a different 'align-content' value
   // and share code.
   if (mPackingSpaceRemaining < 0) {
     if (mAlignContent == NS_STYLE_ALIGN_CONTENT_SPACE_BETWEEN ||
@@ -1928,56 +1982,60 @@ CrossAxisPositionTracker::
         // Half the packing space goes at the beginning
         mPosition += mPackingSpaceRemaining / 2;
         break;
       case NS_STYLE_ALIGN_CONTENT_SPACE_BETWEEN:
         MOZ_ASSERT(mPackingSpaceRemaining >= 0,
                    "negative packing space should make us use 'flex-start' "
                    "instead of 'space-between'");
         // 1 packing space between each flex line, no packing space at ends.
-        mNumPackingSpacesRemaining = aLines.Length() - 1;
+        mNumPackingSpacesRemaining = numLines - 1;
         break;
       case NS_STYLE_ALIGN_CONTENT_SPACE_AROUND: {
         MOZ_ASSERT(mPackingSpaceRemaining >= 0,
                    "negative packing space should make us use 'center' "
                    "instead of 'space-around'");
         // 1 packing space between each flex line, plus half a packing space
         // at beginning & end.  So our number of full packing-spaces is equal
         // to the number of flex lines.
-        mNumPackingSpacesRemaining = aLines.Length();
+        mNumPackingSpacesRemaining = numLines;
         // The edges (start/end) share one full packing space
         nscoord totalEdgePackingSpace =
           mPackingSpaceRemaining / mNumPackingSpacesRemaining;
 
         // ...and we'll use half of that right now, at the start
         mPosition += totalEdgePackingSpace / 2;
         // ...but we need to subtract all of it right away, so that we won't
         // hand out any of it to intermediate packing spaces.
         mPackingSpaceRemaining -= totalEdgePackingSpace;
         mNumPackingSpacesRemaining--;
         break;
       }
-      case NS_STYLE_ALIGN_CONTENT_STRETCH:
+      case NS_STYLE_ALIGN_CONTENT_STRETCH: {
         // Split space equally between the lines:
         MOZ_ASSERT(mPackingSpaceRemaining > 0,
                    "negative packing space should make us use 'flex-start' "
                    "instead of 'stretch' (and we shouldn't bother with this "
                    "code if we have 0 packing space)");
 
-        for (uint32_t i = 0; i < aLines.Length(); i++) {
-          FlexLine& line = aLines[i];
+        uint32_t numLinesLeft = numLines;
+        for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
           // Our share is the amount of space remaining, divided by the number
           // of lines remainig.
-          nscoord shareOfExtraSpace =
-            mPackingSpaceRemaining / (aLines.Length() - i);
-          nscoord newSize = line.GetLineCrossSize() + shareOfExtraSpace;
-          line.SetLineCrossSize(newSize);
+          MOZ_ASSERT(numLinesLeft > 0, "miscalculated num lines");
+          nscoord shareOfExtraSpace = mPackingSpaceRemaining / numLinesLeft;
+          nscoord newSize = line->GetLineCrossSize() + shareOfExtraSpace;
+          line->SetLineCrossSize(newSize);
+
           mPackingSpaceRemaining -= shareOfExtraSpace;
+          numLinesLeft--;
         }
+        MOZ_ASSERT(numLinesLeft == 0, "miscalculated num lines");
         break;
+      }
       default:
         MOZ_CRASH("Unexpected align-content value");
     }
   }
 }
 
 void
 CrossAxisPositionTracker::TraversePackingSpace()
@@ -2009,23 +2067,22 @@ SingleLineCrossAxisPositionTracker::
 }
 
 void
 FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
 {
   nscoord crossStartToFurthestBaseline = nscoord_MIN;
   nscoord crossEndToFurthestBaseline = nscoord_MIN;
   nscoord largestOuterCrossSize = 0;
-  for (uint32_t i = 0; i < mItems.Length(); ++i) {
-    const FlexItem& item = mItems[i];
-    nscoord curOuterCrossSize = item.GetCrossSize() +
-      item.GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
-
-    if (item.GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_BASELINE &&
-        item.GetNumAutoMarginsInAxis(aAxisTracker.GetCrossAxis()) == 0) {
+  for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
+    nscoord curOuterCrossSize = item->GetCrossSize() +
+      item->GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
+
+    if (item->GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_BASELINE &&
+        item->GetNumAutoMarginsInAxis(aAxisTracker.GetCrossAxis()) == 0) {
       // FIXME: Once we support "writing-mode", we'll have to do baseline
       // alignment in vertical flex containers here (w/ horizontal cross-axes).
 
       // Find distance from our item's cross-start and cross-end margin-box
       // edges to its baseline.
       //
       // Here's a diagram of a flex-item that we might be doing this on.
       // "mmm" is the margin-box, "bbb" is the border-box. The bottom of
@@ -2046,17 +2103,17 @@ FlexLine::ComputeCrossSizeAndBaseline(co
       // ---(cross-end)---
       //
       // We already have the curOuterCrossSize, margin-start, and the ascent.
       // * We can get crossStartToBaseline by adding margin-start + ascent.
       // * If we subtract that from the curOuterCrossSize, we get
       //   crossEndToBaseline.
 
       nscoord crossStartToBaseline =
-        item.GetBaselineOffsetFromOuterCrossStart(aAxisTracker.GetCrossAxis());
+        item->GetBaselineOffsetFromOuterCrossStart(aAxisTracker.GetCrossAxis());
       nscoord crossEndToBaseline = curOuterCrossSize - crossStartToBaseline;
 
       // Now, update our "largest" values for these (across all the flex items
       // in this flex line), so we can use them in computing the line's cross
       // size below:
       crossStartToFurthestBaseline = std::max(crossStartToFurthestBaseline,
                                               crossStartToBaseline);
       crossEndToFurthestBaseline = std::max(crossEndToFurthestBaseline,
@@ -2263,43 +2320,51 @@ FlexboxAxisTracker::FlexboxAxisTracker(n
   if (pos->mFlexWrap == NS_STYLE_FLEX_WRAP_WRAP_REVERSE) {
     mCrossAxis = GetReverseAxis(mCrossAxis);
   }
 
   MOZ_ASSERT(IsAxisHorizontal(mMainAxis) != IsAxisHorizontal(mCrossAxis),
              "main & cross axes should be in different dimensions");
 }
 
+// Allocates a new FlexLine, adds it at the back of the given LinkedList,
+// and returs a pointer to it.
+// XXXdholbert Bug 983427 will extend this to let the caller choose whether
+// the new FlexLine goes at the front or the back of the list.
+static FlexLine*
+AddNewFlexLineToList(LinkedList<FlexLine>& aLines)
+{
+  FlexLine* newLine = new FlexLine();
+  aLines.insertBack(newLine);
+  return newLine;
+}
+
 nsresult
 nsFlexContainerFrame::GenerateFlexLines(
   nsPresContext* aPresContext,
   const nsHTMLReflowState& aReflowState,
   nscoord aContentBoxMainSize,
   nscoord aAvailableHeightForContent,
   const nsTArray<StrutInfo>& aStruts,
   const FlexboxAxisTracker& aAxisTracker,
-  nsTArray<FlexLine>& aLines)
+  LinkedList<FlexLine>& aLines)
 {
-  MOZ_ASSERT(aLines.IsEmpty(), "Expecting outparam to start out empty");
+  MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
 
   const bool isSingleLine =
     NS_STYLE_FLEX_WRAP_NOWRAP == aReflowState.mStylePosition->mFlexWrap;
 
   // We have at least one FlexLine. Even an empty flex container has a single
   // (empty) flex line.
-  FlexLine* curLine = aLines.AppendElement();
+  FlexLine* curLine = AddNewFlexLineToList(aLines);
 
   nscoord wrapThreshold;
   if (isSingleLine) {
     // Not wrapping. Set threshold to sentinel value that tells us not to wrap.
     wrapThreshold = NS_UNCONSTRAINEDSIZE;
-
-    // Optimization: We know all items will end up in the first line, so we can
-    // pre-allocate space for them.
-    curLine->mItems.SetCapacity(mFrames.GetLength());
   } else {
     // Wrapping! Set wrap threshold to flex container's content-box main-size.
     wrapThreshold = aContentBoxMainSize;
 
     // If the flex container doesn't have a definite content-box main-size
     // (e.g. if we're 'height:auto'), make sure we at least wrap when we hit
     // its max main-size.
     if (wrapThreshold == NS_UNCONSTRAINEDSIZE) {
@@ -2326,75 +2391,61 @@ nsFlexContainerFrame::GenerateFlexLines(
   // Overall index of the current flex item in the flex container. (This gets
   // checked against entries in aStruts.)
   uint32_t itemIdxInContainer = 0;
 
   for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
     nsIFrame* childFrame = e.get();
 
     // Honor "page-break-before", if we're multi-line and this line isn't empty:
-    if (!isSingleLine && !curLine->mItems.IsEmpty() &&
+    if (!isSingleLine && !curLine->IsEmpty() &&
         childFrame->StyleDisplay()->mBreakBefore) {
-      curLine = aLines.AppendElement();
+      curLine = AddNewFlexLineToList(aLines);
     }
 
-    FlexItem* item;
+    nsAutoPtr<FlexItem> item;
     if (nextStrutIdx < aStruts.Length() &&
         aStruts[nextStrutIdx].mItemIdx == itemIdxInContainer) {
 
       // Use the simplified "strut" FlexItem constructor:
-      item = curLine->mItems.AppendElement(
-               FlexItem(childFrame, aStruts[nextStrutIdx].mStrutCrossSize));
+      item = new FlexItem(childFrame, aStruts[nextStrutIdx].mStrutCrossSize);
       nextStrutIdx++;
     } else {
-      item = curLine->mItems.AppendElement(
-               GenerateFlexItemForChild(aPresContext, childFrame,
-                                        aReflowState, aAxisTracker));
+      item = GenerateFlexItemForChild(aPresContext, childFrame,
+                                      aReflowState, aAxisTracker);
 
       nsresult rv = ResolveFlexItemMaxContentSizing(aPresContext, *item,
                                                     aReflowState, aAxisTracker);
       NS_ENSURE_SUCCESS(rv,rv);
     }
 
     nscoord itemInnerHypotheticalMainSize = item->GetMainSize();
     nscoord itemOuterHypotheticalMainSize = item->GetMainSize() +
       item->GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetMainAxis());
 
     // Check if we need to wrap |item| to a new line
     // (i.e. check if its outer hypothetical main size pushes our line over
     // the threshold)
     if (wrapThreshold != NS_UNCONSTRAINEDSIZE &&
-        curLine->mItems.Length() > 1 && // Don't wrap if it'll leave line empty
+        !curLine->IsEmpty() && // No need to wrap at start of a line.
         wrapThreshold < (curLine->GetTotalOuterHypotheticalMainSize() +
                          itemOuterHypotheticalMainSize)) {
-      // Need to wrap to a new line! Create a new line, create a copy of the
-      // newest FlexItem there, and clear that FlexItem out of the prev. line.
-      curLine = aLines.AppendElement();
-      // NOTE: if that^ AppendElement had to realloc, then |item| may now
-      // point to bogus memory. Null out our pointer and use a freshly-obtained
-      // reference ('itemToCopy'), to be on the safe side.
-      item = nullptr;
-
-      FlexLine& prevLine = aLines[aLines.Length() - 2];
-      uint32_t itemIdxInPrevLine = prevLine.mItems.Length() - 1;
-      FlexItem& itemToCopy = prevLine.mItems[itemIdxInPrevLine];
-
-      // Copy item into cur line:
-      curLine->mItems.AppendElement(itemToCopy);
-      // ...and remove the old copy in prev line:
-      prevLine.mItems.RemoveElementAt(itemIdxInPrevLine);
+      curLine = AddNewFlexLineToList(aLines);
     }
 
-    curLine->AddToMainSizeTotals(itemInnerHypotheticalMainSize,
-                                 itemOuterHypotheticalMainSize);
+    // Add item to current flex line (and update the line's bookkeeping about
+    // how large its items collectively are).
+    curLine->AddItem(item.forget(),
+                     itemInnerHypotheticalMainSize,
+                     itemOuterHypotheticalMainSize);
 
     // Honor "page-break-after", if we're multi-line and have more children:
     if (!isSingleLine && childFrame->GetNextSibling() &&
         childFrame->StyleDisplay()->mBreakAfter) {
-      curLine = aLines.AppendElement();
+      curLine = AddNewFlexLineToList(aLines);
     }
     itemIdxInContainer++;
   }
 
   return NS_OK;
 }
 
 // Retrieves the content-box main-size of our flex container from the
@@ -2412,37 +2463,38 @@ nsFlexContainerFrame::GetMainSizeFromRef
   }
 
   return GetEffectiveComputedHeight(aReflowState);
 }
 
 // Returns the largest outer hypothetical main-size of any line in |aLines|.
 // (i.e. the hypothetical main-size of the largest line)
 static nscoord
-GetLargestLineMainSize(const nsTArray<FlexLine>& aLines)
+GetLargestLineMainSize(const FlexLine* aFirstLine)
 {
   nscoord largestLineOuterSize = 0;
-  for (uint32_t lineIdx = 0; lineIdx < aLines.Length(); lineIdx++) {
-    largestLineOuterSize =
-      std::max(largestLineOuterSize,
-               aLines[lineIdx].GetTotalOuterHypotheticalMainSize());
+  for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
+    largestLineOuterSize = std::max(largestLineOuterSize,
+                                    line->GetTotalOuterHypotheticalMainSize());
   }
   return largestLineOuterSize;
 }
 
 // Returns the content-box main-size of our flex container, based on the
 // available height (if appropriate) and the main-sizes of the flex items.
 static nscoord
 ClampFlexContainerMainSize(const nsHTMLReflowState& aReflowState,
                            const FlexboxAxisTracker& aAxisTracker,
                            nscoord aUnclampedMainSize,
                            nscoord aAvailableHeightForContent,
-                           const nsTArray<FlexLine>& aLines,
+                           const FlexLine* aFirstLine,
                            nsReflowStatus& aStatus)
 {
+  MOZ_ASSERT(aFirstLine, "null first line pointer");
+
   if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
     // Horizontal case is easy -- our main size should already be resolved
     // before we get a call to Reflow. We don't have to worry about doing
     // page-breaking or shrinkwrapping in the horizontal axis.
     return aUnclampedMainSize;
   }
 
   if (aUnclampedMainSize != NS_INTRINSICSIZE) {
@@ -2459,29 +2511,29 @@ ClampFlexContainerMainSize(const nsHTMLR
     // Fragmenting *and* our fixed height is too tall for available height:
     // Mark incomplete so we get a next-in-flow, and take up all of the
     // available height (or the amount of height required by our children, if
     // that's larger; but of course not more than our own computed height).
     // XXXdholbert For now, we don't support pushing children to our next
     // continuation or splitting children, so "amount of height required by
     // our children" is just the main-size (height) of our longest flex line.
     NS_FRAME_SET_INCOMPLETE(aStatus);
-    nscoord largestLineOuterSize = GetLargestLineMainSize(aLines);
+    nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
 
     if (largestLineOuterSize <= aAvailableHeightForContent) {
       return aAvailableHeightForContent;
     }
     return std::min(aUnclampedMainSize, largestLineOuterSize);
   }
 
   // Vertical case, with auto-height:
   // Resolve auto-height to the largest FlexLine-length, clamped to our
   // computed min/max main-size properties (min-height & max-height).
   // XXXdholbert Handle constrained-aAvailableHeightForContent case here.
-  nscoord largestLineOuterSize = GetLargestLineMainSize(aLines);
+  nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
   return NS_CSS_MINMAX(largestLineOuterSize,
                        aReflowState.ComputedMinHeight(),
                        aReflowState.ComputedMaxHeight());
 }
 
 nscoord
 nsFlexContainerFrame::ComputeCrossSize(const nsHTMLReflowState& aReflowState,
                                        const FlexboxAxisTracker& aAxisTracker,
@@ -2535,38 +2587,36 @@ nsFlexContainerFrame::ComputeCrossSize(c
                        aReflowState.ComputedMaxHeight());
 }
 
 void
 FlexLine::PositionItemsInMainAxis(uint8_t aJustifyContent,
                                   nscoord aContentBoxMainSize,
                                   const FlexboxAxisTracker& aAxisTracker)
 {
-  MainAxisPositionTracker mainAxisPosnTracker(aAxisTracker, mItems,
+  MainAxisPositionTracker mainAxisPosnTracker(aAxisTracker, this,
                                               aJustifyContent,
                                               aContentBoxMainSize);
-  for (uint32_t i = 0; i < mItems.Length(); ++i) {
-    FlexItem& item = mItems[i];
-
+  for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
     nscoord itemMainBorderBoxSize =
-      item.GetMainSize() +
-      item.GetBorderPaddingSizeInAxis(mainAxisPosnTracker.GetAxis());
+      item->GetMainSize() +
+      item->GetBorderPaddingSizeInAxis(mainAxisPosnTracker.GetAxis());
 
     // Resolve any main-axis 'auto' margins on aChild to an actual value.
-    mainAxisPosnTracker.ResolveAutoMarginsInMainAxis(item);
+    mainAxisPosnTracker.ResolveAutoMarginsInMainAxis(*item);
 
     // Advance our position tracker to child's upper-left content-box corner,
     // and use that as its position in the main axis.
-    mainAxisPosnTracker.EnterMargin(item.GetMargin());
+    mainAxisPosnTracker.EnterMargin(item->GetMargin());
     mainAxisPosnTracker.EnterChildFrame(itemMainBorderBoxSize);
 
-    item.SetMainPosition(mainAxisPosnTracker.GetPosition());
+    item->SetMainPosition(mainAxisPosnTracker.GetPosition());
 
     mainAxisPosnTracker.ExitChildFrame(itemMainBorderBoxSize);
-    mainAxisPosnTracker.ExitMargin(item.GetMargin());
+    mainAxisPosnTracker.ExitMargin(item->GetMargin());
     mainAxisPosnTracker.TraversePackingSpace();
   }
 }
 
 // Helper method to take care of children who ASK_FOR_BASELINE, when
 // we need their baseline.
 static void
 ResolveReflowedChildAscent(nsIFrame* aFrame,
@@ -2673,33 +2723,32 @@ nsFlexContainerFrame::SizeItemInCrossAxi
 }
 
 void
 FlexLine::PositionItemsInCrossAxis(nscoord aLineStartPosition,
                                    const FlexboxAxisTracker& aAxisTracker)
 {
   SingleLineCrossAxisPositionTracker lineCrossAxisPosnTracker(aAxisTracker);
 
-  for (uint32_t i = 0; i < mItems.Length(); ++i) {
-    FlexItem& item = mItems[i];
+  for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
     // First, stretch the item's cross size (if appropriate), and resolve any
     // auto margins in this axis.
-    item.ResolveStretchedCrossSize(mLineCrossSize, aAxisTracker);
-    lineCrossAxisPosnTracker.ResolveAutoMarginsInCrossAxis(*this, item);
+    item->ResolveStretchedCrossSize(mLineCrossSize, aAxisTracker);
+    lineCrossAxisPosnTracker.ResolveAutoMarginsInCrossAxis(*this, *item);
 
     // Compute the cross-axis position of this item
     nscoord itemCrossBorderBoxSize =
-      item.GetCrossSize() +
-      item.GetBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
-    lineCrossAxisPosnTracker.EnterAlignPackingSpace(*this, item);
-    lineCrossAxisPosnTracker.EnterMargin(item.GetMargin());
+      item->GetCrossSize() +
+      item->GetBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
+    lineCrossAxisPosnTracker.EnterAlignPackingSpace(*this, *item);
+    lineCrossAxisPosnTracker.EnterMargin(item->GetMargin());
     lineCrossAxisPosnTracker.EnterChildFrame(itemCrossBorderBoxSize);
 
-    item.SetCrossPosition(aLineStartPosition +
-                          lineCrossAxisPosnTracker.GetPosition());
+    item->SetCrossPosition(aLineStartPosition +
+                           lineCrossAxisPosnTracker.GetPosition());
 
     // Back out to cross-axis edge of the line.
     lineCrossAxisPosnTracker.ResetPosition();
   }
 }
 
 nsresult
 nsFlexContainerFrame::Reflow(nsPresContext*           aPresContext,
@@ -2779,106 +2828,133 @@ nsFlexContainerFrame::Reflow(nsPresConte
     rv = DoFlexLayout(aPresContext, aDesiredSize, aReflowState, aStatus,
                       contentBoxMainSize, availableHeightForContent,
                       struts, axisTracker);
   }
 
   return rv;
 }
 
+// RAII class to clean up a list of FlexLines.
+// Specifically, this removes each line from the list, deletes all the
+// FlexItems in its list, and deletes the FlexLine.
+class AutoFlexLineListClearer MOZ_STACK_CLASS {
+public:
+  AutoFlexLineListClearer(LinkedList<FlexLine>& aLines
+                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+  : mLines(aLines)
+  {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+  }
+
+  ~AutoFlexLineListClearer()
+  {
+    while (FlexLine* line = mLines.popFirst()) {
+      while (FlexItem* item = line->mItems.popFirst()) {
+        delete item;
+      }
+      delete line;
+    }
+  }
+
+private:
+  LinkedList<FlexLine>& mLines;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 nsresult
 nsFlexContainerFrame::DoFlexLayout(nsPresContext*           aPresContext,
                                    nsHTMLReflowMetrics&     aDesiredSize,
                                    const nsHTMLReflowState& aReflowState,
                                    nsReflowStatus&          aStatus,
                                    nscoord aContentBoxMainSize,
                                    nscoord aAvailableHeightForContent,
                                    nsTArray<StrutInfo>& aStruts,
                                    const FlexboxAxisTracker& aAxisTracker)
 {
   aStatus = NS_FRAME_COMPLETE;
 
-  // Generate an array of our flex items (already sorted), in a FlexLine.
-  nsAutoTArray<FlexLine, 1> lines;
+  LinkedList<FlexLine> lines;
+  AutoFlexLineListClearer cleanupLines(lines);
+
   nsresult rv = GenerateFlexLines(aPresContext, aReflowState,
                                   aContentBoxMainSize,
                                   aAvailableHeightForContent,
                                   aStruts, aAxisTracker, lines);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aContentBoxMainSize =
     ClampFlexContainerMainSize(aReflowState, aAxisTracker,
                                aContentBoxMainSize, aAvailableHeightForContent,
-                               lines, aStatus);
-
-  for (uint32_t i = 0; i < lines.Length(); i++) {
-    lines[i].ResolveFlexibleLengths(aContentBoxMainSize);
+                               lines.getFirst(), aStatus);
+
+  for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
+    line->ResolveFlexibleLengths(aContentBoxMainSize);
   }
 
   // Cross Size Determination - Flexbox spec section 9.4
   // ===================================================
   // Calculate the hypothetical cross size of each item:
   nscoord sumLineCrossSizes = 0;
-  for (uint32_t lineIdx = 0; lineIdx < lines.Length(); ++lineIdx) {
-    FlexLine& line = lines[lineIdx];
-    for (uint32_t i = 0; i < line.mItems.Length(); ++i) {
-      FlexItem& item = line.mItems[i];
-
+  for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
+    for (FlexItem* item = line->GetFirstItem(); item; item = item->getNext()) {
       // (If the item's already been stretched, or it's a strut, then it
       // already knows its cross size.  Don't bother trying to recalculate it.)
-      if (!item.IsStretched() && !item.IsStrut()) {
+      if (!item->IsStretched() && !item->IsStrut()) {
         nsHTMLReflowState childReflowState(aPresContext, aReflowState,
-                                           item.Frame(),
+                                           item->Frame(),
                                            nsSize(aReflowState.ComputedWidth(),
                                                   NS_UNCONSTRAINEDSIZE));
         // Override computed main-size
         if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
-          childReflowState.SetComputedWidth(item.GetMainSize());
+          childReflowState.SetComputedWidth(item->GetMainSize());
         } else {
-          childReflowState.SetComputedHeight(item.GetMainSize());
+          childReflowState.SetComputedHeight(item->GetMainSize());
         }
 
         nsresult rv = SizeItemInCrossAxis(aPresContext, aAxisTracker,
-                                          childReflowState, item);
+                                          childReflowState, *item);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     }
     // Now that we've finished with this line's items, size the line itself:
-    line.ComputeCrossSizeAndBaseline(aAxisTracker);
-    sumLineCrossSizes += line.GetLineCrossSize();
+    line->ComputeCrossSizeAndBaseline(aAxisTracker);
+    sumLineCrossSizes += line->GetLineCrossSize();
   }
 
   bool isCrossSizeDefinite;
   const nscoord contentBoxCrossSize =
     ComputeCrossSize(aReflowState, aAxisTracker, sumLineCrossSizes,
                      aAvailableHeightForContent, &isCrossSizeDefinite, aStatus);
 
   // Set up state for cross-axis alignment, at a high level (outside the
   // scope of a particular flex line)
   CrossAxisPositionTracker
-    crossAxisPosnTracker(lines, aReflowState.mStylePosition->mAlignContent,
+    crossAxisPosnTracker(lines.getFirst(),
+                         aReflowState.mStylePosition->mAlignContent,
                          contentBoxCrossSize, isCrossSizeDefinite,
                          aAxisTracker);
 
   // Now that we know the cross size of each line (including
   // "align-content:stretch" adjustments, from the CrossAxisPositionTracker
   // constructor), we can create struts for any flex items with
   // "visibility: collapse" (and restart flex layout).
   if (aStruts.IsEmpty()) { // (Don't make struts if we already did)
-    BuildStrutInfoFromCollapsedItems(lines, aStruts);
+    BuildStrutInfoFromCollapsedItems(lines.getFirst(), aStruts);
     if (!aStruts.IsEmpty()) {
       // Restart flex layout, using our struts.
       return NS_OK;
     }
   }
 
   // Set the flex container's baseline, from the baseline-alignment position
   // of the first line's baseline-aligned items.
   nscoord flexContainerAscent;
-  nscoord firstLineBaselineOffset = lines[0].GetBaselineOffsetFromCrossStart();
+  nscoord firstLineBaselineOffset =
+    lines.getFirst()->GetBaselineOffsetFromCrossStart();
   if (firstLineBaselineOffset == nscoord_MIN) {
     // No baseline-aligned flex items in first line --> just use a sentinel
     // value for now, and we'll update it during final reflow.
     flexContainerAscent = nscoord_MIN;
   } else {
     // Add the position of the first line to that line's baseline-alignment
     // offset, to get the baseline offset with respect to the *container's*
     // cross-start edge.
@@ -2889,99 +2965,96 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
     // (into distance from top of content-box), plus the top border/padding
     // (since ascent is measured with respect to the top of the border-box).
     flexContainerAscent = aReflowState.ComputedPhysicalBorderPadding().top +
       PhysicalPosFromLogicalPos(firstLineBaselineOffsetWRTContainer,
                                 contentBoxCrossSize,
                                 aAxisTracker.GetCrossAxis());
   }
 
-  for (uint32_t lineIdx = 0; lineIdx < lines.Length(); ++lineIdx) {
-    FlexLine& line = lines[lineIdx];
+  for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
 
     // Main-Axis Alignment - Flexbox spec section 9.5
     // ==============================================
-    line.PositionItemsInMainAxis(aReflowState.mStylePosition->mJustifyContent,
-                                 aContentBoxMainSize,
-                                 aAxisTracker);
+    line->PositionItemsInMainAxis(aReflowState.mStylePosition->mJustifyContent,
+                                  aContentBoxMainSize,
+                                  aAxisTracker);
 
     // Cross-Axis Alignment - Flexbox spec section 9.6
     // ===============================================
-    line.PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
-                                  aAxisTracker);
-    crossAxisPosnTracker.TraverseLine(line);
+    line->PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
+                                   aAxisTracker);
+    crossAxisPosnTracker.TraverseLine(*line);
     crossAxisPosnTracker.TraversePackingSpace();
   }
 
   // Before giving each child a final reflow, calculate the origin of the
   // flex container's content box (with respect to its border-box), so that
   // we can compute our flex item's final positions.
   nsMargin containerBorderPadding(aReflowState.ComputedPhysicalBorderPadding());
   ApplySkipSides(containerBorderPadding, &aReflowState);
   const nsPoint containerContentBoxOrigin(containerBorderPadding.left,
                                           containerBorderPadding.top);
 
   // FINAL REFLOW: Give each child frame another chance to reflow, now that
   // we know its final size and position.
-  for (uint32_t lineIdx = 0; lineIdx < lines.Length(); ++lineIdx) {
-    FlexLine& line = lines[lineIdx];
-    for (uint32_t i = 0; i < line.mItems.Length(); ++i) {
-      FlexItem& item = line.mItems[i];
-
+  for (const FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
+    for (const FlexItem* item = line->GetFirstItem(); item;
+         item = item->getNext()) {
       nsPoint physicalPosn = aAxisTracker.PhysicalPointFromLogicalPoint(
-                               item.GetMainPosition(),
-                               item.GetCrossPosition(),
+                               item->GetMainPosition(),
+                               item->GetCrossPosition(),
                                aContentBoxMainSize,
                                contentBoxCrossSize);
       // Adjust physicalPosn to be relative to the container's border-box
       // (i.e. its frame rect), instead of the container's content-box:
       physicalPosn += containerContentBoxOrigin;
 
       nsHTMLReflowState childReflowState(aPresContext, aReflowState,
-                                         item.Frame(),
+                                         item->Frame(),
                                          nsSize(aReflowState.ComputedWidth(),
                                                 NS_UNCONSTRAINEDSIZE));
 
       // Keep track of whether we've overriden the child's computed height
       // and/or width, so we can set its resize flags accordingly.
       bool didOverrideComputedWidth = false;
       bool didOverrideComputedHeight = false;
 
       // Override computed main-size
       if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
-        childReflowState.SetComputedWidth(item.GetMainSize());
+        childReflowState.SetComputedWidth(item->GetMainSize());
         didOverrideComputedWidth = true;
       } else {
-        childReflowState.SetComputedHeight(item.GetMainSize());
+        childReflowState.SetComputedHeight(item->GetMainSize());
         didOverrideComputedHeight = true;
       }
 
       // Override reflow state's computed cross-size, for stretched items.
-      if (item.IsStretched()) {
-        MOZ_ASSERT(item.GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_STRETCH,
+      if (item->IsStretched()) {
+        MOZ_ASSERT(item->GetAlignSelf() == NS_STYLE_ALIGN_ITEMS_STRETCH,
                    "stretched item w/o 'align-self: stretch'?");
         if (IsAxisHorizontal(aAxisTracker.GetCrossAxis())) {
-          childReflowState.SetComputedWidth(item.GetCrossSize());
+          childReflowState.SetComputedWidth(item->GetCrossSize());
           didOverrideComputedWidth = true;
         } else {
           // If this item's height is stretched, it's a relative height.
-          item.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
-          childReflowState.SetComputedHeight(item.GetCrossSize());
+          item->Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
+          childReflowState.SetComputedHeight(item->GetCrossSize());
           didOverrideComputedHeight = true;
         }
       }
 
       // XXXdholbert Might need to actually set the correct margins in the
       // reflow state at some point, so that they can be saved on the frame for
       // UsedMarginProperty().  Maybe doesn't matter though...?
 
       // If we're overriding the computed width or height, *and* we had an
       // earlier "measuring" reflow, then this upcoming reflow needs to be
       // treated as a resize.
-      if (item.HadMeasuringReflow()) {
+      if (item->HadMeasuringReflow()) {
         if (didOverrideComputedWidth) {
           // (This is somewhat redundant, since the reflow state already
           // sets mHResize whenever our computed width has changed since the
           // previous reflow. Still, it's nice for symmetry, and it may become
           // necessary once we support orthogonal flows.)
           childReflowState.mFlags.mHResize = true;
         }
         if (didOverrideComputedHeight) {
@@ -2989,47 +3062,48 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
         }
       }
       // NOTE: Be very careful about doing anything else with childReflowState
       // after this point, because some of its methods (e.g. SetComputedWidth)
       // internally call InitResizeFlags and stomp on mVResize & mHResize.
 
       nsHTMLReflowMetrics childDesiredSize(childReflowState);
       nsReflowStatus childReflowStatus;
-      nsresult rv = ReflowChild(item.Frame(), aPresContext,
+      nsresult rv = ReflowChild(item->Frame(), aPresContext,
                                 childDesiredSize, childReflowState,
                                 physicalPosn.x, physicalPosn.y,
                                 0, childReflowStatus);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // XXXdholbert Once we do pagination / splitting, we'll need to actually
       // handle incomplete childReflowStatuses. But for now, we give our kids
       // unconstrained available height, which means they should always
       // complete.
       MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus),
                  "We gave flex item unconstrained available height, so it "
                  "should be complete");
 
       childReflowState.ApplyRelativePositioning(&physicalPosn);
 
-      rv = FinishReflowChild(item.Frame(), aPresContext,
+      rv = FinishReflowChild(item->Frame(), aPresContext,
                              childDesiredSize, &childReflowState,
                              physicalPosn.x, physicalPosn.y, 0);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // If this is our first child and we haven't established a baseline for
       // the container yet (i.e. if we don't have 'align-self: baseline' on any
       // children), then use this child's baseline as the container's baseline.
-      if (lineIdx == 0 && i == 0 && flexContainerAscent == nscoord_MIN) {
-        ResolveReflowedChildAscent(item.Frame(), childDesiredSize);
+      if (item->Frame() == mFrames.FirstChild() &&
+          flexContainerAscent == nscoord_MIN) {
+        ResolveReflowedChildAscent(item->Frame(), childDesiredSize);
 
         // (We use GetNormalPosition() instead of physicalPosn because we don't
         // want relative positioning on the child to affect the baseline that we
         // read from it).
-        flexContainerAscent = item.Frame()->GetNormalPosition().y +
+        flexContainerAscent = item->Frame()->GetNormalPosition().y +
           childDesiredSize.TopAscent();
       }
     }
   }
 
   nsSize desiredContentBoxSize =
     aAxisTracker.PhysicalSizeFromLogicalSizes(aContentBoxMainSize,
                                               contentBoxCrossSize);
@@ -3040,17 +3114,17 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
   aDesiredSize.Height() = desiredContentBoxSize.height +
     containerBorderPadding.top;
 
   if (flexContainerAscent == nscoord_MIN) {
     // Still don't have our baseline set -- this happens if we have no
     // children (or if our children are huge enough that they have nscoord_MIN
     // as their baseline... in which case, we'll use the wrong baseline, but no
     // big deal)
-    NS_WARN_IF_FALSE(lines[0].mItems.IsEmpty(),
+    NS_WARN_IF_FALSE(lines.getFirst()->IsEmpty(),
                      "Have flex items but didn't get an ascent - that's odd "
                      "(or there are just gigantic sizes involved)");
     // Per spec, just use the bottom of content-box.
     flexContainerAscent = aDesiredSize.Height();
   }
   aDesiredSize.SetTopAscent(flexContainerAscent);
 
   // Now: If we're complete, add bottom border/padding to desired height
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -6,17 +6,20 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: flex" */
 
 #ifndef nsFlexContainerFrame_h___
 #define nsFlexContainerFrame_h___
 
 #include "nsContainerFrame.h"
-#include "nsTArrayForwardDeclare.h"
+
+namespace mozilla {
+template <class T> class LinkedList;
+}
 
 nsIFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                                    nsStyleContext* aContext);
 
 typedef nsContainerFrame nsFlexContainerFrameSuper;
 
 class nsFlexContainerFrame : public nsFlexContainerFrameSuper {
 public:
@@ -98,36 +101,42 @@ protected:
   template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
   bool SortChildrenIfNeeded();
 
   // Protected flex-container-specific methods / member-vars
 #ifdef DEBUG
   void SanityCheckAnonymousFlexItems() const;
 #endif // DEBUG
 
-  FlexItem GenerateFlexItemForChild(nsPresContext* aPresContext,
-                                    nsIFrame* aChildFrame,
-                                    const nsHTMLReflowState& aParentReflowState,
-                                    const FlexboxAxisTracker& aAxisTracker);
+  // Returns a new FlexItem for the given child frame, allocated on the heap.
+  // Caller is responsible for managing the FlexItem's lifetime.
+  FlexItem* GenerateFlexItemForChild(nsPresContext* aPresContext,
+                                     nsIFrame* aChildFrame,
+                                     const nsHTMLReflowState& aParentReflowState,
+                                     const FlexboxAxisTracker& aAxisTracker);
 
   // Returns nsresult because we might have to reflow aFlexItem.Frame() (to
   // get its vertical intrinsic size in a vertical flexbox), and if that
   // reflow fails (returns a failure nsresult), we want to bail out.
   nsresult ResolveFlexItemMaxContentSizing(nsPresContext* aPresContext,
                                            FlexItem& aFlexItem,
                                            const nsHTMLReflowState& aParentReflowState,
                                            const FlexboxAxisTracker& aAxisTracker);
 
+  // Creates FlexItems for all of our child frames, arranged in a list of
+  // FlexLines.  These are returned by reference in |aLines|. Our actual
+  // return value has to be |nsresult|, in case we have to reflow a child
+  // to establish its flex base size and that reflow fails.
   nsresult GenerateFlexLines(nsPresContext* aPresContext,
                              const nsHTMLReflowState& aReflowState,
                              nscoord aContentBoxMainSize,
                              nscoord aAvailableHeightForContent,
                              const nsTArray<StrutInfo>& aStruts,
                              const FlexboxAxisTracker& aAxisTracker,
-                             nsTArray<FlexLine>& aLines);
+                             mozilla::LinkedList<FlexLine>& aLines);
 
   nscoord GetMainSizeFromReflowState(const nsHTMLReflowState& aReflowState,
                                      const FlexboxAxisTracker& aAxisTracker);
 
   nscoord ComputeCrossSize(const nsHTMLReflowState& aReflowState,
                            const FlexboxAxisTracker& aAxisTracker,
                            nscoord aSumLineCrossSizes,
                            nscoord aAvailableHeightForContent,