Bug 1265342 Part 6a: Implement shape-margin for shape-outside: inset, for some special cases with shape-margin > 0. r=dholbert
authorBrad Werth <bwerth@mozilla.com>
Fri, 13 Apr 2018 11:29:14 -0700
changeset 469096 8d8361873abe44ec51e097db1f463bb179e75684
parent 469095 64161554cd20cac22690c5e05962bcb06132896b
child 469097 93dacd65e0093ba69fc376f0859a54be4e325388
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1265342
milestone61.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 1265342 Part 6a: Implement shape-margin for shape-outside: inset, for some special cases with shape-margin > 0. r=dholbert MozReview-Commit-ID: AEOksiuM0GJ
layout/generic/nsFloatManager.cpp
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -562,16 +562,18 @@ public:
     nscoord aShapeMargin,
     nsIFrame* const aFrame,
     const LogicalRect& aShapeBoxRect,
     WritingMode aWM,
     const nsSize& aContainerSize);
 
   static UniquePtr<ShapeInfo> CreateInset(
     const UniquePtr<StyleBasicShape>& aBasicShape,
+    nscoord aShapeMargin,
+    nsIFrame* aFrame,
     const LogicalRect& aShapeBoxRect,
     WritingMode aWM,
     const nsSize& aContainerSize);
 
   static UniquePtr<ShapeInfo> CreateCircleOrEllipse(
     const UniquePtr<StyleBasicShape>& aBasicShape,
     nscoord aShapeMargin,
     nsIFrame* const aFrame,
@@ -1009,41 +1011,61 @@ nsFloatManager::EllipseShapeInfo::LineRi
 //
 class nsFloatManager::RoundedBoxShapeInfo final : public nsFloatManager::ShapeInfo
 {
 public:
   RoundedBoxShapeInfo(const nsRect& aRect,
                       UniquePtr<nscoord[]> aRadii)
     : mRect(aRect)
     , mRadii(Move(aRadii))
+    , mShapeMargin(0)
   {}
 
+  RoundedBoxShapeInfo(const nsRect& aRect,
+                      UniquePtr<nscoord[]> aRadii,
+                      nscoord aShapeMargin,
+                      int32_t aAppUnitsPerDevPixel);
+
   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 mRect.y; }
   nscoord BEnd() const override { return mRect.YMost(); }
-  bool IsEmpty() const override { return mRect.IsEmpty(); };
+  bool IsEmpty() const override { return mRect.IsEmpty(); }
 
   void Translate(nscoord aLineLeft, nscoord aBlockStart) override
   {
     mRect.MoveBy(aLineLeft, aBlockStart);
   }
 
 private:
   // The rect of the rounded box shape in the float manager's coordinate
   // space.
   nsRect mRect;
   // The half corner radii of the reference box. It's an nscoord[8] array
   // in the float manager's coordinate space. If there are no radii, it's
   // nullptr.
-  UniquePtr<nscoord[]> mRadii;
+  const UniquePtr<nscoord[]> mRadii;
+
+  // A shape-margin value extends the boundaries of the float area.
+  const nscoord mShapeMargin;
 };
 
+nsFloatManager::RoundedBoxShapeInfo::RoundedBoxShapeInfo(const nsRect& aRect,
+  UniquePtr<nscoord[]> aRadii,
+  nscoord aShapeMargin,
+  int32_t aAppUnitsPerDevPixel)
+  : mRect(aRect)
+  , mRadii(Move(aRadii))
+  , mShapeMargin(aShapeMargin)
+{
+
+}
+
 nscoord
 nsFloatManager::RoundedBoxShapeInfo::LineLeft(const nscoord aBStart,
                                               const nscoord aBEnd) const
 {
   if (!mRadii) {
     return mRect.x;
   }
 
@@ -2058,24 +2080,27 @@ nsFloatManager::ShapeInfo::CreateBasicSh
     case StyleBasicShapeType::Polygon:
       return CreatePolygon(aBasicShape, aShapeBoxRect, aWM, aContainerSize);
     case StyleBasicShapeType::Circle:
     case StyleBasicShapeType::Ellipse:
       return CreateCircleOrEllipse(aBasicShape, aShapeMargin, aFrame,
                                    aShapeBoxRect, aWM,
                                    aContainerSize);
     case StyleBasicShapeType::Inset:
-      return CreateInset(aBasicShape, aShapeBoxRect, aWM, aContainerSize);
+      return CreateInset(aBasicShape, aShapeMargin, aFrame, aShapeBoxRect,
+                         aWM, aContainerSize);
   }
   return nullptr;
 }
 
 /* static */ UniquePtr<nsFloatManager::ShapeInfo>
 nsFloatManager::ShapeInfo::CreateInset(
   const UniquePtr<StyleBasicShape>& aBasicShape,
+  nscoord aShapeMargin,
+  nsIFrame* aFrame,
   const LogicalRect& aShapeBoxRect,
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   // Use physical coordinates to compute inset() because the top, right,
   // bottom and left offsets are physical.
   // https://drafts.csswg.org/css-shapes-1/#funcdef-inset
   nsRect physicalShapeBoxRect =
@@ -2085,24 +2110,65 @@ nsFloatManager::ShapeInfo::CreateInset(
 
   nsRect logicalInsetRect =
     ConvertToFloatLogical(LogicalRect(aWM, insetRect, aContainerSize),
                           aWM, aContainerSize);
   nscoord physicalRadii[8];
   bool hasRadii =
     ShapeUtils::ComputeInsetRadii(aBasicShape, insetRect, physicalShapeBoxRect,
                                   physicalRadii);
-  if (!hasRadii) {
+
+  // With a zero shape-margin, we will be able to use the fast constructor.
+  if (aShapeMargin == 0) {
+    if (!hasRadii) {
+      return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
+                                             UniquePtr<nscoord[]>());
+    }
     return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
-                                           UniquePtr<nscoord[]>());
+                                           ConvertToFloatLogical(physicalRadii,
+                                                                 aWM));
   }
 
+  // With a positive shape-margin, we might still be able to use the fast
+  // constructor. With no radii, we can build a rounded box by inflating
+  // logicalInsetRect, and supplying aShapeMargin as the radius for all
+  // corners.
+  if (!hasRadii) {
+    logicalInsetRect.Inflate(aShapeMargin);
+    auto logicalRadii = MakeUnique<nscoord[]>(8);
+    for (int32_t i = 0; i < 8; ++i) {
+      logicalRadii[i] = aShapeMargin;
+    }
+    return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
+                                           Move(logicalRadii));
+  }
+
+  // If we have radii, and each pair is equal, we can inflate both
+  // logicalInsetRect and all the radii and use the fast constructor.
+  if (physicalRadii[0] == physicalRadii[1] &&
+      physicalRadii[2] == physicalRadii[3] &&
+      physicalRadii[4] == physicalRadii[5] &&
+      physicalRadii[6] == physicalRadii[7]) {
+    logicalInsetRect.Inflate(aShapeMargin);
+    for (nscoord& r : physicalRadii) {
+      r += aShapeMargin;
+    }
+    return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
+                                           ConvertToFloatLogical(physicalRadii,
+                                                                 aWM));
+  }
+
+  // With positive shape-margin and unequal radii pairs, we have to use the
+  // slow constructor.
+  nsDeviceContext* dc = aFrame->PresContext()->DeviceContext();
+  int32_t appUnitsPerDevPixel = dc->AppUnitsPerDevPixel();
   return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
                                          ConvertToFloatLogical(physicalRadii,
-                                                               aWM));
+                                                               aWM),
+                                         aShapeMargin, appUnitsPerDevPixel);
 }
 
 /* static */ UniquePtr<nsFloatManager::ShapeInfo>
 nsFloatManager::ShapeInfo::CreateCircleOrEllipse(
   const UniquePtr<StyleBasicShape>& aBasicShape,
   nscoord aShapeMargin,
   nsIFrame* const aFrame,
   const LogicalRect& aShapeBoxRect,