Bug 1218178 part 3 - [css-grid][css-align] Implement ratio-preserving 'stretch' alignment for grid items with an intrinsic ratio. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Sat, 05 Nov 2016 02:57:05 +0100
changeset 351290 4e9d3d21f20db22985bf61346d03b40097bd47e3
parent 351289 60d6fd3a6aa89b4913eaa083e6dc29d03af99697
child 351291 30c652ff1d1e1bded08e12f4e6398429b2c2005b
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1218178
milestone52.0a1
Bug 1218178 part 3 - [css-grid][css-align] Implement ratio-preserving 'stretch' alignment for grid items with an intrinsic ratio. r=dholbert https://github.com/w3c/csswg-drafts/issues/523
layout/base/nsLayoutUtils.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5496,32 +5496,55 @@ nsLayoutUtils::ComputeSizeWithIntrinsicD
   // {min-,max-,}{width,height} according to the rules in
   // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
 
   // Note: throughout the following section of the function, I avoid
   // a * (b / c) because of its reduced accuracy relative to a * b / c
   // or (a * b) / c (which are equivalent).
 
   const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto;
-  bool isAutoBSize = IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
+  const bool isAutoBSize = IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
 
   LogicalSize boxSizingAdjust(aWM);
   if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
     boxSizingAdjust = aBorder + aPadding;
   }
   nscoord boxSizingToMarginEdgeISize =
     aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
       boxSizingAdjust.ISize(aWM);
 
   nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize;
+  // true if we are stretching a Grid item in the inline dimension
+  bool stretchI = false;
+  // true if we are stretching a Grid item in the block dimension
+  bool stretchB = false;
 
   if (!isAutoISize) {
     iSize = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
               aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
               boxSizingToMarginEdgeISize, *inlineStyleCoord);
+  } else if (MOZ_UNLIKELY(isGridItem)) {
+    MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(aFrame));
+    // 'auto' inline-size for grid-level box - apply 'stretch' as needed:
+    auto cbSize = aCBSize.ISize(aWM);
+    if (cbSize != NS_UNCONSTRAINEDSIZE &&
+        !aFrame->StyleMargin()->HasInlineAxisAuto(aWM)) {
+      auto inlineAxisAlignment =
+        aWM.IsOrthogonalTo(aFrame->GetParent()->GetWritingMode()) ?
+          stylePos->UsedAlignSelf(aFrame->GetParent()->StyleContext()) :
+          stylePos->UsedJustifySelf(aFrame->GetParent()->StyleContext());
+      stretchI = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
+                 inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH;
+      if (stretchI) {
+        iSize = std::max(nscoord(0), cbSize -
+                                     aPadding.ISize(aWM) -
+                                     aBorder.ISize(aWM) -
+                                     aMargin.ISize(aWM));
+      }
+    }
   }
 
   const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
 
   if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
       !(isFlexItem && isInlineFlexItem)) {
     maxISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
                  aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
@@ -5557,25 +5580,25 @@ nsLayoutUtils::ComputeSizeWithIntrinsicD
   } else if (MOZ_UNLIKELY(isGridItem)) {
     MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(aFrame));
     // 'auto' block-size for grid-level box - apply 'stretch' as needed:
     auto cbSize = aCBSize.BSize(aWM);
     if (cbSize != NS_AUTOHEIGHT &&
         !aFrame->StyleMargin()->HasBlockAxisAuto(aWM)) {
       auto blockAxisAlignment =
         !aWM.IsOrthogonalTo(aFrame->GetParent()->GetWritingMode()) ?
-          stylePos->UsedAlignSelf(aFrame->StyleContext()->GetParent()) :
-          stylePos->UsedJustifySelf(aFrame->StyleContext()->GetParent());
-      if (blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
-          blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
+          stylePos->UsedAlignSelf(aFrame->GetParent()->StyleContext()) :
+          stylePos->UsedJustifySelf(aFrame->GetParent()->StyleContext());
+      stretchB = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
+                 blockAxisAlignment == NS_STYLE_ALIGN_STRETCH;
+      if (stretchB) {
         bSize = std::max(nscoord(0), cbSize -
                                      aPadding.BSize(aWM) -
                                      aBorder.BSize(aWM) -
                                      aMargin.BSize(aWM));
-        isAutoBSize = false;
       }
     }
   }
 
   const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
 
   if (!IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
       !(isFlexItem && !isInlineFlexItem)) {
@@ -5663,16 +5686,40 @@ nsLayoutUtils::ComputeSizeWithIntrinsicD
         tentBSize = intrinsicBSize;
       } else if (logicalRatio.ISize(aWM) > 0) {
         tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
       } else {
         tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
       }
 
       if (aIntrinsicRatio != nsSize(0, 0)) {
+        if (stretchI || stretchB) {
+          // Stretch within the CB size with preserved intrinsic ratio.
+          if (stretchI && tentISize != iSize) {
+            tentISize = iSize;  // fill the CB iSize
+            if (logicalRatio.ISize(aWM) > 0) {
+              tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
+              if (tentBSize > bSize && stretchB) {
+                // We're stretching in both dimensions and the bSize calculated
+                // from the iSize / ratio would overflow the CB bSize, so stretch
+                // the bSize instead and derive the iSize which will then fit.
+                tentBSize = bSize;  // fill the CB bSize
+                if (logicalRatio.BSize(aWM) > 0) {
+                  tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
+                }
+              }
+            }
+          } else if (stretchB && tentBSize != bSize) {
+            tentBSize = bSize;  // fill the CB bSize
+            if (logicalRatio.BSize(aWM) > 0) {
+              tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
+            }
+          }
+        }
+
         nsSize autoSize =
           ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
                                                  maxISize, maxBSize,
                                                  tentISize, tentBSize);
         // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will
         // actually contain logical values if the parameters passed to it were
         // logical coordinates, so we do NOT perform a physical-to-logical
         // conversion here, but just assign the fields directly to our result.