Bug 1326407 Part 6 - Cache the border radii in BoxShapeInfo. r=dbaron
authorTing-Yu Lin <tlin@mozilla.com>
Thu, 16 Feb 2017 10:51:48 +0800
changeset 343240 0058687f781389dad42c0e01f4117859e8496202
parent 343239 f45cac0c1b91cb5220b74b1dd5b708a4154c9d1f
child 343241 8a514a5851a4435f772ac5030f1ef4ed7303aa90
push id31372
push usercbook@mozilla.com
push dateThu, 16 Feb 2017 12:16:10 +0000
treeherdermozilla-central@2737f66ad6ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1326407
milestone54.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 1326407 Part 6 - Cache the border radii in BoxShapeInfo. r=dbaron The radii can be computed when creating BoxShapeInfo. No need to compute them every time in the LineLeft() and LineRight(). MozReview-Commit-ID: GIDSLgickCT
layout/generic/nsFloatManager.cpp
layout/generic/nsFloatManager.h
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -531,89 +531,43 @@ nsFloatManager::ClearContinues(StyleClea
 /////////////////////////////////////////////////////////////////////////////
 // BoxShapeInfo
 
 nscoord
 nsFloatManager::BoxShapeInfo::LineLeft(WritingMode aWM,
                                        const nscoord aBStart,
                                        const nscoord aBEnd) const
 {
-  nscoord radii[8];
-  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-  if (!hasRadii) {
+  if (!mRadii) {
     return mShapeBoxRect.x;
   }
 
-  // Get the physical side for line-left since border-radii are in
-  // the physical axis.
-  mozilla::Side lineLeftSide =
-    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
-  nscoord blockStartCornerRadiusL =
-    radii[SideToHalfCorner(lineLeftSide, true, false)];
-  nscoord blockStartCornerRadiusB =
-    radii[SideToHalfCorner(lineLeftSide, true, true)];
-  nscoord blockEndCornerRadiusL =
-    radii[SideToHalfCorner(lineLeftSide, false, false)];
-  nscoord blockEndCornerRadiusB =
-    radii[SideToHalfCorner(lineLeftSide, false, true)];
-
-  if (aWM.IsLineInverted()) {
-    // This happens only when aWM is vertical-lr. Need to swap blockStart
-    // and blockEnd corners.
-    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
-  }
-
   nscoord lineLeftDiff =
     ComputeEllipseLineInterceptDiff(
       mShapeBoxRect.y, mShapeBoxRect.YMost(),
-      blockStartCornerRadiusL, blockStartCornerRadiusB,
-      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      mRadii[eCornerTopLeftX], mRadii[eCornerTopLeftY],
+      mRadii[eCornerBottomLeftX], mRadii[eCornerBottomLeftY],
       aBStart, aBEnd);
   return mShapeBoxRect.x + lineLeftDiff;
 }
 
 nscoord
 nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
                                         const nscoord aBStart,
                                         const nscoord aBEnd) const
 {
-  nscoord radii[8];
-  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-  if (!hasRadii) {
+  if (!mRadii) {
     return mShapeBoxRect.XMost();
   }
 
-  // Get the physical side for line-right since border-radii are in
-  // the physical axis.
-  mozilla::Side lineRightSide =
-    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
-  nscoord blockStartCornerRadiusL =
-    radii[SideToHalfCorner(lineRightSide, false, false)];
-  nscoord blockStartCornerRadiusB =
-    radii[SideToHalfCorner(lineRightSide, false, true)];
-  nscoord blockEndCornerRadiusL =
-    radii[SideToHalfCorner(lineRightSide, true, false)];
-  nscoord blockEndCornerRadiusB =
-    radii[SideToHalfCorner(lineRightSide, true, true)];
-
-  if (aWM.IsLineInverted()) {
-    // This happens only when aWM is vertical-lr. Need to swap blockStart
-    // and blockEnd corners.
-    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
-  }
-
   nscoord lineRightDiff =
     ComputeEllipseLineInterceptDiff(
       mShapeBoxRect.y, mShapeBoxRect.YMost(),
-      blockStartCornerRadiusL, blockStartCornerRadiusB,
-      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      mRadii[eCornerTopRightX], mRadii[eCornerTopRightY],
+      mRadii[eCornerBottomRightX], mRadii[eCornerBottomRightY],
       aBStart, aBEnd);
   return mShapeBoxRect.XMost() - lineRightDiff;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // EllipseShapeInfo
 nscoord
 nsFloatManager::EllipseShapeInfo::LineLeft(WritingMode aWM,
@@ -668,19 +622,18 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
     return;
   }
 
   // Initialize <shape-box>'s reference rect.
   LogicalRect shapeBoxRect =
     ShapeInfo::ComputeShapeBoxRect(shapeOutside, mFrame, aMarginRect, aWM);
 
   if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
-    nsRect rect = ShapeInfo::ConvertToFloatLogical(shapeBoxRect, aWM,
-                                                   aContainerSize);
-    mShapeInfo = MakeUnique<BoxShapeInfo>(rect, mFrame);
+    mShapeInfo = ShapeInfo::CreateShapeBox(mFrame, shapeBoxRect, aWM,
+                                           aContainerSize);
   } else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
     StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
 
     switch (basicShape->GetShapeType()) {
       case StyleBasicShapeType::Polygon:
         // Bug 1326409 - Implement the rendering of basic shape polygon()
         // for CSS shape-outside.
         return;
@@ -836,16 +789,37 @@ nsFloatManager::ShapeInfo::ComputeShapeB
                  "Box source type must have <shape-box> specified!");
       break;
   }
 
   return rect;
 }
 
 /* static */ UniquePtr<nsFloatManager::ShapeInfo>
+nsFloatManager::ShapeInfo::CreateShapeBox(
+  nsIFrame* const aFrame,
+  const LogicalRect& aShapeBoxRect,
+  WritingMode aWM,
+  const nsSize& aContainerSize)
+{
+  nsRect logicalShapeBoxRect
+    = ConvertToFloatLogical(aShapeBoxRect, aWM, aContainerSize);
+
+  nscoord physicalRadii[8];
+  bool hasRadii = aFrame->GetShapeBoxBorderRadii(physicalRadii);
+  if (!hasRadii) {
+    return MakeUnique<BoxShapeInfo>(logicalShapeBoxRect,
+                                    UniquePtr<nscoord[]>());
+  }
+
+  return MakeUnique<BoxShapeInfo>(logicalShapeBoxRect,
+                                  ConvertToFloatLogical(physicalRadii, aWM));
+}
+
+/* static */ UniquePtr<nsFloatManager::ShapeInfo>
 nsFloatManager::ShapeInfo::CreateCircleOrEllipse(
   StyleBasicShape* const aBasicShape,
   const LogicalRect& aShapeBoxRect,
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   // Use physical coordinates to compute the center of circle() or ellipse()
   // since the <position> keywords such as 'left', 'top', etc. are physical.
@@ -963,16 +937,61 @@ nsFloatManager::ShapeInfo::ConvertToFloa
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   LogicalPoint logicalPoint(aWM, aPoint, aContainerSize);
   return nsPoint(logicalPoint.LineRelative(aWM, aContainerSize),
                  logicalPoint.B(aWM));
 }
 
+/* static */ UniquePtr<nscoord[]>
+nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8],
+                                                 WritingMode aWM)
+{
+  UniquePtr<nscoord[]> logicalRadii(new nscoord[8]);
+
+  // Get the physical side for line-left and line-right since border radii
+  // are on the physical axis.
+  Side lineLeftSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
+  logicalRadii[eCornerTopLeftX] =
+    aRadii[SideToHalfCorner(lineLeftSide, true, false)];
+  logicalRadii[eCornerTopLeftY] =
+    aRadii[SideToHalfCorner(lineLeftSide, true, true)];
+  logicalRadii[eCornerBottomLeftX] =
+    aRadii[SideToHalfCorner(lineLeftSide, false, false)];
+  logicalRadii[eCornerBottomLeftY] =
+    aRadii[SideToHalfCorner(lineLeftSide, false, true)];
+
+  Side lineRightSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
+  logicalRadii[eCornerTopRightX] =
+    aRadii[SideToHalfCorner(lineRightSide, false, false)];
+  logicalRadii[eCornerTopRightY] =
+    aRadii[SideToHalfCorner(lineRightSide, false, true)];
+  logicalRadii[eCornerBottomRightX] =
+    aRadii[SideToHalfCorner(lineRightSide, true, false)];
+  logicalRadii[eCornerBottomRightY] =
+    aRadii[SideToHalfCorner(lineRightSide, true, true)];
+
+  if (aWM.IsLineInverted()) {
+    // When IsLineInverted() is true, i.e. aWM is vertical-lr,
+    // line-over/line-under are inverted from block-start/block-end. So the
+    // relationship reverses between which corner comes first going
+    // clockwise, and which corner is block-start versus block-end. We need
+    // to swap the values stored in top and bottom corners.
+    std::swap(logicalRadii[eCornerTopLeftX], logicalRadii[eCornerBottomLeftX]);
+    std::swap(logicalRadii[eCornerTopLeftY], logicalRadii[eCornerBottomLeftY]);
+    std::swap(logicalRadii[eCornerTopRightX], logicalRadii[eCornerBottomRightX]);
+    std::swap(logicalRadii[eCornerTopRightY], logicalRadii[eCornerBottomRightY]);
+  }
+
+  return logicalRadii;
+}
+
 //----------------------------------------------------------------------
 
 nsAutoFloatManager::~nsAutoFloatManager()
 {
   // Restore the old float manager in the reflow input if necessary.
   if (mNew) {
 #ifdef DEBUG
     if (nsBlockFrame::gNoisyFloatManager) {
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -372,16 +372,22 @@ private:
     static nsRect ConvertToFloatLogical(const mozilla::LogicalRect& aRect,
                                         mozilla::WritingMode aWM,
                                         const nsSize& aContainerSize)
     {
       return nsRect(aRect.LineLeft(aWM, aContainerSize), aRect.BStart(aWM),
                     aRect.ISize(aWM), aRect.BSize(aWM));
     }
 
+    static mozilla::UniquePtr<ShapeInfo> CreateShapeBox(
+      nsIFrame* const aFrame,
+      const mozilla::LogicalRect& aShapeBoxRect,
+      mozilla::WritingMode aWM,
+      const nsSize& aContainerSize);
+
     static mozilla::UniquePtr<ShapeInfo> CreateCircleOrEllipse(
       mozilla::StyleBasicShape* const aBasicShape,
       const mozilla::LogicalRect& aShapeBoxRect,
       mozilla::WritingMode aWM,
       const nsSize& aContainerSize);
 
   protected:
     // Compute the minimum line-axis difference between the bounding shape
@@ -401,27 +407,33 @@ private:
     static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
                                  const nscoord aRadiusY);
 
     // Convert the physical point to the special logical coordinate space
     // used in float manager.
     static nsPoint ConvertToFloatLogical(const nsPoint& aPoint,
                                          mozilla::WritingMode aWM,
                                          const nsSize& aContainerSize);
+
+    // Convert the half corner radii (nscoord[8]) to the special logical
+    // coordinate space used in float manager.
+    static mozilla::UniquePtr<nscoord[]> ConvertToFloatLogical(
+      const nscoord aRadii[8],
+      mozilla::WritingMode aWM);
   };
 
   // Implements shape-outside: <shape-box>.
   class BoxShapeInfo final : public ShapeInfo
   {
   public:
-    BoxShapeInfo(const nsRect& aShapeBoxRect, nsIFrame* const aFrame)
+    BoxShapeInfo(const nsRect& aShapeBoxRect,
+                 mozilla::UniquePtr<nscoord[]> aRadii)
       : mShapeBoxRect(aShapeBoxRect)
-      , mFrame(aFrame)
-    {
-    }
+      , mRadii(Move(aRadii))
+    {}
 
     nscoord LineLeft(mozilla::WritingMode aWM,
                      const nscoord aBStart,
                      const nscoord aBEnd) const override;
     nscoord LineRight(mozilla::WritingMode aWM,
                       const nscoord aBStart,
                       const nscoord aBEnd) const override;
     nscoord BStart() const override { return mShapeBoxRect.y; }
@@ -433,18 +445,20 @@ private:
       mShapeBoxRect.MoveBy(aLineLeft, aBlockStart);
     }
 
   private:
     // This is the reference box of css shape-outside if specified, which
     // implements the <shape-box> value in the CSS Shapes Module Level 1.
     // The coordinate space is the same as FloatInfo::mRect.
     nsRect mShapeBoxRect;
-    // The frame of the float.
-    nsIFrame* const mFrame;
+    // 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.
+    mozilla::UniquePtr<nscoord[]> mRadii;
   };
 
   // Implements shape-outside: circle() and shape-outside: ellipse().
   class EllipseShapeInfo : public ShapeInfo
   {
   public:
     EllipseShapeInfo(const nsPoint& aCenter,
                      const nsSize& aRadii)