Bug 1273706 - Part 9: Expose nsComputedDOMStyle::SetValueToStyleImage as a static method so that we can compute serialized computed values for gradients. draft
authorJonathan Chan <jyc@eqv.io>
Thu, 18 Aug 2016 15:28:09 -0700
changeset 402898 ab7c3d32f8deb753ffbde444beb0ecbfce8cde87
parent 402897 c3e7cd099dc0483ad1d490796b54a72b823294f9
child 402899 aea3ba284453b6b6cd1ef7c54f3746a739938d78
push id26775
push userjchan@mozilla.com
push dateThu, 18 Aug 2016 22:38:41 +0000
bugs1273706
milestone51.0a1
Bug 1273706 - Part 9: Expose nsComputedDOMStyle::SetValueToStyleImage as a static method so that we can compute serialized computed values for gradients. SetValueToStyleImage doesn't use any member variables in itself or in the methods it calls, but it used various functions that were also non-static. The reason they were non-static is because in the call chain is a function that takes a member function pointer, which requires an object pointer, SetValueToCoord. The member function pointer argument is nullptr by default and not used by any of the functions used by SetValueToStyleImage. SetValueToCoord is modified to take a class object pointer argument and calls are updated appropriately to pass either nullptr or this. This is a little unpleasant, but its a useful method that a later patch needs to use (CSSComputedValue::AppendToString). MozReview-Commit-ID: H5IexfQTTpu
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -926,17 +926,17 @@ already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStackSizing()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
                 eCSSKeyword_ignore);
   return val.forget();
 }
 
-void
+/* static */ void
 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
                                    nscolor aColor)
 {
   if (NS_GET_A(aColor) == 0) {
     aValue->SetIdent(eCSSKeyword_transparent);
     return;
   }
 
@@ -1222,30 +1222,29 @@ nsComputedDOMStyle::DoGetTransformOrigin
 
   /* Store things as a value list */
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   /* Now, get the values. */
   const nsStyleDisplay* display = StyleDisplay();
 
   RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
-  SetValueToCoord(width, display->mTransformOrigin[0], false,
+  SetValueToCoord(width, display->mTransformOrigin[0], false, this,
                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
   valueList->AppendCSSValue(width.forget());
 
   RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
-  SetValueToCoord(height, display->mTransformOrigin[1], false,
+  SetValueToCoord(height, display->mTransformOrigin[1], false, this,
                   &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
   valueList->AppendCSSValue(height.forget());
 
   if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
       display->mTransformOrigin[2].GetCoordValue() != 0) {
     RefPtr<nsROCSSPrimitiveValue> depth = new nsROCSSPrimitiveValue;
-    SetValueToCoord(depth, display->mTransformOrigin[2], false,
-                    nullptr);
+    SetValueToCoord(depth, display->mTransformOrigin[2], false);
     valueList->AppendCSSValue(depth.forget());
   }
 
   return valueList.forget();
 }
 
 /* Convert the stored representation into a list of two values and then hand
  * it back.
@@ -1259,22 +1258,22 @@ nsComputedDOMStyle::DoGetPerspectiveOrig
 
   /* Store things as a value list */
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   /* Now, get the values. */
   const nsStyleDisplay* display = StyleDisplay();
 
   RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
-  SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
+  SetValueToCoord(width, display->mPerspectiveOrigin[0], false, this,
                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
   valueList->AppendCSSValue(width.forget());
 
   RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
-  SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
+  SetValueToCoord(height, display->mPerspectiveOrigin[1], false, this,
                   &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
   valueList->AppendCSSValue(height.forget());
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPerspective()
@@ -1914,17 +1913,17 @@ AppendCSSGradientToBoxPosition(const nsS
     aString.AppendLiteral(" right");
   } else if (xValue != 0.5f) { // do not write "center" keyword
     NS_NOTREACHED("invalid box position");
   }
 
   aNeedSep = true;
 }
 
-void
+/* static */ void
 nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
                                          nsAString& aString)
 {
   if (!aGradient->mLegacySyntax) {
     aString.Truncate();
   } else {
     aString.AssignLiteral("-moz-");
   }
@@ -2045,17 +2044,17 @@ nsComputedDOMStyle::GetCSSGradientString
     }
     needSep = true;
   }
 
   aString.Append(')');
 }
 
 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
-void
+/* static */ void
 nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
                                        const nsStyleSides& aCropRect,
                                        nsString& aString)
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   // <uri>
   RefPtr<nsROCSSPrimitiveValue> valURI = new nsROCSSPrimitiveValue;
@@ -2072,42 +2071,44 @@ nsComputedDOMStyle::GetImageRectString(n
   nsAutoString argumentString;
   valueList->GetCssText(argumentString);
 
   aString = NS_LITERAL_STRING("-moz-image-rect(") +
             argumentString +
             NS_LITERAL_STRING(")");
 }
 
+namespace mozilla {
+
 void
-nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
-                                         nsROCSSPrimitiveValue* aValue)
+SetValueToStyleImage(const nsStyleImage& aStyleImage,
+                     nsROCSSPrimitiveValue* aValue)
 {
   switch (aStyleImage.GetType()) {
     case eStyleImageType_Image:
     {
       imgIRequest *req = aStyleImage.GetImageData();
       nsCOMPtr<nsIURI> uri;
       req->GetURI(getter_AddRefs(uri));
 
       const UniquePtr<nsStyleSides>& cropRect = aStyleImage.GetCropRect();
       if (cropRect) {
         nsAutoString imageRectString;
-        GetImageRectString(uri, *cropRect, imageRectString);
+        nsComputedDOMStyle::GetImageRectString(uri, *cropRect, imageRectString);
         aValue->SetString(imageRectString);
       } else {
         aValue->SetURI(uri);
       }
       break;
     }
     case eStyleImageType_Gradient:
     {
       nsAutoString gradientString;
-      GetCSSGradientString(aStyleImage.GetGradientData(),
-                           gradientString);
+      nsComputedDOMStyle::GetCSSGradientString(aStyleImage.GetGradientData(),
+                                               gradientString);
       aValue->SetString(gradientString);
       break;
     }
     case eStyleImageType_Element:
     {
       nsAutoString elementId;
       nsStyleUtil::AppendEscapedCSSIdent(
         nsDependentString(aStyleImage.GetElementId()), elementId);
@@ -2121,16 +2122,18 @@ nsComputedDOMStyle::SetValueToStyleImage
       aValue->SetIdent(eCSSKeyword_none);
       break;
     default:
       NS_NOTREACHED("unexpected image type");
       break;
   }
 }
 
+} // namespace mozilla
+
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetImageLayerImage(const nsStyleImageLayers& aLayers)
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = aLayers.mImageCount; i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
@@ -2145,17 +2148,17 @@ nsComputedDOMStyle::DoGetImageLayerImage
     //    Instead, we store the local URI in one place -- on Layer::mSourceURI.
     //    Hence, we must serialize using mSourceURI (instead of
     //    SetValueToStyleImage()/mImage) in this case.
     if (aLayers.mLayers[i].mSourceURI.IsLocalRef()) {
       // This is how we represent a 'mask-image' reference for a local URI,
       // such as 'mask-image:url(#mymask)' or 'mask:url(#mymask)'
       SetValueToFragmentOrURL(&aLayers.mLayers[i].mSourceURI, val);
     } else {
-      SetValueToStyleImage(image, val);
+      mozilla::SetValueToStyleImage(image, val);
     }
 
     valueList->AppendCSSValue(val.forget());
   }
 
   return valueList.forget();
 }
 
@@ -2528,34 +2531,34 @@ nsComputedDOMStyle::AppendGridLineNames(
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
                                      const nsStyleCoord& aMaxValue)
 {
   if (aMinValue == aMaxValue) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToCoord(val, aMinValue, true,
-                    nullptr, nsCSSProps::kGridTrackBreadthKTable);
+    SetValueToCoord(val, aMinValue, true, nullptr, nullptr,
+                    nsCSSProps::kGridTrackBreadthKTable);
     return val.forget();
   }
 
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString argumentStr, minmaxStr;
   minmaxStr.AppendLiteral("minmax(");
 
-  SetValueToCoord(val, aMinValue, true,
-                  nullptr, nsCSSProps::kGridTrackBreadthKTable);
+  SetValueToCoord(val, aMinValue, true, nullptr, nullptr,
+                  nsCSSProps::kGridTrackBreadthKTable);
   val->GetCssText(argumentStr);
   minmaxStr.Append(argumentStr);
 
   minmaxStr.AppendLiteral(", ");
 
-  SetValueToCoord(val, aMaxValue, true,
-                  nullptr, nsCSSProps::kGridTrackBreadthKTable);
+  SetValueToCoord(val, aMaxValue, true, nullptr, nullptr,
+                  nsCSSProps::kGridTrackBreadthKTable);
   val->GetCssText(argumentStr);
   minmaxStr.Append(argumentStr);
 
   minmaxStr.Append(char16_t(')'));
   val->SetString(minmaxStr);
   return val.forget();
 }
 
@@ -3587,17 +3590,17 @@ nsComputedDOMStyle::DoGetLineHeight()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscoord lineHeight;
   if (GetLineHeightCoord(lineHeight)) {
     val->SetAppUnits(lineHeight);
   } else {
     SetValueToCoord(val, StyleText()->mLineHeight, true,
-                    nullptr, nsCSSProps::kLineHeightKTable);
+                    nullptr, nullptr, nsCSSProps::kLineHeightKTable);
   }
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetRubyAlign()
 {
@@ -3616,16 +3619,17 @@ nsComputedDOMStyle::DoGetRubyPosition()
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetVerticalAlign()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleDisplay()->mVerticalAlign, false,
+                  this,
                   &nsComputedDOMStyle::GetLineHeightCoord,
                   nsCSSProps::kVerticalAlignKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
                                          const KTableEntry aTable[])
@@ -3835,17 +3839,17 @@ nsComputedDOMStyle::DoGetTextEmphasisSty
   valueList->AppendCSSValue(shapeVal.forget());
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextIndent()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetValueToCoord(val, StyleText()->mTextIndent, false,
+  SetValueToCoord(val, StyleText()->mTextIndent, false, this,
                   &nsComputedDOMStyle::GetCBContentWidth);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextOrientation()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
@@ -4204,31 +4208,31 @@ nsComputedDOMStyle::DoGetBoxSizing()
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageSource()
 {
   const nsStyleBorder* border = StyleBorder();
 
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   const nsStyleImage& image = border->mBorderImageSource;
-  SetValueToStyleImage(image, val);
+  mozilla::SetValueToStyleImage(image, val);
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageSlice()
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   const nsStyleBorder* border = StyleBorder();
   // Four slice numbers.
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
+    SetValueToCoord(val, border->mBorderImageSlice.Get(side), true);
     valueList->AppendCSSValue(val.forget());
   }
 
   // Fill keyword.
   if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_fill);
     valueList->AppendCSSValue(val.forget());
@@ -4240,34 +4244,34 @@ nsComputedDOMStyle::DoGetBorderImageSlic
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageWidth()
 {
   const nsStyleBorder* border = StyleBorder();
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, border->mBorderImageWidth.Get(side),
-                    true, nullptr);
+                    true);
     valueList->AppendCSSValue(val.forget());
   }
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageOutset()
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   const nsStyleBorder* border = StyleBorder();
   // four slice numbers
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, border->mBorderImageOutset.Get(side),
-                    true, nullptr);
+                    true);
     valueList->AppendCSSValue(val.forget());
   }
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageRepeat()
@@ -4304,17 +4308,17 @@ nsComputedDOMStyle::DoGetFlexBasis()
   //     if (my flex container is horizontal) {
   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
   //     } else {
   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
   //     }
   //   }
 
   SetValueToCoord(val, StylePosition()->mFlexBasis, true,
-                  nullptr, nsCSSProps::kWidthKTable);
+                  nullptr, nullptr, nsCSSProps::kWidthKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexDirection()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
@@ -4786,17 +4790,17 @@ nsComputedDOMStyle::DoGetHeight()
       StyleCoordToNSCoord(positionData->mMinHeight,
                           &nsComputedDOMStyle::GetCBContentHeight, 0, true);
 
     nscoord maxHeight =
       StyleCoordToNSCoord(positionData->mMaxHeight,
                           &nsComputedDOMStyle::GetCBContentHeight,
                           nscoord_MAX, true);
 
-    SetValueToCoord(val, positionData->mHeight, true, nullptr,
+    SetValueToCoord(val, positionData->mHeight, true, nullptr, nullptr,
                     nsCSSProps::kWidthKTable, minHeight, maxHeight);
   }
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWidth()
@@ -4830,38 +4834,38 @@ nsComputedDOMStyle::DoGetWidth()
       StyleCoordToNSCoord(positionData->mMinWidth,
                           &nsComputedDOMStyle::GetCBContentWidth, 0, true);
 
     nscoord maxWidth =
       StyleCoordToNSCoord(positionData->mMaxWidth,
                           &nsComputedDOMStyle::GetCBContentWidth,
                           nscoord_MAX, true);
 
-    SetValueToCoord(val, positionData->mWidth, true, nullptr,
+    SetValueToCoord(val, positionData->mWidth, true, nullptr, nullptr,
                     nsCSSProps::kWidthKTable, minWidth, maxWidth);
   }
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMaxHeight()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetValueToCoord(val, StylePosition()->mMaxHeight, true,
+  SetValueToCoord(val, StylePosition()->mMaxHeight, true, this,
                   &nsComputedDOMStyle::GetCBContentHeight,
                   nsCSSProps::kWidthKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMaxWidth()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetValueToCoord(val, StylePosition()->mMaxWidth, true,
+  SetValueToCoord(val, StylePosition()->mMaxWidth, true, this,
                   &nsComputedDOMStyle::GetCBContentWidth,
                   nsCSSProps::kWidthKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMinHeight()
 {
@@ -4871,17 +4875,17 @@ nsComputedDOMStyle::DoGetMinHeight()
   if (eStyleUnit_Auto == minHeight.GetUnit()) {
     // In non-flexbox contexts, "min-height: auto" means "min-height: 0"
     // XXXdholbert For flex items, we should set |minHeight| to the
     // -moz-min-content keyword, instead of 0, once we support -moz-min-content
     // as a height value.
     minHeight.SetCoordValue(0);
   }
 
-  SetValueToCoord(val, minHeight, true,
+  SetValueToCoord(val, minHeight, true, this,
                   &nsComputedDOMStyle::GetCBContentHeight,
                   nsCSSProps::kWidthKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMinWidth()
 {
@@ -4899,17 +4903,17 @@ nsComputedDOMStyle::DoGetMinWidth()
                  flexContainer->GetType() == nsGkAtoms::flexContainerFrame,
                  "IsFlexItem() lied...?");
 
       if (static_cast<nsFlexContainerFrame*>(flexContainer)->IsHorizontal()) {
         minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT, eStyleUnit_Enumerated);
       }
     }
   }
-  SetValueToCoord(val, minWidth, true,
+  SetValueToCoord(val, minWidth, true, this,
                   &nsComputedDOMStyle::GetCBContentWidth,
                   nsCSSProps::kWidthKTable);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMixBlendMode()
 {
@@ -4958,17 +4962,17 @@ nsComputedDOMStyle::DoGetRight()
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTop()
 {
   return GetOffsetWidthFor(NS_SIDE_TOP);
 }
 
-nsDOMCSSValueList*
+/* static */ nsDOMCSSValueList*
 nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
 {
   return new nsDOMCSSValueList(aCommaDelimited, true);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
 {
@@ -5271,41 +5275,47 @@ nsComputedDOMStyle::GetBorderStyleFor(mo
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
                                    nsCSSProps::kBorderStyleKTable));
   return val.forget();
 }
 
-void
+/* static */ void
 nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
                                     const nsStyleCoord& aCoord,
                                     bool aClampNegativeCalc,
+                                    nsComputedDOMStyle*
+                                      aPercentageBaseGetterThis,
                                     PercentageBaseGetter aPercentageBaseGetter,
                                     const KTableEntry aTable[],
                                     nscoord aMinAppUnits,
                                     nscoord aMaxAppUnits)
 {
   NS_PRECONDITION(aValue, "Must have a value to work with");
+  MOZ_ASSERT(!aPercentageBaseGetterThis == !aPercentageBaseGetter,
+             "Must either have both aPercentageBaseGetterThis and "
+             "aPercentageBaseGetter or neither.");
 
   switch (aCoord.GetUnit()) {
     case eStyleUnit_Normal:
       aValue->SetIdent(eCSSKeyword_normal);
       break;
 
     case eStyleUnit_Auto:
       aValue->SetIdent(eCSSKeyword_auto);
       break;
 
     case eStyleUnit_Percent:
       {
         nscoord percentageBase;
         if (aPercentageBaseGetter &&
-            (this->*aPercentageBaseGetter)(percentageBase)) {
+            (aPercentageBaseGetterThis->*aPercentageBaseGetter)(percentageBase))
+        {
           nscoord val = NSCoordSaturatingMultiply(percentageBase,
                                                   aCoord.GetPercentValue());
           aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
         } else {
           aValue->SetPercent(aCoord.GetPercentValue());
         }
       }
       break;
@@ -5341,17 +5351,18 @@ nsComputedDOMStyle::SetValueToCoord(nsRO
         nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
         if (aClampNegativeCalc && val < 0) {
           MOZ_ASSERT(aCoord.IsCalcUnit(),
                      "parser should have rejected value");
           val = 0;
         }
         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
       } else if (aPercentageBaseGetter &&
-                 (this->*aPercentageBaseGetter)(percentageBase)) {
+                 (aPercentageBaseGetterThis->*aPercentageBaseGetter)
+                   (percentageBase)) {
         nscoord val =
           nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
         if (aClampNegativeCalc && val < 0) {
           MOZ_ASSERT(aCoord.IsCalcUnit(),
                      "parser should have rejected value");
           val = 0;
         }
         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
@@ -5955,17 +5966,17 @@ nsComputedDOMStyle::CreatePrimitiveValue
       const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
       MOZ_ASSERT(radii.Length() ==
                  (type == StyleBasicShapeType::Circle ? 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,
+        SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr, nullptr,
                         nsCSSProps::kShapeRadiusKTable);
         value->GetCssText(radius);
         shapeFunctionString.Append(radius);
         shapeFunctionString.Append(' ');
       }
       shapeFunctionString.AppendLiteral("at ");
 
       RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -16,16 +16,17 @@
 #include "nsCSSProps.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsStyleContext.h"
 #include "nsIWeakReferenceUtils.h"
 #include "mozilla/gfx/Types.h"
 #include "nsCoord.h"
 #include "nsColor.h"
 #include "nsIContent.h"
+#include "nsStyleImage.h"
 #include "nsStyleStruct.h"
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 struct ComputedGridTrackInfo;
 } // namespace mozilla
@@ -39,16 +40,21 @@ class nsROCSSPrimitiveValue;
 class nsStyleCoord;
 class nsStyleCorners;
 struct nsStyleFilter;
 class nsStyleGradient;
 struct nsStyleImage;
 class nsStyleSides;
 struct nsTimingFunction;
 
+namespace mozilla {
+void SetValueToStyleImage(const nsStyleImage& aStyleImage,
+                          nsROCSSPrimitiveValue* aValue);
+} // namespace mozilla
+
 class nsComputedDOMStyle final : public nsDOMCSSDeclaration
                                , public nsStubMutationObserver
 {
 private:
   // Convenience typedefs:
   typedef nsCSSProps::KTableEntry KTableEntry;
   typedef mozilla::dom::CSSValue CSSValue;
 
@@ -202,21 +208,28 @@ private:
                                                bool aIsBoxShadow);
 
   already_AddRefed<CSSValue> GetBackgroundList(
     uint8_t nsStyleImageLayers::Layer::* aMember,
     uint32_t nsStyleImageLayers::* aCount,
     const nsStyleImageLayers& aLayers,
     const KTableEntry aTable[]);
 
-  void GetCSSGradientString(const nsStyleGradient* aGradient,
-                            nsAString& aString);
-  void GetImageRectString(nsIURI* aURI,
-                          const nsStyleSides& aCropRect,
-                          nsString& aString);
+  // SetValueToStyleImage uses GetCSSGradientString and GetImageRectString. We
+  // would make it a private member function except that it's used by
+  // CSSComputedValue, which has a member function called by this class, and we
+  // can't forward-declare member functions.
+  friend void mozilla::SetValueToStyleImage(const nsStyleImage& aStyleImage,
+                                            nsROCSSPrimitiveValue* aValue);
+
+  static void GetCSSGradientString(const nsStyleGradient* aGradient,
+                                   nsAString& aString);
+  static void GetImageRectString(nsIURI* aURI,
+                                 const nsStyleSides& aCropRect,
+                                 nsString& aString);
   already_AddRefed<CSSValue> GetScrollSnapPoints(const nsStyleCoord& aCoord);
   void AppendTimingFunction(nsDOMCSSValueList *aValueList,
                             const nsTimingFunction& aTimingFunction);
 
   /* Properties queryable as CSSValues.
    * To avoid a name conflict with nsIDOM*CSS2Properties, these are all
    * DoGetXXX instead of GetXXX.
    */
@@ -574,57 +587,61 @@ private:
   already_AddRefed<CSSValue> DoGetClipPath();
   already_AddRefed<CSSValue> DoGetFilter();
   already_AddRefed<CSSValue> DoGetMaskType();
   already_AddRefed<CSSValue> DoGetPaintOrder();
 
   /* Custom properties */
   already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);
 
-  nsDOMCSSValueList* GetROCSSValueList(bool aCommaDelimited);
+  static nsDOMCSSValueList* GetROCSSValueList(bool aCommaDelimited);
 
   /* Helper functions */
-  void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
-  void SetValueToStyleImage(const nsStyleImage& aStyleImage,
-                            nsROCSSPrimitiveValue* aValue);
+  static void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
   void SetValueToPositionCoord(
     const nsStyleImageLayers::Position::PositionCoord& aCoord,
     nsROCSSPrimitiveValue* aValue);
   void SetValueToPosition(const nsStyleImageLayers::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
   void SetValueToFragmentOrURL(const FragmentOrURL* aFragmentOrURL,
                                nsROCSSPrimitiveValue* aValue);
 
   /**
    * 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&);
 
   /**
    * Method to set aValue to aCoord.  If aCoord is a percentage value and
-   * aPercentageBaseGetter is not null, aPercentageBaseGetter is called.  If it
-   * returns true, the percentage base it outputs in its out param is used
-   * to compute an nscoord value.  If the getter is null or returns false,
-   * the percent value of aCoord is set as a percent value on aValue.  aTable,
-   * if not null, is the keyword table to handle eStyleUnit_Enumerated.  When
-   * calling SetAppUnits on aValue (for coord or percent values), the value
-   * passed in will be clamped to be no less than aMinAppUnits and no more than
-   * aMaxAppUnits.
+   * aPercentageBaseGetter is not null, aPercentageBaseGetter is called.
+   * If aPercentageBaseGetter is provided, you must also supply
+   * aPercentageBaseGetterThis, as the object to call aPercentageBaseGetter on.
+   * (We don't just use |this| because we want to call this method from static
+   * functions that don't supply aPercentageBaseGetter.)  If
+   * aPercentageBaseGetter returns true, the percentage base it outputs in its
+   * out param is used to compute an nscoord value.  If the getter is null or
+   * returns false, the percent value of aCoord is set as a percent value on
+   * aValue.  aTable, if not null, is the keyword table to handle
+   * eStyleUnit_Enumerated.  When calling SetAppUnits on aValue (for coord or
+   * percent values), the value passed in will be clamped to be no less than
+   * aMinAppUnits and no more than aMaxAppUnits.
    *
    * XXXbz should caller pass in some sort of bitfield indicating which units
    * can be expected or something?
    */
-  void SetValueToCoord(nsROCSSPrimitiveValue* aValue,
-                       const nsStyleCoord& aCoord,
-                       bool aClampNegativeCalc,
-                       PercentageBaseGetter aPercentageBaseGetter = nullptr,
-                       const KTableEntry aTable[] = nullptr,
-                       nscoord aMinAppUnits = nscoord_MIN,
-                       nscoord aMaxAppUnits = nscoord_MAX);
+  static void SetValueToCoord(nsROCSSPrimitiveValue* aValue,
+                              const nsStyleCoord& aCoord,
+                              bool aClampNegativeCalc,
+                              nsComputedDOMStyle* aPercentageBaseGetterThis =
+                                nullptr,
+                              PercentageBaseGetter aPercentageBaseGetter = nullptr,
+                              const KTableEntry aTable[] = nullptr,
+                              nscoord aMinAppUnits = nscoord_MIN,
+                              nscoord aMaxAppUnits = nscoord_MAX);
 
   /**
    * If aCoord is a eStyleUnit_Coord returns the nscoord.  If it's
    * eStyleUnit_Percent, attempts to resolve the percentage base and returns
    * the resulting nscoord.  If it's some other unit or a percentge base can't
    * be determined, returns aDefaultValue.
    */
   nscoord StyleCoordToNSCoord(const nsStyleCoord& aCoord,