Bug 1334330 - Part 2: stylo: Use GenericSpecifiedValue abstraction in nsGenericHTMLElement; r?emilio draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 26 Jan 2017 16:51:01 -0800
changeset 480657 aa2347ccb61cd1276d3fa063e707b5a1c8f19041
parent 480656 d3474f8a1d82af7c5c3e74f61637a2548245e266
child 480658 8280480ebf376c44b576ca5d0adff10712335740
push id44619
push userbmo:manishearth@gmail.com
push dateWed, 08 Feb 2017 19:34:01 +0000
reviewersemilio
bugs1334330
milestone54.0a1
Bug 1334330 - Part 2: stylo: Use GenericSpecifiedValue abstraction in nsGenericHTMLElement; r?emilio MozReview-Commit-ID: 7Njz7pUkgft
dom/html/nsGenericHTMLElement.cpp
layout/style/GenericSpecifiedValues.h
layout/style/nsRuleData.h
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1201,93 +1201,87 @@ nsGenericHTMLElement::ParseFrameborderVa
 bool
 nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
                                           nsAttrValue& aResult)
 {
   return aResult.ParseEnumValue(aString, kScrollingTable, false);
 }
 
 static inline void
-MapLangAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aGenericData)
+MapLangAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & (NS_STYLE_INHERIT_BIT(Font) |
-                        NS_STYLE_INHERIT_BIT(Text)))) {
+  if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font) |
+                                       NS_STYLE_INHERIT_BIT(Text))) {
     return;
   }
 
   const nsAttrValue* langValue = aAttributes->GetAttr(nsGkAtoms::lang);
   if (!langValue || langValue->Type() != nsAttrValue::eString) {
     return;
   }
 
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
-    nsCSSValue* lang = aData->ValueForLang();
-    if (lang->GetUnit() == eCSSUnit_Null) {
-      lang->SetStringValue(langValue->GetStringValue(), eCSSUnit_Ident);
-    }
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font))) {
+    aData->SetIdentStringValueIfUnset(eCSSProperty__x_lang,
+                                      langValue->GetStringValue());
   }
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
-    nsCSSValue* emphasisPos = aData->ValueForTextEmphasisPosition();
-    if (emphasisPos->GetUnit() == eCSSUnit_Null) {
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
+    if (!aData->PropertyIsSet(eCSSProperty_text_emphasis_position)) {
       const nsAString& lang = langValue->GetStringValue();
       if (nsStyleUtil::MatchesLanguagePrefix(lang, u"zh")) {
-        emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH,
-                                eCSSUnit_Enumerated);
+        aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
+                               NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH);
       } else if (nsStyleUtil::MatchesLanguagePrefix(lang, u"ja") ||
                  nsStyleUtil::MatchesLanguagePrefix(lang, u"mn")) {
         // This branch is currently no part of the spec.
         // See bug 1040668 comment 69 and comment 75.
-        emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT,
-                                eCSSUnit_Enumerated);
+        aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
+                               NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT);
       }
     }
   }
 }
 
 /**
  * Handle attributes common to all html elements
  */
 void
 nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(const nsMappedAttributes* aAttributes,
-                                                          GenericSpecifiedValues* aGenericData)
+                                                          GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(UserInterface)) {
-    nsCSSValue* userModify = aData->ValueForUserModify();
-    if (userModify->GetUnit() == eCSSUnit_Null) {
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(UserInterface))) {
+    if (!aData->PropertyIsSet(eCSSProperty__moz_user_modify)) {
       const nsAttrValue* value =
         aAttributes->GetAttr(nsGkAtoms::contenteditable);
       if (value) {
         if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
             value->Equals(nsGkAtoms::_true, eIgnoreCase)) {
-          userModify->SetEnumValue(StyleUserModify::ReadWrite);
+          aData->SetKeywordValue(eCSSProperty__moz_user_modify,
+                                 StyleUserModify::ReadWrite);
         }
         else if (value->Equals(nsGkAtoms::_false, eIgnoreCase)) {
-            userModify->SetEnumValue(StyleUserModify::ReadOnly);
+            aData->SetKeywordValue(eCSSProperty__moz_user_modify,
+                                   StyleUserModify::ReadOnly);
         }
       }
     }
   }
 
   MapLangAttributeInto(aAttributes, aData);
 }
 
 void
 nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
-                                              GenericSpecifiedValues* aGenericData)
+                                              GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
   MapCommonAttributesIntoExceptHidden(aAttributes, aData);
 
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
-    nsCSSValue* display = aData->ValueForDisplay();
-    if (display->GetUnit() == eCSSUnit_Null) {
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
+    if (!aData->PropertyIsSet(eCSSProperty_display)) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
-        display->SetEnumValue(StyleDisplay::None);
+        aData->SetKeywordValue(eCSSProperty_display, StyleDisplay::None);
       }
     }
   }
 }
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
@@ -1333,251 +1327,228 @@ nsGenericHTMLElement::sBackgroundAttribu
 /* static */ const Element::MappedAttributeEntry
 nsGenericHTMLElement::sBackgroundColorAttributeMap[] = {
   { &nsGkAtoms::bgcolor },
   { nullptr }
 };
 
 void
 nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                                 GenericSpecifiedValues* aGenericData)
+                                                 GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
     if (value && value->Type() == nsAttrValue::eEnum) {
       int32_t align = value->GetEnumValue();
-      nsCSSValue* cssFloat = aData->ValueForFloat();
-      if (cssFloat->GetUnit() == eCSSUnit_Null) {
+      if (!aData->PropertyIsSet(eCSSProperty_float_)) {
         if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
-          cssFloat->SetEnumValue(StyleFloat::Left);
+          aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Left);
         } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
-          cssFloat->SetEnumValue(StyleFloat::Right);
+          aData->SetKeywordValue(eCSSProperty_float_, StyleFloat::Right);
         }
       }
-      nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
-      if (verticalAlign->GetUnit() == eCSSUnit_Null) {
+      if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
         switch (align) {
         case NS_STYLE_TEXT_ALIGN_LEFT:
         case NS_STYLE_TEXT_ALIGN_RIGHT:
           break;
         default:
-          verticalAlign->SetIntValue(align, eCSSUnit_Enumerated);
+          aData->SetKeywordValue(eCSSProperty_vertical_align, align);
           break;
         }
       }
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                               GenericSpecifiedValues* aGenericData)
+                                               GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
-    nsCSSValue* textAlign = aData->ValueForTextAlign();
-    if (textAlign->GetUnit() == eCSSUnit_Null) {
+  if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
+    if (!aData->PropertyIsSet(eCSSProperty_text_align)) {
       // align: enum
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
       if (value && value->Type() == nsAttrValue::eEnum)
-        textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
+        aData->SetKeywordValue(eCSSProperty_text_align, value->GetEnumValue());
     }
   }
 }
 
 
 void
 nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aGenericData)
+                                                  GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)))
+  if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Margin)))
     return;
 
   const nsAttrValue* value;
 
   // hspace: value
   value = aAttributes->GetAttr(nsGkAtoms::hspace);
   if (value) {
-    nsCSSValue hval;
-    if (value->Type() == nsAttrValue::eInteger)
-      hval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
-    else if (value->Type() == nsAttrValue::ePercent)
-      hval.SetPercentValue(value->GetPercentValue());
-
-    if (hval.GetUnit() != eCSSUnit_Null) {
-      nsCSSValue* left = aData->ValueForMarginLeft();
-      if (left->GetUnit() == eCSSUnit_Null)
-        *left = hval;
-      nsCSSValue* right = aData->ValueForMarginRight();
-      if (right->GetUnit() == eCSSUnit_Null)
-        *right = hval;
+    if (value->Type() == nsAttrValue::eInteger) {
+      aData->SetPixelValueIfUnset(eCSSProperty_margin_left,
+                                  (float)value->GetIntegerValue());
+      aData->SetPixelValueIfUnset(eCSSProperty_margin_right,
+                                  (float)value->GetIntegerValue());
+    } else if (value->Type() == nsAttrValue::ePercent) {
+      aData->SetPercentValueIfUnset(eCSSProperty_margin_left,
+                                    value->GetPercentValue());
+      aData->SetPercentValueIfUnset(eCSSProperty_margin_right,
+                                    value->GetPercentValue());
     }
   }
 
   // vspace: value
   value = aAttributes->GetAttr(nsGkAtoms::vspace);
   if (value) {
-    nsCSSValue vval;
-    if (value->Type() == nsAttrValue::eInteger)
-      vval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
-    else if (value->Type() == nsAttrValue::ePercent)
-      vval.SetPercentValue(value->GetPercentValue());
-  
-    if (vval.GetUnit() != eCSSUnit_Null) {
-      nsCSSValue* top = aData->ValueForMarginTop();
-      if (top->GetUnit() == eCSSUnit_Null)
-        *top = vval;
-      nsCSSValue* bottom = aData->ValueForMarginBottom();
-      if (bottom->GetUnit() == eCSSUnit_Null)
-        *bottom = vval;
+    if (value->Type() == nsAttrValue::eInteger) {
+      aData->SetPixelValueIfUnset(eCSSProperty_margin_top,
+                                  (float)value->GetIntegerValue());
+      aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom,
+                                  (float)value->GetIntegerValue());
+    } else if (value->Type() == nsAttrValue::ePercent) {
+      aData->SetPercentValueIfUnset(eCSSProperty_margin_top,
+                                    value->GetPercentValue());
+      aData->SetPercentValueIfUnset(eCSSProperty_margin_bottom,
+                                    value->GetPercentValue());
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
-                                                 GenericSpecifiedValues* aGenericData)
+                                                 GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)))
+  if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Position)))
     return;
 
   // width: value
-  nsCSSValue* width = aData->ValueForWidth();
-  if (width->GetUnit() == eCSSUnit_Null) {
+  if (!aData->PropertyIsSet(eCSSProperty_width)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
-    if (value && value->Type() == nsAttrValue::eInteger)
-      width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
-    else if (value && value->Type() == nsAttrValue::ePercent)
-      width->SetPercentValue(value->GetPercentValue());
+    if (value && value->Type() == nsAttrValue::eInteger) {
+      aData->SetPixelValue(eCSSProperty_width,
+                           (float)value->GetIntegerValue());
+    } else if (value && value->Type() == nsAttrValue::ePercent) {
+      aData->SetPercentValue(eCSSProperty_width,
+                             value->GetPercentValue());
+    }
   }
 
   // height: value
-  nsCSSValue* height = aData->ValueForHeight();
-  if (height->GetUnit() == eCSSUnit_Null) {
+  if (!aData->PropertyIsSet(eCSSProperty_height)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
-    if (value && value->Type() == nsAttrValue::eInteger)
-      height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel); 
-    else if (value && value->Type() == nsAttrValue::ePercent)
-      height->SetPercentValue(value->GetPercentValue());
+    if (value && value->Type() == nsAttrValue::eInteger) {
+      aData->SetPixelValue(eCSSProperty_height,
+                           (float)value->GetIntegerValue());
+    } else if (value && value->Type() == nsAttrValue::ePercent) {
+      aData->SetPercentValue(eCSSProperty_height,
+                             value->GetPercentValue());
+    }
   }
 }
 
 void
 nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aGenericData)
+                                                  GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)))
+  if (!(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Border))))
     return;
 
   // border: pixels
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
   if (!value)
     return;
   
   nscoord val = 0;
   if (value->Type() == nsAttrValue::eInteger)
     val = value->GetIntegerValue();
 
-  nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
-  if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
-    borderLeftWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
-  nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
-  if (borderTopWidth->GetUnit() == eCSSUnit_Null)
-    borderTopWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
-  nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
-  if (borderRightWidth->GetUnit() == eCSSUnit_Null)
-    borderRightWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
-  nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
-  if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
-    borderBottomWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
-
-  nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyle();
-  if (borderLeftStyle->GetUnit() == eCSSUnit_Null)
-    borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
-  nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
-  if (borderTopStyle->GetUnit() == eCSSUnit_Null)
-    borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
-  nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyle();
-  if (borderRightStyle->GetUnit() == eCSSUnit_Null)
-    borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
-  nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
-  if (borderBottomStyle->GetUnit() == eCSSUnit_Null)
-    borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
-
-  nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColor();
-  if (borderLeftColor->GetUnit() == eCSSUnit_Null)
-    borderLeftColor->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
-  nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
-  if (borderTopColor->GetUnit() == eCSSUnit_Null)
-    borderTopColor->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
-  nsCSSValue* borderRightColor = aData->ValueForBorderRightColor();
-  if (borderRightColor->GetUnit() == eCSSUnit_Null)
-    borderRightColor->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
-  nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
-  if (borderBottomColor->GetUnit() == eCSSUnit_Null)
-    borderBottomColor->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
+  aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)val);
+  aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)val);
+  aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)val);
+  aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)val);
+
+  aData->SetKeywordValueIfUnset(eCSSProperty_border_top_style,
+                                NS_STYLE_BORDER_STYLE_SOLID);
+  aData->SetKeywordValueIfUnset(eCSSProperty_border_right_style,
+                                NS_STYLE_BORDER_STYLE_SOLID);
+  aData->SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
+                                NS_STYLE_BORDER_STYLE_SOLID);
+  aData->SetKeywordValueIfUnset(eCSSProperty_border_left_style,
+                                NS_STYLE_BORDER_STYLE_SOLID);
+
+  aData->SetCurrentColorIfUnset(eCSSProperty_border_top_color);
+  aData->SetCurrentColorIfUnset(eCSSProperty_border_right_color);
+  aData->SetCurrentColorIfUnset(eCSSProperty_border_bottom_color);
+  aData->SetCurrentColorIfUnset(eCSSProperty_border_left_color);
 }
 
 void
 nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aGenericData)
+                                        GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
+
+  if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
     return;
 
-  nsPresContext* presContext = aData->mPresContext;
-  nsCSSValue* backImage = aData->ValueForBackgroundImage();
-  if (backImage->GetUnit() == eCSSUnit_Null &&
+  nsPresContext* presContext = aData->PresContext();
+
+  if (!aData->PropertyIsSet(eCSSProperty_background_image) &&
       presContext->UseDocumentColors()) {
     // background
     nsAttrValue* value =
       const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
-    // If the value is an image, or it is a URL and we attempted a load,
-    // put it in the style tree.
     if (value) {
-      if (value->Type() == nsAttrValue::eURL) {
-        value->LoadImage(presContext->Document());
-      }
-      if (value->Type() == nsAttrValue::eImage) {
-        nsCSSValueList* list = backImage->SetListValue();
-        list->mValue.SetImageValue(value->GetImageValue());
+      nsRuleData* aRuleData = aData->AsRuleData();
+      // Gecko-specific code
+      // Gecko caches the image on the attr directly, but we need not
+      // do the same thing for Servo.
+      if (aRuleData) {
+        nsCSSValue* backImage = aRuleData->ValueForBackgroundImage();
+        // If the value is an image, or it is a URL and we attempted a load,
+        // put it in the style tree.
+        if (value->Type() == nsAttrValue::eURL) {
+          value->LoadImage(presContext->Document());
+        }
+        if (value->Type() == nsAttrValue::eImage) {
+          nsCSSValueList* list = backImage->SetListValue();
+          list->mValue.SetImageValue(value->GetImageValue());
+        }
+      } else {
+        // FIXME(bug 1330041)
+        MOZ_ASSERT_UNREACHABLE("stylo: cannot handle background");
       }
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
-                                     GenericSpecifiedValues* aGenericData)
+                                     GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
-  if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
+  if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
     return;
 
-  nsCSSValue* backColor = aData->ValueForBackgroundColor();
-  if (backColor->GetUnit() == eCSSUnit_Null &&
-      aData->mPresContext->UseDocumentColors()) {
+  if (!aData->PropertyIsSet(eCSSProperty_background_color) &&
+      aData->PresContext()->UseDocumentColors()) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
     nscolor color;
     if (value && value->GetColorValue(color)) {
-      backColor->SetColorValue(color);
+      aData->SetColorValue(eCSSProperty_background_color, color);
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aGenericData)
+                                                  GenericSpecifiedValues* aData)
 {
-  nsRuleData* aData = aGenericData->AsRuleData();
   MapBackgroundInto(aAttributes, aData);
   MapBGColorInto(aAttributes, aData);
 }
 
 //----------------------------------------------------------------------
 
 nsresult
 nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
--- a/layout/style/GenericSpecifiedValues.h
+++ b/layout/style/GenericSpecifiedValues.h
@@ -21,13 +21,57 @@ struct nsRuleData;
 
 // This provides a common interface for attribute mappers (MapAttributesIntoRule)
 // to use regardless of the style backend. If the style backend is Gecko,
 // this will contain an nsRuleData. If it is Servo, it will be a PropertyDeclarationBlock.
 class GenericSpecifiedValues {
 public:
     // Check if we already contain a certain longhand
     virtual bool PropertyIsSet(nsCSSPropertyID aId) = 0;
+    // Check if we are able to hold longhands from a given
+    // style struct. Pass the result of NS_STYLE_INHERIT_BIT to this
+    // function. Can accept multiple inherit bits or'd together.
+    virtual bool ShouldComputeStyleStruct(uint64_t aInheritBits) = 0;
+
+    virtual nsPresContext* PresContext() = 0;
+
+    // Set a property to an identifier (string)
+    virtual void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue) = 0;
+    virtual void SetIdentStringValueIfUnset(nsCSSPropertyID aId, const nsString& aValue) = 0;
+
+    // Set a property to a keyword (usually NS_STYLE_* or StyleFoo::*)
+    virtual void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue) = 0;
+    virtual void SetKeywordValueIfUnset(nsCSSPropertyID aId, int32_t aValue) = 0;
+
+    template<typename T,
+             typename = typename std::enable_if<std::is_enum<T>::value>::type>
+    void SetKeywordValue(nsCSSPropertyID aId, T aValue) {
+        static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
+                      "aValue must be an enum that fits within 32 bits");
+        SetKeywordValue(aId, static_cast<int32_t>(aValue));
+    }
+    template<typename T,
+             typename = typename std::enable_if<std::is_enum<T>::value>::type>
+    void SetKeywordValueIfUnset(nsCSSPropertyID aId, T aValue) {
+        static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
+                      "aValue must be an enum that fits within 32 bits");
+        SetKeywordValueIfUnset(aId, static_cast<int32_t>(aValue));
+    }
+
+    // Set a property to a pixel value
+    virtual void SetPixelValue(nsCSSPropertyID aId, float aValue) = 0;
+    virtual void SetPixelValueIfUnset(nsCSSPropertyID aId, float aValue) = 0;
+
+    // Set a property to a percent value
+    virtual void SetPercentValue(nsCSSPropertyID aId, float aValue) = 0;
+    virtual void SetPercentValueIfUnset(nsCSSPropertyID aId, float aValue) = 0;
+
+    // Set a property to `currentcolor`
+    virtual void SetCurrentColor(nsCSSPropertyID aId) = 0;
+    virtual void SetCurrentColorIfUnset(nsCSSPropertyID aId) = 0;
+
+    // Set a property to an RGBA nscolor value
+    virtual void SetColorValue(nsCSSPropertyID aId, nscolor aValue) = 0;
 
     virtual nsRuleData* AsRuleData() = 0;
 };
 
 #endif // mozilla_GenericSpecifiedValues_h
\ No newline at end of file
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -121,16 +121,87 @@ struct nsRuleData final: GenericSpecifie
   #undef CSS_PROP
   #undef CSS_PROP_PUBLIC_OR_PRIVATE
 
   // GenericSpecifiedValues overrides
   bool PropertyIsSet(nsCSSPropertyID aId) override {
     return ValueFor(aId)->GetUnit() != eCSSUnit_Null;
   }
 
+  bool ShouldComputeStyleStruct(uint64_t aInheritBits) override {
+    return mSIDs & aInheritBits;
+  }
+
+  nsPresContext* PresContext() override {
+    return mPresContext;
+  }
+
+  void SetIdentStringValue(nsCSSPropertyID aId,
+                           const nsString& aValue) override {
+    ValueFor(aId)->SetStringValue(aValue, eCSSUnit_Ident);
+  }
+
+  void SetIdentStringValueIfUnset(nsCSSPropertyID aId,
+                                const nsString& aValue) override {
+    if (!PropertyIsSet(aId)) {
+      SetIdentStringValue(aId, aValue);
+    }
+  }
+
+  void SetKeywordValue(nsCSSPropertyID aId,
+                       int32_t aValue) override {
+    ValueFor(aId)->SetIntValue(aValue, eCSSUnit_Enumerated);
+  }
+
+  void SetKeywordValueIfUnset(nsCSSPropertyID aId,
+                              int32_t aValue) override {
+    if (!PropertyIsSet(aId)) {
+      SetKeywordValue(aId, aValue);
+    }
+  }
+
+  void SetPixelValue(nsCSSPropertyID aId,
+                     float aValue) override {
+    ValueFor(aId)->SetFloatValue(aValue, eCSSUnit_Pixel);
+  }
+
+  void SetPixelValueIfUnset(nsCSSPropertyID aId,
+                            float aValue) override {
+    if (!PropertyIsSet(aId)) {
+      SetPixelValue(aId, aValue);
+    }
+  }
+
+  void SetPercentValue(nsCSSPropertyID aId,
+                       float aValue) override {
+    ValueFor(aId)->SetPercentValue(aValue);
+  }
+
+  void SetPercentValueIfUnset(nsCSSPropertyID aId,
+                              float aValue) override {
+    if (!PropertyIsSet(aId)) {
+      SetPercentValue(aId, aValue);
+    }
+  }
+
+  void SetCurrentColor(nsCSSPropertyID aId) override {
+    ValueFor(aId)->SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
+  }
+
+  void SetCurrentColorIfUnset(nsCSSPropertyID aId) override {
+    if (!PropertyIsSet(aId)) {
+      SetCurrentColor(aId);
+    }
+  }
+
+  void SetColorValue(nsCSSPropertyID aId,
+                     nscolor aValue) override {
+    ValueFor(aId)->SetColorValue(aValue);
+  }
+
   nsRuleData* AsRuleData() override {
     return this;
   }
 
 private:
   inline size_t GetPoisonOffset();
 
 };