Bug 1269045 part 2: Separate out abspos placeholders when creating FlexItems, and give them a trivial reflow at container's content-box origin. r=mats draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 27 Oct 2016 14:08:46 -0700
changeset 430450 5fe8fd86ad37e4055026819f633d36a34533f429
parent 430449 9e23a4bef1c1c3bd5cc417ca7ad4a2a011a87ffc
child 430451 fdca2fc2f3d1179f9c2c6801f634668a840fe741
push id33838
push userdholbert@mozilla.com
push dateThu, 27 Oct 2016 21:10:05 +0000
reviewersmats
bugs1269045
milestone52.0a1
Bug 1269045 part 2: Separate out abspos placeholders when creating FlexItems, and give them a trivial reflow at container's content-box origin. r=mats MozReview-Commit-ID: 5lXUsusLryC
layout/generic/nsFlexContainerFrame.cpp
layout/generic/nsFlexContainerFrame.h
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -3398,17 +3398,18 @@ AddNewFlexLineToList(LinkedList<FlexLine
 void
 nsFlexContainerFrame::GenerateFlexLines(
   nsPresContext* aPresContext,
   const ReflowInput& aReflowInput,
   nscoord aContentBoxMainSize,
   nscoord aAvailableBSizeForContent,
   const nsTArray<StrutInfo>& aStruts,
   const FlexboxAxisTracker& aAxisTracker,
-  LinkedList<FlexLine>& aLines)
+  nsTArray<nsIFrame*>& aPlaceholders, /* out */
+  LinkedList<FlexLine>& aLines /* out */)
 {
   MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
 
   const bool isSingleLine =
     NS_STYLE_FLEX_WRAP_NOWRAP == aReflowInput.mStylePosition->mFlexWrap;
 
   // If we're transparently reversing axes, then we'll need to link up our
   // FlexItems and FlexLines in the reverse order, so that the rest of flex
@@ -3455,16 +3456,22 @@ nsFlexContainerFrame::GenerateFlexLines(
   // aStruts.Length(), that means there are no more struts):
   uint32_t nextStrutIdx = 0;
 
   // Overall index of the current flex item in the flex container. (This gets
   // checked against entries in aStruts.)
   uint32_t itemIdxInContainer = 0;
 
   for (nsIFrame* childFrame : mFrames) {
+    // Don't create flex items / lines for placeholder frames:
+    if (childFrame->GetType() == nsGkAtoms::placeholderFrame) {
+      aPlaceholders.AppendElement(childFrame);
+      continue;
+    }
+
     // Honor "page-break-before", if we're multi-line and this line isn't empty:
     if (!isSingleLine && !curLine->IsEmpty() &&
         childFrame->StyleDisplay()->mBreakBefore) {
       curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
     }
 
     UniquePtr<FlexItem> item;
     if (nextStrutIdx < aStruts.Length() &&
@@ -4030,22 +4037,24 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
                                    nscoord aContentBoxMainSize,
                                    nscoord aAvailableBSizeForContent,
                                    nsTArray<StrutInfo>& aStruts,
                                    const FlexboxAxisTracker& aAxisTracker)
 {
   aStatus = NS_FRAME_COMPLETE;
 
   LinkedList<FlexLine> lines;
+  nsTArray<nsIFrame*> placeholderKids;
   AutoFlexLineListClearer cleanupLines(lines);
 
   GenerateFlexLines(aPresContext, aReflowInput,
                     aContentBoxMainSize,
                     aAvailableBSizeForContent,
-                    aStruts, aAxisTracker, lines);
+                    aStruts, aAxisTracker,
+                    placeholderKids, lines);
 
   aContentBoxMainSize =
     ResolveFlexContainerMainSize(aReflowInput, aAxisTracker,
                                  aContentBoxMainSize, aAvailableBSizeForContent,
                                  lines.getFirst(), aStatus);
 
   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
     line->ResolveFlexibleLengths(aContentBoxMainSize);
@@ -4264,16 +4273,22 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
       // children), then use this child's baseline as the container's baseline.
       if (item == firstItem &&
           flexContainerAscent == nscoord_MIN) {
         flexContainerAscent = itemNormalBPos + item->ResolvedAscent();
       }
     }
   }
 
+  if (!placeholderKids.IsEmpty()) {
+    ReflowPlaceholders(aPresContext, aReflowInput,
+                       placeholderKids, containerContentBoxOrigin,
+                       containerSize);
+  }
+
   // Compute flex container's desired size (in its own writing-mode),
   // starting w/ content-box size & growing from there:
   LogicalSize desiredSizeInFlexWM =
     aAxisTracker.LogicalSizeFromFlexRelativeSizes(aContentBoxMainSize,
                                                   contentBoxCrossSize);
   // Add border/padding (w/ skipSides already applied):
   desiredSizeInFlexWM.ISize(flexWM) += containerBP.IStartEnd(flexWM);
   desiredSizeInFlexWM.BSize(flexWM) += containerBP.BStartEnd(flexWM);
@@ -4465,16 +4480,48 @@ nsFlexContainerFrame::ReflowFlexItem(nsP
 
   FinishReflowChild(aItem.Frame(), aPresContext,
                     childDesiredSize, &childReflowInput,
                     outerWM, aFramePos, aContainerSize, 0);
 
   aItem.SetAscent(childDesiredSize.BlockStartAscent());
 }
 
+void
+nsFlexContainerFrame::ReflowPlaceholders(nsPresContext* aPresContext,
+                                         const ReflowInput& aReflowInput,
+                                         nsTArray<nsIFrame*>& aPlaceholders,
+                                         const LogicalPoint& aContentBoxOrigin,
+                                         const nsSize& aContainerSize)
+{
+  WritingMode outerWM = aReflowInput.GetWritingMode();
+
+  // As noted in this method's documentation, we'll reflow every entry in
+  // |aPlaceholders| at the container's content-box origin.
+  for (nsIFrame* placeholder : aPlaceholders) {
+    MOZ_ASSERT(placeholder->GetType() == nsGkAtoms::placeholderFrame,
+               "placeholders array should only contain placeholder frames");
+    WritingMode wm = placeholder->GetWritingMode();
+    LogicalSize availSize = aReflowInput.ComputedSize(wm);
+    ReflowInput childReflowInput(aPresContext, aReflowInput,
+                                 placeholder, availSize);
+    ReflowOutput childDesiredSize(childReflowInput);
+    nsReflowStatus childReflowStatus;
+    ReflowChild(placeholder, aPresContext,
+                childDesiredSize, childReflowInput,
+                outerWM, aContentBoxOrigin, aContainerSize, 0,
+                childReflowStatus);
+
+    FinishReflowChild(placeholder, aPresContext,
+                      childDesiredSize, &childReflowInput,
+                      outerWM, aContentBoxOrigin, aContainerSize, 0);
+
+  }
+}
+
 /* virtual */ nscoord
 nsFlexContainerFrame::GetMinISize(nsRenderingContext* aRenderingContext)
 {
   nscoord minISize = 0;
   DISPLAY_MIN_WIDTH(this, minISize);
 
   RenumberList();
 
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -188,26 +188,33 @@ protected:
    * on aFlexItem, if needed.
    * (Helper for GenerateFlexItemForChild().)
    */
   void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
                                       FlexItem& aFlexItem,
                                       const ReflowInput& aItemReflowInput,
                                       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.
+  /**
+   * This method:
+   *  - Creates FlexItems for all of our child frames (except placeholders).
+   *  - Groups those FlexItems into FlexLines.
+   *  - Returns those FlexLines in the outparam |aLines|.
+   *
+   * For any child frames which are placeholders, this method will instead just
+   * append that child to the outparam |aPlaceholders| for separate handling.
+   * (Absolutely positioned children of a flex container are *not* flex items.)
+   */
   void GenerateFlexLines(nsPresContext* aPresContext,
                          const ReflowInput& aReflowInput,
                          nscoord aContentBoxMainSize,
                          nscoord aAvailableBSizeForContent,
                          const nsTArray<StrutInfo>& aStruts,
                          const FlexboxAxisTracker& aAxisTracker,
+                         nsTArray<nsIFrame*>& aPlaceholders,
                          mozilla::LinkedList<FlexLine>& aLines);
 
   nscoord GetMainSizeFromReflowInput(const ReflowInput& aReflowInput,
                                      const FlexboxAxisTracker& aAxisTracker);
 
   nscoord ComputeCrossSize(const ReflowInput& aReflowInput,
                            const FlexboxAxisTracker& aAxisTracker,
                            nscoord aSumLineCrossSizes,
@@ -254,15 +261,45 @@ protected:
    */
   void ReflowFlexItem(nsPresContext* aPresContext,
                       const FlexboxAxisTracker& aAxisTracker,
                       const ReflowInput& aReflowInput,
                       const FlexItem& aItem,
                       mozilla::LogicalPoint& aFramePos,
                       const nsSize& aContainerSize);
 
+  /**
+   * Helper-function to perform a "dummy reflow" on all our nsPlaceholderFrame
+   * children, at the container's content-box origin.
+   *
+   * This doesn't actually represent the static position of the placeholders'
+   * out-of-flow (OOF) frames -- we can't compute that until we've reflowed the
+   * OOF, because (depending on the CSS Align properties) the static position
+   * may be influenced by the OOF's size.  So for now, we just co-opt the
+   * placeholder to store the flex container's logical content-box origin, and
+   * we defer to nsAbsoluteContainingBlock to determine the OOF's actual static
+   * position (using this origin, the OOF's size, and the CSS Align
+   * properties).
+   *
+   * XXXdholbert The nsAbsoluteContainingBlock stuff is coming in bug 1269046.
+   *
+   * @param aPresContext       The presentation context being used in reflow.
+   * @param aReflowInput       The flex container's reflow input.
+   * @param aPlaceholders      An array of all the flex container's
+   *                           nsPlaceholderFrame children.
+   * @param aContentBoxOrigin  The flex container's logical content-box
+   *                           origin (in its own coordinate space).
+   * @param aContainerSize     The flex container's size (required by some
+   *                           reflow methods to interpret positions correctly).
+   */
+  void ReflowPlaceholders(nsPresContext* aPresContext,
+                          const ReflowInput& aReflowInput,
+                          nsTArray<nsIFrame*>& aPlaceholders,
+                          const mozilla::LogicalPoint& aContentBoxOrigin,
+                          const nsSize& aContainerSize);
+
   bool mChildrenHaveBeenReordered; // Have we ever had to reorder our kids
                                    // to satisfy their 'order' values?
 
   nscoord mBaselineFromLastReflow;
 };
 
 #endif /* nsFlexContainerFrame_h___ */