Bug 1144096 part 15 - [css-grid] Compute our pre-reflow logical skip sides and cache the result of ComputedLogicalBorderPadding() with that applied. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Fri, 11 Mar 2016 17:39:26 +0100
changeset 288307 c5fd95723f2e70d51a3638534d7039f353b45435
parent 288306 77d251bd9afe14d6b024c6622e03d244289e0da8
child 288308 40456ea738607ff6668d3c22531c682984ef6d68
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1144096
milestone48.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 1144096 part 15 - [css-grid] Compute our pre-reflow logical skip sides and cache the result of ComputedLogicalBorderPadding() with that applied. r=dholbert Our "pre-reflow logical skip sides" assumes each fragment will be the last and have a block-end border. We then skip the block-end side at the end of Reflow if we're INCOMPLETE. This simplifies the logic that checks how many rows fits in this fragment.
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsSplittableFrame.cpp
layout/generic/nsSplittableFrame.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -1558,24 +1558,28 @@ struct MOZ_STACK_CLASS nsGridContainerFr
    * @note mReflowState may be null when using the 2nd ctor above. In this case
    * we'll construct a dummy parent reflow state if we need it to calculate
    * min/max-content contributions when sizing tracks.
    */
   const nsHTMLReflowState* const mReflowState;
   nsRenderingContext& mRenderingContext;
   nsGridContainerFrame* const mFrame;
   SharedGridData* mSharedGridData; // [weak] owned by mFrame's first-in-flow.
+  /** Computed border+padding with mSkipSides applied. */
+  LogicalMargin mBorderPadding;
   /**
    * BStart of this fragment in "grid space" (i.e. the concatenation of content
    * areas of all fragments).  Equal to mRows.mSizes[mStartRow].mPosition,
    * or, if this fragment starts after the last row, the GetConsumedBSize().
    */
   nscoord mFragBStart;
   /** The start row for this fragment. */
   uint32_t mStartRow;
+  /** Our tentative ApplySkipSides bits. */
+  LogicalSides mSkipSides;
   const WritingMode mWM;
 
 private:
   GridReflowState(nsGridContainerFrame*    aFrame,
                   nsRenderingContext&      aRenderingContext,
                   const nsHTMLReflowState* aReflowState,
                   const nsStylePosition*   aGridStyle,
                   const WritingMode&       aWM)
@@ -1588,21 +1592,27 @@ private:
                     mGridStyle->mGridAutoColumnsMax)
     , mRowFunctions(mGridStyle->mGridTemplateRows,
                     mGridStyle->mGridAutoRowsMin,
                     mGridStyle->mGridAutoRowsMax)
     , mReflowState(aReflowState)
     , mRenderingContext(aRenderingContext)
     , mFrame(aFrame)
     , mSharedGridData(nullptr)
+    , mBorderPadding(aWM)
     , mFragBStart(0)
     , mStartRow(0)
     , mWM(aWM)
   {
     MOZ_ASSERT(!aReflowState || aReflowState->frame == mFrame);
+    if (aReflowState) {
+      mBorderPadding = aReflowState->ComputedLogicalBorderPadding();
+      mSkipSides = aFrame->PreReflowBlockLevelLogicalSkipSides();
+      mBorderPadding.ApplySkipSides(mSkipSides);
+    }
   }
 };
 
 /**
  * The Grid implements grid item placement and the state of the grid -
  * the size of the explicit/implicit grid, which cells are occupied etc.
  */
 struct MOZ_STACK_CLASS nsGridContainerFrame::Grid
@@ -4025,21 +4035,18 @@ nsGridContainerFrame::GetNearestFragment
       break;
     }
     nsIAtom* frameType = cbRS->frame->GetType();
     if ((frameType == nsGkAtoms::canvasFrame &&
          PresContext()->IsPaginated()) ||
         frameType == nsGkAtoms::columnSetFrame) {
       data.emplace();
       data->mIsTopOfPage = gridRS->mFlags.mIsTopOfPage;
-      LogicalMargin bp = gridRS->ComputedLogicalBorderPadding();
-      const auto logicalSkipSides = GetLogicalSkipSides();
-      bp.ApplySkipSides(logicalSkipSides);
       data->mToFragmentainerEnd = aState.mFragBStart +
-        gridRS->AvailableBSize() - bp.BStart(wm);
+        gridRS->AvailableBSize() - aState.mBorderPadding.BStart(wm);
       const auto numRows = aState.mRows.mSizes.Length();
       data->mCanBreakAtStart =
         numRows > 0 && aState.mRows.mSizes[0].mPosition > 0;
       nscoord bSize = gridRS->ComputedBSize();
       data->mIsAutoBSize = bSize == NS_AUTOHEIGHT;
       if (data->mIsAutoBSize) {
         bSize = gridRS->ComputedMinBSize();
       } else {
@@ -4189,18 +4196,17 @@ nsGridContainerFrame::ReflowChildren(Gri
   nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
   if (GetPrevInFlow()) {
     ReflowOverflowContainerChildren(PresContext(), *aState.mReflowState,
                                     ocBounds, 0, ocStatus);
   }
 
   WritingMode wm = aState.mReflowState->GetWritingMode();
   const nsSize containerSize =
-    (aContentArea.Size(wm) +
-     aState.mReflowState->ComputedLogicalBorderPadding().Size(wm)).GetPhysicalSize(wm);
+    (aContentArea.Size(wm) + aState.mBorderPadding.Size(wm)).GetPhysicalSize(wm);
 
   nscoord bSize = aContentArea.BSize(wm);
   if (false) {
     // XXX TBD: a later patch will add the fragmented reflow here...
   } else {
     aState.mIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
     for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
       nsIFrame* child = *aState.mIter;
@@ -4402,18 +4408,16 @@ nsGridContainerFrame::Reflow(nsPresConte
                "NS_STATE_GRID_DID_PUSH_ITEMS lied");
     ::MergeSortedFrameLists(mFrames, items, GetContent());
   }
 
 #ifdef DEBUG
   SanityCheckAnonymousGridItems();
 #endif // DEBUG
 
-  LogicalMargin bp = aReflowState.ComputedLogicalBorderPadding();
-  bp.ApplySkipSides(GetLogicalSkipSides());
   const nsStylePosition* stylePos = aReflowState.mStylePosition;
   if (!prevInFlow) {
     InitImplicitNamedAreas(stylePos);
   }
   GridReflowState gridReflowState(this, aReflowState);
   if (gridReflowState.mIter.ItemsAreAlreadyInOrder()) {
     AddStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
   } else {
@@ -4491,28 +4495,37 @@ nsGridContainerFrame::Reflow(nsPresConte
     }
     bSize = NS_CSS_MINMAX(bSize,
                           aReflowState.ComputedMinBSize(),
                           aReflowState.ComputedMaxBSize());
   } else {
     bSize = computedBSize;
   }
   bSize = std::max(bSize - consumedBSize, 0);
+  auto& bp = gridReflowState.mBorderPadding;
   LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
                           computedISize, bSize);
 
   if (!prevInFlow) {
     // Apply 'align/justify-content' to the grid.
     gridReflowState.mCols.AlignJustifyContent(aReflowState, contentArea.Size(wm));
     gridReflowState.mRows.AlignJustifyContent(aReflowState, contentArea.Size(wm));
   }
 
   gridReflowState.mIter.Reset(GridItemCSSOrderIterator::eIncludeAll);
   ReflowChildren(gridReflowState, contentArea, aDesiredSize, aStatus);
 
+  // Skip our block-end border if we're INCOMPLETE.
+  if (!NS_FRAME_IS_COMPLETE(aStatus) &&
+      !gridReflowState.mSkipSides.BEnd() &&
+      StyleBorder()->mBoxDecorationBreak !=
+        NS_STYLE_BOX_DECORATION_BREAK_CLONE) {
+    bp.BEnd(wm) = nscoord(0);
+  }
+
   LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
                               bSize         + bp.BStartEnd(wm));
   aDesiredSize.SetSize(wm, desiredSize);
   aDesiredSize.mOverflowAreas.UnionAllWith(nsRect(0, 0,
                                                   aDesiredSize.Width(),
                                                   aDesiredSize.Height()));
   if (!prevInFlow) {
     auto sharedGridData = static_cast<SharedGridData*>(
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -272,16 +272,30 @@ nsSplittableFrame::GetLogicalSkipSides(c
     if (nif && !IS_TRUE_OVERFLOW_CONTAINER(nif)) {
       skip |= eLogicalSideBitsBEnd;
     }
   }
 
  return skip;
 }
 
+LogicalSides
+nsSplittableFrame::PreReflowBlockLevelLogicalSkipSides() const
+{
+  if (MOZ_UNLIKELY(IS_TRUE_OVERFLOW_CONTAINER(this))) {
+    return LogicalSides(mozilla::eLogicalSideBitsBBoth);
+  }
+  if (MOZ_LIKELY(StyleBorder()->mBoxDecorationBreak !=
+                   NS_STYLE_BOX_DECORATION_BREAK_CLONE) &&
+      GetPrevInFlow()) {
+    return LogicalSides(mozilla::eLogicalSideBitsBStart);
+  }
+  return LogicalSides();
+}
+
 #ifdef DEBUG
 void
 nsSplittableFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
 {
   nsFrame::DumpBaseRegressionData(aPresContext, out, aIndent);
   if (nullptr != mNextContinuation) {
     IndentBy(out, aIndent);
     fprintf(out, "<next-continuation va=\"%p\"/>\n", (void*)mNextContinuation);
--- a/layout/generic/nsSplittableFrame.h
+++ b/layout/generic/nsSplittableFrame.h
@@ -92,16 +92,28 @@ protected:
   nscoord GetEffectiveComputedBSize(const nsHTMLReflowState& aReflowState,
                                     nscoord aConsumed = NS_INTRINSICSIZE) const;
 
   /**
    * @see nsIFrame::GetLogicalSkipSides()
    */
   virtual LogicalSides GetLogicalSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const override;
 
+  /**
+   * A faster version of GetLogicalSkipSides() that is intended to be used
+   * inside Reflow before it's known if |this| frame will be COMPLETE or not.
+   * It returns a result that assumes this fragment is the last and thus
+   * should apply the block-end border/padding etc (except for "true" overflow
+   * containers which always skip block sides).  You're then expected to
+   * recalculate the block-end side (as needed) when you know |this| frame's
+   * reflow status is INCOMPLETE.
+   * This method is intended for frames that breaks in the block axis.
+   */
+  LogicalSides PreReflowBlockLevelLogicalSkipSides() const;
+
 #ifdef DEBUG
   virtual void DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) override;
 #endif
 
   nsIFrame*   mPrevContinuation;
   nsIFrame*   mNextContinuation;
 };