Bug 1176793 part 1 - [css-grid] Implement margin:auto for grid items. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Tue, 01 Dec 2015 23:20:18 +0100
changeset 309247 daf6598a5d7a933c786bd09abfb19874e2ace950
parent 309246 18149c916fbf84ed0a0a9a7972c81142a2eabe0b
child 309248 e52c8b7764e24cdfcd1a9b4a65701f5705af540d
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1176793
milestone45.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 1176793 part 1 - [css-grid] Implement margin:auto for grid items. r=dholbert
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsHTMLReflowState.cpp
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -909,25 +909,46 @@ AlignJustifySelf(uint8_t aAlignment, boo
       marginStart = margin.IStart(wm);
       marginEnd = margin.IEnd(wm);
     } else {
       marginStart = margin.IEnd(wm);
       marginEnd = margin.IStart(wm);
     }
   }
 
+  const auto& styleMargin = aRS.mStyleMargin->mMargin;
+  bool hasAutoMarginStart;
+  bool hasAutoMarginEnd;
+  if (aAxis == eLogicalAxisBlock) {
+    hasAutoMarginStart = styleMargin.GetBStartUnit(wm) == eStyleUnit_Auto;
+    hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
+  } else {
+    hasAutoMarginStart = styleMargin.GetIStartUnit(wm) == eStyleUnit_Auto;
+    hasAutoMarginEnd = styleMargin.GetIEndUnit(wm) == eStyleUnit_Auto;
+  }
+
   // https://drafts.csswg.org/css-align-3/#overflow-values
   // This implements <overflow-position> = 'safe'.
-  if (MOZ_UNLIKELY(aOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) {
+  // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
+  if ((MOZ_UNLIKELY(aOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) ||
+      hasAutoMarginStart || hasAutoMarginEnd) {
     nscoord space = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
                                 aAxis, aCBSize);
     // XXX we might want to include == 0 here as an optimization -
     // I need to see what the baseline/last-baseline code looks like first.
     if (space < 0) {
+      // "Overflowing elements ignore their auto margins and overflow
+      // in the end directions"
       aAlignment = NS_STYLE_ALIGN_START;
+    } else if (hasAutoMarginEnd) {
+      aAlignment = hasAutoMarginStart ? NS_STYLE_ALIGN_CENTER
+                                      : (aSameSide ? NS_STYLE_ALIGN_START
+                                                   : NS_STYLE_ALIGN_END);
+    } else if (hasAutoMarginStart) {
+      aAlignment = aSameSide ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
     }
   }
 
   // Set the position and size (aPos/aContentSize) for the requested alignment.
   bool didResize = false;
   nscoord offset = 0;
   switch (aAlignment) {
     case NS_STYLE_ALIGN_BASELINE:
@@ -942,25 +963,21 @@ AlignJustifySelf(uint8_t aAlignment, boo
       offset = aCBSize - (size + marginEnd);
       break;
     }
     case NS_STYLE_ALIGN_CENTER:
       offset = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
                            aAxis, aCBSize) / 2;
       break;
     case NS_STYLE_ALIGN_STRETCH: {
+      MOZ_ASSERT(!hasAutoMarginStart && !hasAutoMarginEnd);
       offset = marginStart;
-      const auto& styleMargin = aRS.mStyleMargin->mMargin;
       if (aAxis == eLogicalAxisBlock
-             ? (aRS.mStylePosition->BSize(wm).GetUnit() == eStyleUnit_Auto &&
-                styleMargin.GetBStartUnit(wm) != eStyleUnit_Auto &&
-                styleMargin.GetBEndUnit(wm) != eStyleUnit_Auto)
-             : (aRS.mStylePosition->ISize(wm).GetUnit() == eStyleUnit_Auto &&
-                styleMargin.GetIStartUnit(wm) != eStyleUnit_Auto &&
-                styleMargin.GetIEndUnit(wm) != eStyleUnit_Auto)) {
+            ? (aRS.mStylePosition->BSize(wm).GetUnit() == eStyleUnit_Auto)
+            : (aRS.mStylePosition->ISize(wm).GetUnit() == eStyleUnit_Auto)) {
         nscoord size = aAxis == eLogicalAxisBlock ? aChildSize.BSize(wm)
                                                   : aChildSize.ISize(wm);
         nscoord gap = aCBSize - (size + marginStart + marginEnd);
         if (gap > 0) {
           // Note: The ComputedMax* values are always content-box max values,
           // even for box-sizing:border-box.
           LogicalMargin bp = aRS.ComputedLogicalBorderPadding();
           // XXX ApplySkipSides is probably not very useful here since we
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -2284,54 +2284,61 @@ nsHTMLReflowState::InitConstraints(nsPre
     } else {
       AutoMaybeDisableFontInflation an(frame);
 
       bool isBlock = NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType);
       typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags;
       ComputeSizeFlags computeSizeFlags =
         isBlock ? ComputeSizeFlags::eDefault : ComputeSizeFlags::eShrinkWrap;
 
-      // Make sure legend frames with display:block and width:auto still
-      // shrink-wrap.
-      // Also shrink-wrap blocks that are orthogonal to their container.
-      if (isBlock &&
-          ((aFrameType == nsGkAtoms::legendFrame &&
-            frame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) ||
-           (aFrameType == nsGkAtoms::scrollFrame &&
-            frame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame) ||
-           (mCBReflowState &&
-            mCBReflowState->GetWritingMode().IsOrthogonalTo(mWritingMode)))) {
-        computeSizeFlags =
-          ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
-      }
-
       nsIFrame* parent = frame->GetParent();
       nsIAtom* parentFrameType = parent ? parent->GetType() : nullptr;
-      if (parentFrameType == nsGkAtoms::flexContainerFrame) {
-        computeSizeFlags =
-          ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
-
-        // If we're inside of a flex container that needs to measure our
-        // auto height, pass that information along to ComputeSize().
-        if (mFlags.mIsFlexContainerMeasuringHeight) {
+      if (parentFrameType == nsGkAtoms::gridContainerFrame) {
+        // Shrink-wrap grid items that will be aligned (rather than stretched)
+        // in its inline axis.
+        auto inlineAxisAlignment = wm.IsOrthogonalTo(cbwm) ?
+          mStylePosition->ComputedAlignSelf(mStyleDisplay,
+                                            frame->StyleContext()->GetParent()) :
+          mStylePosition->ComputedJustifySelf(mStyleDisplay,
+                                              frame->StyleContext()->GetParent());
+        if (inlineAxisAlignment != NS_STYLE_ALIGN_STRETCH ||
+            mStyleMargin->mMargin.GetIStartUnit(wm) == eStyleUnit_Auto ||
+            mStyleMargin->mMargin.GetIEndUnit(wm) == eStyleUnit_Auto) {
           computeSizeFlags =
-            ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoHeight);
+            ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
         }
       } else {
-        MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight,
-                   "We're not in a flex container, so the flag "
-                   "'mIsFlexContainerMeasuringHeight' shouldn't be set");
+        // Make sure legend frames with display:block and width:auto still
+        // shrink-wrap.
+        // Also shrink-wrap blocks that are orthogonal to their container.
+        if (isBlock &&
+            ((aFrameType == nsGkAtoms::legendFrame &&
+              frame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) ||
+             (aFrameType == nsGkAtoms::scrollFrame &&
+              frame->GetContentInsertionFrame()->GetType() == nsGkAtoms::legendFrame) ||
+             (mCBReflowState &&
+              mCBReflowState->GetWritingMode().IsOrthogonalTo(mWritingMode)))) {
+          computeSizeFlags =
+            ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
+        }
 
-        if (parentFrameType == nsGkAtoms::gridContainerFrame) {
-          auto justifySelf = mStylePosition->ComputedJustifySelf(mStyleDisplay,
-                               frame->StyleContext()->GetParent());
-          if (justifySelf != NS_STYLE_JUSTIFY_STRETCH) {
+        if (parentFrameType == nsGkAtoms::flexContainerFrame) {
+          computeSizeFlags =
+            ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
+
+          // If we're inside of a flex container that needs to measure our
+          // auto height, pass that information along to ComputeSize().
+          if (mFlags.mIsFlexContainerMeasuringHeight) {
             computeSizeFlags =
-              ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
+              ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoHeight);
           }
+        } else {
+          MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight,
+                     "We're not in a flex container, so the flag "
+                     "'mIsFlexContainerMeasuringHeight' shouldn't be set");
         }
       }
 
       if (cbSize.ISize(wm) == NS_UNCONSTRAINEDSIZE) {
         // For orthogonal flows, where we found a parent orthogonal-limit
         // for AvailableISize() in Init(), we'll use the same here as well.
         cbSize.ISize(wm) = AvailableISize();
       }