Backed out 4 changesets (bug 1516454, bug 1530247) for multiple failures on Linux x64 asan. CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Tue, 26 Feb 2019 00:49:27 +0200
changeset 518874 987a62667969a5f88f8c3f4693299e097db60daf
parent 518873 fb2dc1645fcce3142932eb78daa7cee634c9d3b2
child 518875 f5629bb3e671ad15ede908de3cc0b2b2be342728
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1516454, 1530247
milestone67.0a1
backs out180c7672c57cfdcfd0f0753b994d16945dbfae81
a460a4d0a66cd3cbd1d3e6c92e6c6ac5c831e205
c6ab8d3dd19a82d6202a3ef30b2aee3693ef0689
43862dc87e0bebd357c300843bc9f2f3eeb0ae41
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
Backed out 4 changesets (bug 1516454, bug 1530247) for multiple failures on Linux x64 asan. CLOSED TREE Backed out changeset 180c7672c57c (bug 1516454) Backed out changeset a460a4d0a66c (bug 1516454) Backed out changeset c6ab8d3dd19a (bug 1530247) Backed out changeset 43862dc87e0b (bug 1516454)
gfx/2d/Types.h
layout/base/ShapeUtils.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoCSSPropList.mako.py
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleCoord.cpp
layout/style/nsStyleCoord.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
servo/components/style/cbindgen.toml
servo/components/style/gecko/conversions.rs
servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/values/computed/border.rs
servo/components/style/values/generics/border.rs
servo/components/style/values/generics/size.rs
servo/ports/geckolib/glue.rs
testing/web-platform/meta/css/css-shapes/shape-outside/values/shape-outside-inset-006.html.ini
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -513,17 +513,17 @@ constexpr int eCornerCount = 4;
 static inline Corner operator++(Corner& aCorner) {
   MOZ_ASSERT(aCorner >= eCornerTopLeft && aCorner <= eCornerBottomLeft,
              "Out of range corner!");
   aCorner = Corner(aCorner + 1);
   return aCorner;
 }
 
 // Indices into "half corner" arrays (nsStyleCorners e.g.)
-enum HalfCorner : uint8_t {
+enum HalfCorner {
   // This order is important!
   eCornerTopLeftX = 0,
   eCornerTopLeftY = 1,
   eCornerTopRightX = 2,
   eCornerTopRightY = 3,
   eCornerBottomRightX = 4,
   eCornerBottomRightY = 5,
   eCornerBottomLeftX = 6,
--- a/layout/base/ShapeUtils.cpp
+++ b/layout/base/ShapeUtils.cpp
@@ -135,17 +135,17 @@ nsSize ShapeUtils::ComputeEllipseRadii(c
   }
 
   return nsRect(x, y, width, height);
 }
 
 /* static */ bool ShapeUtils::ComputeInsetRadii(
     const StyleBasicShape& aBasicShape, const nsRect& aInsetRect,
     const nsRect& aRefBox, nscoord aRadii[8]) {
-  const auto& radius = aBasicShape.GetRadius();
+  const nsStyleCorners& radius = aBasicShape.GetRadius();
   return nsIFrame::ComputeBorderRadii(radius, aInsetRect.Size(), aRefBox.Size(),
                                       Sides(), aRadii);
 }
 
 /* static */ nsTArray<nsPoint> ShapeUtils::ComputePolygonVertices(
     const StyleBasicShape& aBasicShape, const nsRect& aRefBox) {
   MOZ_ASSERT(aBasicShape.GetShapeType() == StyleBasicShapeType::Polygon,
              "The basic shape must be polygon()!");
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6857,25 +6857,30 @@ static ImgDrawResult DrawImageInternal(
 
   if (aOrientation == StyleImageOrientation::FromImage) {
     img = ImageOps::Orient(img, img->GetOrientation());
   }
 
   return img.forget();
 }
 
-static bool NonZeroCorner(const LengthPercentage& aLength) {
-  // Since negative results are clamped to 0, check > 0.
-  return aLength.Resolve(nscoord_MAX) > 0 || aLength.Resolve(0) > 0;
+static bool NonZeroStyleCoord(const nsStyleCoord& aCoord) {
+  if (aCoord.IsCoordPercentCalcUnit()) {
+    // Since negative results are clamped to 0, check > 0.
+    return aCoord.ComputeCoordPercentCalc(nscoord_MAX) > 0 ||
+           aCoord.ComputeCoordPercentCalc(0) > 0;
+  }
+
+  return true;
 }
 
 /* static */ bool nsLayoutUtils::HasNonZeroCorner(
-    const BorderRadius& aCorners) {
+    const nsStyleCorners& aCorners) {
   NS_FOR_CSS_HALF_CORNERS(corner) {
-    if (NonZeroCorner(aCorners.Get(corner))) return true;
+    if (NonZeroStyleCoord(aCorners.Get(corner))) return true;
   }
   return false;
 }
 
 // aCorner is a "full corner" value, i.e. eCornerTopLeft etc.
 static bool IsCornerAdjacentToSide(uint8_t aCorner, Side aSide) {
   static_assert((int)eSideTop == eCornerTopLeft, "Check for Full Corner");
   static_assert((int)eSideRight == eCornerTopRight, "Check for Full Corner");
@@ -6890,17 +6895,17 @@ static bool IsCornerAdjacentToSide(uint8
                 "Check for Full Corner");
   static_assert((int)eSideLeft == ((eCornerTopLeft - 1) & 3),
                 "Check for Full Corner");
 
   return aSide == aCorner || aSide == ((aCorner - 1) & 3);
 }
 
 /* static */ bool nsLayoutUtils::HasNonZeroCornerOnSide(
-    const BorderRadius& aCorners, Side aSide) {
+    const nsStyleCorners& aCorners, Side aSide) {
   static_assert(eCornerTopLeftX / 2 == eCornerTopLeft,
                 "Check for Non Zero on side");
   static_assert(eCornerTopLeftY / 2 == eCornerTopLeft,
                 "Check for Non Zero on side");
   static_assert(eCornerTopRightX / 2 == eCornerTopRight,
                 "Check for Non Zero on side");
   static_assert(eCornerTopRightY / 2 == eCornerTopRight,
                 "Check for Non Zero on side");
@@ -6911,17 +6916,17 @@ static bool IsCornerAdjacentToSide(uint8
   static_assert(eCornerBottomLeftX / 2 == eCornerBottomLeft,
                 "Check for Non Zero on side");
   static_assert(eCornerBottomLeftY / 2 == eCornerBottomLeft,
                 "Check for Non Zero on side");
 
   NS_FOR_CSS_HALF_CORNERS(corner) {
     // corner is a "half corner" value, so dividing by two gives us a
     // "full corner" value.
-    if (NonZeroCorner(aCorners.Get(corner)) &&
+    if (NonZeroStyleCoord(aCorners.Get(corner)) &&
         IsCornerAdjacentToSide(corner / 2, aSide))
       return true;
   }
   return false;
 }
 
 /* static */ nsTransparencyMode nsLayoutUtils::GetFrameTransparency(
     nsIFrame* aBackgroundFrame, nsIFrame* aCSSRootFrame) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -50,16 +50,17 @@ class nsDisplayItem;
 class nsFontMetrics;
 class nsFontFaceList;
 class nsIImageLoadingContent;
 class nsBlockFrame;
 class nsContainerFrame;
 class nsView;
 class nsIFrame;
 class nsStyleCoord;
+class nsStyleCorners;
 class nsPIDOMWindowOuter;
 class imgIRequest;
 struct nsStyleFont;
 struct nsOverflowAreas;
 
 namespace mozilla {
 class ComputedStyle;
 enum class PseudoStyleType : uint8_t;
@@ -1931,32 +1932,32 @@ class nsLayoutUtils {
    * @param aOrientation The desired orientation.
    */
   static already_AddRefed<imgIContainer> OrientImage(
       imgIContainer* aContainer,
       const mozilla::StyleImageOrientation& aOrientation);
 
   /**
    * Determine if any corner radius is of nonzero size
-   *   @param aCorners the |BorderRadius| object to check
+   *   @param aCorners the |nsStyleCorners| object to check
    *   @return true unless all the coordinates are 0%, 0 or null.
    *
    * A corner radius with one dimension zero and one nonzero is
    * treated as a nonzero-radius corner, even though it will end up
    * being rendered like a zero-radius corner.  This is because such
    * corners are not expected to appear outside of test cases, and it's
    * simpler to implement the test this way.
    */
-  static bool HasNonZeroCorner(const mozilla::BorderRadius& aCorners);
+  static bool HasNonZeroCorner(const nsStyleCorners& aCorners);
 
   /**
    * Determine if there is any corner radius on corners adjacent to the
    * given side.
    */
-  static bool HasNonZeroCornerOnSide(const mozilla::BorderRadius& aCorners,
+  static bool HasNonZeroCornerOnSide(const nsStyleCorners& aCorners,
                                      mozilla::Side aSide);
 
   /**
    * Determine if a widget is likely to require transparency or translucency.
    *   @param aBackgroundFrame The frame that the background is set on. For
    *                           <window>s, this will be the canvas frame.
    *   @param aCSSRootFrame    The frame that holds CSS properties affecting
    *                           the widget's transparency. For menupopups,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1639,25 +1639,35 @@ nsRect nsIFrame::GetContentRectRelativeT
   r.Deflate(bp);
   return r;
 }
 
 nsRect nsIFrame::GetContentRect() const {
   return GetContentRectRelativeToSelf() + GetPosition();
 }
 
-bool nsIFrame::ComputeBorderRadii(const BorderRadius& aBorderRadius,
+bool nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
                                   const nsSize& aFrameSize,
                                   const nsSize& aBorderArea, Sides aSkipSides,
                                   nscoord aRadii[8]) {
   // Percentages are relative to whichever side they're on.
   NS_FOR_CSS_HALF_CORNERS(i) {
-    const LengthPercentage& c = aBorderRadius.Get(i);
+    const nsStyleCoord c = aBorderRadius.Get(i);
     nscoord axis = HalfCornerIsX(i) ? aFrameSize.width : aFrameSize.height;
-    aRadii[i] = std::max(0, c.Resolve(axis));
+
+    if (c.IsCoordPercentCalcUnit()) {
+      aRadii[i] = c.ComputeCoordPercentCalc(axis);
+      if (aRadii[i] < 0) {
+        // clamp calc()
+        aRadii[i] = 0;
+      }
+    } else {
+      MOZ_ASSERT_UNREACHABLE("ComputeBorderRadii: bad unit");
+      aRadii[i] = 0;
+    }
   }
 
   if (aSkipSides.Top()) {
     aRadii[eCornerTopLeftX] = 0;
     aRadii[eCornerTopLeftY] = 0;
     aRadii[eCornerTopRightX] = 0;
     aRadii[eCornerTopRightY] = 0;
   }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1358,17 +1358,17 @@ class nsIFrame : public nsQueryFrame {
    * aBorderArea is used for the adjustment of radii that might be too
    * large.
    * FIXME: In the long run, we can probably get away with only one of
    * these, especially if we change the way we handle outline-radius (by
    * removing it and inflating the border radius)
    *
    * Return whether any radii are nonzero.
    */
-  static bool ComputeBorderRadii(const mozilla::BorderRadius&,
+  static bool ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
                                  const nsSize& aFrameSize,
                                  const nsSize& aBorderArea, Sides aSkipSides,
                                  nscoord aRadii[8]);
 
   /*
    * Given a set of border radii for one box (e.g., border box), convert
    * it to the equivalent set of radii for another box (e.g., in to
    * padding box, out to outline box) by reducing radii or increasing
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -508,18 +508,16 @@ RawServoDeclarationBlockStrong Servo_Par
     RawGeckoURLExtraData* data, mozilla::ParsingMode parsing_mode,
     nsCompatibility quirks_mode, mozilla::css::Loader* loader);
 
 bool Servo_ParseEasing(const nsAString* easing, RawGeckoURLExtraData* data,
                        nsTimingFunctionBorrowedMut output);
 
 void Servo_SerializeEasing(nsTimingFunctionBorrowed easing, nsAString* output);
 
-void Servo_SerializeBorderRadius(const mozilla::StyleBorderRadius*, nsAString*);
-
 void Servo_GetComputedKeyframeValues(
     RawGeckoKeyframeListBorrowed keyframes, RawGeckoElementBorrowed element,
     ComputedStyleBorrowed style, RawServoStyleSetBorrowed set,
     RawGeckoComputedKeyframeValuesListBorrowedMut result);
 
 RawServoAnimationValueStrong Servo_ComputedValues_ExtractAnimationValue(
     ComputedStyleBorrowed computed_values, nsCSSPropertyID property);
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -439,17 +439,16 @@ cbindgen-types = [
     { gecko = "StyleNonNegativeLength", servo = "values::computed::NonNegativeLength" },
     { gecko = "StyleNonNegativeNumber", servo = "values::computed::NonNegativeNumber" },
     { gecko = "StylePercentage", servo = "values::computed::Percentage" },
     { gecko = "StylePerspective", servo = "values::computed::Perspective" },
     { gecko = "StyleGenericPerspective", servo = "values::generics::box_::Perspective" },
     { gecko = "StyleZIndex", servo = "values::computed::ZIndex" },
     { gecko = "StyleGenericZIndex", servo = "values::generics::position::ZIndex" },
     { gecko = "StyleTransformOrigin", servo = "values::computed::TransformOrigin" },
-    { gecko = "StyleGenericBorderRadius", servo = "values::generics::border::BorderRadius" },
 ]
 
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::RustCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
@@ -498,17 +497,16 @@ structs-types = [
     "mozilla::CORSMode",
     "mozilla::FontStretch",
     "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
     "mozilla::MallocSizeOf",
     "mozilla::OriginFlags",
     "mozilla::StyleMotion",
     "mozilla::UniquePtr",
-    "mozilla::StyleBorderRadius",
     "mozilla::StyleDisplayMode",
     "mozilla::StylePrefersColorScheme",
     "mozilla::StyleIntersectionObserverRootMargin",
     "mozilla::StyleComputedFontStretchRange",
     "mozilla::StyleComputedFontStyleDescriptor",
     "mozilla::StyleComputedFontWeightRange",
     "mozilla::StyleFontDisplay",
     "mozilla::StyleUnicodeRange",
--- a/layout/style/ServoCSSPropList.mako.py
+++ b/layout/style/ServoCSSPropList.mako.py
@@ -55,119 +55,120 @@ def is_internal(prop):
 
 def method(prop):
     if prop.name == "float":
         return "CssFloat"
     if prop.name.startswith("-x-"):
         return prop.camel_case[1:]
     return prop.camel_case
 
-# TODO(emilio): Get this to zero.
-LONGHANDS_NOT_SERIALIZED_WITH_SERVO = [
-    "animation-delay",
-    "animation-duration",
-    "animation-iteration-count",
-    "animation-name",
-    "border-bottom-left-radius",
-    "border-bottom-right-radius",
-    "border-end-end-radius",
-    "border-end-start-radius",
-    "border-image-width",
-    "border-spacing",
-    "border-start-end-radius",
-    "border-start-start-radius",
-    "border-top-left-radius",
-    "border-top-right-radius",
-    "border-image-width",
-    "border-spacing",
-    "box-shadow",
-    "caret-color",
-    "color",
-    "column-count",
-    "column-gap",
-    "column-rule-width",
-    "column-width",
-    "contain",
-    "display",
-    "fill",
-    "fill-opacity",
-    "filter",
-    "flex-basis",
-    "flex-grow",
-    "flex-shrink",
-    "grid-auto-columns",
-    "grid-auto-flow",
-    "grid-auto-rows",
-    "grid-column-end",
-    "grid-column-start",
-    "grid-row-end",
-    "grid-row-start",
-    "grid-template-areas",
-    "initial-letter",
-    "letter-spacing",
-    "marker-end",
-    "marker-mid",
-    "marker-start",
-    "max-block-size",
-    "max-height",
-    "max-inline-size",
-    "max-width",
-    "min-block-size",
-    "min-height",
-    "min-inline-size",
-    "min-width",
-    "-moz-binding",
-    "-moz-box-flex",
-    "-moz-force-broken-image-icon",
-    "-moz-osx-font-smoothing",
-    "-moz-outline-radius-bottomleft",
-    "-moz-outline-radius-bottomright",
-    "-moz-outline-radius-topleft",
-    "-moz-outline-radius-topright",
-    "outline-width",
-    "paint-order",
-    "row-gap",
-    "scrollbar-color",
-    "scroll-snap-points-x",
-    "scroll-snap-points-y",
-    "stroke",
-    "stroke-dasharray",
-    "stroke-dashoffset",
-    "stroke-miterlimit",
-    "stroke-opacity",
-    "stroke-width",
-    "text-decoration-line",
-    "text-emphasis-position",
-    "text-emphasis-style",
-    "text-overflow",
-    "text-shadow",
-    "touch-action",
-    "transition-delay",
-    "transition-duration",
-    "transition-property",
-    "vertical-align",
-    "-webkit-text-stroke-width",
-    "will-change",
-    "word-spacing",
+# Colors, integers and lengths are easy as well.
+#
+# TODO(emilio): This will go away once the rest of the longhands have been
+# moved or perhaps using a blacklist for the ones with non-layout-dependence
+# but other non-trivial dependence like scrollbar colors.
+SERIALIZED_PREDEFINED_TYPES = [
+    "Appearance",
+    "AlignContent",
+    "AlignItems",
+    "AlignSelf",
+    "BackgroundRepeat",
+    "BackgroundSize",
+    "BorderImageRepeat",
+    "BorderStyle",
+    "BreakBetween",
+    "BreakWithin",
+    "Clear",
+    "ClipRectOrAuto",
+    "Color",
+    "Content",
+    "CounterIncrement",
+    "CounterReset",
+    "Cursor",
+    "FillRule",
+    "Float",
+    "FontFamily",
+    "FontFeatureSettings",
+    "FontLanguageOverride",
+    "FontSize",
+    "FontSizeAdjust",
+    "FontStretch",
+    "FontStyle",
+    "FontSynthesis",
+    "FontVariant",
+    "FontVariantAlternates",
+    "FontVariantEastAsian",
+    "FontVariantLigatures",
+    "FontVariantNumeric",
+    "FontVariationSettings",
+    "FontWeight",
+    "Integer",
+    "ImageLayer",
+    "JustifyContent",
+    "JustifyItems",
+    "JustifySelf",
+    "Length",
+    "LengthPercentage",
+    "NonNegativeLength",
+    "NonNegativeLengthPercentage",
+    "NonNegativeLengthPercentageOrAuto",
+    "ListStyleType",
+    "OffsetPath",
+    "Opacity",
+    "OutlineStyle",
+    "OverflowWrap",
+    "Position",
+    "Quotes",
+    "Resize",
+    "Rotate",
+    "Scale",
+    "TextAlign",
+    "Translate",
+    "TimingFunction",
+    "TransformOrigin",
+    "TransformStyle",
+    "UserSelect",
+    "background::BackgroundSize",
+    "basic_shape::ClippingShape",
+    "basic_shape::FloatAreaShape",
+    "position::HorizontalPosition",
+    "position::VerticalPosition",
+    "url::ImageUrlOrNone",
+    "Appearance",
+    "OverscrollBehavior",
+    "OverflowAnchor",
+    "OverflowClipBox",
+    "ScrollSnapAlign",
+    "ScrollSnapType",
+    "Float",
+    "Overflow",
+    "BorderImageSlice",
+    "NonNegativeLengthOrNumberRect",
+    "NonNegativeLengthOrNumber",
+    "ZIndex",
+    "Perspective",
 ]
 
 def serialized_by_servo(prop):
     # If the property requires layout information, no such luck.
     if "GETCS_NEEDS_LAYOUT_FLUSH" in prop.flags:
         return False
     if prop.type() == "shorthand":
         # FIXME: Need to serialize a value interpolated with currentcolor
         # properly to be able to use text-decoration, and figure out what to do
         # with relative mask urls.
         return prop.name != "text-decoration" and prop.name != "mask"
     # Keywords are all fine, except -moz-osx-font-smoothing, which does
     # resistfingerprinting stuff.
     if prop.keyword and prop.name != "-moz-osx-font-smoothing":
         return True
-    return prop.name not in LONGHANDS_NOT_SERIALIZED_WITH_SERVO
+    if prop.predefined_type in SERIALIZED_PREDEFINED_TYPES:
+        return True
+    # TODO(emilio): Enable the rest of the longhands.
+    return False
 
 def exposed_on_getcs(prop):
     if prop.type() == "longhand":
         return not is_internal(prop)
     # TODO: bug 137688 / https://github.com/w3c/csswg-drafts/issues/2529
     if prop.type() == "shorthand":
         return "SHORTHAND_IN_GETCS" in prop.flags
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1897,34 +1897,34 @@ already_AddRefed<CSSValue> nsComputedDOM
   return GetEllipseRadii(StyleOutline()->mOutlineRadius, eCornerTopLeft);
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetOutlineRadiusTopRight() {
   return GetEllipseRadii(StyleOutline()->mOutlineRadius, eCornerTopRight);
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::GetEllipseRadii(
-    const BorderRadius& aRadius, Corner aFullCorner) {
-  const auto& radiusX = aRadius.Get(FullToHalfCorner(aFullCorner, false));
-  const auto& radiusY = aRadius.Get(FullToHalfCorner(aFullCorner, true));
+    const nsStyleCorners& aRadius, Corner aFullCorner) {
+  nsStyleCoord radiusX = aRadius.Get(FullToHalfCorner(aFullCorner, false));
+  nsStyleCoord radiusY = aRadius.Get(FullToHalfCorner(aFullCorner, true));
 
   // for compatibility, return a single value if X and Y are equal
   if (radiusX == radiusY) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToLengthPercentage(val, radiusX, true);
+    SetValueToCoord(val, radiusX, true);
     return val.forget();
   }
 
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
 
-  SetValueToLengthPercentage(valX, radiusX, true);
-  SetValueToLengthPercentage(valY, radiusY, true);
+  SetValueToCoord(valX, radiusX, true);
+  SetValueToCoord(valY, radiusY, true);
 
   valueList->AppendCSSValue(valX.forget());
   valueList->AppendCSSValue(valY.forget());
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::GetCSSShadowArray(
@@ -3268,19 +3268,32 @@ void nsComputedDOMStyle::BoxValuesToStri
       if (value2 != value4) {
         aString.Append(' ');
         aString.Append(value4);
       }
     }
   }
 }
 
-void nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
-                                                 const BorderRadius& aCorners) {
-  Servo_SerializeBorderRadius(&aCorners, &aCssText);
+void nsComputedDOMStyle::BasicShapeRadiiToString(
+    nsAString& aCssText, const nsStyleCorners& aCorners) {
+  nsTArray<nsStyleCoord> horizontal, vertical;
+  nsAutoString horizontalString, verticalString;
+  NS_FOR_CSS_FULL_CORNERS(corner) {
+    horizontal.AppendElement(aCorners.Get(FullToHalfCorner(corner, false)));
+    vertical.AppendElement(aCorners.Get(FullToHalfCorner(corner, true)));
+  }
+  BoxValuesToString(horizontalString, horizontal, true);
+  BoxValuesToString(verticalString, vertical, true);
+  aCssText.Append(horizontalString);
+  if (horizontalString == verticalString) {
+    return;
+  }
+  aCssText.AppendLiteral(" / ");
+  aCssText.Append(verticalString);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
     const UniquePtr<StyleBasicShape>& aStyleBasicShape) {
   MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
 
   StyleBasicShapeType type = aStyleBasicShape->GetShapeType();
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -36,16 +36,17 @@ struct ComputedGridTrackInfo;
 struct ComputedStyleMap;
 struct nsCSSKTableEntry;
 class nsIFrame;
 class nsIPresShell;
 class nsDOMCSSValueList;
 struct nsMargin;
 class nsROCSSPrimitiveValue;
 class nsStyleCoord;
+class nsStyleCorners;
 struct nsStyleFilter;
 class nsStyleGradient;
 struct nsStyleImage;
 class nsStyleSides;
 
 class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
                                  public nsStubMutationObserver {
  private:
@@ -164,20 +165,21 @@ class nsComputedDOMStyle final : public 
 #undef STYLE_STRUCT
 
   /**
    * A method to get a percentage base for a percentage value.  Returns true
    * if a percentage base value was determined, false otherwise.
    */
   typedef bool (nsComputedDOMStyle::*PercentageBaseGetter)(nscoord&);
 
-  already_AddRefed<CSSValue> GetEllipseRadii(const mozilla::BorderRadius&,
+  already_AddRefed<CSSValue> GetEllipseRadii(const nsStyleCorners& aRadius,
                                              mozilla::Corner aFullCorner);
 
-  already_AddRefed<CSSValue> GetOffsetWidthFor(mozilla::Side);
+  already_AddRefed<CSSValue> GetOffsetWidthFor(mozilla::Side aSide);
+
   already_AddRefed<CSSValue> GetAbsoluteOffset(mozilla::Side);
   nscoord GetUsedAbsoluteOffset(mozilla::Side);
   already_AddRefed<CSSValue> GetNonStaticPositionOffset(
       mozilla::Side aSide, bool aResolveAuto, PercentageBaseGetter aWidthGetter,
       PercentageBaseGetter aHeightGetter);
 
   already_AddRefed<CSSValue> GetStaticOffset(mozilla::Side aSide);
 
@@ -289,17 +291,16 @@ class nsComputedDOMStyle final : public 
   already_AddRefed<CSSValue> DoGetBorderBottomWidth();
   already_AddRefed<CSSValue> DoGetBorderLeftWidth();
   already_AddRefed<CSSValue> DoGetBorderRightWidth();
   already_AddRefed<CSSValue> DoGetBorderBottomLeftRadius();
   already_AddRefed<CSSValue> DoGetBorderBottomRightRadius();
   already_AddRefed<CSSValue> DoGetBorderTopLeftRadius();
   already_AddRefed<CSSValue> DoGetBorderTopRightRadius();
 
-
   /* Border Image */
   already_AddRefed<CSSValue> DoGetBorderImageWidth();
 
   /* Box Shadow */
   already_AddRefed<CSSValue> DoGetBoxShadow();
 
   /* Margin Properties */
   already_AddRefed<CSSValue> DoGetMarginTopWidth();
@@ -309,17 +310,16 @@ class nsComputedDOMStyle final : public 
 
   /* Outline Properties */
   already_AddRefed<CSSValue> DoGetOutlineWidth();
   already_AddRefed<CSSValue> DoGetOutlineRadiusBottomLeft();
   already_AddRefed<CSSValue> DoGetOutlineRadiusBottomRight();
   already_AddRefed<CSSValue> DoGetOutlineRadiusTopLeft();
   already_AddRefed<CSSValue> DoGetOutlineRadiusTopRight();
 
-
   /* Text Properties */
   already_AddRefed<CSSValue> DoGetInitialLetter();
   already_AddRefed<CSSValue> DoGetLineHeight();
   already_AddRefed<CSSValue> DoGetTextDecoration();
   already_AddRefed<CSSValue> DoGetTextDecorationColor();
   already_AddRefed<CSSValue> DoGetTextDecorationLine();
   already_AddRefed<CSSValue> DoGetTextDecorationStyle();
   already_AddRefed<CSSValue> DoGetTextEmphasisPosition();
@@ -491,17 +491,17 @@ class nsComputedDOMStyle final : public 
 
   // Helper function for computing basic shape styles.
   already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(
       const mozilla::UniquePtr<mozilla::StyleBasicShape>& aStyleBasicShape);
   void BoxValuesToString(nsAString& aString,
                          const nsTArray<nsStyleCoord>& aBoxValues,
                          bool aClampNegativeCalc);
   void BasicShapeRadiiToString(nsAString& aCssText,
-                               const mozilla::BorderRadius&);
+                               const nsStyleCorners& aCorners);
 
   // Find out if we can safely skip flushing for aDocument (i.e. pending
   // restyles does not affect mContent).
   bool NeedsToFlush(Document*) const;
 
   static ComputedStyleMap* GetComputedStyleMap();
 
   // We don't really have a good immutable representation of "presentation".
--- a/layout/style/nsStyleCoord.cpp
+++ b/layout/style/nsStyleCoord.cpp
@@ -198,16 +198,52 @@ bool nsStyleSides::operator==(const nsSt
   }
   return true;
 }
 
 void nsStyleSides::Reset() {
   NS_FOR_CSS_SIDES(i) { nsStyleCoord::Reset(mUnits[i], mValues[i]); }
 }
 
+nsStyleCorners::nsStyleCorners() {
+  NS_FOR_CSS_HALF_CORNERS(i) { mUnits[i] = eStyleUnit_Null; }
+  mozilla::PodArrayZero(mValues);
+}
+
+nsStyleCorners::nsStyleCorners(const nsStyleCorners& aOther) {
+  NS_FOR_CSS_HALF_CORNERS(i) { mUnits[i] = eStyleUnit_Null; }
+  *this = aOther;
+}
+
+nsStyleCorners::~nsStyleCorners() { Reset(); }
+
+nsStyleCorners& nsStyleCorners::operator=(const nsStyleCorners& aCopy) {
+  if (this != &aCopy) {
+    NS_FOR_CSS_HALF_CORNERS(i) {
+      nsStyleCoord::SetValue(mUnits[i], mValues[i], aCopy.mUnits[i],
+                             aCopy.mValues[i]);
+    }
+  }
+  return *this;
+}
+
+bool nsStyleCorners::operator==(const nsStyleCorners& aOther) const {
+  NS_FOR_CSS_HALF_CORNERS(i) {
+    if (nsStyleCoord(mValues[i], (nsStyleUnit)mUnits[i]) !=
+        nsStyleCoord(aOther.mValues[i], (nsStyleUnit)aOther.mUnits[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void nsStyleCorners::Reset() {
+  NS_FOR_CSS_HALF_CORNERS(i) { nsStyleCoord::Reset(mUnits[i], mValues[i]); }
+}
+
 // Validation of SideIsVertical.
 #define CASE(side, result) \
   static_assert(SideIsVertical(side) == result, "SideIsVertical is wrong")
 CASE(eSideTop, false);
 CASE(eSideRight, true);
 CASE(eSideBottom, false);
 CASE(eSideLeft, true);
 #undef CASE
--- a/layout/style/nsStyleCoord.h
+++ b/layout/style/nsStyleCoord.h
@@ -39,17 +39,16 @@ enum LogicalCorner {
   eLogicalCornerBEndIStart = 3
 };
 
 using LengthPercentage = StyleLengthPercentage;
 using LengthPercentageOrAuto = StyleLengthPercentageOrAuto;
 using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage;
 using NonNegativeLengthPercentageOrAuto =
     StyleNonNegativeLengthPercentageOrAuto;
-using BorderRadius = StyleBorderRadius;
 
 nscoord StyleCSSPixelLength::ToAppUnits() const {
   // We want to resolve the length part of the calc() expression rounding 0.5
   // away from zero, instead of the default behavior of NSToCoordRoundWithClamp
   // which is floor(x + 0.5).
   //
   // This is what the rust code in the app_units crate does, and not doing this
   // would regress bug 1323735, for example.
@@ -247,24 +246,16 @@ bool StyleRect<T>::All(Predicate aPredic
 }
 
 template <typename T>
 template <typename Predicate>
 bool StyleRect<T>::Any(Predicate aPredicate) const {
   return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3);
 }
 
-template <>
-inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const {
-  static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, "");
-  static_assert(alignof(BorderRadius) == alignof(LengthPercentage), "");
-  auto* self = reinterpret_cast<const LengthPercentage*>(this);
-  return self[aCorner];
-}
-
 }  // namespace mozilla
 
 enum nsStyleUnit : uint8_t {
   eStyleUnit_Null = 0,           // (no value) value is not specified
   eStyleUnit_Normal = 1,         // (no value)
   eStyleUnit_Auto = 2,           // (no value)
   eStyleUnit_None = 3,           // (no value)
   eStyleUnit_Percent = 10,       // (float) 1.0 == 100%
@@ -593,16 +584,55 @@ class nsStyleSides {
     return true;
   }
 
  protected:
   nsStyleUnit mUnits[4];
   nsStyleUnion mValues[4];
 };
 
+/**
+ * Class that represents a set of top-left/top-right/bottom-right/bottom-left
+ * nsStyleCoord pairs.  This is used to hold the dimensions of the
+ * corners of a box (for, e.g., border-radius and outline-radius).
+ */
+/** <div rustbindgen private accessor="unsafe"></div> */
+class nsStyleCorners {
+ public:
+  nsStyleCorners();
+  nsStyleCorners(const nsStyleCorners&);
+  ~nsStyleCorners();
+
+  // use compiler's version
+  nsStyleCorners& operator=(const nsStyleCorners& aCopy);
+  bool operator==(const nsStyleCorners& aOther) const;
+  bool operator!=(const nsStyleCorners& aOther) const;
+
+  // aHalfCorner is always one of enum HalfCorner in gfx/2d/Types.h.
+  inline nsStyleUnit GetUnit(uint8_t aHalfCorner) const;
+
+  inline nsStyleCoord Get(uint8_t aHalfCorner) const;
+
+  // Sets each corner to null and releases any refcounted objects.  Only use
+  // this if the object is initialized (i.e. don't use it in nsStyleCorners
+  // constructors).
+  void Reset();
+
+  inline void Set(uint8_t aHalfCorner, const nsStyleCoord& aCoord);
+
+ protected:
+  // Stored as:
+  // top-left.x, top-left.y,
+  // top-right.x, top-right.y,
+  // bottom-right.x, bottom-right.y,
+  // bottom-left.x, bottom-left.y
+  nsStyleUnit mUnits[8];
+  nsStyleUnion mValues[8];
+};
+
 // -------------------------
 // nsStyleCoord inlines
 //
 inline nsStyleCoord::nsStyleCoord(nscoord aValue, CoordConstructorType)
     : mUnit(eStyleUnit_Coord) {
   mValue.mInt = aValue;
 }
 
@@ -795,9 +825,29 @@ inline void nsStyleSides::SetTop(const n
 
 inline void nsStyleSides::SetRight(const nsStyleCoord& aCoord) {
   Set(mozilla::eSideRight, aCoord);
 }
 
 inline void nsStyleSides::SetBottom(const nsStyleCoord& aCoord) {
   Set(mozilla::eSideBottom, aCoord);
 }
+
+// -------------------------
+// nsStyleCorners inlines
+//
+inline bool nsStyleCorners::operator!=(const nsStyleCorners& aOther) const {
+  return !((*this) == aOther);
+}
+
+inline nsStyleUnit nsStyleCorners::GetUnit(uint8_t aCorner) const {
+  return (nsStyleUnit)mUnits[aCorner];
+}
+
+inline nsStyleCoord nsStyleCorners::Get(uint8_t aCorner) const {
+  return nsStyleCoord(mValues[aCorner], nsStyleUnit(mUnits[aCorner]));
+}
+
+inline void nsStyleCorners::Set(uint8_t aCorner, const nsStyleCoord& aCoord) {
+  nsStyleCoord::SetValue(mUnits[aCorner], mValues[aCorner], aCoord);
+}
+
 #endif /* nsStyleCoord_h___ */
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -237,40 +237,38 @@ nsChangeHint nsStylePadding::CalcDiffere
   return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
 }
 
 static nscoord TwipsPerPixel(const Document& aDocument) {
   auto* pc = aDocument.GetPresContext();
   return pc ? pc->AppUnitsPerDevPixel() : mozilla::AppUnitsPerCSSPixel();
 }
 
-static inline BorderRadius ZeroBorderRadius() {
-  auto zero = LengthPercentage::Zero();
-  return {{{zero, zero}}, {{zero, zero}}, {{zero, zero}}, {{zero, zero}}};
-}
-
 nsStyleBorder::nsStyleBorder(const Document& aDocument)
-    : mBorderRadius(ZeroBorderRadius())
-    , mBorderImageOutset(
+    : mBorderImageOutset(
           StyleRectWithAllSides(StyleNonNegativeLengthOrNumber::Number(0.))),
       mBorderImageSlice(
           {StyleRectWithAllSides(StyleNumberOrPercentage::Percentage({1.})),
            false}),
       mBorderImageRepeatH(StyleBorderImageRepeat::Stretch),
       mBorderImageRepeatV(StyleBorderImageRepeat::Stretch),
       mFloatEdge(StyleFloatEdge::ContentBox),
       mBoxDecorationBreak(StyleBoxDecorationBreak::Slice),
       mBorderTopColor(StyleComplexColor::CurrentColor()),
       mBorderRightColor(StyleComplexColor::CurrentColor()),
       mBorderBottomColor(StyleComplexColor::CurrentColor()),
       mBorderLeftColor(StyleComplexColor::CurrentColor()),
       mComputedBorder(0, 0, 0, 0),
       mTwipsPerPixel(TwipsPerPixel(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
+  NS_FOR_CSS_HALF_CORNERS(corner) {
+    mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
+  }
+
   nscoord medium = kMediumBorderWidth;
   NS_FOR_CSS_SIDES(side) {
     mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
     mBorder.Side(side) = medium;
     mBorderStyle[side] = StyleBorderStyle::None;
   }
 }
 
@@ -397,24 +395,26 @@ nsChangeHint nsStyleBorder::CalcDifferen
       mBorderImageWidth != aNewData.mBorderImageWidth) {
     return nsChangeHint_NeutralChange;
   }
 
   return nsChangeHint(0);
 }
 
 nsStyleOutline::nsStyleOutline(const Document& aDocument)
-    : mOutlineRadius(ZeroBorderRadius()),
-      mOutlineWidth(kMediumBorderWidth),
+    : mOutlineWidth(kMediumBorderWidth),
       mOutlineOffset(0),
       mOutlineColor(StyleComplexColor::CurrentColor()),
       mOutlineStyle(StyleOutlineStyle::BorderStyle(StyleBorderStyle::None)),
       mActualOutlineWidth(0),
       mTwipsPerPixel(TwipsPerPixel(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleOutline);
+  // spacing values not inherited
+  nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
+  NS_FOR_CSS_HALF_CORNERS(corner) { mOutlineRadius.Set(corner, zero); }
 }
 
 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
     : mOutlineRadius(aSrc.mOutlineRadius),
       mOutlineWidth(aSrc.mOutlineWidth),
       mOutlineOffset(aSrc.mOutlineOffset),
       mOutlineColor(aSrc.mOutlineColor),
       mOutlineStyle(aSrc.mOutlineStyle),
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -938,17 +938,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   imgIRequest* GetBorderImageRequest() const {
     if (mBorderImageSource.GetType() == eStyleImageType_Image) {
       return mBorderImageSource.GetImageData();
     }
     return nullptr;
   }
 
  public:
-  mozilla::StyleBorderRadius mBorderRadius;  // coord, percent
+  nsStyleCorners mBorderRadius;  // coord, percent
   nsStyleImage mBorderImageSource;
   nsStyleSides mBorderImageWidth;  // length, factor, percent, auto
   mozilla::StyleNonNegativeLengthOrNumberRect mBorderImageOutset;
   mozilla::StyleBorderImageSlice mBorderImageSlice;  // factor, percent
   mozilla::StyleBorderImageRepeat mBorderImageRepeatH;
   mozilla::StyleBorderImageRepeat mBorderImageRepeatV;
   mozilla::StyleFloatEdge mFloatEdge;
   mozilla::StyleBoxDecorationBreak mBoxDecorationBreak;
@@ -1042,17 +1042,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   explicit nsStyleOutline(const mozilla::dom::Document&);
   nsStyleOutline(const nsStyleOutline& aOutline);
   ~nsStyleOutline() { MOZ_COUNT_DTOR(nsStyleOutline); }
   void TriggerImageLoads(mozilla::dom::Document&, const nsStyleOutline*) {}
   const static bool kHasTriggerImageLoads = false;
 
   nsChangeHint CalcDifference(const nsStyleOutline& aNewData) const;
 
-  mozilla::StyleBorderRadius mOutlineRadius;
+  nsStyleCorners mOutlineRadius;  // coord, percent, calc
 
   // This is the specified value of outline-width, but with length values
   // computed to absolute.  mActualOutlineWidth stores the outline-width
   // value used by layout.  (We must store mOutlineWidth for the same
   // style struct resolution reasons that we do nsStyleBorder::mBorder;
   // see that field's comment.)
   nscoord mOutlineWidth;
   nscoord mOutlineOffset;
@@ -1649,26 +1649,27 @@ class StyleBasicShape final {
     MOZ_ASSERT(mType == StyleBasicShapeType::Circle ||
                    mType == StyleBasicShapeType::Ellipse,
                "expected circle or ellipse");
     return mPosition;
   }
 
   bool HasRadius() const {
     MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
+    nsStyleCoord zero;
+    zero.SetCoordValue(0);
     NS_FOR_CSS_HALF_CORNERS(corner) {
-      auto& radius = mRadius.Get(corner);
-      if (radius.HasPercent() || radius.LengthInCSSPixels() != 0.0f) {
+      if (mRadius.Get(corner) != zero) {
         return true;
       }
     }
     return false;
   }
 
-  const mozilla::StyleBorderRadius& GetRadius() const {
+  const nsStyleCorners& GetRadius() const {
     MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
     return mRadius;
   }
 
   // mCoordinates has coordinates for polygon or radii for
   // ellipse and circle.
   const nsTArray<nsStyleCoord>& Coordinates() const { return mCoordinates; }
 
@@ -1687,17 +1688,17 @@ class StyleBasicShape final {
 
   // mCoordinates has coordinates for polygon or radii for
   // ellipse and circle.
   // (top, right, bottom, left) for inset
   nsTArray<nsStyleCoord> mCoordinates;
   // position of center for ellipse or circle
   mozilla::Position mPosition;
   // corner radii for inset (0 if not set)
-  mozilla::StyleBorderRadius mRadius;
+  nsStyleCorners mRadius;
 };
 
 struct StyleSVGPath final {
   const nsTArray<StylePathCommand>& Path() const { return mPath; }
 
   StyleFillRule FillRule() const { return mFillRule; }
 
   bool operator==(const StyleSVGPath& aOther) const {
--- a/servo/components/style/cbindgen.toml
+++ b/servo/components/style/cbindgen.toml
@@ -8,17 +8,16 @@ autogen_warning = """/* DO NOT MODIFY TH
  *   2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
  */
 #include "nsCoord.h"
 #include "Units.h"
 #include "mozilla/gfx/Types.h"
 class nsAtom;
 namespace mozilla {
   class WritingMode;
-  enum HalfCorner : uint8_t;
   enum LogicalSide : uint8_t;
   namespace css {
     struct URLValue;
   }
 
   // Work-around weird cbindgen renaming.
   typedef css::URLValue StyleURLValue;
   typedef nsAtom StylensAtom;
@@ -84,18 +83,16 @@ include = [
   "Rect",
   "IntersectionObserverRootMargin",
   "Size",
   "MaxSize",
   "FlexBasis",
   "Position",
   "BackgroundSize",
   "BorderImageSlice",
-  "BorderSpacing",
-  "BorderRadius",
   "NonNegativeLengthOrNumberRect",
   "Perspective",
   "ZIndex",
   "TransformOrigin",
 ]
 item_types = ["enums", "structs", "typedefs"]
 
 [export.body]
@@ -183,12 +180,8 @@ item_types = ["enums", "structs", "typed
   // Defined in WritingModes.h
   inline const T& Get(mozilla::Side) const;
   inline const T& Get(mozilla::WritingMode, mozilla::LogicalSide) const;
   inline const T& GetIStart(mozilla::WritingMode) const;
   inline const T& GetBStart(mozilla::WritingMode) const;
   inline const T& GetIEnd(mozilla::WritingMode) const;
   inline const T& GetBEnd(mozilla::WritingMode) const;
 """
-
-"GenericBorderRadius" = """
-  inline const StyleLengthPercentage& Get(mozilla::HalfCorner) const;
-"""
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -570,34 +570,38 @@ impl nsStyleImage {
         })
     }
 }
 
 pub mod basic_shape {
     //! Conversions from and to CSS shape representations.
 
     use crate::gecko::values::GeckoStyleCoordConvertible;
-    use crate::gecko_bindings::structs::nsStyleCoord;
+    use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCorners};
     use crate::gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType};
     use crate::gecko_bindings::structs::{
         StyleGeometryBox, StyleShapeSource, StyleShapeSourceType,
     };
+    use crate::gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
     use crate::gecko_bindings::sugar::refptr::RefPtr;
     use crate::values::computed::basic_shape::{
         BasicShape, ClippingShape, FloatAreaShape, ShapeRadius,
     };
+    use crate::values::computed::border::{BorderCornerRadius, BorderRadius};
     use crate::values::computed::length::LengthPercentage;
     use crate::values::computed::motion::OffsetPath;
     use crate::values::computed::url::ComputedUrl;
     use crate::values::generics::basic_shape::{
         BasicShape as GenericBasicShape, InsetRect, Polygon,
     };
     use crate::values::generics::basic_shape::{Circle, Ellipse, Path, PolygonCoord};
     use crate::values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
+    use crate::values::generics::border::BorderRadius as GenericBorderRadius;
     use crate::values::generics::rect::Rect;
+    use crate::values::generics::NonNegative;
     use crate::values::specified::SVGPathData;
     use std::borrow::Borrow;
 
     impl StyleShapeSource {
         /// Convert StyleShapeSource to ShapeSource except URL and Image
         /// types.
         fn into_shape_source<ReferenceBox, ImageOrUrl>(
             &self,
@@ -697,17 +701,17 @@ pub mod basic_shape {
     impl<'a> From<&'a StyleBasicShape> for BasicShape {
         fn from(other: &'a StyleBasicShape) -> Self {
             match other.mType {
                 StyleBasicShapeType::Inset => {
                     let t = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[0]);
                     let r = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
                     let b = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
                     let l = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
-                    let round = other.mRadius;
+                    let round: BorderRadius = (&other.mRadius).into();
                     let round = if round.all_zero() { None } else { Some(round) };
                     let rect = Rect::new(
                         t.expect("inset() offset should be a length, percentage, or calc value"),
                         r.expect("inset() offset should be a length, percentage, or calc value"),
                         b.expect("inset() offset should be a length, percentage, or calc value"),
                         l.expect("inset() offset should be a length, percentage, or calc value"),
                     );
                     GenericBasicShape::Inset(InsetRect { rect, round })
@@ -743,16 +747,75 @@ pub mod basic_shape {
                         fill: other.mFillRule,
                         coordinates: coords,
                     })
                 },
             }
         }
     }
 
+    impl<'a> From<&'a nsStyleCorners> for BorderRadius {
+        fn from(other: &'a nsStyleCorners) -> Self {
+            let get_corner = |index| {
+                BorderCornerRadius::new(
+                    NonNegative(
+                        LengthPercentage::from_gecko_style_coord(&other.data_at(index)).expect(
+                            "<border-radius> should be a length, percentage, or calc value",
+                        ),
+                    ),
+                    NonNegative(
+                        LengthPercentage::from_gecko_style_coord(&other.data_at(index + 1)).expect(
+                            "<border-radius> should be a length, percentage, or calc value",
+                        ),
+                    ),
+                )
+            };
+
+            GenericBorderRadius {
+                top_left: get_corner(0),
+                top_right: get_corner(2),
+                bottom_right: get_corner(4),
+                bottom_left: get_corner(6),
+            }
+        }
+    }
+
+    // Can't be a From impl since we need to set an existing
+    // nsStyleCorners, not create a new one
+    impl BorderRadius {
+        /// Set this `BorderRadius` into a given `nsStyleCoord`.
+        pub fn set_corners(&self, other: &mut nsStyleCorners) {
+            let mut set_corner = |field: &BorderCornerRadius, index| {
+                field
+                    .0
+                    .width()
+                    .to_gecko_style_coord(&mut other.data_at_mut(index));
+                field
+                    .0
+                    .height()
+                    .to_gecko_style_coord(&mut other.data_at_mut(index + 1));
+            };
+            set_corner(&self.top_left, 0);
+            set_corner(&self.top_right, 2);
+            set_corner(&self.bottom_right, 4);
+            set_corner(&self.bottom_left, 6);
+        }
+    }
+
+    /// We use None for a nonexistant radius, but Gecko uses (0 0 0 0 / 0 0 0 0)
+    pub fn set_corners_from_radius(radius: Option<BorderRadius>, other: &mut nsStyleCorners) {
+        if let Some(radius) = radius {
+            radius.set_corners(other);
+        } else {
+            for i in 0..8 {
+                other.data_at_mut(i).set_value(CoordDataValue::Coord(0));
+            }
+        }
+    }
+
     impl<'a> From<&'a nsStyleCoord> for ShapeRadius {
         fn from(other: &'a nsStyleCoord) -> Self {
             let other = other.borrow();
             ShapeRadius::from_gecko_style_coord(other)
                 .expect("<shape-radius> should be a length, percentage, calc, or keyword value")
         }
     }
 
--- a/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! Rust helpers for Gecko's `nsStyleCoord`.
 
 use crate::gecko_bindings::bindings;
 use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCoord_Calc, nsStyleCoord_CalcValue};
-use crate::gecko_bindings::structs::nsStyleSides;
+use crate::gecko_bindings::structs::{nsStyleCorners, nsStyleSides};
 use crate::gecko_bindings::structs::{nsStyleUnion, nsStyleUnit, nscoord};
 use std::mem;
 
 impl nsStyleCoord {
     #[inline]
     /// Get a `null` nsStyleCoord.
     pub fn null() -> Self {
         // Can't construct directly because it has private fields
@@ -118,16 +118,74 @@ unsafe impl<'a> CoordData for SidesDataM
 unsafe impl<'a> CoordDataMut for SidesDataMut<'a> {
     unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
         let unit = &mut self.sides.get_mUnits_mut()[self.index] as *mut _;
         let value = &mut self.sides.get_mValues_mut()[self.index] as *mut _;
         (&mut *unit, &mut *value)
     }
 }
 
+impl nsStyleCorners {
+    /// Get a `nsStyleCoord` like object representing the given index's value
+    /// and unit.
+    #[inline]
+    pub fn data_at(&self, index: usize) -> CornersData {
+        CornersData {
+            corners: self,
+            index: index,
+        }
+    }
+
+    /// Get a `nsStyleCoord` like object representing the mutable given index's
+    /// value and unit.
+    #[inline]
+    pub fn data_at_mut(&mut self, index: usize) -> CornersDataMut {
+        CornersDataMut {
+            corners: self,
+            index: index,
+        }
+    }
+}
+
+/// A `nsStyleCoord`-like struct on top of `nsStyleCorners`.
+pub struct CornersData<'a> {
+    corners: &'a nsStyleCorners,
+    index: usize,
+}
+
+/// A `nsStyleCoord`-like struct on top of a mutable `nsStyleCorners` reference.
+pub struct CornersDataMut<'a> {
+    corners: &'a mut nsStyleCorners,
+    index: usize,
+}
+
+unsafe impl<'a> CoordData for CornersData<'a> {
+    fn unit(&self) -> nsStyleUnit {
+        unsafe { self.corners.get_mUnits()[self.index] }
+    }
+    fn union(&self) -> nsStyleUnion {
+        unsafe { self.corners.get_mValues()[self.index] }
+    }
+}
+unsafe impl<'a> CoordData for CornersDataMut<'a> {
+    fn unit(&self) -> nsStyleUnit {
+        unsafe { self.corners.get_mUnits()[self.index] }
+    }
+    fn union(&self) -> nsStyleUnion {
+        unsafe { self.corners.get_mValues()[self.index] }
+    }
+}
+unsafe impl<'a> CoordDataMut for CornersDataMut<'a> {
+    unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
+        let unit = &mut self.corners.get_mUnits_mut()[self.index] as *mut _;
+        let value = &mut self.corners.get_mValues_mut()[self.index] as *mut _;
+        (&mut *unit, &mut *value)
+    }
+}
+
 /// Enum representing the tagged union that is CoordData.
 ///
 /// In release mode this should never actually exist in the code, and will be
 /// optimized out by threading matches and inlining.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum CoordDataValue {
     /// eStyleUnit_Null
     Null,
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -47,17 +47,17 @@ use crate::gecko::values::round_border_t
 use crate::logical_geometry::WritingMode;
 use crate::media_queries::Device;
 use crate::properties::computed_value_flags::*;
 use crate::properties::longhands;
 use crate::rule_tree::StrongRuleNode;
 use crate::selector_parser::PseudoElement;
 use servo_arc::{Arc, RawOffsetArc};
 use std::marker::PhantomData;
-use std::mem::{forget, uninitialized, zeroed};
+use std::mem::{forget, uninitialized, transmute, zeroed};
 use std::{cmp, ops, ptr};
 use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
 use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
 use crate::values::computed::BorderStyle;
 use crate::values::computed::font::FontSize;
 use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow};
 use crate::values::generics::column::ColumnCount;
 use crate::values::generics::transform::TransformStyle;
@@ -812,33 +812,44 @@ def set_gecko_property(ffi_name, expr):
     }
 
     #[allow(non_snake_case)]
     pub fn reset_${ident}(&mut self, other: &Self) {
         self.copy_${ident}_from(other)
     }
 </%def>
 
-<%def name="impl_corner_style_coord(ident, gecko_ffi_name, corner)">
+<%def name="impl_corner_style_coord(ident, gecko_ffi_name, x_index, y_index)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
-        self.gecko.${gecko_ffi_name}.${corner} = v;
+        v.0.width().to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${x_index}));
+        v.0.height().to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${y_index}));
     }
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
-        self.gecko.${gecko_ffi_name}.${corner} =
-            other.gecko.${gecko_ffi_name}.${corner};
+        self.gecko.${gecko_ffi_name}.data_at_mut(${x_index})
+                  .copy_from(&other.gecko.${gecko_ffi_name}.data_at(${x_index}));
+        self.gecko.${gecko_ffi_name}.data_at_mut(${y_index})
+                  .copy_from(&other.gecko.${gecko_ffi_name}.data_at(${y_index}));
     }
     #[allow(non_snake_case)]
     pub fn reset_${ident}(&mut self, other: &Self) {
         self.copy_${ident}_from(other)
     }
+
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
-        self.gecko.${gecko_ffi_name}.${corner}
+        use crate::values::computed::border::BorderCornerRadius;
+        let width = GeckoStyleCoordConvertible::from_gecko_style_coord(
+                        &self.gecko.${gecko_ffi_name}.data_at(${x_index}))
+                        .expect("Failed to clone ${ident}");
+        let height = GeckoStyleCoordConvertible::from_gecko_style_coord(
+                        &self.gecko.${gecko_ffi_name}.data_at(${y_index}))
+                        .expect("Failed to clone ${ident}");
+        BorderCornerRadius::new(width, height)
     }
 </%def>
 
 <%def name="impl_css_url(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         match v {
             UrlOrNone::Url(ref url) => {
@@ -1371,40 +1382,55 @@ impl ${style_struct.gecko_struct_name} {
 
 <%!
 class Side(object):
     def __init__(self, name, index):
         self.name = name
         self.ident = name.lower()
         self.index = index
 
+class Corner(object):
+    def __init__(self, vert, horiz, index):
+        self.x_name = "HalfCorner::eCorner" + vert + horiz + "X"
+        self.y_name = "HalfCorner::eCorner" + vert + horiz + "Y"
+        self.ident = (vert + "_" + horiz).lower()
+        self.x_index = 2 * index
+        self.y_index = 2 * index + 1
+
 class GridLine(object):
     def __init__(self, name):
         self.ident = "grid-" + name.lower()
         self.name = self.ident.replace('-', '_')
         self.gecko = "m" + to_camel_case(self.ident)
 
 SIDES = [Side("Top", 0), Side("Right", 1), Side("Bottom", 2), Side("Left", 3)]
-CORNERS = ["top_left", "top_right", "bottom_right", "bottom_left"]
+CORNERS = [Corner("Top", "Left", 0), Corner("Top", "Right", 1),
+           Corner("Bottom", "Right", 2), Corner("Bottom", "Left", 3)]
 GRID_LINES = map(GridLine, ["row-start", "row-end", "column-start", "column-end"])
 %>
 
 #[allow(dead_code)]
 fn static_assert() {
+    unsafe {
+        % for corner in CORNERS:
+        transmute::<_, [u32; ${corner.x_index}]>([1; structs::${corner.x_name} as usize]);
+        transmute::<_, [u32; ${corner.y_index}]>([1; structs::${corner.y_name} as usize]);
+        % endfor
+    }
     // Note: using the above technique with an enum hits a rust bug when |structs| is in a different crate.
     % for side in SIDES:
     { const DETAIL: u32 = [0][(structs::Side::eSide${side.name} as usize != ${side.index}) as usize]; let _ = DETAIL; }
     % endfor
 }
 
 
 <% skip_border_longhands = " ".join(["border-{0}-{1}".format(x.ident, y)
                                      for x in SIDES
                                      for y in ["color", "style", "width"]] +
-                                    ["border-{0}-radius".format(x.replace("_", "-"))
+                                    ["border-{0}-radius".format(x.ident.replace("_", "-"))
                                      for x in CORNERS]) %>
 
 <%self:impl_trait style_struct_name="Border"
                   skip_longhands="${skip_border_longhands} border-image-source
                                   border-image-repeat border-image-width">
     % for side in SIDES:
     pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) {
         self.gecko.mBorderStyle[${side.index}] = v;
@@ -1463,19 +1489,20 @@ fn static_assert() {
                                 round_to_pixels=True) %>
 
     pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
         self.gecko.mComputedBorder.${side.ident} != 0
     }
     % endfor
 
     % for corner in CORNERS:
-    <% impl_corner_style_coord("border_%s_radius" % corner,
+    <% impl_corner_style_coord("border_%s_radius" % corner.ident,
                                "mBorderRadius",
-                               corner) %>
+                               corner.x_index,
+                               corner.y_index) %>
     % endfor
 
     pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) {
         unsafe {
             // Prevent leaking of the last elements we did set
             Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
         }
 
@@ -1995,17 +2022,17 @@ fn static_assert() {
         };
 
         Either::First(TemplateAreasArc(Arc::new(TemplateAreas{ areas, strings, width })))
     }
 
 </%self:impl_trait>
 
 <% skip_outline_longhands = " ".join("outline-style outline-width".split() +
-                                     ["-moz-outline-radius-{0}".format(x.replace("_", ""))
+                                     ["-moz-outline-radius-{0}".format(x.ident.replace("_", ""))
                                       for x in CORNERS]) %>
 <%self:impl_trait style_struct_name="Outline"
                   skip_longhands="${skip_outline_longhands}">
 
     pub fn set_outline_style(&mut self, v: longhands::outline_style::computed_value::T) {
         self.gecko.mOutlineStyle = v;
         // NB: This is needed to correctly handling the initial value of
         // outline-width when outline-style changes, see the
@@ -2027,19 +2054,20 @@ fn static_assert() {
         self.gecko.mOutlineStyle.clone()
     }
 
     <% impl_non_negative_length("outline_width", "mActualOutlineWidth",
                                 inherit_from="mOutlineWidth",
                                 round_to_pixels=True) %>
 
     % for corner in CORNERS:
-    <% impl_corner_style_coord("_moz_outline_radius_%s" % corner.replace("_", ""),
+    <% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""),
                                "mOutlineRadius",
-                               corner) %>
+                               corner.x_index,
+                               corner.y_index) %>
     % endfor
 
     pub fn outline_has_nonzero_width(&self) -> bool {
         self.gecko.mActualOutlineWidth != 0
     }
 </%self:impl_trait>
 
 <%
@@ -4560,16 +4588,17 @@ fn set_style_svg_path(
     gecko_path.mFillRule = fill;
 }
 
 <%def name="impl_shape_source(ident, gecko_ffi_name)">
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         use crate::gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource};
         use crate::gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType};
         use crate::gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource};
+        use crate::gecko::conversions::basic_shape::set_corners_from_radius;
         use crate::gecko::values::GeckoStyleCoordConvertible;
         use crate::values::generics::basic_shape::{BasicShape, ShapeSource};
 
         let ref mut ${ident} = self.gecko.${gecko_ffi_name};
 
         // clean up existing struct
         unsafe { Gecko_DestroyShapeSource(${ident}) };
         ${ident}.mType = StyleShapeSourceType::None;
@@ -4624,20 +4653,18 @@ fn set_style_svg_path(
                         shape.mCoordinates[0].leaky_set_null();
                         inset.rect.0.to_gecko_style_coord(&mut shape.mCoordinates[0]);
                         shape.mCoordinates[1].leaky_set_null();
                         inset.rect.1.to_gecko_style_coord(&mut shape.mCoordinates[1]);
                         shape.mCoordinates[2].leaky_set_null();
                         inset.rect.2.to_gecko_style_coord(&mut shape.mCoordinates[2]);
                         shape.mCoordinates[3].leaky_set_null();
                         inset.rect.3.to_gecko_style_coord(&mut shape.mCoordinates[3]);
-                        shape.mRadius = match inset.round {
-                            Some(radius) => radius,
-                            None => crate::values::computed::BorderRadius::zero(),
-                        };
+
+                        set_corners_from_radius(inset.round, &mut shape.mRadius);
                     }
                     BasicShape::Circle(circ) => {
                         let shape = init_shape(${ident}, StyleBasicShapeType::Circle);
                         unsafe { shape.mCoordinates.set_len(1) };
                         shape.mCoordinates[0].leaky_set_null();
                         circ.radius.to_gecko_style_coord(&mut shape.mCoordinates[0]);
 
                         shape.mPosition = circ.position.into();
--- a/servo/components/style/values/computed/border.rs
+++ b/servo/components/style/values/computed/border.rs
@@ -82,26 +82,16 @@ impl BorderCornerRadius {
         GenericBorderCornerRadius(Size2D::new(
             NonNegativeLengthPercentage::zero(),
             NonNegativeLengthPercentage::zero(),
         ))
     }
 }
 
 impl BorderRadius {
-    /// Returns a `0` border radius.
-    pub fn zero() -> Self {
-        Self {
-            top_left: BorderCornerRadius::zero(),
-            top_right: BorderCornerRadius::zero(),
-            bottom_right: BorderCornerRadius::zero(),
-            bottom_left: BorderCornerRadius::zero(),
-        }
-    }
-
     /// Returns whether all the values are `0px`.
     pub fn all_zero(&self) -> bool {
         fn all(corner: &BorderCornerRadius) -> bool {
             fn is_zero(l: &NonNegativeLengthPercentage) -> bool {
                 *l == NonNegativeLengthPercentage::zero()
             }
             is_zero(corner.0.width()) && is_zero(corner.0.height())
         }
--- a/servo/components/style/values/generics/border.rs
+++ b/servo/components/style/values/generics/border.rs
@@ -48,20 +48,17 @@ pub use self::GenericBorderImageSlice as
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToAnimatedZero,
     ToComputedValue,
     ToCss,
 )]
-#[repr(C)]
-pub struct GenericBorderCornerRadius<L>(#[css(field_bound)] pub Size2D<L>);
-
-pub use self::GenericBorderCornerRadius as BorderCornerRadius;
+pub struct BorderCornerRadius<L>(#[css(field_bound)] pub Size2D<L>);
 
 impl<L> BorderCornerRadius<L> {
     /// Trivially create a `BorderCornerRadius`.
     pub fn new(w: L, h: L) -> Self {
         BorderCornerRadius(Size2D::new(w, h))
     }
 }
 
@@ -75,17 +72,16 @@ impl<L> BorderCornerRadius<L> {
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToAnimatedZero,
     ToComputedValue,
     ToCss,
 )]
-#[repr(transparent)]
 pub struct BorderSpacing<L>(#[css(field_bound)] pub Size2D<L>);
 
 impl<L> BorderSpacing<L> {
     /// Trivially create a `BorderCornerRadius`.
     pub fn new(w: L, h: L) -> Self {
         BorderSpacing(Size2D::new(w, h))
     }
 }
@@ -100,30 +96,27 @@ impl<L> BorderSpacing<L> {
     Copy,
     Debug,
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToComputedValue,
 )]
-#[repr(C)]
-pub struct GenericBorderRadius<LengthPercentage> {
+pub struct BorderRadius<LengthPercentage> {
     /// The top left radius.
-    pub top_left: GenericBorderCornerRadius<LengthPercentage>,
+    pub top_left: BorderCornerRadius<LengthPercentage>,
     /// The top right radius.
-    pub top_right: GenericBorderCornerRadius<LengthPercentage>,
+    pub top_right: BorderCornerRadius<LengthPercentage>,
     /// The bottom right radius.
-    pub bottom_right: GenericBorderCornerRadius<LengthPercentage>,
+    pub bottom_right: BorderCornerRadius<LengthPercentage>,
     /// The bottom left radius.
-    pub bottom_left: GenericBorderCornerRadius<LengthPercentage>,
+    pub bottom_left: BorderCornerRadius<LengthPercentage>,
 }
 
-pub use self::GenericBorderRadius as BorderRadius;
-
 impl<L> BorderRadius<L> {
     /// Returns a new `BorderRadius<L>`.
     #[inline]
     pub fn new(
         tl: BorderCornerRadius<L>,
         tr: BorderCornerRadius<L>,
         br: BorderCornerRadius<L>,
         bl: BorderCornerRadius<L>,
--- a/servo/components/style/values/generics/size.rs
+++ b/servo/components/style/values/generics/size.rs
@@ -20,17 +20,16 @@ use style_traits::{CssWriter, ParseError
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedZero,
     ToAnimatedValue,
     ToComputedValue,
 )]
 #[allow(missing_docs)]
-#[repr(C)]
 pub struct Size2D<L> {
     pub width: L,
     pub height: L,
 }
 
 impl<L> Size2D<L> {
     #[inline]
     /// Create a new `Size2D` for an area of given width and height.
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3698,25 +3698,16 @@ pub unsafe extern "C" fn Servo_Serialize
     output: *mut nsAString,
 ) {
     easing
         .mTiming
         .to_css(&mut CssWriter::new(&mut *output))
         .unwrap();
 }
 
-
-#[no_mangle]
-pub unsafe extern "C" fn Servo_SerializeBorderRadius(
-    radius: *const computed::BorderRadius,
-    output: *mut nsAString,
-) {
-    (*radius).to_css(&mut CssWriter::new(&mut *output)).unwrap();
-}
-
 #[no_mangle]
 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
     element: RawGeckoElementBorrowed,
     list: RawGeckoCSSPropertyIDListBorrowed,
     set: nsCSSPropertyIDSetBorrowedMut,
 ) {
     let element = GeckoElement(element);
     let element_data = match element.borrow_data() {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-shapes/shape-outside/values/shape-outside-inset-006.html.ini
@@ -0,0 +1,22 @@
+[shape-outside-inset-006.html]
+  [inset(10px round 10.1200px 20.34px 30.56px 40.780px) - computed]
+    expected: FAIL
+
+  [inset(10px round 10.123px 20.00px 30.10px 40.5678px) - computed]
+    expected: FAIL
+
+  [inset(10px round +10.1200px +20.340px +30.56px +40.780px) - computed]
+    expected: FAIL
+
+  [inset(10px round 10.1200px 20.34px 30.56px 40.780px / 10.1200px 20.34px 30.56px 40.780px) - computed]
+    expected: FAIL
+
+  [inset(10px round 10.123px 20.00px 30.10px 40.5678px / 10.123px 20.00px 30.10px 40.5678px) - computed]
+    expected: FAIL
+
+  [inset(10px round +10.1200px +20.340px +30.56px +40.780px / +10.1200px +20.340px +30.56px +40.780px) - computed]
+    expected: FAIL
+
+  [inset(10px round +10.123px +20.00px +30.10px +40.5678px / 10.123px +20.00px +30.10px +40.5678px) - computed]
+    expected: FAIL
+