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 787947 754d0696cc20ba754d2abf632ed3343518e577bd
parent 787946 c74ab8bdb317ce51e011c10cb6d1f1cd50697e2b
child 787948 0ab5069aaa05f9c6dc21bcd556ab84a7d3b8b71f
push id107854
push userbwerth@mozilla.com
push dateWed, 25 Apr 2018 18:14:35 +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.
@@ -979,17 +981,19 @@ nsFloatManager::PolygonShapeInfo::XInter
 class nsFloatManager::ImageShapeInfo final : public nsFloatManager::ShapeInfo
 {
 public:
   ImageShapeInfo(uint8_t* aAlphaPixels,
                  int32_t aStride,
                  const LayoutDeviceIntSize& aImageSize,
                  int32_t aAppUnitsPerDevPixel,
                  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; }
@@ -1029,75 +1033,83 @@ private:
 };
 
 nsFloatManager::ImageShapeInfo::ImageShapeInfo(
   uint8_t* aAlphaPixels,
   int32_t aStride,
   const LayoutDeviceIntSize& aImageSize,
   int32_t aAppUnitsPerDevPixel,
   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 i loop.
-  const int32_t bSize = aWM.IsVertical() ? w : h;
-  const int32_t iSize = aWM.IsVertical() ? h : w;
-  for (int32_t b = 0; b < bSize; ++b) {
-    // iMin and iMax store the start and end of the float area for the row
-    // or column represented by this iteration of the b loop.
-    int32_t iMin = -1;
-    int32_t iMax = -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 bSize = aWM.IsVertical() ? w : h;
+    const int32_t iSize = aWM.IsVertical() ? h : w;
+    for (int32_t b = 0; b < bSize; ++b) {
+      // iMin 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 iMin = -1;
+      int32_t iMax = -1;
+
+      for (int32_t i = 0; i < iSize; ++i) {
+        const int32_t col = aWM.IsVertical() ? b : i;
+        const int32_t row = aWM.IsVertical() ? i : b;
 
-    for (int32_t i = 0; i < iSize; ++i) {
-      const int32_t col = aWM.IsVertical() ? b : i;
-      const int32_t row = aWM.IsVertical() ? i : b;
+        // Determine if the alpha pixel at this row and column has a value
+        // greater than the threshold. If it does, update our iMin and iMax 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 (iMin == -1) {
+            iMin = i;
+          }
+          MOZ_ASSERT(iMax < i);
+          iMax = i;
+        }
+      }
 
-      // Determine if the alpha pixel at this row and column has a value
-      // greater than the threshold. If it does, update our iMin and iMax 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 (iMin == -1) {
-          iMin = i;
-        }
-        MOZ_ASSERT(iMax < i);
-        iMax = i;
+      // At the end of a row or column; did we find something?
+      if (iMin != -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(iMin, iMax, b, aAppUnitsPerDevPixel,
+                       aContentRect.TopLeft(), aWM, aContainerSize);
       }
     }
 
-    // At the end of a row or column; did we find something?
-    if (iMin != -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(iMin, iMax, b, aAppUnitsPerDevPixel,
-                     aContentRect.TopLeft(), aWM, aContainerSize);
+    if (aWM.IsVerticalRL()) {
+      // vertical-rl or sideways-rl.
+      // 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()) {
-    // vertical-rl or sideways-rl.
-    // 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].Y();
     mBEnd = mIntervals.LastElement().YMost();
   }
 }
 
 void
 nsFloatManager::ImageShapeInfo::CreateInterval(
@@ -1247,19 +1259,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 = nsLayoutUtils::ResolveToLength<true>(
+        mFrame->StyleDisplay()->mShapeMargin,
+        LogicalSize(aWM, aContainerSize).ISize(aWM));
       mShapeInfo = ShapeInfo::CreateImageShape(shapeOutside.GetShapeImage(),
                                                shapeImageThreshold,
+                                               shapeMargin,
                                                mFrame,
+                                               aMarginRect,
                                                aWM,
                                                aContainerSize);
       if (!mShapeInfo) {
         // Image is not ready, or fails to load, etc.
         return;
       }
 
       break;
@@ -1559,17 +1576,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(),
@@ -1618,27 +1637,31 @@ nsFloatManager::ShapeInfo::CreateImageSh
 
   if (!map.IsMapped()) {
     return nullptr;
   }
 
   MOZ_ASSERT(sourceSurface->GetSize() == contentSizeInDevPixels.ToUnknownSize(),
              "Who changes the size?");
 
+  nsRect marginRect = aMarginRect.GetPhysicalRect(aWM, aContainerSize);
+
   uint8_t* alphaPixels = map.GetData();
   int32_t stride = map.GetStride();
 
   // NOTE: ImageShapeInfo constructor does not keep a persistent copy of
   // alphaPixels; it's only used during the constructor to compute pixel ranges.
   return MakeUnique<ImageShapeInfo>(alphaPixels,
                                     stride,
                                     contentSizeInDevPixels,
                                     appUnitsPerDevPixel,
                                     aShapeImageThreshold,
+                                    aShapeMargin,
                                     contentRect,
+                                    marginRect,
                                     aWM,
                                     aContainerSize);
 }
 
 /* static */ nscoord
 nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
   const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
   const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,