Bug 1428339: Make attribute mapping work without a pres context. r?heycam draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 05 Jan 2018 13:47:04 +0100
changeset 717761 55d255b8e7899d19a1f4367796ad945ed6a4c3a9
parent 717738 6f5fac320fcb6625603fa8a744ffa8523f8b3d71
child 717762 26900b7289a6cf88da18c82748c85501d26bb0e6
push id94763
push userbmo:emilio@crisal.io
push dateTue, 09 Jan 2018 14:08:16 +0000
reviewersheycam
bugs1428339
milestone59.0a1
Bug 1428339: Make attribute mapping work without a pres context. r?heycam MozReview-Commit-ID: FisYWoArX0N
dom/base/nsMappedAttributes.cpp
dom/base/nsMappedAttributes.h
dom/html/HTMLBodyElement.cpp
dom/html/HTMLFontElement.cpp
dom/html/HTMLHRElement.cpp
dom/html/HTMLTableCellElement.cpp
dom/html/HTMLTableElement.cpp
dom/html/nsGenericHTMLElement.cpp
dom/mathml/nsMathMLElement.cpp
layout/style/GenericSpecifiedValues.h
layout/style/GenericSpecifiedValuesInlines.h
layout/style/ServoSpecifiedValues.cpp
layout/style/ServoSpecifiedValues.h
layout/style/ServoStyleSet.cpp
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsHTMLStyleSheet.h
layout/style/nsRuleData.cpp
layout/style/nsRuleData.h
layout/style/nsRuleNode.cpp
--- a/dom/base/nsMappedAttributes.cpp
+++ b/dom/base/nsMappedAttributes.cpp
@@ -355,19 +355,19 @@ nsMappedAttributes::SizeOfIncludingThis(
   size_t n = aMallocSizeOf(this);
   for (uint16_t i = 0; i < mAttrCount; ++i) {
     n += Attrs()[i].mValue.SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
 void
-nsMappedAttributes::LazilyResolveServoDeclaration(nsPresContext* aContext)
+nsMappedAttributes::LazilyResolveServoDeclaration(nsIDocument* aDoc)
 {
 
   MOZ_ASSERT(!mServoStyle,
              "LazilyResolveServoDeclaration should not be called if mServoStyle is already set");
   if (mRuleMapper) {
     mServoStyle = Servo_DeclarationBlock_CreateEmpty().Consume();
-    ServoSpecifiedValues servo = ServoSpecifiedValues(aContext, mServoStyle.get());
+    ServoSpecifiedValues servo = ServoSpecifiedValues(aDoc, mServoStyle.get());
     (*mRuleMapper)(this, &servo);
   }
 }
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -70,17 +70,17 @@ public:
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   void RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue);
   const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
   int32_t IndexOfAttr(nsAtom* aLocalName) const;
 
   // Apply the contained mapper to the contained set of servo rules,
   // unless the servo rules have already been initialized.
-  void LazilyResolveServoDeclaration(nsPresContext* aPresContext);
+  void LazilyResolveServoDeclaration(nsIDocument* aDocument);
 
   // Obtain the contained servo declaration block
   // May return null if called before the inner block
   // has been (lazily) resolved
   const RefPtr<RawServoDeclarationBlock>& GetServoStyle() const
   {
     return mServoStyle;
   }
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -162,17 +162,17 @@ HTMLBodyElement::MapAttributesIntoRule(c
         }
         aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)bodyRightMargin);
       }
     }
 
     // if marginwidth or marginheight is set in the <frame> and not set in the <body>
     // reflect them as margin in the <body>
     if (bodyMarginWidth == -1 || bodyMarginHeight == -1) {
-      nsCOMPtr<nsIDocShell> docShell(aData->mPresContext->GetDocShell());
+      nsCOMPtr<nsIDocShell> docShell(aData->Document()->GetDocShell());
       if (docShell) {
         nscoord frameMarginWidth=-1;  // default value
         nscoord frameMarginHeight=-1; // default value
         docShell->GetMarginWidth(&frameMarginWidth); // -1 indicates not set
         docShell->GetMarginHeight(&frameMarginHeight);
 
         if (bodyMarginWidth == -1 && frameMarginWidth >= 0) {
           if (bodyLeftMargin == -1) {
@@ -192,51 +192,45 @@ HTMLBodyElement::MapAttributesIntoRule(c
           }
         }
       }
     }
   }
 
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))) {
     // When display if first asked for, go ahead and get our colors set up.
-    nsIPresShell *presShell = aData->PresContext()->GetPresShell();
-    if (presShell) {
-      nsIDocument *doc = presShell->GetDocument();
-      if (doc) {
-        nsHTMLStyleSheet* styleSheet = doc->GetAttributeStyleSheet();
-        if (styleSheet) {
-          const nsAttrValue* value;
-          nscolor color;
-          value = aAttributes->GetAttr(nsGkAtoms::link);
-          if (value && value->GetColorValue(color)) {
-            styleSheet->SetLinkColor(color);
-          }
+    if (nsHTMLStyleSheet* styleSheet = aData->Document()->GetAttributeStyleSheet()) {
+      const nsAttrValue* value;
+      nscolor color;
+      value = aAttributes->GetAttr(nsGkAtoms::link);
+      if (value && value->GetColorValue(color)) {
+        styleSheet->SetLinkColor(color);
+      }
 
-          value = aAttributes->GetAttr(nsGkAtoms::alink);
-          if (value && value->GetColorValue(color)) {
-            styleSheet->SetActiveLinkColor(color);
-          }
+      value = aAttributes->GetAttr(nsGkAtoms::alink);
+      if (value && value->GetColorValue(color)) {
+        styleSheet->SetActiveLinkColor(color);
+      }
 
-          value = aAttributes->GetAttr(nsGkAtoms::vlink);
-          if (value && value->GetColorValue(color)) {
-            styleSheet->SetVisitedLinkColor(color);
-          }
-        }
+      value = aAttributes->GetAttr(nsGkAtoms::vlink);
+      if (value && value->GetColorValue(color)) {
+        styleSheet->SetVisitedLinkColor(color);
       }
     }
   }
 
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
     if (!aData->PropertyIsSet(eCSSProperty_color) &&
-        aData->PresContext()->UseDocumentColors()) {
+        !aData->ShouldIgnoreColors()) {
       // color: color
       nscolor color;
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::text);
-      if (value && value->GetColorValue(color))
+      if (value && value->GetColorValue(color)) {
         aData->SetColorValue(eCSSProperty_color, color);
+      }
     }
   }
 
   nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 nsMapRuleToAttributesFunc
--- a/dom/html/HTMLFontElement.cpp
+++ b/dom/html/HTMLFontElement.cpp
@@ -71,27 +71,27 @@ HTMLFontElement::MapAttributesIntoRule(c
     if (!aData->PropertyIsSet(eCSSProperty_font_size)) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
       if (value && value->Type() == nsAttrValue::eInteger)
         aData->SetKeywordValue(eCSSProperty_font_size, value->GetIntegerValue());
     }
   }
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
     if (!aData->PropertyIsSet(eCSSProperty_color) &&
-        aData->PresContext()->UseDocumentColors()) {
+        !aData->ShouldIgnoreColors()) {
       // color: color
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
       nscolor color;
       if (value && value->GetColorValue(color)) {
         aData->SetColorValue(eCSSProperty_color, color);
       }
     }
   }
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(TextReset)) &&
-      aData->PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
+      aData->Document()->GetCompatibilityMode() == eCompatibility_NavQuirks) {
     // Make <a><font color="red">text</font></a> give the text a red underline
     // in quirks mode.  The NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL flag only
     // affects quirks mode rendering.
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
     nscolor color;
     if (value && value->GetColorValue(color)) {
       aData->SetTextDecorationColorOverride();
     }
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -164,18 +164,17 @@ HTMLHRElement::MapAttributesIntoRule(con
            *props != eCSSProperty_UNKNOWN; ++props) {
         aData->SetPixelValueIfUnset(*props, 10000.0f);
       }
     }
   }
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
     // color: a color
     // (we got the color attribute earlier)
-    if (colorIsSet &&
-        aData->PresContext()->UseDocumentColors()) {
+    if (colorIsSet && !aData->ShouldIgnoreColors()) {
       aData->SetColorValueIfUnset(eCSSProperty_color, color);
     }
   }
 
   nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -232,17 +232,17 @@ HTMLTableCellElement::MapAttributesIntoR
     }
   }
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
     if (!aData->PropertyIsSet(eCSSProperty_white_space)) {
       // nowrap: enum
       if (aAttributes->GetAttr(nsGkAtoms::nowrap)) {
         // See if our width is not a nonzero integer width.
         const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
-        nsCompatibility mode = aData->PresContext()->CompatibilityMode();
+        nsCompatibility mode = aData->Document()->GetCompatibilityMode();
         if (!value || value->Type() != nsAttrValue::eInteger ||
             value->GetIntegerValue() == 0 ||
             eCompatibility_NavQuirks != mode) {
           aData->SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Nowrap);
         }
       }
     }
   }
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -947,18 +947,17 @@ HTMLTableElement::MapAttributesIntoRule(
   // table cells.  (nsHTMLTableCellElement overrides
   // WalkContentStyleRules so that this happens.)  This violates the
   // nsIStyleRule contract, since it's the same style rule object doing
   // the mapping in two different ways.  It's also incorrect since it's
   // testing the display type of the style context rather than checking
   // which *element* it's matching (style rules should not stop matching
   // when the display type is changed).
 
-  nsPresContext* presContext = aData->PresContext();
-  nsCompatibility mode = presContext->CompatibilityMode();
+  nsCompatibility mode = aData->Document()->GetCompatibilityMode();
 
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(TableBorder))) {
     // cellspacing
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellspacing);
     if (value && value->Type() == nsAttrValue::eInteger &&
         !aData->PropertyIsSet(eCSSProperty_border_spacing)) {
       aData->SetPixelValue(eCSSProperty_border_spacing, float(value->GetIntegerValue()));
     }
@@ -994,18 +993,17 @@ HTMLTableElement::MapAttributesIntoRule(
         aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)value->GetIntegerValue());
       }
     }
   }
   if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Border))) {
     // bordercolor
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
     nscolor color;
-    if (value && presContext->UseDocumentColors() &&
-        value->GetColorValue(color)) {
+    if (value && !aData->ShouldIgnoreColors() && value->GetColorValue(color)) {
       aData->SetColorValueIfUnset(eCSSProperty_border_top_color, color);
       aData->SetColorValueIfUnset(eCSSProperty_border_left_color, color);
       aData->SetColorValueIfUnset(eCSSProperty_border_bottom_color, color);
       aData->SetColorValueIfUnset(eCSSProperty_border_right_color, color);
     }
 
     // border
     const nsAttrValue* borderValue = aAttributes->GetAttr(nsGkAtoms::border);
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1539,17 +1539,17 @@ void
 nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
                                         GenericSpecifiedValues* aData)
 {
 
   if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
     return;
 
   if (!aData->PropertyIsSet(eCSSProperty_background_image) &&
-      aData->PresContext()->UseDocumentColors()) {
+      !aData->ShouldIgnoreColors()) {
     // background
     nsAttrValue* value =
       const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
     if (value) {
       aData->SetBackgroundImage(*value);
     }
   }
 }
@@ -1557,17 +1557,17 @@ nsGenericHTMLElement::MapBackgroundInto(
 void
 nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
                                      GenericSpecifiedValues* aData)
 {
   if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
     return;
 
   if (!aData->PropertyIsSet(eCSSProperty_background_color) &&
-      aData->PresContext()->UseDocumentColors()) {
+      !aData->ShouldIgnoreColors()) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
     nscolor color;
     if (value && value->GetColorValue(color)) {
       aData->SetColorValue(eCSSProperty_background_color, color);
     }
   }
 }
 
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -523,17 +523,17 @@ nsMathMLElement::MapMathMLAttributesInto
         nsresult errorCode;
         float floatValue = str.ToFloat(&errorCode);
         // Negative scriptsizemultipliers are not parsed
         if (NS_SUCCEEDED(errorCode) && floatValue >= 0.0f) {
           aData->SetNumberValue(eCSSProperty__moz_script_size_multiplier, floatValue);
         } else {
           ReportParseErrorNoTag(str,
                                 nsGkAtoms::scriptsizemultiplier_,
-                                aData->mPresContext->Document());
+                                aData->Document());
         }
       }
     }
 
     // scriptminsize
     //
     // "Specifies the minimum font size allowed due to changes in scriptlevel.
     // Note that this does not limit the font size due to changes to mathsize."
@@ -545,17 +545,17 @@ nsMathMLElement::MapMathMLAttributesInto
     // Unitless and percent values give a multiple of the default value.
     //
     value = aAttributes->GetAttr(nsGkAtoms::scriptminsize_);
     if (value && value->Type() == nsAttrValue::eString &&
         !aData->PropertyIsSet(eCSSProperty__moz_script_min_size)) {
       nsCSSValue scriptMinSize;
       ParseNumericValue(value->GetStringValue(), scriptMinSize,
                         PARSE_ALLOW_UNITLESS | CONVERT_UNITLESS_TO_PERCENT,
-                        aData->mPresContext->Document());
+                        aData->Document());
 
       if (scriptMinSize.GetUnit() == eCSSUnit_Percent) {
         scriptMinSize.SetFloatValue(8.0 * scriptMinSize.GetPercentValue(),
                                      eCSSUnit_Point);
       }
       if (scriptMinSize.GetUnit() != eCSSUnit_Null) {
         aData->SetLengthValue(eCSSProperty__moz_script_min_size, scriptMinSize);
       }
@@ -589,17 +589,17 @@ nsMathMLElement::MapMathMLAttributesInto
           if (ch == '+' || ch == '-') {
             aData->SetIntValue(eCSSProperty__moz_script_level, intValue);
           } else {
             aData->SetNumberValue(eCSSProperty__moz_script_level, intValue);
           }
         } else {
           ReportParseErrorNoTag(str,
                                 nsGkAtoms::scriptlevel_,
-                                aData->mPresContext->Document());
+                                aData->Document());
         }
       }
     }
 
     // mathsize
     //
     // "Specifies the size to display the token content. The values 'small' and
     // 'big' choose a size smaller or larger than the current font size, but
@@ -623,17 +623,17 @@ nsMathMLElement::MapMathMLAttributesInto
     bool parseSizeKeywords = true;
     value = aAttributes->GetAttr(nsGkAtoms::mathsize_);
     if (!value) {
       parseSizeKeywords = false;
       value = aAttributes->GetAttr(nsGkAtoms::fontsize_);
       if (value) {
         WarnDeprecated(nsGkAtoms::fontsize_->GetUTF16String(),
                        nsGkAtoms::mathsize_->GetUTF16String(),
-                       aData->mPresContext->Document());
+                       aData->Document());
       }
     }
     if (value && value->Type() == nsAttrValue::eString &&
         !aData->PropertyIsSet(eCSSProperty_font_size)) {
       nsAutoString str(value->GetStringValue());
       nsCSSValue fontSize;
       if (!ParseNumericValue(str, fontSize, PARSE_SUPPRESS_WARNINGS |
                              PARSE_ALLOW_UNITLESS | CONVERT_UNITLESS_TO_PERCENT,
@@ -666,17 +666,17 @@ nsMathMLElement::MapMathMLAttributesInto
     // CSS for more information. Deprecated in favor of mathvariant."
     //
     // values: string
     //
     value = aAttributes->GetAttr(nsGkAtoms::fontfamily_);
     if (value) {
       WarnDeprecated(nsGkAtoms::fontfamily_->GetUTF16String(),
                      nsGkAtoms::mathvariant_->GetUTF16String(),
-                     aData->mPresContext->Document());
+                     aData->Document());
     }
     if (value && value->Type() == nsAttrValue::eString &&
         !aData->PropertyIsSet(eCSSProperty_font_family)) {
       aData->SetFontFamily(value->GetStringValue());
     }
 
     // fontstyle
     //
@@ -687,17 +687,17 @@ nsMathMLElement::MapMathMLAttributesInto
     // default:	normal (except on <mi>)
     //
     // Note that the font-style property is reset in layout/style/ when
     // -moz-math-variant is specified.
     value = aAttributes->GetAttr(nsGkAtoms::fontstyle_);
     if (value) {
       WarnDeprecated(nsGkAtoms::fontstyle_->GetUTF16String(),
                        nsGkAtoms::mathvariant_->GetUTF16String(),
-                       aData->mPresContext->Document());
+                       aData->Document());
       if (value->Type() == nsAttrValue::eString &&
           !aData->PropertyIsSet(eCSSProperty_font_style)) {
         nsAutoString str(value->GetStringValue());
         str.CompressWhitespace();
         if (str.EqualsASCII("normal")) {
           aData->SetKeywordValue(eCSSProperty_font_style,
                                  NS_STYLE_FONT_STYLE_NORMAL);
         } else if (str.EqualsASCII("italic")) {
@@ -716,17 +716,17 @@ nsMathMLElement::MapMathMLAttributesInto
     // default: normal
     //
     // Note that the font-weight property is reset in layout/style/ when
     // -moz-math-variant is specified.
     value = aAttributes->GetAttr(nsGkAtoms::fontweight_);
     if (value) {
       WarnDeprecated(nsGkAtoms::fontweight_->GetUTF16String(),
                        nsGkAtoms::mathvariant_->GetUTF16String(),
-                       aData->mPresContext->Document());
+                       aData->Document());
       if (value->Type() == nsAttrValue::eString &&
           !aData->PropertyIsSet(eCSSProperty_font_weight)) {
         nsAutoString str(value->GetStringValue());
         str.CompressWhitespace();
         if (str.EqualsASCII("normal")) {
           aData->SetKeywordValue(eCSSProperty_font_weight,
                                  NS_STYLE_FONT_WEIGHT_NORMAL);
         } else if (str.EqualsASCII("bold")) {
@@ -801,17 +801,17 @@ nsMathMLElement::MapMathMLAttributesInto
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)) {
     const nsAttrValue* value =
       aAttributes->GetAttr(nsGkAtoms::mathbackground_);
     if (!value) {
       value = aAttributes->GetAttr(nsGkAtoms::background);
       if (value) {
         WarnDeprecated(nsGkAtoms::background->GetUTF16String(),
                        nsGkAtoms::mathbackground_->GetUTF16String(),
-                       aData->mPresContext->Document());
+                       aData->Document());
       }
     }
     if (value) {
       nscolor color;
       if (value->GetColorValue(color)) {
         aData->SetColorValueIfUnset(eCSSProperty_background_color, color);
       }
     }
@@ -836,17 +836,17 @@ nsMathMLElement::MapMathMLAttributesInto
   //
   if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Color)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::mathcolor_);
     if (!value) {
       value = aAttributes->GetAttr(nsGkAtoms::color);
       if (value) {
         WarnDeprecated(nsGkAtoms::color->GetUTF16String(),
                        nsGkAtoms::mathcolor_->GetUTF16String(),
-                       aData->mPresContext->Document());
+                       aData->Document());
       }
     }
     nscolor color;
     if (value && value->GetColorValue(color)) {
       aData->SetColorValueIfUnset(eCSSProperty_color, color);
     }
   }
 
@@ -863,18 +863,17 @@ nsMathMLElement::MapMathMLAttributesInto
     // values: "auto" | length
     // default: auto
     //
     if (!aData->PropertyIsSet(eCSSProperty_width)) {
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
       nsCSSValue width;
       // This does not handle auto and unitless values
       if (value && value->Type() == nsAttrValue::eString) {
-        ParseNumericValue(value->GetStringValue(), width, 0,
-                          aData->mPresContext->Document());
+        ParseNumericValue(value->GetStringValue(), width, 0, aData->Document());
         if (width.GetUnit() == eCSSUnit_Percent) {
           aData->SetPercentValue(eCSSProperty_width,
                                  width.GetPercentValue());
         } else if (width.GetUnit() != eCSSUnit_Null) {
           aData->SetLengthValue(eCSSProperty_width, width);
         }
       }
     }
--- a/layout/style/GenericSpecifiedValues.h
+++ b/layout/style/GenericSpecifiedValues.h
@@ -11,53 +11,60 @@
  */
 
 #ifndef mozilla_GenericSpecifiedValues_h
 #define mozilla_GenericSpecifiedValues_h
 
 #include "mozilla/ServoUtils.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
-#include "nsPresContext.h"
+#include "StyleBackendType.h"
 
+class nsAttrValue;
 struct nsRuleData;
 
 namespace mozilla {
 
 class ServoSpecifiedValues;
 
-// 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.
+// 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
 {
 protected:
-  explicit GenericSpecifiedValues(StyleBackendType aType,
-                                  nsPresContext* aPresContext,
-                                  uint32_t aSIDs)
+  explicit GenericSpecifiedValues(StyleBackendType aType, nsIDocument* aDoc, uint32_t aSIDs)
     : mType(aType)
-    , mPresContext(aPresContext)
+    , mDocument(aDoc)
     , mSIDs(aSIDs)
   {}
 
 public:
   MOZ_DECL_STYLO_METHODS(nsRuleData, ServoSpecifiedValues)
 
+  nsIDocument* Document()
+  {
+    return mDocument;
+  }
+
+  // Whether we should ignore document colors.
+  inline bool ShouldIgnoreColors() const;
+
   // Check if we already contain a certain longhand
   inline bool PropertyIsSet(nsCSSPropertyID aId);
+
   // 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.
   inline bool ShouldComputeStyleStruct(uint64_t aInheritBits)
   {
     return aInheritBits & mSIDs;
   }
 
-  inline nsPresContext* PresContext() { return mPresContext; }
-
   // Set a property to an identifier (string)
   inline void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue);
   inline void SetIdentStringValueIfUnset(nsCSSPropertyID aId,
                                          const nsString& aValue);
 
   inline void SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue);
   inline void SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsAtom* aValue);
 
@@ -111,15 +118,15 @@ public:
 
   // Set font-family to a string
   inline void SetFontFamily(const nsString& aValue);
   // Add a quirks-mode override to the decoration color of elements nested in <a>
   inline void SetTextDecorationColorOverride();
   inline void SetBackgroundImage(nsAttrValue& value);
 
   const mozilla::StyleBackendType mType;
-  nsPresContext* const mPresContext;
+  nsIDocument* const mDocument;
   const uint32_t mSIDs;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_GenericSpecifiedValues_h
--- a/layout/style/GenericSpecifiedValuesInlines.h
+++ b/layout/style/GenericSpecifiedValuesInlines.h
@@ -20,16 +20,29 @@
 
 namespace mozilla {
 
 MOZ_DEFINE_STYLO_METHODS(GenericSpecifiedValues,
                          nsRuleData,
                          ServoSpecifiedValues)
 
 bool
+GenericSpecifiedValues::ShouldIgnoreColors() const
+{
+  if (IsServo()) {
+    // Servo handles this during cascading.
+    //
+    // FIXME(emilio): We should eventually move it to the document though.
+    return false;
+  }
+
+  return !AsGecko()->mPresContext->UseDocumentColors();
+}
+
+bool
 GenericSpecifiedValues::PropertyIsSet(nsCSSPropertyID aId)
 {
   MOZ_STYLO_FORWARD(PropertyIsSet, (aId))
 }
 
 void
 GenericSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
                                             const nsString& aValue)
--- a/layout/style/ServoSpecifiedValues.cpp
+++ b/layout/style/ServoSpecifiedValues.cpp
@@ -2,35 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoSpecifiedValues.h"
 
-namespace {
-
-#define STYLE_STRUCT(name, checkdata_cb) | NS_STYLE_INHERIT_BIT(name)
-const uint64_t ALL_SIDS = 0
-#include "nsStyleStructList.h"
-  ;
-#undef STYLE_STRUCT
-
-} // anonymous namespace
-
 using namespace mozilla;
 
-ServoSpecifiedValues::ServoSpecifiedValues(nsPresContext* aContext,
-                                           RawServoDeclarationBlock* aDecl)
-
-  : GenericSpecifiedValues(StyleBackendType::Servo, aContext, ALL_SIDS)
-  , mDecl(aDecl)
-{}
-
 bool
 ServoSpecifiedValues::PropertyIsSet(nsCSSPropertyID aId)
 {
   return Servo_DeclarationBlock_PropertyIsSet(mDecl, aId);
 }
 
 void
 ServoSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
@@ -40,19 +23,27 @@ ServoSpecifiedValues::SetIdentStringValu
   SetIdentAtomValue(aId, atom);
 }
 
 void
 ServoSpecifiedValues::SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue)
 {
   Servo_DeclarationBlock_SetIdentStringValue(mDecl, aId, aValue);
   if (aId == eCSSProperty__x_lang) {
-    // This forces the lang prefs result to be cached
-    // so that we can access them off main thread during traversal
-    mPresContext->ForceCacheLang(aValue);
+    // This forces the lang prefs result to be cached so that we can access them
+    // off main thread during traversal.
+    //
+    // FIXME(emilio): Can we move mapped attribute declarations across
+    // documents? Isn't this wrong in that case? This is pretty out of place
+    // anyway.
+    if (nsIPresShell* shell = mDocument->GetShell()) {
+      if (nsPresContext* pc = shell->GetPresContext()) {
+        pc->ForceCacheLang(aValue);
+      }
+    }
   }
 }
 
 void
 ServoSpecifiedValues::SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
 {
   Servo_DeclarationBlock_SetKeywordValue(mDecl, aId, aValue);
 }
@@ -124,10 +115,10 @@ ServoSpecifiedValues::SetBackgroundImage
 {
   if (aValue.Type() != nsAttrValue::eURL &&
       aValue.Type() != nsAttrValue::eImage) {
     return;
   }
   nsAutoString str;
   aValue.ToString(str);
   Servo_DeclarationBlock_SetBackgroundImage(
-    mDecl, str, mPresContext->Document()->DefaultStyleAttrURLData());
+    mDecl, str, mDocument->DefaultStyleAttrURLData());
 }
--- a/layout/style/ServoSpecifiedValues.h
+++ b/layout/style/ServoSpecifiedValues.h
@@ -15,18 +15,20 @@
 #include "mozilla/GenericSpecifiedValues.h"
 #include "mozilla/ServoBindingTypes.h"
 
 namespace mozilla {
 
 class ServoSpecifiedValues final : public GenericSpecifiedValues
 {
 public:
-  ServoSpecifiedValues(nsPresContext* aContext,
-                       RawServoDeclarationBlock* aDecl);
+  ServoSpecifiedValues(nsIDocument* aDocument, RawServoDeclarationBlock* aDecl)
+    : GenericSpecifiedValues(StyleBackendType::Servo, aDocument, NS_STYLE_INHERIT_MASK)
+    , mDecl(aDecl)
+  {}
 
   // GenericSpecifiedValues overrides
   bool PropertyIsSet(nsCSSPropertyID aId);
 
   void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue);
 
   void SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue);
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -348,17 +348,17 @@ ServoStyleSet::Snapshots()
 {
   return mPresContext->RestyleManager()->AsServo()->Snapshots();
 }
 
 void
 ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
 {
   if (nsHTMLStyleSheet* sheet = mPresContext->Document()->GetAttributeStyleSheet()) {
-    sheet->CalculateMappedServoDeclarations(mPresContext);
+    sheet->CalculateMappedServoDeclarations();
   }
 
   mPresContext->Document()->ResolveScheduledSVGPresAttrs();
 }
 
 void
 ServoStyleSet::PreTraverseSync()
 {
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -562,28 +562,25 @@ nsHTMLStyleSheet::DropMappedAttributes(n
 #endif
 
   mMappedAttrTable.Remove(aMapped);
 
   NS_ASSERTION(entryCount == mMappedAttrTable.EntryCount(), "not removed");
 }
 
 void
-nsHTMLStyleSheet::CalculateMappedServoDeclarations(nsPresContext* aPresContext)
+nsHTMLStyleSheet::CalculateMappedServoDeclarations()
 {
-  MOZ_ASSERT(!mDocument->GetShell() ||
-             mDocument->GetShell()->GetPresContext() == aPresContext);
-
   for (auto iter = mMappedAttrTable.Iter(); !iter.Done(); iter.Next()) {
     MappedAttrTableEntry* attr = static_cast<MappedAttrTableEntry*>(iter.Get());
     if (attr->mAttributes->GetServoStyle()) {
       // Only handle cases which haven't been filled in already
       continue;
     }
-    attr->mAttributes->LazilyResolveServoDeclaration(aPresContext);
+    attr->mAttributes->LazilyResolveServoDeclaration(mDocument);
   }
 }
 
 nsIStyleRule*
 nsHTMLStyleSheet::LangRuleFor(const nsAtom* aLanguage)
 {
   auto entry =
     static_cast<LangRuleTableEntry*>(mLangRuleTable.Add(aLanguage, fallible));
--- a/layout/style/nsHTMLStyleSheet.h
+++ b/layout/style/nsHTMLStyleSheet.h
@@ -72,17 +72,17 @@ public:
 
   // Mapped Attribute management methods
   already_AddRefed<nsMappedAttributes>
     UniqueMappedAttributes(nsMappedAttributes* aMapped);
   void DropMappedAttributes(nsMappedAttributes* aMapped);
   // For each mapped presentation attribute in the cache, resolve
   // the attached ServoDeclarationBlock by running the mapping
   // and converting the ruledata to Servo specified values.
-  void CalculateMappedServoDeclarations(nsPresContext* aPresContext);
+  void CalculateMappedServoDeclarations();
 
   nsIStyleRule* LangRuleFor(const nsAtom* aLanguage);
 
 private:
   nsHTMLStyleSheet(const nsHTMLStyleSheet& aCopy) = delete;
   nsHTMLStyleSheet& operator=(const nsHTMLStyleSheet& aCopy) = delete;
 
   ~nsHTMLStyleSheet() {}
--- a/layout/style/nsRuleData.cpp
+++ b/layout/style/nsRuleData.cpp
@@ -3,16 +3,18 @@
 /* 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 http://mozilla.org/MPL/2.0/. */
 
 #include "nsRuleData.h"
 
 #include "nsAttrValueInlines.h"
 #include "nsCSSParser.h"
+#include "nsPresContext.h"
+#include "mozilla/GeckoStyleContext.h"
 #include "mozilla/Poison.h"
 #include <stdint.h>
 
 using namespace mozilla;
 
 inline size_t
 nsRuleData::GetPoisonOffset()
 {
@@ -26,20 +28,20 @@ nsRuleData::GetPoisonOffset()
   static_assert(size_t(-1) > size_t(0), "expect size_t to be unsigned");
   uintptr_t framePoisonValue = mozPoisonValue();
   return size_t(framePoisonValue - uintptr_t(mValueStorage)) /
          sizeof(nsCSSValue);
 }
 
 nsRuleData::nsRuleData(uint32_t aSIDs,
                        nsCSSValue* aValueStorage,
-                       nsPresContext* aContext,
                        GeckoStyleContext* aStyleContext)
-  : GenericSpecifiedValues(StyleBackendType::Gecko, aContext, aSIDs)
+  : GenericSpecifiedValues(StyleBackendType::Gecko, aStyleContext->PresContext()->Document(), aSIDs)
   , mStyleContext(aStyleContext)
+  , mPresContext(aStyleContext->PresContext())
   , mValueStorage(aValueStorage)
 {
 #ifndef MOZ_VALGRIND
   size_t framePoisonOffset = GetPoisonOffset();
   for (size_t i = 0; i < nsStyleStructID_Length; ++i) {
     mValueOffsets[i] = framePoisonOffset;
   }
 #endif
@@ -66,17 +68,17 @@ nsRuleData::SetTextDecorationColorOverri
 
 void
 nsRuleData::SetBackgroundImage(nsAttrValue& aValue)
 {
   nsCSSValue* backImage = ValueForBackgroundImage();
   // If the value is an image, or it is a URL and we attempted a load,
   // put it in the style tree.
   if (aValue.Type() == nsAttrValue::eURL) {
-    aValue.LoadImage(mPresContext->Document());
+    aValue.LoadImage(mDocument);
   }
   if (aValue.Type() == nsAttrValue::eImage) {
     nsCSSValueList* list = backImage->SetListValue();
     list->mValue.SetImageValue(aValue.GetImageValue());
   }
 }
 
 #ifdef DEBUG
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -31,16 +31,17 @@ class GeckoStyleContext;
 typedef void (*nsPostResolveFunc)(void* aStyleStruct, nsRuleData* aData);
 
 struct nsRuleData final : mozilla::GenericSpecifiedValues
 {
   mozilla::RuleNodeCacheConditions mConditions;
   bool mIsImportantRule;
   mozilla::SheetType mLevel;
   mozilla::GeckoStyleContext* const mStyleContext;
+  nsPresContext* const mPresContext;
 
   // We store nsCSSValues needed to compute the data for one or more
   // style structs (specified by the bitfield mSIDs).  These are stored
   // in a single array allocation (which our caller allocates; see
   // AutoCSSValueArray)   The offset of each property |prop| in
   // mValueStorage is the sum of
   // mValueOffsets[nsCSSProps::kSIDTable[prop]] and
   // nsCSSProps::PropertyIndexInStruct(prop).  The only place we gather
@@ -50,17 +51,16 @@ struct nsRuleData final : mozilla::Gener
   // mValueOffsets for the one struct in mSIDs is zero.
   nsCSSValue* const mValueStorage; // our user owns this array
   size_t mValueOffsets[nsStyleStructID_Length];
 
   nsAutoPtr<mozilla::CSSVariableDeclarations> mVariables;
 
   nsRuleData(uint32_t aSIDs,
              nsCSSValue* aValueStorage,
-             nsPresContext* aContext,
              mozilla::GeckoStyleContext* aStyleContext);
 
 #ifdef DEBUG
   ~nsRuleData();
 #else
   ~nsRuleData() {}
 #endif
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2469,17 +2469,17 @@ nsRuleNode::WalkRuleTree(const nsStyleSt
   // use placement new[] on the result of alloca() to allocate a
   // variable-sized stack array, including execution of constructors,
   // and use an RAII class to run the destructors too.
   size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
   AutoCSSValueArray dataArray(dataStorage, nprops);
 
   nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
-                      dataArray.get(), mPresContext, aContext);
+                      dataArray.get(), aContext);
   ruleData.mValueOffsets[aSID] = 0;
 
   // We start at the most specific rule in the tree.
   void* startStruct = nullptr;
 
   nsRuleNode* ruleNode = this;
   nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
                                     // that has the same properties
@@ -4079,18 +4079,17 @@ nsRuleNode::SetGenericFont(nsPresContext
   // and use an RAII class to run the destructors too.
   size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
 
   for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
     GeckoStyleContext* context = contextPath[i];
     AutoCSSValueArray dataArray(dataStorage, nprops);
 
-    nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
-                        aPresContext, context);
+    nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(), context);
     ruleData.mValueOffsets[eStyleStruct_Font] = 0;
 
     // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
     // Note that we *do* need to do this for our own data, since what is
     // in |fontData| in ComputeFontData is only for the rules below
     // aStartStruct.
     for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
          ruleNode = ruleNode->GetParent()) {
@@ -10188,18 +10187,17 @@ nsRuleNode::HasAuthorSpecifiedRules(Geck
     paddingOffset = nprops;
     nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
   }
 
   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
   AutoCSSValueArray dataArray(dataStorage, nprops);
 
   /* We're relying on the use of |styleContext| not mutating it! */
-  nsRuleData ruleData(inheritBits, dataArray.get(),
-                      styleContext->PresContext(), styleContext);
+  nsRuleData ruleData(inheritBits, dataArray.get(), styleContext);
 
   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
     ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
   }
 
   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
     ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
   }
@@ -10382,18 +10380,17 @@ nsRuleNode::ComputePropertiesOverridingA
       nprops += nsCSSProps::PropertyCountInStruct(sid);
     }
   }
 
   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
   AutoCSSValueArray dataArray(dataStorage, nprops);
 
   // We're relying on the use of |aStyleContext| not mutating it!
-  nsRuleData ruleData(structBits, dataArray.get(),
-                      aStyleContext->PresContext(), aStyleContext);
+  nsRuleData ruleData(structBits, dataArray.get(), aStyleContext);
   for (nsStyleStructID sid = nsStyleStructID(0);
        sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
     if (structBits & nsCachedStyleData::GetBitForSID(sid)) {
       ruleData.mValueOffsets[sid] = offsets[sid];
     }
   }
 
   /*