Bug 1274835 - Refactor code to process basic shape from clip-path. draft
authorTing-Yu Lin <tlin@mozilla.com>
Sun, 22 May 2016 20:41:19 +0800
changeset 369355 3efb130c6dca2cd2899f0e99befb546ad8cfc241
parent 369317 16663eb3dcfa759f25b5e27b101bc79270c156f2
child 369356 e86874eb26634a51353eb792a2fad0696aa3ee0f
child 369357 4a2572801891dd659be587c2a22c753ef3ac8af3
child 369619 d9fd7a942b5ee0fa6062500cc25de58d1a43537f
push id18835
push userbmo:tlin@mozilla.com
push dateSun, 22 May 2016 17:00:30 +0000
bugs1274835
milestone49.0a1
Bug 1274835 - Refactor code to process basic shape from clip-path. This can be used in the implementation of shape-outside. MozReview-Commit-ID: C7bd4D2Kwpm
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsRuleNode.h
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5882,93 +5882,103 @@ nsComputedDOMStyle::BasicShapeRadiiToStr
   if (horizontalString == verticalString) {
     return;
   }
   aCssText.AppendLiteral(" / ");
   aCssText.Append(verticalString);
 }
 
 already_AddRefed<CSSValue>
+nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
+  const nsStyleBasicShape* aStyleBasicShape)
+{
+  MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
+
+  nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
+  // Shape function name and opening parenthesis.
+  nsAutoString shapeFunctionString;
+  AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
+                       aStyleBasicShape->GetShapeTypeName()),
+                     shapeFunctionString);
+  shapeFunctionString.Append('(');
+  switch (type) {
+    case nsStyleBasicShape::Type::ePolygon: {
+      bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
+        NS_STYLE_FILL_RULE_EVENODD;
+      if (hasEvenOdd) {
+        shapeFunctionString.AppendLiteral("evenodd");
+      }
+      for (size_t i = 0;
+           i < aStyleBasicShape->Coordinates().Length(); i += 2) {
+        nsAutoString coordString;
+        if (i > 0 || hasEvenOdd) {
+          shapeFunctionString.AppendLiteral(", ");
+        }
+        SetCssTextToCoord(coordString,
+                          aStyleBasicShape->Coordinates()[i]);
+        shapeFunctionString.Append(coordString);
+        shapeFunctionString.Append(' ');
+        SetCssTextToCoord(coordString,
+                          aStyleBasicShape->Coordinates()[i + 1]);
+        shapeFunctionString.Append(coordString);
+      }
+      break;
+    }
+    case nsStyleBasicShape::Type::eCircle:
+    case nsStyleBasicShape::Type::eEllipse: {
+      const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
+      MOZ_ASSERT(radii.Length() ==
+                 (type == nsStyleBasicShape::Type::eCircle ? 1 : 2),
+                 "wrong number of radii");
+      for (size_t i = 0; i < radii.Length(); ++i) {
+        nsAutoString radius;
+        RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+        bool clampNegativeCalc = true;
+        SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
+                        nsCSSProps::kShapeRadiusKTable);
+        value->GetCssText(radius);
+        shapeFunctionString.Append(radius);
+        shapeFunctionString.Append(' ');
+      }
+      shapeFunctionString.AppendLiteral("at ");
+
+      RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
+      nsAutoString positionString;
+      SetValueToPosition(aStyleBasicShape->GetPosition(), position);
+      position->GetCssText(positionString);
+      shapeFunctionString.Append(positionString);
+      break;
+    }
+    case nsStyleBasicShape::Type::eInset: {
+      BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
+      if (aStyleBasicShape->HasRadius()) {
+        shapeFunctionString.AppendLiteral(" round ");
+        nsAutoString radiiString;
+        BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
+        shapeFunctionString.Append(radiiString);
+      }
+      break;
+    }
+    default:
+      NS_NOTREACHED("unexpected type");
+  }
+  shapeFunctionString.Append(')');
+  RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
+  functionValue->SetString(shapeFunctionString);
+  return functionValue.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
   const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   if (aStyleBasicShape) {
-    nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
-    // Shape function name and opening parenthesis.
-    nsAutoString shapeFunctionString;
-    AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
-                         aStyleBasicShape->GetShapeTypeName()),
-                       shapeFunctionString);
-    shapeFunctionString.Append('(');
-    switch (type) {
-      case nsStyleBasicShape::Type::ePolygon: {
-        bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
-                              NS_STYLE_FILL_RULE_EVENODD;
-        if (hasEvenOdd) {
-          shapeFunctionString.AppendLiteral("evenodd");
-        }
-        for (size_t i = 0;
-             i < aStyleBasicShape->Coordinates().Length(); i += 2) {
-          nsAutoString coordString;
-          if (i > 0 || hasEvenOdd) {
-            shapeFunctionString.AppendLiteral(", ");
-          }
-          SetCssTextToCoord(coordString,
-                            aStyleBasicShape->Coordinates()[i]);
-          shapeFunctionString.Append(coordString);
-          shapeFunctionString.Append(' ');
-          SetCssTextToCoord(coordString,
-                            aStyleBasicShape->Coordinates()[i + 1]);
-          shapeFunctionString.Append(coordString);
-        }
-        break;
-      }
-      case nsStyleBasicShape::Type::eCircle:
-      case nsStyleBasicShape::Type::eEllipse: {
-        const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
-        MOZ_ASSERT(radii.Length() ==
-                   (type == nsStyleBasicShape::Type::eCircle ? 1 : 2),
-                   "wrong number of radii");
-        for (size_t i = 0; i < radii.Length(); ++i) {
-          nsAutoString radius;
-          RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
-          bool clampNegativeCalc = true;
-          SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
-                          nsCSSProps::kShapeRadiusKTable);
-          value->GetCssText(radius);
-          shapeFunctionString.Append(radius);
-          shapeFunctionString.Append(' ');
-        }
-        shapeFunctionString.AppendLiteral("at ");
-
-        RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
-        nsAutoString positionString;
-        SetValueToPosition(aStyleBasicShape->GetPosition(), position);
-        position->GetCssText(positionString);
-        shapeFunctionString.Append(positionString);
-        break;
-      }
-      case nsStyleBasicShape::Type::eInset: {
-        BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
-        if (aStyleBasicShape->HasRadius()) {
-          shapeFunctionString.AppendLiteral(" round ");
-          nsAutoString radiiString;
-          BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
-          shapeFunctionString.Append(radiiString);
-        }
-        break;
-      }
-      default:
-        NS_NOTREACHED("unexpected type");
-    }
-    shapeFunctionString.Append(')');
-    RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
-    functionValue->SetString(shapeFunctionString);
-    valueList->AppendCSSValue(functionValue.forget());
+    valueList->AppendCSSValue(
+      CreatePrimitiveValueForBasicShape(aStyleBasicShape));
   }
 
   if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
     return valueList.forget();
   }
 
   nsAutoString boxString;
   AppendASCIItoUTF16(
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -638,19 +638,22 @@ private:
   bool GetFrameBorderRectWidth(nscoord& aWidth);
   bool GetFrameBorderRectHeight(nscoord& aHeight);
 
   /* Helper functions for computing the filter property style. */
   void SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord);
   already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter(
     const nsStyleFilter& aStyleFilter);
 
-  // Helper function for computing basic shape styles.
   already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath(
     const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox);
+
+  // Helper function for computing basic shape styles.
+  already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(
+    const nsStyleBasicShape* aStyleBasicShape);
   void BoxValuesToString(nsAString& aString,
                          const nsTArray<nsStyleCoord>& aBoxValues);
   void BasicShapeRadiiToString(nsAString& aCssText,
                                const nsStyleCorners& aCorners);
 
 
   static nsComputedStyleMap* GetComputedStyleMap();
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -9517,16 +9517,165 @@ nsRuleNode::ComputeSVGData(void* aStartS
               svg->mTextAnchor, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentSVG->mTextAnchor,
               NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(SVG, svg)
 }
 
+already_AddRefed<nsStyleBasicShape>
+nsRuleNode::GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
+                                           nsStyleContext* aStyleContext,
+                                           nsPresContext* aPresContext,
+                                           RuleNodeCacheConditions& aConditions)
+{
+  RefPtr<nsStyleBasicShape> basicShape;
+
+  nsCSSValue::Array* shapeFunction = aValue.GetArrayValue();
+  nsCSSKeyword functionName =
+    (nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
+
+  if (functionName == eCSSKeyword_polygon) {
+    MOZ_ASSERT(!basicShape, "did not expect value");
+    basicShape = new nsStyleBasicShape(nsStyleBasicShape::ePolygon);
+    MOZ_ASSERT(shapeFunction->Count() > 1,
+               "polygon has wrong number of arguments");
+    size_t j = 1;
+    if (shapeFunction->Item(j).GetUnit() == eCSSUnit_Enumerated) {
+      basicShape->SetFillRule(shapeFunction->Item(j).GetIntValue());
+      ++j;
+    }
+    const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
+      SETCOORD_STORE_CALC;
+    const nsCSSValuePairList* curPair =
+      shapeFunction->Item(j).GetPairListValue();
+    nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
+    while (curPair) {
+      nsStyleCoord xCoord, yCoord;
+      DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
+                                              nsStyleCoord(), mask,
+                                              aStyleContext, aPresContext,
+                                              aConditions);
+      coordinates.AppendElement(xCoord);
+      MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
+      DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
+                                              nsStyleCoord(), mask,
+                                              aStyleContext, aPresContext,
+                                              aConditions);
+      coordinates.AppendElement(yCoord);
+      MOZ_ASSERT(didSetCoordY, "unexpected y coordinate unit");
+      curPair = curPair->mNext;
+    }
+  } else if (functionName == eCSSKeyword_circle ||
+             functionName == eCSSKeyword_ellipse) {
+    nsStyleBasicShape::Type type = functionName == eCSSKeyword_circle ?
+      nsStyleBasicShape::eCircle :
+      nsStyleBasicShape::eEllipse;
+    MOZ_ASSERT(!basicShape, "did not expect value");
+    basicShape = new nsStyleBasicShape(type);
+    const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
+      SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
+    size_t count = type == nsStyleBasicShape::eCircle ? 2 : 3;
+    MOZ_ASSERT(shapeFunction->Count() == count + 1,
+               "unexpected arguments count");
+    MOZ_ASSERT(type == nsStyleBasicShape::eCircle ||
+               (shapeFunction->Item(1).GetUnit() == eCSSUnit_Null) ==
+               (shapeFunction->Item(2).GetUnit() == eCSSUnit_Null),
+               "ellipse should have two radii or none");
+    for (size_t j = 1; j < count; ++j) {
+      const nsCSSValue& val = shapeFunction->Item(j);
+      nsStyleCoord radius;
+      if (val.GetUnit() != eCSSUnit_Null) {
+        DebugOnly<bool> didSetRadius = SetCoord(val, radius,
+                                                nsStyleCoord(), mask,
+                                                aStyleContext,
+                                                aPresContext,
+                                                aConditions);
+        MOZ_ASSERT(didSetRadius, "unexpected radius unit");
+      } else {
+        radius.SetIntValue(NS_RADIUS_CLOSEST_SIDE, eStyleUnit_Enumerated);
+      }
+      basicShape->Coordinates().AppendElement(radius);
+    }
+    const nsCSSValue& positionVal = shapeFunction->Item(count);
+    if (positionVal.GetUnit() == eCSSUnit_Array) {
+      ComputePositionValue(aStyleContext, positionVal,
+                           basicShape->GetPosition(),
+                           aConditions);
+    } else {
+      MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
+                 "expected no value");
+    }
+  } else if (functionName == eCSSKeyword_inset) {
+    MOZ_ASSERT(!basicShape, "did not expect value");
+    basicShape = new nsStyleBasicShape(nsStyleBasicShape::eInset);
+    MOZ_ASSERT(shapeFunction->Count() == 6,
+               "inset function has wrong number of arguments");
+    MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
+               "no shape arguments defined");
+    const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
+      SETCOORD_STORE_CALC;
+    nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
+    for (size_t j = 1; j <= 4; ++j) {
+      const nsCSSValue& val = shapeFunction->Item(j);
+      nsStyleCoord inset;
+      // Fill missing values to get 4 at the end.
+      if (val.GetUnit() == eCSSUnit_Null) {
+        if (j == 4) {
+          inset = coords[1];
+        } else {
+          MOZ_ASSERT(j != 1, "first argument not specified");
+          inset = coords[0];
+        }
+      } else {
+        DebugOnly<bool> didSetInset = SetCoord(val, inset,
+                                               nsStyleCoord(), mask,
+                                               aStyleContext, aPresContext,
+                                               aConditions);
+        MOZ_ASSERT(didSetInset, "unexpected inset unit");
+      }
+      coords.AppendElement(inset);
+    }
+
+    nsStyleCorners& insetRadius = basicShape->GetRadius();
+    if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
+      nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
+      NS_FOR_CSS_FULL_CORNERS(corner) {
+        int cx = NS_FULL_TO_HALF_CORNER(corner, false);
+        int cy = NS_FULL_TO_HALF_CORNER(corner, true);
+        const nsCSSValue& radius = radiiArray->Item(corner);
+        nsStyleCoord coordX, coordY;
+        DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
+                                                    nsStyleCoord(),
+                                                    nsStyleCoord(), mask,
+                                                    aStyleContext,
+                                                    aPresContext,
+                                                    aConditions);
+        MOZ_ASSERT(didSetRadii, "unexpected radius unit");
+        insetRadius.Set(cx, coordX);
+        insetRadius.Set(cy, coordY);
+      }
+    } else {
+      MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
+                 "unexpected value");
+      // Initialize border-radius
+      nsStyleCoord zero;
+      zero.SetCoordValue(0);
+      NS_FOR_CSS_HALF_CORNERS(j) {
+        insetRadius.Set(j, zero);
+      }
+    }
+  } else {
+    NS_NOTREACHED("unexpected basic shape function");
+  }
+
+  return basicShape.forget();
+}
+
 void
 nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
                                        const nsCSSValue* aValue,
                                        nsStyleContext* aStyleContext,
                                        nsPresContext* aPresContext,
                                        RuleNodeCacheConditions& aConditions)
 {
   MOZ_ASSERT(aValue->GetUnit() == eCSSUnit_Array,
@@ -9543,153 +9692,18 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
       int32_t type = array->Item(i).GetIntValue();
       if (type > NS_STYLE_CLIP_SHAPE_SIZING_VIEW ||
           type < NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
         NS_NOTREACHED("unexpected reference box");
         return;
       }
       sizingBox = (uint8_t)type;
     } else if (array->Item(i).GetUnit() == eCSSUnit_Function) {
-      nsCSSValue::Array* shapeFunction = array->Item(i).GetArrayValue();
-      nsCSSKeyword functionName =
-        (nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
-      if (functionName == eCSSKeyword_polygon) {
-        MOZ_ASSERT(!basicShape, "did not expect value");
-        basicShape = new nsStyleBasicShape(nsStyleBasicShape::ePolygon);
-        MOZ_ASSERT(shapeFunction->Count() > 1,
-                   "polygon has wrong number of arguments");
-        size_t j = 1;
-        if (shapeFunction->Item(j).GetUnit() == eCSSUnit_Enumerated) {
-          basicShape->SetFillRule(shapeFunction->Item(j).GetIntValue());
-          ++j;
-        }
-        const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
-                             SETCOORD_STORE_CALC;
-        const nsCSSValuePairList* curPair =
-          shapeFunction->Item(j).GetPairListValue();
-        nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
-        while (curPair) {
-          nsStyleCoord xCoord, yCoord;
-          DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
-                                                  nsStyleCoord(), mask,
-                                                  aStyleContext, aPresContext,
-                                                  aConditions);
-          coordinates.AppendElement(xCoord);
-          MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
-          DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
-                                                  nsStyleCoord(), mask,
-                                                  aStyleContext, aPresContext,
-                                                  aConditions);
-          coordinates.AppendElement(yCoord);
-          MOZ_ASSERT(didSetCoordY, "unexpected y coordinate unit");
-          curPair = curPair->mNext;
-        }
-      } else if (functionName == eCSSKeyword_circle ||
-                 functionName == eCSSKeyword_ellipse) {
-        nsStyleBasicShape::Type type = functionName == eCSSKeyword_circle ?
-                                       nsStyleBasicShape::eCircle :
-                                       nsStyleBasicShape::eEllipse;
-        MOZ_ASSERT(!basicShape, "did not expect value");
-        basicShape = new nsStyleBasicShape(type);
-        const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
-                             SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
-        size_t count = type == nsStyleBasicShape::eCircle ? 2 : 3;
-        MOZ_ASSERT(shapeFunction->Count() == count + 1,
-                   "unexpected arguments count");
-        MOZ_ASSERT(type == nsStyleBasicShape::eCircle ||
-                   (shapeFunction->Item(1).GetUnit() == eCSSUnit_Null) ==
-                   (shapeFunction->Item(2).GetUnit() == eCSSUnit_Null),
-                   "ellipse should have two radii or none");
-        for (size_t j = 1; j < count; ++j) {
-          const nsCSSValue& val = shapeFunction->Item(j);
-          nsStyleCoord radius;
-          if (val.GetUnit() != eCSSUnit_Null) {
-            DebugOnly<bool> didSetRadius = SetCoord(val, radius,
-                                                    nsStyleCoord(), mask,
-                                                    aStyleContext,
-                                                    aPresContext,
-                                                    aConditions);
-            MOZ_ASSERT(didSetRadius, "unexpected radius unit");
-          } else {
-            radius.SetIntValue(NS_RADIUS_CLOSEST_SIDE, eStyleUnit_Enumerated);
-          }
-          basicShape->Coordinates().AppendElement(radius);
-        }
-        const nsCSSValue& positionVal = shapeFunction->Item(count);
-        if (positionVal.GetUnit() == eCSSUnit_Array) {
-          ComputePositionValue(aStyleContext, positionVal,
-                               basicShape->GetPosition(),
-                               aConditions);
-        } else {
-            MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
-                       "expected no value");
-        }
-      } else if (functionName == eCSSKeyword_inset) {
-        MOZ_ASSERT(!basicShape, "did not expect value");
-        basicShape = new nsStyleBasicShape(nsStyleBasicShape::eInset);
-        MOZ_ASSERT(shapeFunction->Count() == 6,
-                   "inset function has wrong number of arguments");
-        MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
-                   "no shape arguments defined");
-        const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
-                             SETCOORD_STORE_CALC;
-        nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
-        for (size_t j = 1; j <= 4; ++j) {
-          const nsCSSValue& val = shapeFunction->Item(j);
-          nsStyleCoord inset;
-          // Fill missing values to get 4 at the end.
-          if (val.GetUnit() == eCSSUnit_Null) {
-            if (j == 4) {
-              inset = coords[1];
-            } else {
-              MOZ_ASSERT(j != 1, "first argument not specified");
-              inset = coords[0];
-            }
-          } else {
-            DebugOnly<bool> didSetInset = SetCoord(val, inset,
-                                                   nsStyleCoord(), mask,
-                                                   aStyleContext, aPresContext,
-                                                   aConditions);
-            MOZ_ASSERT(didSetInset, "unexpected inset unit");
-          }
-          coords.AppendElement(inset);
-        }
-
-        nsStyleCorners& insetRadius = basicShape->GetRadius();
-        if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
-          nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
-          NS_FOR_CSS_FULL_CORNERS(corner) {
-            int cx = NS_FULL_TO_HALF_CORNER(corner, false);
-            int cy = NS_FULL_TO_HALF_CORNER(corner, true);
-            const nsCSSValue& radius = radiiArray->Item(corner);
-            nsStyleCoord coordX, coordY;
-            DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
-                                                        nsStyleCoord(),
-                                                        nsStyleCoord(), mask,
-                                                        aStyleContext,
-                                                        aPresContext,
-                                                        aConditions);
-            MOZ_ASSERT(didSetRadii, "unexpected radius unit");
-            insetRadius.Set(cx, coordX);
-            insetRadius.Set(cy, coordY);
-          }
-        } else {
-          MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
-                     "unexpected value");
-          // Initialize border-radius
-          nsStyleCoord zero;
-          zero.SetCoordValue(0);
-          NS_FOR_CSS_HALF_CORNERS(j) {
-            insetRadius.Set(j, zero);
-          }
-        }
-      } else {
-        NS_NOTREACHED("unexpected basic shape function");
-        return;
-      }
+      basicShape = GetStyleBasicShapeFromCSSValue(array->Item(i), aStyleContext,
+                                                  aPresContext, aConditions);
     } else {
       NS_NOTREACHED("unexpected value");
       return;
     }
   }
 
   if (basicShape) {
     aStyleClipPath->SetBasicShape(basicShape, sizingBox);
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -783,16 +783,21 @@ protected:
   inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID,
                                              const nsRuleData* aRuleData);
 
   already_AddRefed<nsCSSShadowArray>
               GetShadowData(const nsCSSValueList* aList,
                             nsStyleContext* aContext,
                             bool aIsBoxShadow,
                             mozilla::RuleNodeCacheConditions& aConditions);
+  already_AddRefed<nsStyleBasicShape>
+  GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
+                                 nsStyleContext* aStyleContext,
+                                 nsPresContext* aPresContext,
+                                 mozilla::RuleNodeCacheConditions& aConditions);
   bool SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
                                 const nsCSSValue& aValue,
                                 nsStyleContext* aStyleContext,
                                 nsPresContext* aPresContext,
                                 mozilla::RuleNodeCacheConditions& aConditions);
   void SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
                                   const nsCSSValue* aValue,
                                   nsStyleContext* aStyleContext,