Bug 1163435 part 1 - [css-grid][css-flexbox] Propagate an explicit CB width/height to the reflow state to resolve percentage lengths for grid items properly. Resolve percent against the size in the same axis for abs.pos. children too. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Tue, 03 Nov 2015 21:45:33 +0100
changeset 306462 9dbec0f99fd0a17e99bf07da22e8833a8de3492c
parent 306461 d4e6581738478b66f78b5d4f77aa45f20353731c
child 306463 a8b188bf416f21bc7078ba225c0c8b82ab9a0f7a
push id7139
push usergijskruitbosch@gmail.com
push dateWed, 04 Nov 2015 15:17:15 +0000
reviewersdholbert
bugs1163435
milestone45.0a1
Bug 1163435 part 1 - [css-grid][css-flexbox] Propagate an explicit CB width/height to the reflow state to resolve percentage lengths for grid items properly. Resolve percent against the size in the same axis for abs.pos. children too. r=dholbert Grid items are supposed to use the size of their 'grid area', not their grid container, as their containing block.
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
layout/generic/nsIFrame.h
layout/generic/nsIFrameInlines.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -2794,22 +2794,23 @@ nsGridContainerFrame::ReflowChildren(Gri
       MOZ_ASSERT(area.IsDefinite());
       cb = ContainingBlockFor(aState, area);
       cb += gridOrigin;
     } else {
       cb = aContentArea;
     }
     WritingMode childWM = child->GetWritingMode();
     LogicalSize childCBSize = cb.Size(wm).ConvertTo(childWM, wm);
+    LogicalSize percentBasis(childCBSize);
     // XXX temporary workaround to avoid being INCOMPLETE until we have
     // support for fragmentation (bug 1144096)
     childCBSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
 
     Maybe<nsHTMLReflowState> childRS; // Maybe<> so we can reuse the space
-    childRS.emplace(pc, *aState.mReflowState, child, childCBSize);
+    childRS.emplace(pc, *aState.mReflowState, child, childCBSize, &percentBasis);
     // We need the width of the child before we can correctly convert
     // the writing-mode of its origin, so we reflow at (0, 0) using a dummy
     // containerSize, and then pass the correct position to FinishReflowChild.
     Maybe<nsHTMLReflowMetrics> childSize; // Maybe<> so we can reuse the space
     childSize.emplace(*childRS);
     nsReflowStatus childStatus;
     const nsSize dummyContainerSize;
     ReflowChild(child, pc, *childSize, *childRS, childWM, LogicalPoint(childWM),
@@ -2830,17 +2831,17 @@ nsGridContainerFrame::ReflowChildren(Gri
       Maybe<LogicalAxis> justifyResize =
         JustifySelf(justify, cb, wm, *childRS, oldSize, &newContentSize, &childPos);
       if (alignResize || justifyResize) {
         FinishReflowChild(child, pc, *childSize, childRS.ptr(), childWM,
                           LogicalPoint(childWM), containerSize,
                           NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW);
         childSize.reset(); // In reverse declaration order since it runs
         childRS.reset();   // destructors.
-        childRS.emplace(pc, *aState.mReflowState, child, childCBSize);
+        childRS.emplace(pc, *aState.mReflowState, child, childCBSize, &percentBasis);
         if ((alignResize && alignResize.value() == eLogicalAxisBlock) ||
             (justifyResize && justifyResize.value() == eLogicalAxisBlock)) {
           childRS->SetComputedBSize(newContentSize.BSize(childWM));
           childRS->SetBResize(true);
         }
         if ((alignResize && alignResize.value() == eLogicalAxisInline) ||
             (justifyResize && justifyResize.value() == eLogicalAxisInline)) {
           childRS->SetComputedISize(newContentSize.ISize(childWM));
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -2031,28 +2031,29 @@ IsSideCaption(nsIFrame* aFrame, const ns
   if (aStyleDisplay->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION) {
     return false;
   }
   uint8_t captionSide = aFrame->StyleTableBorder()->mCaptionSide;
   return captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
          captionSide == NS_STYLE_CAPTION_SIDE_RIGHT;
 }
 
-// Flex items resolve block-axis percentage margin & padding against the flex
-// container's block-size (which is the containing block block-size).
+// Flex/grid items resolve block-axis percentage margin & padding against the
+// containing block block-size (also for abs/fixed-pos child frames).
 // For everything else: the CSS21 spec requires that margin and padding
 // percentage values are calculated with respect to the inline-size of the
 // containing block, even for margin & padding in the block axis.
 static LogicalSize
 OffsetPercentBasis(const nsIFrame*    aFrame,
                    WritingMode        aWM,
                    const LogicalSize& aContainingBlockSize)
 {
   LogicalSize offsetPercentBasis = aContainingBlockSize;
-  if (!aFrame->IsFlexOrGridItem()) {
+  if (MOZ_LIKELY(!aFrame->GetParent() ||
+                 !aFrame->GetParent()->IsFlexOrGridContainer())) {
     offsetPercentBasis.BSize(aWM) = offsetPercentBasis.ISize(aWM);
   } else if (offsetPercentBasis.BSize(aWM) == NS_AUTOHEIGHT) {
     offsetPercentBasis.BSize(aWM) = 0;
   }
 
   return offsetPercentBasis;
 }
 
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -647,19 +647,19 @@ public:
    * state are copied from the parent's reflow state. The remainder is computed.
    *
    * @param aPresContext Must be equal to aFrame->PresContext().
    * @param aParentReflowState A reference to an nsHTMLReflowState object that
    *        is to be the parent of this object.
    * @param aFrame The frame for whose reflow state is being constructed.
    * @param aAvailableSpace See comments for availableHeight and availableWidth
    *        members.
-   * @param aContainingBlockSize An optional size, in app units, that
-   *        is used by absolute positioning code to override default containing
-   *        block sizes.
+   * @param aContainingBlockSize An optional size, in app units, specifying
+   *        the containing block size to use instead of the default which is
+   *        to use the aAvailableSpace.
    * @param aFlags A set of flags used for additional boolean parameters (see
    *        below).
    */
   nsHTMLReflowState(nsPresContext*              aPresContext,
                     const nsHTMLReflowState&    aParentReflowState,
                     nsIFrame*                   aFrame,
                     const mozilla::LogicalSize& aAvailableSpace,
                     const mozilla::LogicalSize* aContainingBlockSize = nullptr,
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2948,16 +2948,17 @@ NS_PTR_TO_INT32(frame->Properties().Get(
   /**
    * Is this a flex item? (i.e. a non-abs-pos child of a flex container)
    */
   inline bool IsFlexItem() const;
   /**
    * Is this a flex or grid item? (i.e. a non-abs-pos child of a flex/grid container)
    */
   inline bool IsFlexOrGridItem() const;
+  inline bool IsFlexOrGridContainer() const;
 
   /**
    * @return true if this frame is used as a table caption.
    */
   inline bool IsTableCaption() const;
 
   inline bool IsBlockInside() const;
   inline bool IsBlockOutside() const;
--- a/layout/generic/nsIFrameInlines.h
+++ b/layout/generic/nsIFrameInlines.h
@@ -15,25 +15,29 @@ bool
 nsIFrame::IsFlexItem() const
 {
   return GetParent() &&
     GetParent()->GetType() == nsGkAtoms::flexContainerFrame &&
     !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
 }
 
 bool
+nsIFrame::IsFlexOrGridContainer() const
+{
+  nsIAtom* t = GetType();
+  return t == nsGkAtoms::flexContainerFrame ||
+         t == nsGkAtoms::gridContainerFrame;
+}
+
+bool
 nsIFrame::IsFlexOrGridItem() const
 {
-  if (GetParent()) {
-    nsIAtom* t = GetParent()->GetType();
-    return (t == nsGkAtoms::flexContainerFrame ||
-            t == nsGkAtoms::gridContainerFrame) &&
-      !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
-  }
-  return false;
+  return !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
+         GetParent() &&
+         GetParent()->IsFlexOrGridContainer();
 }
 
 bool
 nsIFrame::IsTableCaption() const
 {
   return StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION &&
     GetParent()->StyleContext()->GetPseudo() == nsCSSAnonBoxes::tableOuter;
 }