Bug 1265342 Part 3: Stub in shape-margin for shape-outside: image, by implementing only for shape-margin: 0. draft
authorBrad Werth <bwerth@mozilla.com>
Mon, 12 Mar 2018 17:04:34 -0700
changeset 767048 e500d452953077e1e540bd1e2516382f7cbdbd8c
parent 767047 531999a7a46a758050ea8e4bc0d892c022c3d520
child 767049 cfca91346fdf97eaeb01b5331a52411f48b5073e
push id102494
push userbwerth@mozilla.com
push dateTue, 13 Mar 2018 20:51:39 +0000
bugs1265342
milestone61.0a1
Bug 1265342 Part 3: Stub in shape-margin for shape-outside: image, by implementing only for shape-margin: 0. MozReview-Commit-ID: 2gVRyQtd7Io
layout/generic/nsFloatManager.cpp
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -579,17 +579,19 @@ public:
     const UniquePtr<StyleBasicShape>& aBasicShape,
     const LogicalRect& aShapeBoxRect,
     WritingMode aWM,
     const nsSize& aContainerSize);
 
   static UniquePtr<ShapeInfo> CreateImageShape(
     const UniquePtr<nsStyleImage>& aShapeImage,
     float aShapeImageThreshold,
+    nscoord aShapeMargin,
     nsIFrame* const aFrame,
+    const LogicalRect& aMarginRect,
     WritingMode aWM,
     const nsSize& aContainerSize);
 
 protected:
   // Compute the minimum line-axis difference between the bounding shape
   // box and its rounded corner within the given band (block-axis region).
   // This is used as a helper function to compute the LineRight() and
   // LineLeft(). See the picture in the implementation for an example.
@@ -966,19 +968,21 @@ nsFloatManager::PolygonShapeInfo::XInter
 //
 // Implements shape-outside: <image>
 //
 class nsFloatManager::ImageShapeInfo final : public nsFloatManager::ShapeInfo
 {
 public:
   ImageShapeInfo(uint8_t* aAlphaPixels,
                  int32_t aStride,
-                 const CSSIntSize& aSize,
+                 const CSSIntSize& aImageSize,
                  float aShapeImageThreshold,
+                 nscoord aShapeMargin,
                  const nsRect& aContentRect,
+                 const nsRect& aMarginRect,
                  WritingMode aWM,
                  const nsSize& aContainerSize);
 
   nscoord LineLeft(const nscoord aBStart,
                    const nscoord aBEnd) const override;
   nscoord LineRight(const nscoord aBStart,
                     const nscoord aBEnd) const override;
   nscoord BStart() const override { return mBStart; }
@@ -1022,74 +1026,82 @@ private:
                       const nsSize& aContainerSize);
 };
 
 nsFloatManager::ImageShapeInfo::ImageShapeInfo(
   uint8_t* aAlphaPixels,
   int32_t aStride,
   const CSSIntSize& aImageSize,
   float aShapeImageThreshold,
+  nscoord aShapeMargin,
   const nsRect& aContentRect,
+  const nsRect& aMarginRect,
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   MOZ_ASSERT(aShapeImageThreshold >=0.0 && aShapeImageThreshold <=1.0,
              "The computed value of shape-image-threshold is wrong!");
 
   const uint8_t threshold = NSToIntFloor(aShapeImageThreshold * 255);
   const int32_t w = aImageSize.width;
   const int32_t h = aImageSize.height;
 
-  // Scan the pixels in a double loop. For horizontal writing modes, we do
-  // this row by row, from top to bottom. For vertical writing modes, we do
-  // column by column, from left to right. We define the two loops
-  // generically, then figure out the rows and cols within the inner loop.
-  const int32_t outerLimit = aWM.IsVertical() ? w : h;
-  const int32_t innerLimit = aWM.IsVertical() ? h : w;
-  for (int32_t outer = 0; outer < outerLimit; ++outer) {
-    // min and max store the start and end of the float area for the row
-    // or column represented by this iteration of the outer loop.
-    int32_t min = -1;
-    int32_t max = -1;
+  if (aShapeMargin <= 0) {
+    // Without a positive aShapeMargin, all we have to do is a
+    // direct threshold comparison of the alpha pixels.
+    // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
+
+    // Scan the pixels in a double loop. For horizontal writing modes, we do
+    // this row by row, from top to bottom. For vertical writing modes, we do
+    // column by column, from left to right. We define the two loops
+    // generically, then figure out the rows and cols within the inner loop.
+    const int32_t outerLimit = aWM.IsVertical() ? w : h;
+    const int32_t innerLimit = aWM.IsVertical() ? h : w;
+    for (int32_t outer = 0; outer < outerLimit; ++outer) {
+      // min and max store the start and end of the float area for the row
+      // or column represented by this iteration of the outer loop.
+      int32_t min = -1;
+      int32_t max = -1;
+
+      for (int32_t inner = 0; inner < innerLimit; ++inner) {
+        const int32_t col = aWM.IsVertical() ? outer : inner;
+        const int32_t row = aWM.IsVertical() ? inner : outer;
 
-    for (int32_t inner = 0; inner < innerLimit; ++inner) {
-      const int32_t col = aWM.IsVertical() ? outer : inner;
-      const int32_t row = aWM.IsVertical() ? inner : outer;
+        // Determine if the alpha pixel at this row and column has a value
+        // greater than the threshold. If it does, update our min and max values
+        // to track the edges of the float area for this row or column.
+        // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
+        const uint8_t alpha = aAlphaPixels[col + row * aStride];
+        if (alpha > threshold) {
+          if (min == -1) {
+            min = inner;
+          }
+          MOZ_ASSERT(max < inner);
+          max = inner;
+        }
+      }
 
-      // Determine if the alpha pixel at this row and column has a value
-      // greater than the threshold. If it does, update our min and max values
-      // to track the edges of the float area for this row or column.
-      // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
-      const uint8_t alpha = aAlphaPixels[col + row * aStride];
-      if (alpha > threshold) {
-        if (min == -1) {
-          min = inner;
-        }
-        MOZ_ASSERT(max < inner);
-        max = inner;
+      // At the end of a row or column; did we find something?
+      if (min != -1) {
+        // We need to supply an offset of the content rect top left, since
+        // our col and row have been calculated from the content rect,
+        // instead of the margin rect (against which floats are applied).
+        CreateInterval(min, max, outer, aContentRect.TopLeft(),
+                       aWM, aContainerSize);
       }
     }
 
-    // At the end of a row or column; did we find something?
-    if (min != -1) {
-      // We need to supply an offset of the content rect top left, since
-      // our col and row have been calculated from the content rect,
-      // instead of the margin rect (against which floats are applied).
-      CreateInterval(min, max, outer, aContentRect.TopLeft(),
-                     aWM, aContainerSize);
+    if (aWM.IsVerticalRL()) {
+      // Because we scan the columns from left to right, we need to reverse
+      // the array so that it's sorted (in ascending order) on the block
+      // direction.
+      mIntervals.Reverse();
     }
   }
 
-  if (aWM.IsVerticalRL()) {
-    // Because we scan the columns from left to right, we need to reverse
-    // the array so that it's sorted (in ascending order) on the block
-    // direction.
-    mIntervals.Reverse();
-  }
-
   if (!mIntervals.IsEmpty()) {
     mBStart = mIntervals[0].mLineLeft.Y();
     mBEnd = mIntervals[mIntervals.Length() - 1].mLineLeft.Y();
   }
 }
 
 void
 nsFloatManager::ImageShapeInfo::CreateInterval(
@@ -1216,16 +1228,32 @@ nsFloatManager::ImageShapeInfo::Translat
 
   mBStart += aBlockStart;
   mBEnd += aBlockStart;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // FloatInfo
 
+static bool
+IsPercentOfIndefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
+{
+  return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
+}
+
+static nscoord
+ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
+{
+  MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
+  if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) {
+    return nscoord(0);
+  }
+  return std::max(nscoord(0), aCoord.ComputeCoordPercentCalc(aPercentBasis));
+}
+
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
                                      nscoord aLineLeft, nscoord aBlockStart,
                                      const LogicalRect& aMarginRect,
                                      WritingMode aWM,
                                      const nsSize& aContainerSize)
   : mFrame(aFrame)
   , mRect(ShapeInfo::ConvertToFloatLogical(aMarginRect, aWM, aContainerSize) +
           nsPoint(aLineLeft, aBlockStart))
@@ -1250,19 +1278,24 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
       return;
 
     case StyleShapeSourceType::URL:
       MOZ_ASSERT_UNREACHABLE("shape-outside doesn't have URL source type!");
       return;
 
     case StyleShapeSourceType::Image: {
       float shapeImageThreshold = mFrame->StyleDisplay()->mShapeImageThreshold;
+      nscoord shapeMargin =
+        ::ResolveToDefiniteSize(mFrame->StyleDisplay()->mShapeMargin,
+                                aContainerSize.width);
       mShapeInfo = ShapeInfo::CreateImageShape(shapeOutside.GetShapeImage(),
                                                shapeImageThreshold,
+                                               shapeMargin,
                                                mFrame,
+                                               aMarginRect,
                                                aWM,
                                                aContainerSize);
       if (!mShapeInfo) {
         // Image is not ready, or fails to load, etc.
         return;
       }
 
       break;
@@ -1562,17 +1595,19 @@ nsFloatManager::ShapeInfo::CreatePolygon
 
   return MakeUnique<PolygonShapeInfo>(Move(vertices));
 }
 
 /* static */ UniquePtr<nsFloatManager::ShapeInfo>
 nsFloatManager::ShapeInfo::CreateImageShape(
   const UniquePtr<nsStyleImage>& aShapeImage,
   float aShapeImageThreshold,
+  nscoord aShapeMargin,
   nsIFrame* const aFrame,
+  const LogicalRect& aMarginRect,
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   MOZ_ASSERT(aShapeImage ==
              aFrame->StyleDisplay()->mShapeOutside.GetShapeImage(),
              "aFrame should be the frame that we got aShapeImage from");
 
   nsImageRenderer imageRenderer(aFrame, aShapeImage.get(),
@@ -1611,22 +1646,28 @@ nsFloatManager::ShapeInfo::CreateImageSh
 
   if (!map.IsMapped()) {
     return nullptr;
   }
 
   MOZ_ASSERT(sourceSurface->GetSize() == imageIntSize.ToUnknownSize(),
              "Who changes the size?");
 
+  nsRect marginRect = aMarginRect.GetPhysicalRect(aWM, aContainerSize);
+
   uint8_t* alphaPixels = map.GetData();
   int32_t stride = map.GetStride();
   return MakeUnique<ImageShapeInfo>(alphaPixels,
                                     stride,
                                     imageIntSize,
-                                    aShapeImageThreshold, contentRect, aWM,
+                                    aShapeImageThreshold,
+                                    aShapeMargin,
+                                    contentRect,
+                                    marginRect,
+                                    aWM,
                                     aContainerSize);
 }
 
 /* static */ nscoord
 nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
   const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
   const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
   const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,