Merge inbound to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Mon, 25 Jun 2018 22:02:08 +0300
changeset 423571 6e8e861540e6d8c85c73ab7b2afa1f027fb3750c
parent 423570 6e4cd8b5f7f242647b69447c3d22966b601c0bf3 (current diff)
parent 423569 27db2b2703d2a86be00bb83e8638ecc734b51a85 (diff)
child 423572 fec38bca2fefb47d840bcce4881064381853a207
child 423682 b9353dfa681ce493ff69cd9aefda55fc1a8e35fd
push id65499
push usernerli@mozilla.com
push dateMon, 25 Jun 2018 19:15:10 +0000
treeherderautoland@fec38bca2fef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
6e8e861540e6 / 63.0a1 / 20180625220119 / files
nightly linux64
6e8e861540e6 / 63.0a1 / 20180625220119 / files
nightly mac
6e8e861540e6 / 63.0a1 / 20180625220119 / files
nightly win32
6e8e861540e6 / 63.0a1 / 20180625220119 / files
nightly win64
6e8e861540e6 / 63.0a1 / 20180625220119 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
editor/libeditor/StyleSheetTransactions.cpp
editor/libeditor/StyleSheetTransactions.h
editor/libeditor/tests/test_bug468353.html
js/src/gc/GCHelperState.h
layout/base/crashtests/crashtests.list
layout/style/GenericSpecifiedValues.h
layout/style/GenericSpecifiedValuesInlines.h
layout/style/ServoSpecifiedValues.cpp
layout/style/ServoSpecifiedValues.h
--- a/.eslintignore
+++ b/.eslintignore
@@ -122,20 +122,16 @@ devtools/shared/qrcode/tests/mochitest/t
 devtools/shared/tests/mochitest/*.html
 devtools/shared/webconsole/test/test_*.html
 
 # Soon to be removed
 devtools/client/commandline/**
 # Soon to be removed, the new/ directory is explicitly excluded below due to
 # also being an imported repository.
 devtools/client/debugger/**
-# Soon to be removed
-devtools/client/webconsole/old/net/**
-devtools/client/webconsole/old/test/**
-devtools/client/webconsole/old/webconsole.js
 
 # Ignore devtools imported repositories
 devtools/client/debugger/new/**
 devtools/client/shared/components/reps/**
 
 # Ignore devtools preferences files
 devtools/client/preferences/**
 devtools/client/webide/preferences/**
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1627,17 +1627,17 @@ nsDocument::~nsDocument()
       }
       if (mHasUnsafeInlineCSP) {
         Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
       }
       if (mHasUnsafeEvalCSP) {
         Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
       }
 
-      if (MOZ_UNLIKELY(GetMathMLEnabled())) {
+      if (MOZ_UNLIKELY(mMathMLEnabled)) {
         ScalarAdd(Telemetry::ScalarID::MATHML_DOC_COUNT, 1);
       }
     }
   }
 
   ReportUseCounters();
 
   mInDestructor = true;
@@ -1690,17 +1690,16 @@ nsDocument::~nsDocument()
   for (auto& sheets : mAdditionalSheets) {
     for (StyleSheet* sheet : sheets) {
       sheet->ClearAssociatedDocumentOrShadowRoot();
     }
   }
   if (mAttrStyleSheet) {
     mAttrStyleSheet->SetOwningDocument(nullptr);
   }
-  // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
 
   if (mListenerManager) {
     mListenerManager->Disconnect();
     UnsetFlags(NODE_HAS_LISTENERMANAGER);
   }
 
   if (mScriptLoader) {
     mScriptLoader->DropDocumentReference();
@@ -1913,17 +1912,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
 
   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
   }
 
   // Traverse animation components
@@ -2452,32 +2450,30 @@ nsIDocument::ResetStylesheetsToURI(nsIUR
 {
   MOZ_ASSERT(aURI);
 
   if (mStyleSetFilled) {
     // Skip removing style sheets from the style set if we know we haven't
     // filled the style set.  (This allows us to avoid calling
     // GetStyleBackendType() too early.)
     RemoveDocStyleSheetsFromStyleSets();
-    RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, SheetType::Agent);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], SheetType::Agent);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], SheetType::User);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], SheetType::Doc);
 
     if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
       RemoveStyleSheetsFromStyleSets(
         *sheetService->AuthorStyleSheets(), SheetType::Doc);
     }
 
     mStyleSetFilled = false;
   }
 
   // Release all the sheets
   mStyleSheets.Clear();
-  mOnDemandBuiltInUASheets.Clear();
   for (auto& sheets : mAdditionalSheets) {
     sheets.Clear();
   }
 
   // NOTE:  We don't release the catalog sheets.  It doesn't really matter
   // now, but it could in the future -- in which case not releasing them
   // is probably the right thing to do.
 
@@ -2531,23 +2527,16 @@ nsIDocument::FillStyleSet(ServoStyleSet*
   if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
     nsTArray<RefPtr<StyleSheet>>& sheets =
       *sheetService->AuthorStyleSheets();
     for (StyleSheet* sheet : sheets) {
       aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
     }
   }
 
-  // Iterate backwards to maintain order
-  for (StyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
-    if (sheet->IsApplicable()) {
-      aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
-    }
-  }
-
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
                          SheetType::Agent);
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
                          SheetType::User);
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
                          SheetType::Doc);
 
   mStyleSetFilled = true;
@@ -4127,53 +4116,16 @@ nsIDocument::RemoveChildNode(nsIContent*
   mCachedRootElement = nullptr;
   doRemoveChildAt(ComputeIndexOf(aKid), aNotify, aKid, mChildren);
   MOZ_ASSERT(mCachedRootElement != aKid,
              "Stale pointer in mCachedRootElement, after we tried to clear it "
              "(maybe somebody called GetRootElement() too early?)");
 }
 
 void
-nsIDocument::EnsureOnDemandBuiltInUASheet(StyleSheet* aSheet)
-{
-  if (mOnDemandBuiltInUASheets.Contains(aSheet)) {
-    return;
-  }
-  AddOnDemandBuiltInUASheet(aSheet);
-}
-
-void
-nsIDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
-{
-  MOZ_ASSERT(!mOnDemandBuiltInUASheets.Contains(aSheet));
-
-  // Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
-  // the same order that they should end up in the style set.
-  mOnDemandBuiltInUASheets.InsertElementAt(0, aSheet);
-
-  if (aSheet->IsApplicable()) {
-    // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
-    if (nsIPresShell* shell = GetShell()) {
-      // Note that prepending here is necessary to make sure that html.css etc.
-      // does not override Firefox OS/Mobile's content.css sheet.
-      //
-      // Maybe we should have an insertion point to match the order of
-      // nsDocumentViewer::CreateStyleSet though?
-      //
-      // FIXME(emilio): We probably should, randomly prepending stuff here is
-      // very prone to subtle bugs, behavior differences...
-      shell->StyleSet()->PrependStyleSheet(SheetType::Agent, aSheet);
-      shell->ApplicableStylesChanged();
-    }
-  }
-
-  NotifyStyleSheetAdded(aSheet, false);
-}
-
-void
 nsIDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
 {
   if (nsIPresShell* shell = GetShell()) {
     shell->StyleSet()->AddDocStyleSheet(aSheet, this);
     shell->ApplicableStylesChanged();
   }
 }
 
@@ -9537,31 +9489,16 @@ nsIDocument::CreateStaticClone(nsIDocShe
             NS_WARNING_ASSERTION(clonedSheet,
                                  "Cloning a stylesheet didn't work!");
             if (clonedSheet) {
               clonedDoc->AddStyleSheet(clonedSheet);
             }
           }
         }
       }
-
-      // Iterate backwards to maintain order
-      for (StyleSheet* sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
-        if (sheet) {
-          if (sheet->IsApplicable()) {
-            RefPtr<StyleSheet> clonedSheet =
-              sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
-            NS_WARNING_ASSERTION(clonedSheet,
-                                 "Cloning a stylesheet didn't work!");
-            if (clonedSheet) {
-              clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
-            }
-          }
-        }
-      }
     }
   }
   mCreatingStaticClone = false;
   return clonedDoc.forget();
 }
 
 void
 nsIDocument::UnlinkOriginalDocumentIfStatic()
@@ -11756,21 +11693,16 @@ nsDocument::DocAddSizeOfExcludingThis(ns
   // Therefore, the measurement of the nsIDocument superclass must happen after
   // the measurement of DOM nodes (above), because nsIDocument contains the
   // PresShell, which contains the frame tree.
   nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes);
 
   aWindowSizes.mLayoutStyleSheetsSize +=
     SizeOfOwnedSheetArrayExcludingThis(mStyleSheets,
                                        aWindowSizes.mState.mMallocSizeOf);
-  // Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
-  // (the nsLayoutStyleSheetCache singleton does).
-  aWindowSizes.mLayoutStyleSheetsSize +=
-    mOnDemandBuiltInUASheets.ShallowSizeOfExcludingThis(
-      aWindowSizes.mState.mMallocSizeOf);
   for (auto& sheetArray : mAdditionalSheets) {
     aWindowSizes.mLayoutStyleSheetsSize +=
       SizeOfOwnedSheetArrayExcludingThis(sheetArray,
                                          aWindowSizes.mState.mMallocSizeOf);
   }
   // Lumping in the loader with the style-sheets size is not ideal,
   // but most of the things in there are in fact stylesheets, so it
   // doesn't seem worthwhile to separate it out.
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -831,24 +831,16 @@ public:
    * it affects a frame model irreversibly, and plays even though
    * the document no longer contains bidi data.
    */
   void SetBidiEnabled()
   {
     mBidiEnabled = true;
   }
 
-  /**
-   * Check if the document contains (or has contained) any MathML elements.
-   */
-  bool GetMathMLEnabled() const
-  {
-    return mMathMLEnabled;
-  }
-
   void SetMathMLEnabled()
   {
     mMathMLEnabled = true;
   }
 
   /**
    * Ask this document whether it's the initial document in its window.
    */
@@ -1463,38 +1455,16 @@ public:
   // Get the "head" element in the sense of document.head.
   mozilla::dom::HTMLSharedElement* GetHead();
 
   /**
    * Accessors to the collection of stylesheets owned by this document.
    * Style sheets are ordered, most significant last.
    */
 
-  /**
-   * These exists to allow us to on-demand load user-agent style sheets that
-   * would otherwise be loaded by nsDocumentViewer::CreateStyleSet. This allows
-   * us to keep the memory used by a document's rule cascade data (the stuff in
-   * its nsStyleSet's nsCSSRuleProcessors) - which can be considerable - lower
-   * than it would be if we loaded all built-in user-agent style sheets up
-   * front.
-   *
-   * By "built-in" user-agent style sheets we mean the user-agent style sheets
-   * that gecko itself supplies (such as html.css and svg.css) as opposed to
-   * user-agent level style sheets inserted by add-ons or the like.
-   *
-   * This function prepends the given style sheet to the document's style set
-   * in order to make sure that it does not override user-agent style sheets
-   * supplied by add-ons or by the app (Firefox OS or Firefox Mobile, for
-   * example), since their sheets should override built-in sheets.
-   *
-   * TODO We can get rid of the whole concept of delayed loading if we fix
-   * bug 77999.
-   */
-  void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
-
   mozilla::dom::StyleSheetList* StyleSheets()
   {
     return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
   }
 
   void InsertSheetAt(size_t aIndex, mozilla::StyleSheet&);
 
   /**
@@ -3611,17 +3581,16 @@ protected:
 
   bool GetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mChildDocumentUseCounters[aUseCounter];
   }
 
   void UpdateDocumentStates(mozilla::EventStates);
 
-  void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
   void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(
       const nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets,
       mozilla::SheetType aType);
   void ResetStylesheetsToURI(nsIURI* aURI);
   void FillStyleSet(mozilla::ServoStyleSet* aStyleSet);
   void AddStyleSheetToStyleSets(mozilla::StyleSheet* aSheet);
   void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
@@ -4413,17 +4382,16 @@ protected:
   mozilla::CSSToLayoutDeviceScale mPixelRatio;
   mozilla::CSSSize mViewportSize;
 
   RefPtr<mozilla::EventListenerManager> mListenerManager;
 
   nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
   nsCOMPtr<nsIRequest> mOnloadBlocker;
 
-  nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
   nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
 
   // Member to store out last-selected stylesheet set.
   nsString mLastStyleSheetSet;
   nsString mPreferredStyleSheetSet;
 
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
 
--- a/dom/base/nsMappedAttributeElement.cpp
+++ b/dom/base/nsMappedAttributeElement.cpp
@@ -22,18 +22,18 @@ nsMappedAttributeElement::SetAndSwapMapp
 
 nsMapRuleToAttributesFunc
 nsMappedAttributeElement::GetAttributeMappingFunction() const
 {
   return &MapNoAttributesInto;
 }
 
 void
-nsMappedAttributeElement::MapNoAttributesInto(const nsMappedAttributes* aAttributes,
-                                              mozilla::GenericSpecifiedValues* aGenericData)
+nsMappedAttributeElement::MapNoAttributesInto(const nsMappedAttributes*,
+                                              mozilla::MappedDeclarations&)
 {
 }
 
 void
 nsMappedAttributeElement::NodeInfoChanged(nsIDocument* aOldDoc)
 {
   nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
   mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
--- a/dom/base/nsMappedAttributeElement.h
+++ b/dom/base/nsMappedAttributeElement.h
@@ -8,41 +8,44 @@
  * nsMappedAttributeElement is the base for elements supporting style mapped
  * attributes via nsMappedAttributes (HTML and MathML).
  */
 
 #ifndef NS_MAPPEDATTRIBUTEELEMENT_H_
 #define NS_MAPPEDATTRIBUTEELEMENT_H_
 
 #include "mozilla/Attributes.h"
-#include "mozilla/GenericSpecifiedValues.h"
 #include "nsStyledElement.h"
 
+namespace mozilla {
+class MappedDeclarations;
+}
+
 class nsMappedAttributes;
 struct nsRuleData;
 
 typedef void (*nsMapRuleToAttributesFunc)(const nsMappedAttributes* aAttributes,
-                                          mozilla::GenericSpecifiedValues* aData);
+                                          mozilla::MappedDeclarations&);
 
 typedef nsStyledElement nsMappedAttributeElementBase;
 
 class nsMappedAttributeElement : public nsMappedAttributeElementBase
 {
 
 protected:
 
   explicit nsMappedAttributeElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsMappedAttributeElementBase(aNodeInfo)
   {}
 
 public:
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
 
   static void MapNoAttributesInto(const nsMappedAttributes* aAttributes,
-                                  mozilla::GenericSpecifiedValues* aGenericData);
+                                  mozilla::MappedDeclarations&);
 
   virtual bool SetAndSwapMappedAttribute(nsAtom* aName,
                                          nsAttrValue& aValue,
                                          bool* aValueWasSet,
                                          nsresult* aRetval) override;
 
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 };
--- a/dom/base/nsMappedAttributes.cpp
+++ b/dom/base/nsMappedAttributes.cpp
@@ -7,20 +7,19 @@
 /*
  * A unique per-element set of attributes that is used as an
  * nsIStyleRule; used to implement presentational attributes.
  */
 
 #include "nsMappedAttributes.h"
 #include "nsHTMLStyleSheet.h"
 #include "mozilla/DeclarationBlock.h"
-#include "mozilla/GenericSpecifiedValues.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/ServoSpecifiedValues.h"
 
 using namespace mozilla;
 
 bool
 nsMappedAttributes::sShuttingDown = false;
 nsTArray<void*>*
 nsMappedAttributes::sCachedMappedAttributeAllocations = nullptr;
 
@@ -306,13 +305,14 @@ nsMappedAttributes::SizeOfIncludingThis(
 
 void
 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(aDoc, mServoStyle.get());
-    (*mRuleMapper)(this, &servo);
+    MappedDeclarations declarations(
+      aDoc, Servo_DeclarationBlock_CreateEmpty().Consume());
+    (*mRuleMapper)(this, declarations);
+    mServoStyle = declarations.TakeDeclarationBlock();
   }
 }
--- a/dom/html/HTMLBRElement.cpp
+++ b/dom/html/HTMLBRElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLBRElement.h"
 #include "mozilla/dom/HTMLBRElementBinding.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(BR)
 
 namespace mozilla {
@@ -48,24 +48,24 @@ HTMLBRElement::ParseAttribute(int32_t aN
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLBRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                     GenericSpecifiedValues* aData)
+                                     MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_clear)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_clear)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::clear);
     if (value && value->Type() == nsAttrValue::eEnum)
-      aData->SetKeywordValue(eCSSProperty_clear, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_clear, value->GetEnumValue());
   }
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLBRElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::clear },
     { nullptr }
--- a/dom/html/HTMLBRElement.h
+++ b/dom/html/HTMLBRElement.h
@@ -43,16 +43,16 @@ public:
   }
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   virtual ~HTMLBRElement();
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "HTMLBodyElement.h"
 #include "mozilla/dom/HTMLBodyElementBinding.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/TextEditor.h"
 #include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
@@ -69,17 +69,17 @@ HTMLBodyElement::ParseAttribute(int32_t 
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                       GenericSpecifiedValues* aData)
+                                       MappedDeclarations& aDecls)
 {
   // This is the one place where we try to set the same property
   // multiple times in presentation attributes. Servo does not support
   // querying if a property is set (because that is O(n) behavior
   // in ServoSpecifiedValues). Instead, we use the below values to keep
   // track of whether we have already set a property, and if so, what value
   // we set it to (which is used when handling margin
   // attributes from the containing frame element)
@@ -94,109 +94,109 @@ HTMLBodyElement::MapAttributesIntoRule(c
   const nsAttrValue* value;
   // if marginwidth/marginheight are set, reflect them as 'margin'
   value = aAttributes->GetAttr(nsGkAtoms::marginwidth);
   if (value && value->Type() == nsAttrValue::eInteger) {
     bodyMarginWidth = value->GetIntegerValue();
     if (bodyMarginWidth < 0) {
       bodyMarginWidth = 0;
     }
-    aData->SetPixelValueIfUnset(eCSSProperty_margin_left, (float)bodyMarginWidth);
-    aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)bodyMarginWidth);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left, (float)bodyMarginWidth);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_margin_right, (float)bodyMarginWidth);
   }
 
   value = aAttributes->GetAttr(nsGkAtoms::marginheight);
   if (value && value->Type() == nsAttrValue::eInteger) {
     bodyMarginHeight = value->GetIntegerValue();
     if (bodyMarginHeight < 0) {
       bodyMarginHeight = 0;
     }
-    aData->SetPixelValueIfUnset(eCSSProperty_margin_top, (float)bodyMarginHeight);
-    aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)bodyMarginHeight);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_margin_top, (float)bodyMarginHeight);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)bodyMarginHeight);
   }
 
     // topmargin (IE-attribute)
   if (bodyMarginHeight == -1) {
     value = aAttributes->GetAttr(nsGkAtoms::topmargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyTopMargin = value->GetIntegerValue();
       if (bodyTopMargin < 0) {
         bodyTopMargin = 0;
       }
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_top, (float)bodyTopMargin);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_top, (float)bodyTopMargin);
     }
   }
     // bottommargin (IE-attribute)
 
   if (bodyMarginHeight == -1) {
     value = aAttributes->GetAttr(nsGkAtoms::bottommargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyBottomMargin = value->GetIntegerValue();
       if (bodyBottomMargin < 0) {
         bodyBottomMargin = 0;
       }
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)bodyBottomMargin);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)bodyBottomMargin);
     }
   }
 
     // leftmargin (IE-attribute)
   if (bodyMarginWidth == -1) {
     value = aAttributes->GetAttr(nsGkAtoms::leftmargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyLeftMargin = value->GetIntegerValue();
       if (bodyLeftMargin < 0) {
         bodyLeftMargin = 0;
       }
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_left, (float)bodyLeftMargin);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left, (float)bodyLeftMargin);
     }
   }
     // rightmargin (IE-attribute)
   if (bodyMarginWidth == -1) {
     value = aAttributes->GetAttr(nsGkAtoms::rightmargin);
     if (value && value->Type() == nsAttrValue::eInteger) {
       bodyRightMargin = value->GetIntegerValue();
       if (bodyRightMargin < 0) {
         bodyRightMargin = 0;
       }
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)bodyRightMargin);
+      aDecls.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->Document()->GetDocShell());
+    nsCOMPtr<nsIDocShell> docShell(aDecls.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) {
-          aData->SetPixelValueIfUnset(eCSSProperty_margin_left, (float)frameMarginWidth);
+          aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left, (float)frameMarginWidth);
         }
         if (bodyRightMargin == -1) {
-          aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)frameMarginWidth);
+          aDecls.SetPixelValueIfUnset(eCSSProperty_margin_right, (float)frameMarginWidth);
         }
       }
 
       if (bodyMarginHeight == -1 && frameMarginHeight >= 0) {
         if (bodyTopMargin == -1) {
-          aData->SetPixelValueIfUnset(eCSSProperty_margin_top, (float)frameMarginHeight);
+          aDecls.SetPixelValueIfUnset(eCSSProperty_margin_top, (float)frameMarginHeight);
         }
         if (bodyBottomMargin == -1) {
-          aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)frameMarginHeight);
+          aDecls.SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)frameMarginHeight);
         }
       }
     }
   }
 
   // When display if first asked for, go ahead and get our colors set up.
-  if (nsHTMLStyleSheet* styleSheet = aData->Document()->GetAttributeStyleSheet()) {
+  if (nsHTMLStyleSheet* styleSheet = aDecls.Document()->GetAttributeStyleSheet()) {
     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)) {
@@ -204,27 +204,27 @@ HTMLBodyElement::MapAttributesIntoRule(c
     }
 
     value = aAttributes->GetAttr(nsGkAtoms::vlink);
     if (value && value->GetColorValue(color)) {
       styleSheet->SetVisitedLinkColor(color);
     }
   }
 
-  if (!aData->PropertyIsSet(eCSSProperty_color)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_color)) {
     // color: color
     nscolor color;
     value = aAttributes->GetAttr(nsGkAtoms::text);
     if (value && value->GetColorValue(color)) {
-      aData->SetColorValue(eCSSProperty_color, color);
+      aDecls.SetColorValue(eCSSProperty_color, color);
     }
   }
 
-  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsMapRuleToAttributesFunc
 HTMLBodyElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
--- a/dom/html/HTMLBodyElement.h
+++ b/dom/html/HTMLBodyElement.h
@@ -149,15 +149,15 @@ public:
 
 protected:
   virtual ~HTMLBodyElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLBodyElement_h___ */
--- a/dom/html/HTMLDivElement.cpp
+++ b/dom/html/HTMLDivElement.cpp
@@ -56,29 +56,29 @@ HTMLDivElement::ParseAttribute(int32_t a
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLDivElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                      GenericSpecifiedValues* aData)
+                                      MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 static void
-MapMarqueeAttributesIntoRule(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData)
+MapMarqueeAttributesIntoRule(const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapBGColorInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapBGColorInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLDivElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   if (mNodeInfo->Equals(nsGkAtoms::div)) {
     static const MappedAttributeEntry* const map[] = {
       sDivAlignAttributeMap,
--- a/dom/html/HTMLDivElement.h
+++ b/dom/html/HTMLDivElement.h
@@ -41,15 +41,15 @@ public:
 
 protected:
   virtual ~HTMLDivElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLDivElement_h___ */
--- a/dom/html/HTMLEmbedElement.cpp
+++ b/dom/html/HTMLEmbedElement.cpp
@@ -233,38 +233,38 @@ HTMLEmbedElement::ParseAttribute(int32_t
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 static void
 MapAttributesIntoRuleBase(const nsMappedAttributes *aAttributes,
-                          GenericSpecifiedValues* aData)
+                          MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aDecls);
 }
 
 static void
 MapAttributesIntoRuleExceptHidden(const nsMappedAttributes *aAttributes,
-                                  GenericSpecifiedValues* aData)
+                                  MappedDeclarations& aDecls)
 {
-  MapAttributesIntoRuleBase(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aAttributes, aData);
+  MapAttributesIntoRuleBase(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(aAttributes, aDecls);
 }
 
 void
 HTMLEmbedElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
-  MapAttributesIntoRuleBase(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  MapAttributesIntoRuleBase(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLEmbedElement::IsAttributeMapped(const nsAtom *aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sCommonAttributeMap,
     sImageMarginSizeAttributeMap,
--- a/dom/html/HTMLEmbedElement.h
+++ b/dom/html/HTMLEmbedElement.h
@@ -145,17 +145,17 @@ protected:
 private:
   ~HTMLEmbedElement();
 
   nsContentPolicyType GetContentPolicyType() const override;
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 
   /**
    * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
    * It will not be called if the value is being unset.
    *
    * @param aNamespaceID the namespace of the attr being set
    * @param aName the localname of the attribute being set
    * @param aNotify Whether we plan to notify document observers.
--- a/dom/html/HTMLFontElement.cpp
+++ b/dom/html/HTMLFontElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "HTMLFontElement.h"
 #include "mozilla/dom/HTMLFontElementBinding.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsMappedAttributes.h"
 #include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Font)
 
 namespace mozilla {
 namespace dom {
@@ -50,52 +50,52 @@ HTMLFontElement::ParseAttribute(int32_t 
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLFontElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                       GenericSpecifiedValues* aData)
+                                       MappedDeclarations& aDecls)
 {
   // face: string list
-  if (!aData->PropertyIsSet(eCSSProperty_font_family)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_font_family)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::face);
     if (value && value->Type() == nsAttrValue::eString &&
         !value->IsEmptyString()) {
-      aData->SetFontFamily(value->GetStringValue());
+      aDecls.SetFontFamily(value->GetStringValue());
     }
   }
   // size: int
-  if (!aData->PropertyIsSet(eCSSProperty_font_size)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_font_size)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
     if (value && value->Type() == nsAttrValue::eInteger)
-      aData->SetKeywordValue(eCSSProperty_font_size, value->GetIntegerValue());
+      aDecls.SetKeywordValue(eCSSProperty_font_size, value->GetIntegerValue());
   }
-  if (!aData->PropertyIsSet(eCSSProperty_color)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_color)) {
     // color: color
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
     nscolor color;
     if (value && value->GetColorValue(color)) {
-      aData->SetColorValue(eCSSProperty_color, color);
+      aDecls.SetColorValue(eCSSProperty_color, color);
     }
   }
-  if (aData->Document()->GetCompatibilityMode() == eCompatibility_NavQuirks) {
+  if (aDecls.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();
+      aDecls.SetTextDecorationColorOverride();
     }
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLFontElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::face },
     { &nsGkAtoms::size },
--- a/dom/html/HTMLFontElement.h
+++ b/dom/html/HTMLFontElement.h
@@ -57,15 +57,15 @@ public:
 
 protected:
   virtual ~HTMLFontElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* HTMLFontElement_h___ */
--- a/dom/html/HTMLFrameElement.h
+++ b/dom/html/HTMLFrameElement.h
@@ -115,15 +115,15 @@ public:
 
 protected:
   virtual ~HTMLFrameElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLFrameElement_h
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -56,17 +56,17 @@ HTMLHRElement::ParseAttribute(int32_t aN
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLHRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                     GenericSpecifiedValues* aData)
+                                     MappedDeclarations& aDecls)
 {
   bool noshade = false;
 
   const nsAttrValue* colorValue = aAttributes->GetAttr(nsGkAtoms::color);
   nscolor color;
   bool colorIsSet = colorValue && colorValue->GetColorValue(color);
 
   if (colorIsSet) {
@@ -76,42 +76,42 @@ HTMLHRElement::MapAttributesIntoRule(con
   }
 
   // align: enum
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
   if (value && value->Type() == nsAttrValue::eEnum) {
     // Map align attribute into auto side margins
     switch (value->GetEnumValue()) {
     case NS_STYLE_TEXT_ALIGN_LEFT:
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_left, 0.0f);
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_right);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left, 0.0f);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_right);
       break;
     case NS_STYLE_TEXT_ALIGN_RIGHT:
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_left);
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_right, 0.0f);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_left);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_right, 0.0f);
       break;
     case NS_STYLE_TEXT_ALIGN_CENTER:
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_left);
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_right);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_left);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_right);
       break;
     }
   }
-  if (!aData->PropertyIsSet(eCSSProperty_height)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_height)) {
     // size: integer
     if (noshade) {
       // noshade case: size is set using the border
-      aData->SetAutoValue(eCSSProperty_height);
+      aDecls.SetAutoValue(eCSSProperty_height);
     } else {
       // normal case
       // the height includes the top and bottom borders that are initially 1px.
       // for size=1, html.css has a special case rule that makes this work by
       // removing all but the top border.
       const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::size);
       if (value && value->Type() == nsAttrValue::eInteger) {
-        aData->SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
+        aDecls.SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
       } // else use default value from html.css
     }
   }
 
   // if not noshade, border styles are dealt with by html.css
   if (noshade) {
     // size: integer
     // if a size is set, use half of it per side, otherwise, use 1px per side
@@ -125,53 +125,53 @@ HTMLHRElement::MapAttributesIntoRule(con
         // subpixel borders should be removed.
         // In the meantime, this makes http://www.microsoft.com/ look right.
         sizePerSide = 1.0f;
         allSides = false;
       }
     } else {
       sizePerSide = 1.0f; // default to a 2px high line
     }
-    aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, sizePerSide);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_border_top_width, sizePerSide);
     if (allSides) {
-      aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, sizePerSide);
-      aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, sizePerSide);
-      aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, sizePerSide);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_right_width, sizePerSide);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, sizePerSide);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_left_width, sizePerSide);
     }
 
-    if (!aData->PropertyIsSet(eCSSProperty_border_top_style))
-      aData->SetKeywordValue(eCSSProperty_border_top_style,
+    if (!aDecls.PropertyIsSet(eCSSProperty_border_top_style))
+      aDecls.SetKeywordValue(eCSSProperty_border_top_style,
                              NS_STYLE_BORDER_STYLE_SOLID);
     if (allSides) {
-      aData->SetKeywordValueIfUnset(eCSSProperty_border_right_style,
+      aDecls.SetKeywordValueIfUnset(eCSSProperty_border_right_style,
                                     NS_STYLE_BORDER_STYLE_SOLID);
-      aData->SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
+      aDecls.SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
                                     NS_STYLE_BORDER_STYLE_SOLID);
-      aData->SetKeywordValueIfUnset(eCSSProperty_border_left_style,
+      aDecls.SetKeywordValueIfUnset(eCSSProperty_border_left_style,
                                     NS_STYLE_BORDER_STYLE_SOLID);
 
       // If it would be noticeable, set the border radius to
       // 10000px on all corners; this triggers the clamping to make
       // circular ends.  This assumes the <hr> isn't larger than
       // that in *both* dimensions.
       for (const nsCSSPropertyID* props =
             nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
            *props != eCSSProperty_UNKNOWN; ++props) {
-        aData->SetPixelValueIfUnset(*props, 10000.0f);
+        aDecls.SetPixelValueIfUnset(*props, 10000.0f);
       }
     }
   }
   // color: a color
   // (we got the color attribute earlier)
   if (colorIsSet) {
-    aData->SetColorValueIfUnset(eCSSProperty_color, color);
+    aDecls.SetColorValueIfUnset(eCSSProperty_color, color);
   }
 
-  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLHRElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
     { &nsGkAtoms::width },
--- a/dom/html/HTMLHRElement.h
+++ b/dom/html/HTMLHRElement.h
@@ -81,15 +81,15 @@ public:
 
 protected:
   virtual ~HTMLHRElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLHRElement_h
--- a/dom/html/HTMLHeadingElement.cpp
+++ b/dom/html/HTMLHeadingElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLHeadingElement.h"
 #include "mozilla/dom/HTMLHeadingElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "mozAutoDocUpdate.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Heading)
 
 namespace mozilla {
@@ -42,20 +42,20 @@ HTMLHeadingElement::ParseAttribute(int32
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLHeadingElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                          GenericSpecifiedValues* aData)
+                                          MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLHeadingElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sDivAlignAttributeMap,
     sCommonAttributeMap
--- a/dom/html/HTMLHeadingElement.h
+++ b/dom/html/HTMLHeadingElement.h
@@ -42,15 +42,15 @@ public:
 
 protected:
   virtual ~HTMLHeadingElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLHeadingElement_h
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/HTMLIFrameElementBinding.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsError.h"
 #include "nsStyleConsts.h"
 #include "nsContentUtils.h"
 #include "nsSandboxFlags.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
@@ -77,37 +77,37 @@ HTMLIFrameElement::ParseAttribute(int32_
   return nsGenericHTMLFrameElement::ParseAttribute(aNamespaceID, aAttribute,
                                                    aValue,
                                                    aMaybeScriptedPrincipal,
                                                    aResult);
 }
 
 void
 HTMLIFrameElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                         GenericSpecifiedValues* aData)
+                                         MappedDeclarations& aDecls)
 {
   // frameborder: 0 | 1 (| NO | YES in quirks mode)
   // If frameborder is 0 or No, set border to 0
   // else leave it as the value set in html.css
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::frameborder);
   if (value && value->Type() == nsAttrValue::eEnum) {
     int32_t frameborder = value->GetEnumValue();
     if (NS_STYLE_FRAME_0 == frameborder ||
         NS_STYLE_FRAME_NO == frameborder ||
         NS_STYLE_FRAME_OFF == frameborder) {
-      aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, 0.0f);
-      aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, 0.0f);
-      aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, 0.0f);
-      aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, 0.0f);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_top_width, 0.0f);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_right_width, 0.0f);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, 0.0f);
+      aDecls.SetPixelValueIfUnset(eCSSProperty_border_left_width, 0.0f);
     }
   }
 
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLIFrameElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::width },
     { &nsGkAtoms::height },
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -200,17 +200,17 @@ protected:
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 bool aNotify) override;
   virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
                                           const nsAttrValueOrString& aValue,
                                           bool aNotify) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 
   static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
 
   /**
    * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
    * This function will be called by AfterSetAttr whether the attribute is being
    * set or unset.
    *
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -39,17 +39,17 @@
 #include "imgILoader.h"
 #include "imgINotificationObserver.h"
 #include "imgRequestProxy.h"
 
 #include "nsILoadGroup.h"
 
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 #include "nsLayoutUtils.h"
 
 using namespace mozilla::net;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Image)
 
@@ -243,23 +243,23 @@ HTMLImageElement::ParseAttribute(int32_t
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLImageElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsChangeHint
 HTMLImageElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                          int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -402,17 +402,17 @@ protected:
 
   // Created when we're tracking responsive image state
   RefPtr<ResponsiveImageSelector> mResponsiveSelector;
 
 private:
   bool SourceElementMatches(Element* aSourceElement);
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
   /**
    * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
    * It will not be called if the value is being unset.
    *
    * @param aNamespaceID the namespace of the attr being set
    * @param aName the localname of the attribute being set
    * @param aValue the value it's being set to represented as either a string or
    *        a parsed nsAttrValue.
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -60,17 +60,17 @@
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsVariant.h"
 
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/TextEditor.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 
 #include <algorithm>
 
 // input type=radio
@@ -5576,29 +5576,29 @@ HTMLInputElement::ParseAttribute(int32_t
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLInputElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
   if (value && value->Type() == nsAttrValue::eEnum &&
       value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
-    nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aData);
-    nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aData);
-    nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aData);
+    nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aDecls);
+    nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aDecls);
+    nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aDecls);
     // Images treat align as "float"
-    nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
-  }
-
-  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
+    nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aDecls);
+  }
+
+  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsChangeHint
 HTMLInputElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                          int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1662,17 +1662,17 @@ protected:
   bool                     mNumberControlSpinnerSpinsUp : 1;
   bool                     mPickerRunning : 1;
   bool                     mSelectionCached : 1;
   bool                     mIsPreviewEnabled : 1;
   bool                     mHasPatternAttribute : 1;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 
   /**
    * Returns true if this input's type will fire a DOM "change" event when it
    * loses focus if its value has changed since it gained focus.
    */
   bool MayFireChangeOnBlur() const {
     return MayFireChangeOnBlur(mType);
   }
--- a/dom/html/HTMLLIElement.cpp
+++ b/dom/html/HTMLLIElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLLIElement.h"
 #include "mozilla/dom/HTMLLIElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(LI)
 
 namespace mozilla {
@@ -62,26 +62,26 @@ HTMLLIElement::ParseAttribute(int32_t aN
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLLIElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                     GenericSpecifiedValues* aData)
+                                     MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_list_style_type)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_list_style_type)) {
     // type: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
     if (value && value->Type() == nsAttrValue::eEnum)
-      aData->SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLLIElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::type },
     { nullptr },
--- a/dom/html/HTMLLIElement.h
+++ b/dom/html/HTMLLIElement.h
@@ -55,15 +55,15 @@ public:
 
 protected:
   virtual ~HTMLLIElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLLIElement_h
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -460,24 +460,24 @@ HTMLObjectElement::ParseAttribute(int32_
     }
   }
 
   return nsGenericHTMLFormElement::ParseAttribute(aNamespaceID, aAttribute,
                                                   aValue, aMaybeScriptedPrincipal, aResult);
 }
 
 void
-HTMLObjectElement::MapAttributesIntoRule(const nsMappedAttributes *aAttributes,
-                                         GenericSpecifiedValues *aData)
+HTMLObjectElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
+                                         MappedDeclarations& aDecls)
 {
-  nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aData);
-  nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aData);
-  nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLObjectElement::IsAttributeMapped(const nsAtom *aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sCommonAttributeMap,
     sImageMarginSizeAttributeMap,
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -270,17 +270,17 @@ private:
     return nsIContentPolicy::TYPE_INTERNAL_OBJECT;
   }
 
   virtual ~HTMLObjectElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 
   /**
    * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
    * This function will be called by AfterSetAttr whether the attribute is being
    * set or unset.
    *
    * @param aNamespaceID the namespace of the attr being set
    * @param aName the localname of the attribute being set
--- a/dom/html/HTMLOptionsCollection.cpp
+++ b/dom/html/HTMLOptionsCollection.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLOptionsCollection.h"
 
 #include "HTMLOptGroupElement.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
 #include "mozilla/dom/HTMLSelectElement.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIComboboxControlFrame.h"
--- a/dom/html/HTMLParagraphElement.cpp
+++ b/dom/html/HTMLParagraphElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLParagraphElement.h"
 #include "mozilla/dom/HTMLParagraphElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Paragraph)
 
 namespace mozilla {
 namespace dom {
@@ -35,20 +35,20 @@ HTMLParagraphElement::ParseAttribute(int
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLParagraphElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                            GenericSpecifiedValues* aData)
+                                            MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLParagraphElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry* const map[] = {
     sDivAlignAttributeMap,
     sCommonAttributeMap,
--- a/dom/html/HTMLParagraphElement.h
+++ b/dom/html/HTMLParagraphElement.h
@@ -49,15 +49,15 @@ public:
 
 protected:
   virtual ~HTMLParagraphElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLParagraphElement_h
--- a/dom/html/HTMLPreElement.cpp
+++ b/dom/html/HTMLPreElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLPreElement.h"
 #include "mozilla/dom/HTMLPreElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Pre)
 
 namespace mozilla {
@@ -38,25 +38,25 @@ HTMLPreElement::ParseAttribute(int32_t a
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLPreElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                      GenericSpecifiedValues* aData)
+                                      MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_white_space)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_white_space)) {
     // wrap: empty
     if (aAttributes->GetAttr(nsGkAtoms::wrap))
-      aData->SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::PreWrap);
+      aDecls.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::PreWrap);
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLPreElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   if (!mNodeInfo->Equals(nsGkAtoms::pre)) {
     return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
   }
--- a/dom/html/HTMLPreElement.h
+++ b/dom/html/HTMLPreElement.h
@@ -48,15 +48,15 @@ public:
 
 protected:
   virtual ~HTMLPreElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLPreElement_h
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -12,17 +12,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/HTMLOptGroupElement.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLSelectElementBinding.h"
 #include "mozilla/dom/UnionTypes.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIComboboxControlFrame.h"
 #include "nsIDocument.h"
 #include "nsIFormControlFrame.h"
 #include "nsIForm.h"
@@ -1268,20 +1268,20 @@ HTMLSelectElement::ParseAttribute(int32_
     }
   }
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLSelectElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                         GenericSpecifiedValues* aData)
+                                         MappedDeclarations& aDecls)
 {
-  nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsChangeHint
 HTMLSelectElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -608,15 +608,15 @@ protected:
 
   /**
    * The current displayed preview text.
   */
   nsString  mPreviewValue;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSelectElement_h
--- a/dom/html/HTMLSharedElement.cpp
+++ b/dom/html/HTMLSharedElement.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/HTMLBaseElementBinding.h"
 #include "mozilla/dom/HTMLDirectoryElementBinding.h"
 #include "mozilla/dom/HTMLHeadElementBinding.h"
 #include "mozilla/dom/HTMLHtmlElementBinding.h"
 #include "mozilla/dom/HTMLParamElementBinding.h"
 #include "mozilla/dom/HTMLQuoteElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 #include "nsContentUtils.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
@@ -74,31 +74,31 @@ HTMLSharedElement::ParseAttribute(int32_
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 static void
 DirectoryMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                               GenericSpecifiedValues* aData)
+                               MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_list_style_type)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_list_style_type)) {
     // type: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
     if (value) {
       if (value->Type() == nsAttrValue::eEnum) {
-        aData->SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
+        aDecls.SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
       } else {
-        aData->SetKeywordValue(eCSSProperty_list_style_type, NS_STYLE_LIST_STYLE_DISC);
+        aDecls.SetKeywordValue(eCSSProperty_list_style_type, NS_STYLE_LIST_STYLE_DISC);
       }
     }
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLSharedElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   if (mNodeInfo->Equals(nsGkAtoms::dir)) {
     static const MappedAttributeEntry attributes[] = {
       { &nsGkAtoms::type },
--- a/dom/html/HTMLSharedListElement.cpp
+++ b/dom/html/HTMLSharedListElement.cpp
@@ -4,17 +4,17 @@
  * 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/dom/HTMLSharedListElement.h"
 #include "mozilla/dom/HTMLDListElementBinding.h"
 #include "mozilla/dom/HTMLOListElementBinding.h"
 #include "mozilla/dom/HTMLUListElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(SharedList)
 
@@ -76,27 +76,27 @@ HTMLSharedListElement::ParseAttribute(in
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLSharedListElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                             GenericSpecifiedValues* aData)
+                                             MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_list_style_type)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_list_style_type)) {
     // type: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
     if (value && value->Type() == nsAttrValue::eEnum) {
-      aData->SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
     }
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLSharedListElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   if (mNodeInfo->Equals(nsGkAtoms::ol) ||
       mNodeInfo->Equals(nsGkAtoms::ul)) {
     static const MappedAttributeEntry attributes[] = {
--- a/dom/html/HTMLSharedListElement.h
+++ b/dom/html/HTMLSharedListElement.h
@@ -70,15 +70,15 @@ public:
 
 protected:
   virtual ~HTMLSharedListElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSharedListElement_h
--- a/dom/html/HTMLSpanElement.cpp
+++ b/dom/html/HTMLSpanElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLSpanElement.h"
 #include "mozilla/dom/HTMLSpanElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsAtom.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Span)
 
 namespace mozilla {
 namespace dom {
--- a/dom/html/HTMLTableCaptionElement.cpp
+++ b/dom/html/HTMLTableCaptionElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLTableCaptionElement.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsMappedAttributes.h"
 #include "mozilla/dom/HTMLTableCaptionElementBinding.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableCaption)
 
 namespace mozilla {
 namespace dom {
@@ -48,25 +48,25 @@ HTMLTableCaptionElement::ParseAttribute(
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTableCaptionElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                               GenericSpecifiedValues* aData)
+                                               MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_caption_side)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_caption_side)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
     if (value && value->Type() == nsAttrValue::eEnum)
-      aData->SetKeywordValue(eCSSProperty_caption_side, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_caption_side, value->GetEnumValue());
   }
 
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableCaptionElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
     { nullptr }
--- a/dom/html/HTMLTableCaptionElement.h
+++ b/dom/html/HTMLTableCaptionElement.h
@@ -43,15 +43,15 @@ public:
 
 protected:
   virtual ~HTMLTableCaptionElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableCaptionElement_h */
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLTableCellElement.h"
 #include "mozilla/dom/HTMLTableElement.h"
 #include "mozilla/dom/HTMLTableRowElement.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "celldata.h"
 #include "mozilla/dom/HTMLTableCellElementBinding.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableCell)
 
 namespace mozilla {
@@ -178,64 +178,64 @@ HTMLTableCellElement::ParseAttribute(int
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTableCellElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                            GenericSpecifiedValues* aData)
+                                            MappedDeclarations& aDecls)
 {
   // width: value
-  if (!aData->PropertyIsSet(eCSSProperty_width)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_width)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
     if (value && value->Type() == nsAttrValue::eInteger) {
       if (value->GetIntegerValue() > 0)
-        aData->SetPixelValue(eCSSProperty_width, (float)value->GetIntegerValue());
+        aDecls.SetPixelValue(eCSSProperty_width, (float)value->GetIntegerValue());
       // else 0 implies auto for compatibility.
     }
     else if (value && value->Type() == nsAttrValue::ePercent) {
       if (value->GetPercentValue() > 0.0f)
-        aData->SetPercentValue(eCSSProperty_width, value->GetPercentValue());
+        aDecls.SetPercentValue(eCSSProperty_width, value->GetPercentValue());
       // else 0 implies auto for compatibility
     }
   }
   // height: value
-  if (!aData->PropertyIsSet(eCSSProperty_height)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_height)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
     if (value && value->Type() == nsAttrValue::eInteger) {
       if (value->GetIntegerValue() > 0)
-        aData->SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
+        aDecls.SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
       // else 0 implies auto for compatibility.
     }
     else if (value && value->Type() == nsAttrValue::ePercent) {
       if (value->GetPercentValue() > 0.0f)
-        aData->SetPercentValue(eCSSProperty_height, value->GetPercentValue());
+        aDecls.SetPercentValue(eCSSProperty_height, value->GetPercentValue());
       // else 0 implies auto for compatibility
     }
   }
-  if (!aData->PropertyIsSet(eCSSProperty_white_space)) {
+  if (!aDecls.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->Document()->GetCompatibilityMode();
+      nsCompatibility mode = aDecls.Document()->GetCompatibilityMode();
       if (!value || value->Type() != nsAttrValue::eInteger ||
           value->GetIntegerValue() == 0 ||
           eCompatibility_NavQuirks != mode) {
-        aData->SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Nowrap);
+        aDecls.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Nowrap);
       }
     }
   }
 
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableCellElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
     { &nsGkAtoms::valign },
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -156,15 +156,15 @@ protected:
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLTableElement* GetTable() const;
 
   HTMLTableRowElement* GetRow() const;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableCellElement_h */
--- a/dom/html/HTMLTableColElement.cpp
+++ b/dom/html/HTMLTableColElement.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLTableColElement.h"
 #include "mozilla/dom/HTMLTableColElementBinding.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableCol)
 
 namespace mozilla {
 namespace dom {
 
 // use the same protection as ancient code did
 // http://lxr.mozilla.org/classic/source/lib/layout/laytable.c#46
@@ -60,36 +60,36 @@ HTMLTableColElement::ParseAttribute(int3
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTableColElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                           GenericSpecifiedValues* aData)
+                                           MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty__x_span)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty__x_span)) {
     // span: int
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::span);
     if (value && value->Type() == nsAttrValue::eInteger) {
       int32_t val = value->GetIntegerValue();
       // Note: Do NOT use this code for table cells!  The value "0"
       // means something special for colspan and rowspan, but for <col
       // span> and <colgroup span> it's just disallowed.
       if (val > 0) {
-        aData->SetIntValue(eCSSProperty__x_span, value->GetIntegerValue());
+        aDecls.SetIntValue(eCSSProperty__x_span, value->GetIntegerValue());
       }
     }
   }
 
-  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableColElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::width },
     { &nsGkAtoms::align },
--- a/dom/html/HTMLTableColElement.h
+++ b/dom/html/HTMLTableColElement.h
@@ -84,15 +84,15 @@ public:
 
 protected:
   virtual ~HTMLTableColElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableColElement_h */
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLTableElement.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsAttrValueInlines.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsMappedAttributes.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/HTMLTableElementBinding.h"
 #include "nsContentUtils.h"
 #include "jsfriendapi.h"
 
@@ -927,94 +927,94 @@ HTMLTableElement::ParseAttribute(int32_t
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 
 
 void
 HTMLTableElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
   // XXX Bug 211636:  This function is used by a single style rule
   // that's used to match two different type of elements -- tables, and
   // 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 ComputedStyle rather than checking
   // which *element* it's matching (style rules should not stop matching
   // when the display type is changed).
 
-  nsCompatibility mode = aData->Document()->GetCompatibilityMode();
+  nsCompatibility mode = aDecls.Document()->GetCompatibilityMode();
 
   // 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()));
+      !aDecls.PropertyIsSet(eCSSProperty_border_spacing)) {
+    aDecls.SetPixelValue(eCSSProperty_border_spacing, float(value->GetIntegerValue()));
   }
   // align; Check for enumerated type (it may be another type if
   // illegal)
   value = aAttributes->GetAttr(nsGkAtoms::align);
   if (value && value->Type() == nsAttrValue::eEnum) {
     if (value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_CENTER ||
         value->GetEnumValue() == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) {
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_left);
-      aData->SetAutoValueIfUnset(eCSSProperty_margin_right);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_left);
+      aDecls.SetAutoValueIfUnset(eCSSProperty_margin_right);
     }
   }
 
   // hspace is mapped into left and right margin,
   // vspace is mapped into top and bottom margins
   // - *** Quirks Mode only ***
   if (eCompatibility_NavQuirks == mode) {
     value = aAttributes->GetAttr(nsGkAtoms::hspace);
 
     if (value && value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_left, (float)value->GetIntegerValue());
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_right, (float)value->GetIntegerValue());
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left, (float)value->GetIntegerValue());
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_right, (float)value->GetIntegerValue());
     }
 
     value = aAttributes->GetAttr(nsGkAtoms::vspace);
 
     if (value && value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_top, (float)value->GetIntegerValue());
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)value->GetIntegerValue());
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_top, (float)value->GetIntegerValue());
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_bottom, (float)value->GetIntegerValue());
     }
   }
   // bordercolor
   value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
   nscolor color;
   if (value && 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);
+    aDecls.SetColorValueIfUnset(eCSSProperty_border_top_color, color);
+    aDecls.SetColorValueIfUnset(eCSSProperty_border_left_color, color);
+    aDecls.SetColorValueIfUnset(eCSSProperty_border_bottom_color, color);
+    aDecls.SetColorValueIfUnset(eCSSProperty_border_right_color, color);
   }
 
   // border
   const nsAttrValue* borderValue = aAttributes->GetAttr(nsGkAtoms::border);
   if (borderValue) {
     // border = 1 pixel default
     int32_t borderThickness = 1;
 
     if (borderValue->Type() == nsAttrValue::eInteger)
       borderThickness = borderValue->GetIntegerValue();
 
     // by default, set all border sides to the specified width
-    aData->SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)borderThickness);
-    aData->SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)borderThickness);
-    aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)borderThickness);
-    aData->SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)borderThickness);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)borderThickness);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)borderThickness);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)borderThickness);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)borderThickness);
   }
 
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::cellpadding },
     { &nsGkAtoms::cellspacing },
@@ -1042,28 +1042,28 @@ HTMLTableElement::IsAttributeMapped(cons
 nsMapRuleToAttributesFunc
 HTMLTableElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
 static void
 MapInheritedTableAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aData)
+                                    MappedDeclarations& aDecls)
 {
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::cellpadding);
   if (value && value->Type() == nsAttrValue::eInteger) {
     // We have cellpadding.  This will override our padding values if we
     // don't have any set.
     float pad = float(value->GetIntegerValue());
 
-    aData->SetPixelValueIfUnset(eCSSProperty_padding_top, pad);
-    aData->SetPixelValueIfUnset(eCSSProperty_padding_right, pad);
-    aData->SetPixelValueIfUnset(eCSSProperty_padding_bottom, pad);
-    aData->SetPixelValueIfUnset(eCSSProperty_padding_left, pad);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_padding_top, pad);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_padding_right, pad);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_padding_bottom, pad);
+    aDecls.SetPixelValueIfUnset(eCSSProperty_padding_left, pad);
   }
 }
 
 nsMappedAttributes*
 HTMLTableElement::GetAttributesMappedForCell()
 {
   return mTableInheritedAttributes;
 }
--- a/dom/html/HTMLTableElement.h
+++ b/dom/html/HTMLTableElement.h
@@ -236,15 +236,15 @@ protected:
   RefPtr<nsContentList> mTBodies;
   RefPtr<TableRowsCollection> mRows;
   nsMappedAttributes *mTableInheritedAttributes;
   void BuildInheritedAttributes();
   void ReleaseInheritedAttributes();
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableElement_h */
--- a/dom/html/HTMLTableRowElement.cpp
+++ b/dom/html/HTMLTableRowElement.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLTableRowElement.h"
 #include "mozilla/dom/HTMLTableElement.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLTableRowElementBinding.h"
 #include "nsContentList.h"
 #include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableRow)
@@ -255,23 +255,23 @@ HTMLTableRowElement::ParseAttribute(int3
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTableRowElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                           GenericSpecifiedValues* aData)
+                                           MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableRowElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
     { &nsGkAtoms::valign },
--- a/dom/html/HTMLTableRowElement.h
+++ b/dom/html/HTMLTableRowElement.h
@@ -98,15 +98,15 @@ protected:
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLTableSectionElement* GetSection() const;
   HTMLTableElement* GetTable() const;
   RefPtr<nsContentList> mCells;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableRowElement_h */
--- a/dom/html/HTMLTableSectionElement.cpp
+++ b/dom/html/HTMLTableSectionElement.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/dom/HTMLTableSectionElement.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLTableSectionElementBinding.h"
 #include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableSection)
 
@@ -158,28 +158,28 @@ HTMLTableSectionElement::ParseAttribute(
                                                         aAttribute, aValue,
                                                         aResult) ||
          nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTableSectionElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                               GenericSpecifiedValues* aData)
+                                               MappedDeclarations& aDecls)
 {
   // height: value
-  if (!aData->PropertyIsSet(eCSSProperty_height)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_height)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
     if (value && value->Type() == nsAttrValue::eInteger)
-      aData->SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
+      aDecls.SetPixelValue(eCSSProperty_height, (float)value->GetIntegerValue());
   }
-  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapVAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapBackgroundAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLTableSectionElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::align },
     { &nsGkAtoms::valign },
--- a/dom/html/HTMLTableSectionElement.h
+++ b/dom/html/HTMLTableSectionElement.h
@@ -80,15 +80,15 @@ protected:
   virtual ~HTMLTableSectionElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   RefPtr<nsContentList> mRows;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLTableSectionElement_h */
--- a/dom/html/HTMLTemplateElement.cpp
+++ b/dom/html/HTMLTemplateElement.cpp
@@ -2,17 +2,17 @@
 /* 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/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLTemplateElementBinding.h"
 
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsAtom.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Template)
 
 namespace mozilla {
 namespace dom {
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -8,17 +8,17 @@
 
 #include "mozAutoDocUpdate.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/HTMLTextAreaElementBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/MouseEvents.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentCID.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
 #include "nsIComponentManager.h"
 #include "nsIConstraintValidation.h"
@@ -422,29 +422,29 @@ HTMLTextAreaElement::ParseAttribute(int3
     }
   }
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLTextAreaElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                           GenericSpecifiedValues* aData)
+                                           MappedDeclarations& aDecls)
 {
   // wrap=off
-  if (!aData->PropertyIsSet(eCSSProperty_white_space)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_white_space)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::wrap);
     if (value && value->Type() == nsAttrValue::eString &&
         value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
-      aData->SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre);
+      aDecls.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre);
     }
   }
 
-  nsGenericHTMLFormElementWithState::MapDivAlignAttributeInto(aAttributes, aData);
-  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLFormElementWithState::MapDivAlignAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 nsChangeHint
 HTMLTextAreaElement::GetAttributeChangeHint(const nsAtom* aAttribute,
                                             int32_t aModType) const
 {
   nsChangeHint retval =
       nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -413,16 +413,16 @@ protected:
    * if we have no editor state.
    */
   void GetSelectionRange(uint32_t* aSelectionStart,
                          uint32_t* aSelectionEnd,
                          ErrorResult& aRv);
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -96,20 +96,20 @@ HTMLVideoElement::ParseAttribute(int32_t
    }
 
    return HTMLMediaElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                            aMaybeScriptedPrincipal, aResult);
 }
 
 void
 HTMLVideoElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
-  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
+  nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
 }
 
 NS_IMETHODIMP_(bool)
 HTMLVideoElement::IsAttributeMapped(const nsAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::width },
     { &nsGkAtoms::height },
--- a/dom/html/HTMLVideoElement.h
+++ b/dom/html/HTMLVideoElement.h
@@ -161,17 +161,17 @@ protected:
   void UpdateScreenWakeLock();
 
   RefPtr<WakeLock> mScreenWakeLock;
 
   bool mIsOrientationLocked;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
-                                    GenericSpecifiedValues* aGenericData);
+                                    MappedDeclarations&);
 
   static bool IsVideoStatsEnabled();
   double TotalPlayTime() const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DeclarationBlock.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEditor.h"
 
 #include "nscore.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsCOMPtr.h"
@@ -1157,75 +1157,75 @@ nsGenericHTMLElement::ParseFrameborderVa
 bool
 nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
                                           nsAttrValue& aResult)
 {
   return aResult.ParseEnumValue(aString, kScrollingTable, false);
 }
 
 static inline void
-MapLangAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValues* aData)
+MapLangAttributeInto(const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls)
 {
   const nsAttrValue* langValue = aAttributes->GetAttr(nsGkAtoms::lang);
   if (!langValue) {
     return;
   }
   MOZ_ASSERT(langValue->Type() == nsAttrValue::eAtom);
-  aData->SetIdentAtomValueIfUnset(eCSSProperty__x_lang,
+  aDecls.SetIdentAtomValueIfUnset(eCSSProperty__x_lang,
                                   langValue->GetAtomValue());
-  if (!aData->PropertyIsSet(eCSSProperty_text_emphasis_position)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_text_emphasis_position)) {
     const nsAtom* lang = langValue->GetAtomValue();
     if (nsStyleUtil::MatchesLanguagePrefix(lang, u"zh")) {
-      aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
+      aDecls.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.
-      aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
+      aDecls.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* aData)
+                                                          MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty__moz_user_modify)) {
+  if (!aDecls.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)) {
-        aData->SetKeywordValue(eCSSProperty__moz_user_modify,
+        aDecls.SetKeywordValue(eCSSProperty__moz_user_modify,
                                StyleUserModify::ReadWrite);
       }
       else if (value->Equals(nsGkAtoms::_false, eIgnoreCase)) {
-          aData->SetKeywordValue(eCSSProperty__moz_user_modify,
+          aDecls.SetKeywordValue(eCSSProperty__moz_user_modify,
                                  StyleUserModify::ReadOnly);
       }
     }
   }
 
-  MapLangAttributeInto(aAttributes, aData);
+  MapLangAttributeInto(aAttributes, aDecls);
 }
 
 void
 nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
-                                              GenericSpecifiedValues* aData)
+                                              MappedDeclarations& aDecls)
 {
-  MapCommonAttributesIntoExceptHidden(aAttributes, aData);
-
-  if (!aData->PropertyIsSet(eCSSProperty_display)) {
+  MapCommonAttributesIntoExceptHidden(aAttributes, aDecls);
+
+  if (!aDecls.PropertyIsSet(eCSSProperty_display)) {
     if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
-      aData->SetKeywordValue(eCSSProperty_display, StyleDisplay::None);
+      aDecls.SetKeywordValue(eCSSProperty_display, StyleDisplay::None);
     }
   }
 }
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
   { &nsGkAtoms::lang },
@@ -1270,213 +1270,213 @@ nsGenericHTMLElement::sBackgroundAttribu
 /* static */ const Element::MappedAttributeEntry
 nsGenericHTMLElement::sBackgroundColorAttributeMap[] = {
   { &nsGkAtoms::bgcolor },
   { nullptr }
 };
 
 void
 nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                                 GenericSpecifiedValues* aData)
+                                                 MappedDeclarations& aDecls)
 {
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
   if (value && value->Type() == nsAttrValue::eEnum) {
     int32_t align = value->GetEnumValue();
-    if (!aData->PropertyIsSet(eCSSProperty_float)) {
+    if (!aDecls.PropertyIsSet(eCSSProperty_float)) {
       if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
-        aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Left);
+        aDecls.SetKeywordValue(eCSSProperty_float, StyleFloat::Left);
       } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
-        aData->SetKeywordValue(eCSSProperty_float, StyleFloat::Right);
+        aDecls.SetKeywordValue(eCSSProperty_float, StyleFloat::Right);
       }
     }
-    if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
+    if (!aDecls.PropertyIsSet(eCSSProperty_vertical_align)) {
       switch (align) {
       case NS_STYLE_TEXT_ALIGN_LEFT:
       case NS_STYLE_TEXT_ALIGN_RIGHT:
         break;
       default:
-        aData->SetKeywordValue(eCSSProperty_vertical_align, align);
+        aDecls.SetKeywordValue(eCSSProperty_vertical_align, align);
         break;
       }
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                               GenericSpecifiedValues* aData)
+                                               MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_text_align)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_text_align)) {
     // align: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
     if (value && value->Type() == nsAttrValue::eEnum)
-      aData->SetKeywordValue(eCSSProperty_text_align, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_text_align, value->GetEnumValue());
   }
 }
 
 void
 nsGenericHTMLElement::MapVAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                             GenericSpecifiedValues* aData)
+                                             MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_vertical_align)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_vertical_align)) {
     // align: enum
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::valign);
     if (value && value->Type() == nsAttrValue::eEnum)
-      aData->SetKeywordValue(eCSSProperty_vertical_align, value->GetEnumValue());
+      aDecls.SetKeywordValue(eCSSProperty_vertical_align, value->GetEnumValue());
   }
 }
 
 void
 nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aData)
+                                                  MappedDeclarations& aDecls)
 {
   const nsAttrValue* value;
 
   // hspace: value
   value = aAttributes->GetAttr(nsGkAtoms::hspace);
   if (value) {
     if (value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_left,
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_left,
                                   (float)value->GetIntegerValue());
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_right,
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_right,
                                   (float)value->GetIntegerValue());
     } else if (value->Type() == nsAttrValue::ePercent) {
-      aData->SetPercentValueIfUnset(eCSSProperty_margin_left,
+      aDecls.SetPercentValueIfUnset(eCSSProperty_margin_left,
                                     value->GetPercentValue());
-      aData->SetPercentValueIfUnset(eCSSProperty_margin_right,
+      aDecls.SetPercentValueIfUnset(eCSSProperty_margin_right,
                                     value->GetPercentValue());
     }
   }
 
   // vspace: value
   value = aAttributes->GetAttr(nsGkAtoms::vspace);
   if (value) {
     if (value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_top,
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_top,
                                   (float)value->GetIntegerValue());
-      aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom,
+      aDecls.SetPixelValueIfUnset(eCSSProperty_margin_bottom,
                                   (float)value->GetIntegerValue());
     } else if (value->Type() == nsAttrValue::ePercent) {
-      aData->SetPercentValueIfUnset(eCSSProperty_margin_top,
+      aDecls.SetPercentValueIfUnset(eCSSProperty_margin_top,
                                     value->GetPercentValue());
-      aData->SetPercentValueIfUnset(eCSSProperty_margin_bottom,
+      aDecls.SetPercentValueIfUnset(eCSSProperty_margin_bottom,
                                     value->GetPercentValue());
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapWidthAttributeInto(const nsMappedAttributes* aAttributes,
-                                            GenericSpecifiedValues* aData)
+                                            MappedDeclarations& aDecls)
 {
   // width: value
-  if (!aData->PropertyIsSet(eCSSProperty_width)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_width)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
     if (value && value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValue(eCSSProperty_width,
+      aDecls.SetPixelValue(eCSSProperty_width,
                            (float)value->GetIntegerValue());
     } else if (value && value->Type() == nsAttrValue::ePercent) {
-      aData->SetPercentValue(eCSSProperty_width,
+      aDecls.SetPercentValue(eCSSProperty_width,
                              value->GetPercentValue());
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapHeightAttributeInto(const nsMappedAttributes* aAttributes,
-                                             GenericSpecifiedValues* aData)
+                                             MappedDeclarations& aDecls)
 {
   // height: value
-  if (!aData->PropertyIsSet(eCSSProperty_height)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_height)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
     if (value && value->Type() == nsAttrValue::eInteger) {
-      aData->SetPixelValue(eCSSProperty_height,
+      aDecls.SetPixelValue(eCSSProperty_height,
                            (float)value->GetIntegerValue());
     } else if (value && value->Type() == nsAttrValue::ePercent) {
-      aData->SetPercentValue(eCSSProperty_height,
+      aDecls.SetPercentValue(eCSSProperty_height,
                              value->GetPercentValue());
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
-                                                 GenericSpecifiedValues* aData)
+                                                 MappedDeclarations& aDecls)
 {
-  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aData);
-  nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aData);
+  nsGenericHTMLElement::MapWidthAttributeInto(aAttributes, aDecls);
+  nsGenericHTMLElement::MapHeightAttributeInto(aAttributes, aDecls);
 }
 
 void
 nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aData)
+                                                  MappedDeclarations& aDecls)
 {
   // border: pixels
   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
   if (!value)
     return;
 
   nscoord val = 0;
   if (value->Type() == nsAttrValue::eInteger)
     val = value->GetIntegerValue();
 
-  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,
+  aDecls.SetPixelValueIfUnset(eCSSProperty_border_top_width, (float)val);
+  aDecls.SetPixelValueIfUnset(eCSSProperty_border_right_width, (float)val);
+  aDecls.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, (float)val);
+  aDecls.SetPixelValueIfUnset(eCSSProperty_border_left_width, (float)val);
+
+  aDecls.SetKeywordValueIfUnset(eCSSProperty_border_top_style,
                                 NS_STYLE_BORDER_STYLE_SOLID);
-  aData->SetKeywordValueIfUnset(eCSSProperty_border_right_style,
+  aDecls.SetKeywordValueIfUnset(eCSSProperty_border_right_style,
                                 NS_STYLE_BORDER_STYLE_SOLID);
-  aData->SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
+  aDecls.SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,
                                 NS_STYLE_BORDER_STYLE_SOLID);
-  aData->SetKeywordValueIfUnset(eCSSProperty_border_left_style,
+  aDecls.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);
+  aDecls.SetCurrentColorIfUnset(eCSSProperty_border_top_color);
+  aDecls.SetCurrentColorIfUnset(eCSSProperty_border_right_color);
+  aDecls.SetCurrentColorIfUnset(eCSSProperty_border_bottom_color);
+  aDecls.SetCurrentColorIfUnset(eCSSProperty_border_left_color);
 }
 
 void
 nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
-                                        GenericSpecifiedValues* aData)
+                                        MappedDeclarations& aDecls)
 {
 
-  if (!aData->PropertyIsSet(eCSSProperty_background_image)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_background_image)) {
     // background
     nsAttrValue* value =
       const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
     if (value) {
-      aData->SetBackgroundImage(*value);
+      aDecls.SetBackgroundImage(*value);
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
-                                     GenericSpecifiedValues* aData)
+                                     MappedDeclarations& aDecls)
 {
-  if (!aData->PropertyIsSet(eCSSProperty_background_color)) {
+  if (!aDecls.PropertyIsSet(eCSSProperty_background_color)) {
     const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
     nscolor color;
     if (value && value->GetColorValue(color)) {
-      aData->SetColorValue(eCSSProperty_background_color, color);
+      aDecls.SetColorValue(eCSSProperty_background_color, color);
     }
   }
 }
 
 void
 nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
-                                                  GenericSpecifiedValues* aData)
+                                                  MappedDeclarations& aDecls)
 {
-  MapBackgroundInto(aAttributes, aData);
-  MapBGColorInto(aAttributes, aData);
+  MapBackgroundInto(aAttributes, aDecls);
+  MapBGColorInto(aAttributes, aDecls);
 }
 
 //----------------------------------------------------------------------
 
 int32_t
 nsGenericHTMLElement::GetIntAttr(nsAtom* aAttr, int32_t aDefault) const
 {
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -445,26 +445,26 @@ public:
    * called by subclasses' attribute mapping functions.  Currently handles
    * dir, lang and hidden, could handle others.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
-                                      mozilla::GenericSpecifiedValues* aGenericData);
+                                      mozilla::MappedDeclarations&);
   /**
    * Same as MapCommonAttributesInto except that it does not handle hidden.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapCommonAttributesIntoExceptHidden(const nsMappedAttributes* aAttributes,
-                                                  mozilla::GenericSpecifiedValues* aGenericData);
+                                                  mozilla::MappedDeclarations&);
 
   static const MappedAttributeEntry sCommonAttributeMap[];
   static const MappedAttributeEntry sImageMarginSizeAttributeMap[];
   static const MappedAttributeEntry sImageBorderAttributeMap[];
   static const MappedAttributeEntry sImageAlignAttributeMap[];
   static const MappedAttributeEntry sDivAlignAttributeMap[];
   static const MappedAttributeEntry sBackgroundAttributeMap[];
   static const MappedAttributeEntry sBackgroundColorAttributeMap[];
@@ -472,126 +472,126 @@ public:
   /**
    * Helper to map the align attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                         mozilla::GenericSpecifiedValues* aGenericData);
+                                         mozilla::MappedDeclarations&);
 
   /**
    * Helper to map the align attribute into a style struct for things
    * like <div>, <h1>, etc.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                       mozilla::GenericSpecifiedValues* aGenericData);
+                                       mozilla::MappedDeclarations&);
 
   /**
    * Helper to map the valign attribute into a style struct for things
    * like <col>, <tr>, <section>, etc.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapVAlignAttributeInto(const nsMappedAttributes* aAttributes,
-                                     mozilla::GenericSpecifiedValues* aGenericData);
+                                     mozilla::MappedDeclarations&);
 
   /**
    * Helper to map the image border attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
-                                          mozilla::GenericSpecifiedValues* aGenericData);
+                                          mozilla::MappedDeclarations&);
   /**
    * Helper to map the image margin attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
-                                          mozilla::GenericSpecifiedValues* aGenericData);
+                                          mozilla::MappedDeclarations&);
   /**
    * Helper to map the image position attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
-                                         mozilla::GenericSpecifiedValues* aGenericData);
+                                         mozilla::MappedDeclarations&);
 
   /**
    * Helper to map `width` attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapWidthAttributeInto(const nsMappedAttributes* aAttributes,
-                                    mozilla::GenericSpecifiedValues* aGenericData);
+                                    mozilla::MappedDeclarations&);
   /**
    * Helper to map `height` attribute into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapHeightAttributeInto(const nsMappedAttributes* aAttributes,
-                                     mozilla::GenericSpecifiedValues* aGenericData);
+                                     mozilla::MappedDeclarations&);
   /**
    * Helper to map the background attribute
    * into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapBackgroundInto(const nsMappedAttributes* aAttributes,
-                                mozilla::GenericSpecifiedValues* aGenericData);
+                                mozilla::MappedDeclarations&);
   /**
    * Helper to map the bgcolor attribute
    * into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapBGColorInto(const nsMappedAttributes* aAttributes,
-                             mozilla::GenericSpecifiedValues* aGenericData);
+                             mozilla::MappedDeclarations&);
   /**
    * Helper to map the background attributes (currently background and bgcolor)
    * into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
-                                          mozilla::GenericSpecifiedValues* aGenericData);
+                                          mozilla::MappedDeclarations&);
   /**
    * Helper to map the scrolling attribute on FRAME and IFRAME
    * into a style struct.
    *
    * @param aAttributes the list of attributes to map
    * @param aData the returned rule data [INOUT]
    * @see GetAttributeMappingFunction
    */
   static void MapScrollingAttributeInto(const nsMappedAttributes* aAttributes,
-                                        mozilla::GenericSpecifiedValues* aGenericData);
+                                        mozilla::MappedDeclarations&);
   /**
    * Get the presentation context for this content node.
    * @return the presentation context
    */
   enum PresContextFor
   {
     eForComposedDoc,
     eForUncomposedDoc
--- a/dom/ipc/StructuredCloneData.cpp
+++ b/dom/ipc/StructuredCloneData.cpp
@@ -370,17 +370,17 @@ StructuredCloneData::CopyFromClonedMessa
   MOZ_ASSERT(NS_IsMainThread());
   UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
 }
 
 void
 StructuredCloneData::CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
 {
   MOZ_ASSERT(IsOnBackgroundThread());
-  UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
+  UnpackClonedMessageData<CopyMemory, Parent>(aClonedData, *this);
 }
 
 void
 StructuredCloneData::CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
 {
   UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
 }
 
@@ -458,11 +458,17 @@ bool
 StructuredCloneData::StealExternalData(JSStructuredCloneData& aData)
 {
   MOZ_ASSERT(!mInitialized);
   mSharedData = new SharedJSAllocatedData(std::move(aData));
   mInitialized = true;
   return true;
 }
 
+already_AddRefed<SharedJSAllocatedData>
+StructuredCloneData::TakeSharedData()
+{
+  return mSharedData.forget();
+}
+
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/StructuredCloneData.h
+++ b/dom/ipc/StructuredCloneData.h
@@ -292,16 +292,19 @@ public:
 
   // For IPC serialization
   void WriteIPCParams(IPC::Message* aMessage) const;
   bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
 
 protected:
   explicit StructuredCloneData(TransferringSupport aSupportsTransferring);
 
+  already_AddRefed<SharedJSAllocatedData>
+  TakeSharedData();
+
 private:
   JSStructuredCloneData mExternalData;
   RefPtr<SharedJSAllocatedData> mSharedData;
 
   // This array is needed because AutoIPCStream DTOR must be executed after the
   // sending of the data via IPC. This will be fixed by bug 1353475.
   FallibleTArray<mozilla::ipc::AutoIPCStream> mIPCStreams;
   bool mInitialized;
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -21,17 +21,17 @@
 #include "nsPresContext.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIScriptError.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/GenericSpecifiedValuesInlines.h"
+#include "mozilla/MappedDeclarations.h"
 #include "mozilla/dom/ElementBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
@@ -101,35 +101,19 @@ nsMathMLElement::BindToTree(nsIDocument*
                                                 aBindingParent,
                                                 aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aDocument) {
     aDocument->RegisterPendingLinkUpdate(this);
   }
 
-  nsIDocument* doc = GetComposedDoc();
-  if (doc) {
-    if (!doc->GetMathMLEnabled()) {
-      // Enable MathML and setup the style sheet during binding, not element
-      // construction, because we could move a MathML element from the document
-      // that created it to another document.
-      auto cache = nsLayoutStylesheetCache::Singleton();
-      doc->SetMathMLEnabled();
-      doc->EnsureOnDemandBuiltInUASheet(cache->MathMLSheet());
-
-      // Rebuild style data for the presshell, because style system
-      // optimizations may have taken place assuming MathML was disabled.
-      // (See nsRuleNode::CheckSpecifiedProperties.)
-      RefPtr<nsPresContext> presContext = doc->GetPresContext();
-      if (presContext) {
-        presContext->
-          PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_Subtree);
-      }
-    }
+  // Set the bit in the document for telemetry.
+  if (nsIDocument* doc = GetComposedDoc()) {
+    doc->SetMathMLEnabled();
   }
 
   return rv;
 }
 
 void
 nsMathMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
@@ -495,43 +479,43 @@ nsMathMLElement::ParseNumericValue(const
   }
 
   aCSSValue.SetFloatValue(floatValue, cssUnit);
   return true;
 }
 
 void
 nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
-                                         GenericSpecifiedValues* aData)
+                                         MappedDeclarations& aDecls)
 {
   // scriptsizemultiplier
   //
   // "Specifies the multiplier to be used to adjust font size due to changes
   // in scriptlevel.
   //
   // values: number
   // default: 0.71
   //
   const nsAttrValue* value =
     aAttributes->GetAttr(nsGkAtoms::scriptsizemultiplier_);
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty__moz_script_size_multiplier)) {
+      !aDecls.PropertyIsSet(eCSSProperty__moz_script_size_multiplier)) {
     nsAutoString str(value->GetStringValue());
     str.CompressWhitespace();
     // MathML numbers can't have leading '+'
     if (str.Length() > 0 && str.CharAt(0) != '+') {
       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);
+        aDecls.SetNumberValue(eCSSProperty__moz_script_size_multiplier, floatValue);
       } else {
         ReportParseErrorNoTag(str,
                               nsGkAtoms::scriptsizemultiplier_,
-                              aData->Document());
+                              aDecls.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."
@@ -539,65 +523,65 @@ nsMathMLElement::MapMathMLAttributesInto
   // values: length
   // default: 8pt
   //
   // We don't allow negative values.
   // 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)) {
+      !aDecls.PropertyIsSet(eCSSProperty__moz_script_min_size)) {
     nsCSSValue scriptMinSize;
     ParseNumericValue(value->GetStringValue(), scriptMinSize,
                       PARSE_ALLOW_UNITLESS | CONVERT_UNITLESS_TO_PERCENT,
-                      aData->Document());
+                      aDecls.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);
+      aDecls.SetLengthValue(eCSSProperty__moz_script_min_size, scriptMinSize);
     }
   }
 
   // scriptlevel
   //
   // "Changes the scriptlevel in effect for the children. When the value is
   // given without a sign, it sets scriptlevel to the specified value; when a
   // sign is given, it increments ("+") or decrements ("-") the current
   // value. (Note that large decrements can result in negative values of
   // scriptlevel, but these values are considered legal.)"
   //
   // values: ( "+" | "-" )? unsigned-integer
   // default: inherited
   //
   value = aAttributes->GetAttr(nsGkAtoms::scriptlevel_);
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty__moz_script_level)) {
+      !aDecls.PropertyIsSet(eCSSProperty__moz_script_level)) {
     nsAutoString str(value->GetStringValue());
     str.CompressWhitespace();
     if (str.Length() > 0) {
       nsresult errorCode;
       int32_t intValue = str.ToInteger(&errorCode);
       if (NS_SUCCEEDED(errorCode)) {
         // This is kind of cheesy ... if the scriptlevel has a sign,
         // then it's a relative value and we store the nsCSSValue as an
         // Integer to indicate that. Otherwise we store it as a Number
         // to indicate that the scriptlevel is absolute.
         char16_t ch = str.CharAt(0);
         if (ch == '+' || ch == '-') {
-          aData->SetIntValue(eCSSProperty__moz_script_level, intValue);
+          aDecls.SetIntValue(eCSSProperty__moz_script_level, intValue);
         } else {
-          aData->SetNumberValue(eCSSProperty__moz_script_level, intValue);
+          aDecls.SetNumberValue(eCSSProperty__moz_script_level, intValue);
         }
       } else {
         ReportParseErrorNoTag(str,
                               nsGkAtoms::scriptlevel_,
-                              aData->Document());
+                              aDecls.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
@@ -621,91 +605,91 @@ 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->Document());
+                     aDecls.Document());
     }
   }
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty_font_size)) {
+      !aDecls.PropertyIsSet(eCSSProperty_font_size)) {
     nsAutoString str(value->GetStringValue());
     nsCSSValue fontSize;
     if (!ParseNumericValue(str, fontSize, PARSE_SUPPRESS_WARNINGS |
                            PARSE_ALLOW_UNITLESS | CONVERT_UNITLESS_TO_PERCENT,
                            nullptr)
         && parseSizeKeywords) {
       static const char sizes[3][7] = { "small", "normal", "big" };
       static const int32_t values[MOZ_ARRAY_LENGTH(sizes)] = {
         NS_STYLE_FONT_SIZE_SMALL, NS_STYLE_FONT_SIZE_MEDIUM,
         NS_STYLE_FONT_SIZE_LARGE
       };
       str.CompressWhitespace();
       for (uint32_t i = 0; i < ArrayLength(sizes); ++i) {
         if (str.EqualsASCII(sizes[i])) {
-          aData->SetKeywordValue(eCSSProperty_font_size, values[i]);
+          aDecls.SetKeywordValue(eCSSProperty_font_size, values[i]);
           break;
         }
       }
     } else if (fontSize.GetUnit() == eCSSUnit_Percent) {
-      aData->SetPercentValue(eCSSProperty_font_size,
+      aDecls.SetPercentValue(eCSSProperty_font_size,
                              fontSize.GetPercentValue());
     } else if (fontSize.GetUnit() != eCSSUnit_Null) {
-      aData->SetLengthValue(eCSSProperty_font_size, fontSize);
+      aDecls.SetLengthValue(eCSSProperty_font_size, fontSize);
     }
   }
 
   // fontfamily
   //
   // "Should be the name of a font that may be available to a MathML renderer,
   // or a CSS font specification; See Section 6.5 Using CSS with MathML and
   // 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->Document());
+                   aDecls.Document());
   }
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty_font_family)) {
-    aData->SetFontFamily(value->GetStringValue());
+      !aDecls.PropertyIsSet(eCSSProperty_font_family)) {
+    aDecls.SetFontFamily(value->GetStringValue());
   }
 
   // fontstyle
   //
   // "Specified the font style to use for the token. Deprecated in favor of
   //  mathvariant."
   //
   // values: "normal" | "italic"
   // 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->Document());
+                   aDecls.Document());
     if (value->Type() == nsAttrValue::eString &&
-        !aData->PropertyIsSet(eCSSProperty_font_style)) {
+        !aDecls.PropertyIsSet(eCSSProperty_font_style)) {
       nsAutoString str(value->GetStringValue());
       str.CompressWhitespace();
       // FIXME(emilio): This should use FontSlantStyle or what not. Or even
       // better, it looks deprecated since forever, we should just kill it.
       if (str.EqualsASCII("normal")) {
-        aData->SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_NORMAL);
+        aDecls.SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_NORMAL);
       } else if (str.EqualsASCII("italic")) {
-        aData->SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_ITALIC);
+        aDecls.SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_ITALIC);
       }
     }
   }
 
   // fontweight
   //
   // "Specified the font weight for the token. Deprecated in favor of
   // mathvariant."
@@ -714,26 +698,26 @@ 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->Document());
+                   aDecls.Document());
     if (value->Type() == nsAttrValue::eString &&
-        !aData->PropertyIsSet(eCSSProperty_font_weight)) {
+        !aDecls.PropertyIsSet(eCSSProperty_font_weight)) {
       nsAutoString str(value->GetStringValue());
       str.CompressWhitespace();
       if (str.EqualsASCII("normal")) {
-        aData->SetKeywordValue(eCSSProperty_font_weight,
+        aDecls.SetKeywordValue(eCSSProperty_font_weight,
                                FontWeight::Normal().ToFloat());
       } else if (str.EqualsASCII("bold")) {
-        aData->SetKeywordValue(eCSSProperty_font_weight,
+        aDecls.SetKeywordValue(eCSSProperty_font_weight,
                                FontWeight::Bold().ToFloat());
       }
     }
   }
 
   // mathvariant
   //
   // "Specifies the logical class of the token. Note that this class is more
@@ -742,17 +726,17 @@ nsMathMLElement::MapMathMLAttributesInto
   // values: "normal" | "bold" | "italic" | "bold-italic" | "double-struck" |
   // "bold-fraktur" | "script" | "bold-script" | "fraktur" | "sans-serif" |
   // "bold-sans-serif" | "sans-serif-italic" | "sans-serif-bold-italic" |
   // "monospace" | "initial" | "tailed" | "looped" | "stretched"
   // default: normal (except on <mi>)
   //
   value = aAttributes->GetAttr(nsGkAtoms::mathvariant_);
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty__moz_math_variant)) {
+      !aDecls.PropertyIsSet(eCSSProperty__moz_math_variant)) {
     nsAutoString str(value->GetStringValue());
     str.CompressWhitespace();
     static const char sizes[19][23] = {
       "normal", "bold", "italic", "bold-italic", "script", "bold-script",
       "fraktur", "double-struck", "bold-fraktur", "sans-serif",
       "bold-sans-serif", "sans-serif-italic", "sans-serif-bold-italic",
       "monospace", "initial", "tailed", "looped", "stretched"
     };
@@ -766,17 +750,17 @@ nsMathMLElement::MapMathMLAttributesInto
       NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC,
       NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC,
       NS_MATHML_MATHVARIANT_MONOSPACE, NS_MATHML_MATHVARIANT_INITIAL,
       NS_MATHML_MATHVARIANT_TAILED, NS_MATHML_MATHVARIANT_LOOPED,
       NS_MATHML_MATHVARIANT_STRETCHED
     };
     for (uint32_t i = 0; i < ArrayLength(sizes); ++i) {
       if (str.EqualsASCII(sizes[i])) {
-        aData->SetKeywordValue(eCSSProperty__moz_math_variant, values[i]);
+        aDecls.SetKeywordValue(eCSSProperty__moz_math_variant, values[i]);
         break;
       }
     }
   }
 
   // mathbackground
   //
   // "Specifies the background color to be used to fill in the bounding box of
@@ -796,23 +780,23 @@ nsMathMLElement::MapMathMLAttributesInto
   // default: "transparent"
   //
   value = aAttributes->GetAttr(nsGkAtoms::mathbackground_);
   if (!value) {
     value = aAttributes->GetAttr(nsGkAtoms::background);
     if (value) {
       WarnDeprecated(nsGkAtoms::background->GetUTF16String(),
                      nsGkAtoms::mathbackground_->GetUTF16String(),
-                     aData->Document());
+                     aDecls.Document());
     }
   }
   if (value) {
     nscolor color;
     if (value->GetColorValue(color)) {
-      aData->SetColorValueIfUnset(eCSSProperty_background_color, color);
+      aDecls.SetColorValueIfUnset(eCSSProperty_background_color, color);
     }
   }
 
   // mathcolor
   //
   // "Specifies the foreground color to use when drawing the components of this
   // element, such as the content for token elements or any lines, surds, or
   // other decorations. It also establishes the default mathcolor used for
@@ -829,47 +813,47 @@ nsMathMLElement::MapMathMLAttributesInto
   // default: inherited
   //
   value = aAttributes->GetAttr(nsGkAtoms::mathcolor_);
   if (!value) {
     value = aAttributes->GetAttr(nsGkAtoms::color);
     if (value) {
       WarnDeprecated(nsGkAtoms::color->GetUTF16String(),
                      nsGkAtoms::mathcolor_->GetUTF16String(),
-                     aData->Document());
+                     aDecls.Document());
     }
   }
   nscolor color;
   if (value && value->GetColorValue(color)) {
-    aData->SetColorValueIfUnset(eCSSProperty_color, color);
+    aDecls.SetColorValueIfUnset(eCSSProperty_color, color);
   }
 
   // width
   //
   // "Specifies the desired width of the entire table and is intended for
   // visual user agents. When the value is a percentage value, the value is
   // relative to the horizontal space a MathML renderer has available for the
   // math element. When the value is "auto", the MathML renderer should
   // calculate the table width from its contents using whatever layout
   // algorithm it chooses. "
   //
   // values: "auto" | length
   // default: auto
   //
-  if (!aData->PropertyIsSet(eCSSProperty_width)) {
+  if (!aDecls.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->Document());
+      ParseNumericValue(value->GetStringValue(), width, 0, aDecls.Document());
       if (width.GetUnit() == eCSSUnit_Percent) {
-        aData->SetPercentValue(eCSSProperty_width,
+        aDecls.SetPercentValue(eCSSProperty_width,
                                width.GetPercentValue());
       } else if (width.GetUnit() != eCSSUnit_Null) {
-        aData->SetLengthValue(eCSSProperty_width, width);
+        aDecls.SetLengthValue(eCSSProperty_width, width);
       }
     }
   }
 
   // dir
   //
   // Overall Directionality of Mathematics Formulas:
   // "The overall directionality for a formula, basically the direction of the
@@ -886,25 +870,25 @@ nsMathMLElement::MapMathMLAttributesInto
   // see Section 3.1.5.1 Overall Directionality of Mathematics Formulas for
   // further discussion. It has no effect on mspace."
   //
   // values: "ltr" | "rtl"
   // default: inherited
   //
   value = aAttributes->GetAttr(nsGkAtoms::dir);
   if (value && value->Type() == nsAttrValue::eString &&
-      !aData->PropertyIsSet(eCSSProperty_direction)) {
+      !aDecls.PropertyIsSet(eCSSProperty_direction)) {
     nsAutoString str(value->GetStringValue());
     static const char dirs[][4] = { "ltr", "rtl" };
     static const int32_t dirValues[MOZ_ARRAY_LENGTH(dirs)] = {
       NS_STYLE_DIRECTION_LTR, NS_STYLE_DIRECTION_RTL
     };
     for (uint32_t i = 0; i < ArrayLength(dirs); ++i) {
       if (str.EqualsASCII(dirs[i])) {
-        aData->SetKeywordValue(eCSSProperty_direction, dirValues[i]);
+        aDecls.SetKeywordValue(eCSSProperty_direction, dirValues[i]);
         break;
       }
     }
   }
 }
 
 void
 nsMathMLElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
--- a/dom/mathml/nsMathMLElement.h
+++ b/dom/mathml/nsMathMLElement.h
@@ -61,17 +61,17 @@ public:
                                    uint32_t        aFlags);
 
   static bool ParseNumericValue(const nsString& aString,
                                 nsCSSValue&     aCSSValue,
                                 uint32_t        aFlags,
                                 nsIDocument*    aDocument);
 
   static void MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
-                                      mozilla::GenericSpecifiedValues* aGenericData);
+                                      mozilla::MappedDeclarations&);
 
   void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      mozilla::EventChainPostVisitor& aVisitor) override;
   nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
                  bool aPreallocateChildren) const override;
   virtual mozilla::EventStates IntrinsicState() const override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -576,17 +576,17 @@ PluginModuleChromeParent::InitCrashRepor
     }
 
     NativeThreadId threadId;
     if (!CallInitCrashReporter(shmem, &threadId)) {
         return false;
     }
 
     {
-      mozilla::MutexAutoLock lock(mCrashReporterMutex);
+      mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
       mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
         GeckoProcessType_Plugin,
         shmem,
         threadId);
     }
 
     return true;
 }
@@ -716,17 +716,17 @@ PluginModuleChromeParent::~PluginModuleC
 
     mozilla::BackgroundHangMonitor::UnregisterAnnotator(*this);
 }
 
 void
 PluginModuleChromeParent::WriteExtraDataForMinidump()
 {
     // mCrashReporterMutex is already held by the caller
-    mCrashReporterMutex.AssertCurrentThreadOwns();
+    mCrashReporterMutex.AssertCurrentThreadIn();
 
     typedef nsDependentCString cstring;
 
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
@@ -1082,17 +1082,17 @@ PluginModuleContentParent::OnExitedSyncS
 }
 
 void
 PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
                                            const nsAString& aBrowserDumpId,
                                            std::function<void(nsString)>&& aCallback,
                                            bool aAsync)
 {
-    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+    mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
 
     if (!mCrashReporter || !mTakeFullMinidumpCallback.IsEmpty()) {
         aCallback(EmptyString());
         return;
     }
     mTakeFullMinidumpCallback.Init(std::move(aCallback), aAsync);
 
     nsString browserDumpId{aBrowserDumpId};
@@ -1169,17 +1169,17 @@ PluginModuleChromeParent::ReleasePluginR
 }
 
 void
 PluginModuleChromeParent::TakeBrowserAndPluginMinidumps(bool aReportsReady,
                                                         base::ProcessId aContentPid,
                                                         const nsAString& aBrowserDumpId,
                                                         bool aAsync)
 {
-    mCrashReporterMutex.AssertCurrentThreadOwns();
+    mCrashReporterMutex.AssertCurrentThreadIn();
 
     // Generate crash report including plugin and browser process minidumps.
     // The plugin process is the parent report with additional dumps including
     // the browser process, content process when running under e10s, and
     // various flash subprocesses if we're the flash module.
     if (!aReportsReady) {
         mBrowserDumpFile = nullptr;
         CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
@@ -1204,17 +1204,17 @@ PluginModuleChromeParent::TakeBrowserAnd
     }
 }
 
 void
 PluginModuleChromeParent::OnTakeFullMinidumpComplete(bool aReportsReady,
                                                      base::ProcessId aContentPid,
                                                      const nsAString& aBrowserDumpId)
 {
-    mCrashReporterMutex.AssertCurrentThreadOwns();
+    mCrashReporterMutex.AssertCurrentThreadIn();
 
     if (aReportsReady) {
         nsString dumpId = mCrashReporter->MinidumpID();
         PLUGIN_LOG_DEBUG(
                          ("generated paired browser/plugin minidumps: %s)",
                           NS_ConvertUTF16toUTF8(dumpId).get()));
         nsAutoCString additionalDumps("browser");
         nsCOMPtr<nsIFile> pluginDumpFile;
@@ -1289,17 +1289,17 @@ PluginModuleChromeParent::TerminateChild
         TerminateChildProcessOnDumpComplete(aMsgLoop, aMonitorDescription);
     }
 }
 
 void
 PluginModuleChromeParent::TerminateChildProcessOnDumpComplete(MessageLoop* aMsgLoop,
                                                               const nsCString& aMonitorDescription)
 {
-    mCrashReporterMutex.AssertCurrentThreadOwns();
+    mCrashReporterMutex.AssertCurrentThreadIn();
 
     if (!mCrashReporter) {
         // If mCrashReporter is null then the hang has ended, the plugin module
         // is shutting down. There's nothing to do here.
         mTerminateChildProcessCallback.Invoke(true);
         return;
     }
     mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginHang"),
@@ -1506,17 +1506,17 @@ RemoveMinidump(nsIFile* minidump)
         extraFile->Remove(true);
     }
 }
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
 void
 PluginModuleChromeParent::ProcessFirstMinidump()
 {
-    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+    mozilla::RecursiveMutexAutoLock lock(mCrashReporterMutex);
 
     if (!mCrashReporter)
         return;
 
     WriteExtraDataForMinidump();
 
     if (mCrashReporter->HasMinidump()) {
         // A minidump may be set in TerminateChildProcess, which means the
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -12,16 +12,17 @@
 #include "mozilla/HangAnnotations.h"
 #include "mozilla/PluginLibrary.h"
 #include "mozilla/ipc/CrashReporterHost.h"
 #include "mozilla/plugins/PluginProcessParent.h"
 #include "mozilla/plugins/PPluginModuleParent.h"
 #include "mozilla/plugins/PluginMessageUtils.h"
 #include "mozilla/plugins/PluginTypes.h"
 #include "mozilla/ipc/TaskFactory.h"
+#include "mozilla/RecursiveMutex.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Unused.h"
 #include "npapi.h"
 #include "npfunctions.h"
 #include "nsExceptionHandler.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
@@ -312,19 +313,21 @@ protected:
 
     RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocatorForDirectBitmap;
     RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocatorForDXGISurface;
 
     /**
      * This mutex protects the crash reporter when the Plugin Hang UI event
      * handler is executing off main thread. It is intended to protect both
      * the mCrashReporter variable in addition to the CrashReporterHost object
-     * that mCrashReporter refers to.
+     * that mCrashReporter refers to. Sometimes asynchronous crash reporter
+     * callbacks are dispatched synchronously while the caller is still holding
+     * the mutex. This requires recursive locking support in the mutex.
      */
-    mozilla::Mutex mCrashReporterMutex;
+    mozilla::RecursiveMutex mCrashReporterMutex;
     UniquePtr<ipc::CrashReporterHost> mCrashReporter;
 };
 
 class PluginModuleContentParent : public PluginModuleParent
 {
   public:
     explicit PluginModuleContentParent();
 
--- a/dom/serviceworkers/ServiceWorker.cpp
+++ b/dom/serviceworkers/ServiceWorker.cpp
@@ -3,27 +3,27 @@
 /* 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 "ServiceWorker.h"
 
 #include "nsIDocument.h"
 #include "nsPIDOMWindow.h"
+#include "ServiceWorkerCloneData.h"
 #include "ServiceWorkerImpl.h"
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerPrivate.h"
 
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerPrivate.h"
-#include "mozilla/dom/ipc/StructuredCloneData.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 using mozilla::ErrorResult;
 using namespace mozilla::dom;
 
@@ -174,18 +174,18 @@ ServiceWorker::PostMessage(JSContext* aC
 
   JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
   aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
                                                           &transferable);
   if (aRv.Failed()) {
     return;
   }
 
-  ipc::StructuredCloneData data;
-  data.Write(aCx, aMessage, transferable, aRv);
+  RefPtr<ServiceWorkerCloneData> data = new ServiceWorkerCloneData();
+  data->Write(aCx, aMessage, transferable, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   mInner->PostMessage(std::move(data), clientInfo.ref(), clientState.ref());
 }
 
 
--- a/dom/serviceworkers/ServiceWorker.h
+++ b/dom/serviceworkers/ServiceWorker.h
@@ -15,19 +15,17 @@
 #undef PostMessage
 #endif
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
-namespace ipc {
-class StructuredCloneData;
-} // namespace ipc
+class ServiceWorkerCloneData;
 
 #define NS_DOM_SERVICEWORKER_IID \
   {0xd42e0611, 0x3647, 0x4319, {0xae, 0x05, 0x19, 0x89, 0x59, 0xba, 0x99, 0x5e}}
 
 bool
 ServiceWorkerVisible(JSContext* aCx, JSObject* aObj);
 
 class ServiceWorker final : public DOMEventTargetHelper
@@ -53,17 +51,17 @@ public:
     AddServiceWorker(ServiceWorker* aWorker) = 0;
 
     // This is called when the DOM ServiceWorker object is
     // destroyed and drops its ref to the Inner object.
     virtual void
     RemoveServiceWorker(ServiceWorker* aWorker) = 0;
 
     virtual void
-    PostMessage(ipc::StructuredCloneData&& aData,
+    PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
                 const ClientInfo& aClientInfo,
                 const ClientState& aClientState) = 0;
 
     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
   };
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_SERVICEWORKER_IID)
   NS_DECL_ISUPPORTS_INHERITED
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/ServiceWorkerCloneData.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "ServiceWorkerCloneData.h"
+
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+namespace dom {
+
+ServiceWorkerCloneData::~ServiceWorkerCloneData()
+{
+  RefPtr<ipc::SharedJSAllocatedData> sharedData = TakeSharedData();
+  if (sharedData) {
+    NS_ProxyRelease(__func__, mEventTarget, sharedData.forget());
+  }
+}
+
+ServiceWorkerCloneData::ServiceWorkerCloneData()
+  : mEventTarget(GetCurrentThreadSerialEventTarget())
+{
+  MOZ_DIAGNOSTIC_ASSERT(mEventTarget);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/ServiceWorkerCloneData.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef mozilla_dom_ServiceWorkerCloneData_h__
+#define mozilla_dom_ServiceWorkerCloneData_h__
+
+#include "mozilla/dom/ipc/StructuredCloneData.h"
+
+namespace mozilla {
+namespace dom {
+
+// Helper class used to pack structured clone data so that it can be
+// passed across thread and process boundaries.  Currently the raw
+// StructuredCloneData and StructureCloneHolder APIs both make it
+// difficult to meet this needs directly.  This helper class improves
+// the situation by:
+//
+//  1. Provides a ref-counted version of StructuredCloneData.  We need
+//     StructuredCloneData so we can serialize/deserialize across IPC.
+//     The move constructor problems in StructuredCloneData (bug 1462676),
+//     though, makes it hard to pass it around.  Passing a ref-counted
+//     pointer addresses this problem.
+//  2. Normally StructuredCloneData runs into problems if you try to move
+//     it across thread boundaries because it releases its SharedJSAllocatedData
+//     on the wrong thread.  This helper will correctly proxy release the
+//     shared data on the correct thread.
+//
+// This helper class should really just be used to serialize on one thread
+// and then move the reference across thread/process boundries to the
+// target worker thread.  This class is not intended to support simultaneous
+// read/write operations from different threads at the same time.
+class ServiceWorkerCloneData final : public ipc::StructuredCloneData
+{
+  nsCOMPtr<nsISerialEventTarget> mEventTarget;
+
+  ~ServiceWorkerCloneData();
+
+public:
+  ServiceWorkerCloneData();
+
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServiceWorkerCloneData)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ServiceWorkerCloneData_h__
--- a/dom/serviceworkers/ServiceWorkerImpl.cpp
+++ b/dom/serviceworkers/ServiceWorkerImpl.cpp
@@ -32,17 +32,17 @@ void
 ServiceWorkerImpl::RemoveServiceWorker(ServiceWorker* aWorker)
 {
   MOZ_DIAGNOSTIC_ASSERT(mOuter);
   MOZ_DIAGNOSTIC_ASSERT(mOuter == aWorker);
   mOuter = nullptr;
 }
 
 void
-ServiceWorkerImpl::PostMessage(ipc::StructuredCloneData&& aData,
+ServiceWorkerImpl::PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
                                const ClientInfo& aClientInfo,
                                const ClientState& aClientState)
 {
   mInfo->PostMessage(std::move(aData), aClientInfo, aClientState);
 }
 
 void
 ServiceWorkerImpl::SetState(ServiceWorkerState aState)
--- a/dom/serviceworkers/ServiceWorkerImpl.h
+++ b/dom/serviceworkers/ServiceWorkerImpl.h
@@ -26,17 +26,17 @@ class ServiceWorkerImpl final : public S
   // ServiceWorker::Inner interface
   void
   AddServiceWorker(ServiceWorker* aWorker) override;
 
   void
   RemoveServiceWorker(ServiceWorker* aWorker) override;
 
   void
-  PostMessage(ipc::StructuredCloneData&& aData,
+  PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
               const ClientInfo& aClientInfo,
               const ClientState& aClientState) override;
 
   // ServiceWorkerInfo::Listener interface
   void
   SetState(ServiceWorkerState aState) override;
 
 public:
--- a/dom/serviceworkers/ServiceWorkerInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerInfo.cpp
@@ -238,17 +238,17 @@ void
 ServiceWorkerInfo::RemoveListener(Listener* aListener)
 {
   MOZ_DIAGNOSTIC_ASSERT(aListener);
   DebugOnly<bool> removed = mInstances.RemoveElement(aListener);
   MOZ_ASSERT(removed);
 }
 
 void
-ServiceWorkerInfo::PostMessage(ipc::StructuredCloneData&& aData,
+ServiceWorkerInfo::PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
                                const ClientInfo& aClientInfo,
                                const ClientState& aClientState)
 {
   mServiceWorkerPrivate->SendMessageEvent(std::move(aData),
                                           ClientInfoAndState(aClientInfo.ToIPC(),
                                                              aClientState.ToIPC()));
 }
 
--- a/dom/serviceworkers/ServiceWorkerInfo.h
+++ b/dom/serviceworkers/ServiceWorkerInfo.h
@@ -12,16 +12,18 @@
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/OriginAttributes.h"
 #include "nsIServiceWorkerManager.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientInfoAndState;
+class ClientState;
+class ServiceWorkerCloneData;
 class ServiceWorkerPrivate;
 
 /*
  * Wherever the spec treats a worker instance and a description of said worker
  * as the same thing; i.e. "Resolve foo with
  * _GetNewestWorker(serviceWorkerRegistration)", we represent the description
  * by this class and spawn a ServiceWorker in the right global when required.
  */
@@ -92,17 +94,17 @@ public:
 
   void
   AddListener(Listener* aListener);
 
   void
   RemoveListener(Listener* aListener);
 
   void
-  PostMessage(ipc::StructuredCloneData&& aData,
+  PostMessage(RefPtr<ServiceWorkerCloneData>&& aData,
               const ClientInfo& aClientInfo,
               const ClientState& aClientState);
 
   class ServiceWorkerPrivate*
   WorkerPrivate() const
   {
     MOZ_ASSERT(mServiceWorkerPrivate);
     return mServiceWorkerPrivate;
--- a/dom/serviceworkers/ServiceWorkerPrivate.cpp
+++ b/dom/serviceworkers/ServiceWorkerPrivate.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "ServiceWorkerPrivate.h"
 
+#include "ServiceWorkerCloneData.h"
 #include "ServiceWorkerManager.h"
 #include "nsContentUtils.h"
 #include "nsICacheInfoChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsINamed.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIPushErrorReporter.h"
@@ -30,17 +31,16 @@
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/PushEventBinding.h"
 #include "mozilla/dom/RequestBinding.h"
-#include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/WorkerDebugger.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
@@ -49,19 +49,16 @@ using namespace mozilla::dom;
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::PrincipalInfo;
 
 NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(ServiceWorkerPrivate)
 NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(ServiceWorkerPrivate)
 NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ServiceWorkerPrivate)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mSandbox)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ServiceWorkerPrivate, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ServiceWorkerPrivate, Release)
 
 // Tracks the "dom.serviceWorkers.disable_open_click_delay" preference.  Modified
 // on main thread, read on worker threads.
 // It is updated every time a "notificationclick" event is dispatched. While
 // this is done without synchronization, at the worst, the thread will just get
 // an older value within which a popup is allowed to be displayed, which will
@@ -110,18 +107,16 @@ ServiceWorkerPrivate::ServiceWorkerPriva
 ServiceWorkerPrivate::~ServiceWorkerPrivate()
 {
   MOZ_ASSERT(!mWorkerPrivate);
   MOZ_ASSERT(!mTokenCount);
   MOZ_ASSERT(!mInfo);
   MOZ_ASSERT(mSupportsArray.IsEmpty());
 
   mIdleWorkerTimer->Cancel();
-
-  DropJSObjects(this);
 }
 
 namespace {
 
 class CheckScriptEvaluationWithCallback final : public WorkerRunnable
 {
   nsMainThreadPtrHandle<ServiceWorkerPrivate> mServiceWorkerPrivate;
   nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
@@ -215,36 +210,16 @@ ServiceWorkerPrivate::CheckScriptEvaluat
                                                                    aScriptEvaluationCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-void
-ServiceWorkerPrivate::GetOrCreateSandbox(JSContext* aCx,
-                                         JS::MutableHandle<JSObject*> aSandbox)
-{
-  AssertIsOnMainThread();
-
-  if (!mSandbox) {
-    nsIXPConnect* xpc = nsContentUtils::XPConnect();
-
-    JS::Rooted<JSObject*> sandbox(aCx);
-    nsresult rv = xpc->CreateSandbox(aCx, mInfo->Principal(), sandbox.address());
-    NS_ENSURE_SUCCESS_VOID(rv);
-
-    mSandbox = sandbox;
-    HoldJSObjects(this);
-  }
-
-  aSandbox.set(mSandbox);
-}
-
 namespace {
 
 enum ExtendableEventResult {
     Rejected = 0,
     Resolved
 };
 
 class ExtendableEventCallback {
@@ -523,45 +498,46 @@ public:
       return NS_ERROR_XPC_JS_THREW_EXCEPTION;
     }
 
     return NS_OK;
   }
 };
 
 class SendMessageEventRunnable final : public ExtendableEventWorkerRunnable
-                                     , public StructuredCloneHolder
 {
   const ClientInfoAndState mClientInfoAndState;
+  RefPtr<ServiceWorkerCloneData> mData;
 
 public:
   SendMessageEventRunnable(WorkerPrivate*  aWorkerPrivate,
                            KeepAliveToken* aKeepAliveToken,
-                           const ClientInfoAndState& aClientInfoAndState)
+                           const ClientInfoAndState& aClientInfoAndState,
+                           RefPtr<ServiceWorkerCloneData>&& aData)
     : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
-    , StructuredCloneHolder(CloningSupported, TransferringSupported,
-                            JS::StructuredCloneScope::SameProcessDifferentThread)
     , mClientInfoAndState(aClientInfoAndState)
+    , mData(std::move(aData))
   {
     MOZ_ASSERT(NS_IsMainThread());
+    MOZ_DIAGNOSTIC_ASSERT(mData);
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     JS::Rooted<JS::Value> messageData(aCx);
     nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
     ErrorResult rv;
-    Read(sgo, aCx, &messageData, rv);
+    mData->Read(aCx, &messageData, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return true;
     }
 
     Sequence<OwningNonNull<MessagePort>> ports;
-    if (!TakeTransferredPortsAsSequence(ports)) {
+    if (!mData->TakeTransferredPortsAsSequence(ports)) {
       return true;
     }
 
     RootedDictionary<ExtendableMessageEventInit> init(aCx);
 
     init.mBubbles = false;
     init.mCancelable = false;
 
@@ -586,83 +562,28 @@ public:
                                                              extendableEvent,
                                                              nullptr));
   }
 };
 
 } // anonymous namespace
 
 nsresult
-ServiceWorkerPrivate::SendMessageEvent(ipc::StructuredCloneData&& aData,
+ServiceWorkerPrivate::SendMessageEvent(RefPtr<ServiceWorkerCloneData>&& aData,
                                        const ClientInfoAndState& aClientInfoAndState)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  ErrorResult rv;
-
-  // Ideally we would simply move the StructuredCloneData to the
-  // SendMessageEventRunnable, but we cannot because it uses non-threadsafe
-  // ref-counting.  The following gnarly code unpacks the IPC-friendly
-  // StructuredCloneData and re-packs it into the thread-friendly
-  // StructuredCloneHolder.  In the future we should remove this and make
-  // it easier to simple move the data to the other thread.  See bug 1458936.
-
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> global(cx);
-  GetOrCreateSandbox(cx, &global);
-  NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
-
-  // The CreateSandbox call returns a proxy to the actual sandbox object.  We
-  // don't need a proxy here.
-  global = js::UncheckedUnwrap(global);
-
-  JSAutoRealm ar(cx, global);
-
-  JS::Rooted<JS::Value> messageData(cx);
-  aData.Read(cx, &messageData, rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  Sequence<OwningNonNull<MessagePort>> ports;
-  if (!aData.TakeTransferredPortsAsSequence(ports)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, ports.Length()));
-  NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
-
-  for (uint32_t i = 0; i < ports.Length(); ++i) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!GetOrCreateDOMReflector(cx, ports[i], &value)) {
-      JS_ClearPendingException(cx);
-      return NS_ERROR_FAILURE;
-    }
-
-    if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-  }
-
-  JS::Rooted<JS::Value> transferable(cx);
-  transferable.setObject(*array);
-
-  rv = SpawnWorkerIfNeeded(MessageEvent);
-  if (NS_WARN_IF(rv.Failed())) {
-    return rv.StealNSResult();
-  }
+  nsresult rv = SpawnWorkerIfNeeded(MessageEvent);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<SendMessageEventRunnable> runnable =
-    new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState);
-
-  runnable->Write(cx, messageData, transferable, JS::CloneDataPolicy(), rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
+    new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState,
+                                 std::move(aData));
 
   if (!runnable->Dispatch()) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
--- a/dom/serviceworkers/ServiceWorkerPrivate.h
+++ b/dom/serviceworkers/ServiceWorkerPrivate.h
@@ -18,16 +18,17 @@ class nsIInterceptedChannel;
 namespace mozilla {
 
 class JSObjectHolder;
 
 namespace dom {
 
 class ClientInfoAndState;
 class KeepAliveToken;
+class ServiceWorkerCloneData;
 class ServiceWorkerInfo;
 class ServiceWorkerRegistrationInfo;
 
 namespace ipc {
 class StructuredCloneData;
 } // namespace ipc
 
 class LifeCycleEventCallback : public Runnable
@@ -72,29 +73,29 @@ public:
 // ExtendableEventWorkerRunnable.
 class ServiceWorkerPrivate final
 {
   friend class KeepAliveToken;
 
 public:
   NS_IMETHOD_(MozExternalRefCountType) AddRef();
   NS_IMETHOD_(MozExternalRefCountType) Release();
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(ServiceWorkerPrivate)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ServiceWorkerPrivate)
 
   typedef mozilla::FalseType HasThreadSafeRefCnt;
 
 protected:
   nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
 public:
   explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
 
   nsresult
-  SendMessageEvent(ipc::StructuredCloneData&& aData,
+  SendMessageEvent(RefPtr<ServiceWorkerCloneData>&& aData,
                    const ClientInfoAndState& aClientInfoAndState);
 
   // This is used to validate the worker script and continue the installation
   // process.
   nsresult
   CheckScriptEvaluation(LifeCycleEventCallback* aCallback);
 
   nsresult
@@ -200,40 +201,32 @@ private:
                       bool* aNewWorkerCreated = nullptr,
                       nsILoadGroup* aLoadGroup = nullptr);
 
   ~ServiceWorkerPrivate();
 
   already_AddRefed<KeepAliveToken>
   CreateEventKeepAliveToken();
 
-  void
-  GetOrCreateSandbox(JSContext* aCx, JS::MutableHandle<JSObject*> aSandbox);
-
   // The info object owns us. It is possible to outlive it for a brief period
   // of time if there are pending waitUntil promises, in which case it
   // will be null and |SpawnWorkerIfNeeded| will always fail.
   ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
 
   // The WorkerPrivate object can only be closed by this class or by the
   // RuntimeService class if gecko is shutting down. Closing the worker
   // multiple times is OK, since the second attempt will be a no-op.
   RefPtr<WorkerPrivate> mWorkerPrivate;
 
   nsCOMPtr<nsITimer> mIdleWorkerTimer;
 
   // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
   // worker a grace period after each event.
   RefPtr<KeepAliveToken> mIdleKeepAliveToken;
 
-  // Sandbox global used to re-pack structured clone data before sending
-  // to the service worker thread.  Ideally we would remove this and just
-  // make StructuredCloneData thread safe enough to pass to the worker thread.
-  JS::Heap<JSObject*> mSandbox;
-
   uint64_t mDebuggerCount;
 
   uint64_t mTokenCount;
 
   // Meant for keeping objects alive while handling requests from the worker
   // on the main thread. Access to this array is provided through
   // |StoreISupports| and |RemoveISupports|. Note that the array is also
   // cleared whenever the worker is terminated.
--- a/dom/serviceworkers/ServiceWorkerRegisterJob.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegisterJob.cpp
@@ -2,16 +2,17 @@
 /* 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 "ServiceWorkerRegisterJob.h"
 
 #include "mozilla/dom/WorkerCommon.h"
+#include "ServiceWorkerManager.h"
 
 namespace mozilla {
 namespace dom {
 
 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
     nsIPrincipal* aPrincipal,
     const nsACString& aScope,
     const nsACString& aScriptSpec,
--- a/dom/serviceworkers/ServiceWorkerUpdateJob.h
+++ b/dom/serviceworkers/ServiceWorkerUpdateJob.h
@@ -13,16 +13,17 @@
 namespace mozilla {
 namespace dom {
 
 namespace serviceWorkerScriptCache {
 enum class OnFailure : uint8_t;
 } // namespace serviceWorkerScriptCache
 
 class ServiceWorkerManager;
+class ServiceWorkerRegistrationInfo;
 
 // A job class that performs the Update and Install algorithms from the
 // service worker spec.  This class is designed to be inherited and customized
 // as a different job type.  This is necessary because the register job
 // performs largely the same operations as the update job, but has a few
 // different starting steps.
 class ServiceWorkerUpdateJob : public ServiceWorkerJob
 {
--- a/dom/serviceworkers/moz.build
+++ b/dom/serviceworkers/moz.build
@@ -23,16 +23,17 @@ EXPORTS.mozilla.dom += [
     'ServiceWorkerRegistration.h',
     'ServiceWorkerRegistrationDescriptor.h',
     'ServiceWorkerRegistrationInfo.h',
     'ServiceWorkerUtils.h',
 ]
 
 UNIFIED_SOURCES += [
     'ServiceWorker.cpp',
+    'ServiceWorkerCloneData.cpp',
     'ServiceWorkerContainer.cpp',
     'ServiceWorkerContainerImpl.cpp',
     'ServiceWorkerDescriptor.cpp',
     'ServiceWorkerEvents.cpp',
     'ServiceWorkerImpl.cpp',
     'ServiceWorkerInfo.cpp',
     'ServiceWorkerInterceptController.cpp',
     'ServiceWorkerJob.cpp',
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -20,17 +20,16 @@
 #include "EditAggregateTransaction.h"   // for EditAggregateTransaction
 #include "EditorEventListener.h"        // for EditorEventListener
 #include "HTMLEditRules.h"              // for HTMLEditRules
 #include "InsertNodeTransaction.h"      // for InsertNodeTransaction
 #include "InsertTextTransaction.h"      // for InsertTextTransaction
 #include "JoinNodeTransaction.h"        // for JoinNodeTransaction
 #include "PlaceholderTransaction.h"     // for PlaceholderTransaction
 #include "SplitNodeTransaction.h"       // for SplitNodeTransaction
-#include "StyleSheetTransactions.h"     // for AddStyleSheetTransaction, etc.
 #include "TextEditUtils.h"              // for TextEditUtils
 #include "mozilla/CheckedInt.h"         // for CheckedInt
 #include "mozilla/ComputedStyle.h"      // for ComputedStyle
 #include "mozilla/EditAction.h"         // for EditSubAction
 #include "mozilla/EditorDOMPoint.h"     // for EditorDOMPoint
 #include "mozilla/EditorSpellCheck.h"   // for EditorSpellCheck
 #include "mozilla/EditorUtils.h"        // for various helper classes.
 #include "mozilla/EditTransactionBase.h" // for EditTransactionBase
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -46,17 +46,16 @@ class nsINode;
 class nsIPresShell;
 class nsISupports;
 class nsITransaction;
 class nsITransactionListener;
 class nsIWidget;
 class nsRange;
 
 namespace mozilla {
-class AddStyleSheetTransaction;
 class AutoSelectionRestorer;
 class AutoTopLevelEditSubActionNotifier;
 class AutoTransactionsConserveSelection;
 class AutoUpdateViewBatch;
 class ChangeAttributeTransaction;
 class CompositionTransaction;
 class CreateElementTransaction;
 class CSSEditUtils;
@@ -68,17 +67,16 @@ class EditTransactionBase;
 class ErrorResult;
 class HTMLEditor;
 class HTMLEditUtils;
 class IMEContentObserver;
 class InsertNodeTransaction;
 class InsertTextTransaction;
 class JoinNodeTransaction;
 class PlaceholderTransaction;
-class RemoveStyleSheetTransaction;
 class SplitNodeResult;
 class SplitNodeTransaction;
 class TextComposition;
 class TextEditor;
 class TextEditRules;
 class TextInputListener;
 class TextServicesDocument;
 class TypeInState;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -17,17 +17,16 @@
 #include "nsCRT.h"
 
 #include "nsUnicharUtils.h"
 
 #include "HTMLEditorEventListener.h"
 #include "HTMLEditRules.h"
 #include "HTMLEditUtils.h"
 #include "HTMLURIRefObject.h"
-#include "StyleSheetTransactions.h"
 #include "TextEditUtils.h"
 #include "TypeInState.h"
 
 #include "nsHTMLDocument.h"
 #include "nsIDocumentInlines.h"
 #include "nsISelectionController.h"
 #include "nsILinkHandler.h"
 #include "nsIInlineSpellChecker.h"
@@ -265,17 +264,16 @@ NS_IMPL_RELEASE_INHERITED(HTMLEditor, Ed
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLEditor)
   NS_INTERFACE_MAP_ENTRY(nsIHTMLEditor)
   NS_INTERFACE_MAP_ENTRY(nsIHTMLObjectResizer)
   NS_INTERFACE_MAP_ENTRY(nsIHTMLAbsPosEditor)
   NS_INTERFACE_MAP_ENTRY(nsIHTMLInlineTableEditor)
   NS_INTERFACE_MAP_ENTRY(nsITableEditor)
   NS_INTERFACE_MAP_ENTRY(nsIEditorStyleSheets)
-  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
 NS_INTERFACE_MAP_END_INHERITING(TextEditor)
 
 nsresult
 HTMLEditor::Init(nsIDocument& aDoc,
                  Element* aRoot,
                  nsISelectionController* aSelCon,
                  uint32_t aFlags,
@@ -2911,84 +2909,16 @@ HTMLEditor::GetLinkedObjects(nsIArray** 
   }
 
   nodes.forget(aNodeList);
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
-HTMLEditor::AddStyleSheet(const nsAString& aURL)
-{
-  // Enable existing sheet if already loaded.
-  if (EnableExistingStyleSheet(aURL)) {
-    return NS_OK;
-  }
-
-  // Lose the previously-loaded sheet so there's nothing to replace
-  // This pattern is different from Override methods because
-  //  we must wait to remove mLastStyleSheetURL and add new sheet
-  //  at the same time (in StyleSheetLoaded callback) so they are undoable together
-  mLastStyleSheetURL.Truncate();
-  return ReplaceStyleSheet(aURL);
-}
-
-NS_IMETHODIMP
-HTMLEditor::ReplaceStyleSheet(const nsAString& aURL)
-{
-  // Enable existing sheet if already loaded.
-  if (EnableExistingStyleSheet(aURL)) {
-    // Disable last sheet if not the same as new one
-    if (!mLastStyleSheetURL.IsEmpty() && !mLastStyleSheetURL.Equals(aURL)) {
-      return EnableStyleSheet(mLastStyleSheetURL, false);
-    }
-    return NS_OK;
-  }
-
-  // Make sure the pres shell doesn't disappear during the load.
-  if (NS_WARN_IF(!IsInitialized())) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  nsCOMPtr<nsIPresShell> ps = GetPresShell();
-  NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
-
-  nsCOMPtr<nsIURI> uaURI;
-  nsresult rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return ps->GetDocument()->CSSLoader()->LoadSheet(
-    uaURI, false, nullptr, nullptr, this);
-}
-
-NS_IMETHODIMP
-HTMLEditor::RemoveStyleSheet(const nsAString& aURL)
-{
-  return RemoveStyleSheetWithTransaction(aURL);
-}
-
-nsresult
-HTMLEditor::RemoveStyleSheetWithTransaction(const nsAString& aURL)
-{
-  RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
-  if (NS_WARN_IF(!sheet)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  RefPtr<RemoveStyleSheetTransaction> transaction =
-    RemoveStyleSheetTransaction::Create(*this, *sheet);
-  nsresult rv = DoTransaction(transaction);
-  if (NS_SUCCEEDED(rv)) {
-    mLastStyleSheetURL.Truncate();        // forget it
-  }
-  // Remove it from our internal list
-  return RemoveStyleSheetFromList(aURL);
-}
-
-
-NS_IMETHODIMP
 HTMLEditor::AddOverrideStyleSheet(const nsAString& aURL)
 {
   // Enable existing sheet if already loaded.
   if (EnableExistingStyleSheet(aURL)) {
     return NS_OK;
   }
 
   // Make sure the pres shell doesn't disappear during the load.
@@ -3063,18 +2993,17 @@ HTMLEditor::RemoveOverrideStyleSheet(con
   ps->RemoveOverrideStyleSheet(sheet);
   ps->ApplicableStylesChanged();
 
   // Remove it from our internal list
   return rv;
 }
 
 NS_IMETHODIMP
-HTMLEditor::EnableStyleSheet(const nsAString& aURL,
-                             bool aEnable)
+HTMLEditor::EnableStyleSheet(const nsAString& aURL, bool aEnable)
 {
   RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
   NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found
 
   // Ensure the style sheet is owned by our document.
   nsCOMPtr<nsIDocument> document = GetDocument();
   sheet->SetAssociatedDocumentOrShadowRoot(
     document, StyleSheet::NotOwnedByDocumentOrShadowRoot);
@@ -3461,47 +3390,16 @@ HTMLEditor::DebugUnitTests(int32_t* outN
   tester->Run(this, outNumTests, outNumTestsFailed);
   delete tester;
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
-NS_IMETHODIMP
-HTMLEditor::StyleSheetLoaded(StyleSheet* aSheet,
-                             bool aWasDeferred,
-                             nsresult aStatus)
-{
-  AutoPlaceholderBatch batchIt(this);
-
-  if (!mLastStyleSheetURL.IsEmpty()) {
-    RemoveStyleSheetWithTransaction(mLastStyleSheetURL);
-  }
-
-  RefPtr<AddStyleSheetTransaction> transaction =
-    AddStyleSheetTransaction::Create(*this, *aSheet);
-  nsresult rv = DoTransaction(transaction);
-  if (NS_SUCCEEDED(rv)) {
-    // Get the URI, then url spec from the sheet
-    nsAutoCString spec;
-    rv = aSheet->GetSheetURI()->GetSpec(spec);
-
-    if (NS_SUCCEEDED(rv)) {
-      // Save it so we can remove before applying the next one
-      CopyASCIItoUTF16(spec, mLastStyleSheetURL);
-
-      // Also save in our arrays of urls and sheets
-      AddNewStyleSheetToList(mLastStyleSheetURL, aSheet);
-    }
-  }
-
-  return NS_OK;
-}
-
 void
 HTMLEditor::OnStartToHandleTopLevelEditSubAction(
               EditSubAction aEditSubAction,
               nsIEditor::EDirection aDirection)
 {
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -65,17 +65,16 @@ enum class ParagraphSeparator { div, p, 
  */
 class HTMLEditor final : public TextEditor
                        , public nsIHTMLEditor
                        , public nsIHTMLObjectResizer
                        , public nsIHTMLAbsPosEditor
                        , public nsITableEditor
                        , public nsIHTMLInlineTableEditor
                        , public nsIEditorStyleSheets
-                       , public nsICSSLoaderObserver
                        , public nsStubMutationObserver
 {
 public:
   /****************************************************************************
    * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
    *       classes under libeditor except EditorEventListener and
    *       HTMLEditorEventListener because each public method which may fire
    *       eEditorInput event will need to instantiate new stack class for
@@ -111,20 +110,16 @@ public:
   NS_DECL_NSIEDITORMAILSUPPORT
 
   // nsITableEditor methods
   NS_DECL_NSITABLEEDITOR
 
   // nsISelectionListener overrides
   NS_DECL_NSISELECTIONLISTENER
 
-  // nsICSSLoaderObserver
-  NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet,
-                              bool aWasAlternate, nsresult aStatus) override;
-
   HTMLEditor();
 
   nsHTMLDocument* GetHTMLDocument() const;
 
   virtual void PreDestroy(bool aDestroyingFrames) override;
 
   bool GetReturnInParagraphCreatesNewParagraph();
   Element* GetSelectionContainer();
@@ -777,22 +772,16 @@ protected: // Shouldn't be used by frien
 
   /**
    * InsertBrElementAtSelectionWithTransaction() inserts a new <br> element at
    * selection.  If there is non-collapsed selection ranges, the selected
    * ranges is deleted first.
    */
   nsresult InsertBrElementAtSelectionWithTransaction();
 
-  /**
-   * RemoveStyleSheetWithTransaction() removes the given URL stylesheet
-   * from mStyleSheets and mStyleSheetURLs.
-   */
-  nsresult RemoveStyleSheetWithTransaction(const nsAString& aURL);
-
   nsresult LoadHTML(const nsAString& aInputString);
 
   nsresult GetCSSBackgroundColorState(bool* aMixed, nsAString& aOutColor,
                                       bool aBlockLevel);
   nsresult GetHTMLBackgroundColorState(bool* aMixed, nsAString& outColor);
 
   nsresult GetLastCellInRow(nsINode* aRowNode,
                             nsINode** aCellNode);
deleted file mode 100644
--- a/editor/libeditor/StyleSheetTransactions.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 "StyleSheetTransactions.h"
-
-#include <stddef.h>                     // for nullptr
-
-#include "nsAString.h"
-#include "nsCOMPtr.h"                   // for nsCOMPtr, do_QueryInterface, etc.
-#include "mozilla/StyleSheet.h"   // for mozilla::StyleSheet
-#include "mozilla/StyleSheetInlines.h"
-#include "nsDebug.h"                    // for NS_ENSURE_TRUE
-#include "nsError.h"                    // for NS_OK, etc.
-#include "nsIDocument.h"                // for nsIDocument
-
-namespace mozilla {
-
-static void
-AddStyleSheet(EditorBase& aEditor, StyleSheet* aSheet)
-{
-  if (nsCOMPtr<nsIDocument> doc = aEditor.GetDocument()) {
-    doc->AddStyleSheet(aSheet);
-  }
-}
-
-static void
-RemoveStyleSheet(EditorBase& aEditor, StyleSheet* aSheet)
-{
-  if (nsCOMPtr<nsIDocument> doc = aEditor.GetDocument()) {
-    doc->RemoveStyleSheet(aSheet);
-  }
-}
-
-/******************************************************************************
- * AddStyleSheetTransaction
- ******************************************************************************/
-
-AddStyleSheetTransaction::AddStyleSheetTransaction(EditorBase& aEditorBase,
-                                                   StyleSheet& aStyleSheet)
-  : mEditorBase(&aEditorBase)
-  , mSheet(&aStyleSheet)
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(AddStyleSheetTransaction,
-                                   EditTransactionBase,
-                                   mEditorBase,
-                                   mSheet)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddStyleSheetTransaction)
-NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
-
-NS_IMETHODIMP
-AddStyleSheetTransaction::DoTransaction()
-{
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  AddStyleSheet(*mEditorBase, mSheet);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-AddStyleSheetTransaction::UndoTransaction()
-{
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  RemoveStyleSheet(*mEditorBase, mSheet);
-  return NS_OK;
-}
-
-/******************************************************************************
- * RemoveStyleSheetTransaction
- ******************************************************************************/
-
-RemoveStyleSheetTransaction::RemoveStyleSheetTransaction(
-                               EditorBase& aEditorBase,
-                               StyleSheet& aStyleSheet)
-  : mEditorBase(&aEditorBase)
-  , mSheet(&aStyleSheet)
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(RemoveStyleSheetTransaction,
-                                   EditTransactionBase,
-                                   mEditorBase,
-                                   mSheet)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoveStyleSheetTransaction)
-NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
-
-NS_IMETHODIMP
-RemoveStyleSheetTransaction::DoTransaction()
-{
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  RemoveStyleSheet(*mEditorBase, mSheet);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-RemoveStyleSheetTransaction::UndoTransaction()
-{
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  AddStyleSheet(*mEditorBase, mSheet);
-  return NS_OK;
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/editor/libeditor/StyleSheetTransactions.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#ifndef StylesheetTransactions_h
-#define StylesheetTransactions_h
-
-#include "mozilla/EditorBase.h"         // mEditor
-#include "mozilla/EditTransactionBase.h" // for EditTransactionBase, etc.
-#include "mozilla/StyleSheet.h"   // for mozilla::StyleSheet
-#include "nsCycleCollectionParticipant.h"
-#include "nsID.h"                       // for REFNSIID
-#include "nscore.h"                     // for NS_IMETHOD
-
-namespace mozilla {
-
-class AddStyleSheetTransaction final : public EditTransactionBase
-{
-protected:
-  AddStyleSheetTransaction(EditorBase& aEditor, StyleSheet& aStyleSheet);
-
-public:
-  /**
-   * Creates an add style sheet transaction.  This never returns nullptr.
-   *
-   * @param aEditorBase The editor.
-   * @param aSheet      The style sheet to add.
-   */
-  static already_AddRefed<AddStyleSheetTransaction>
-  Create(EditorBase& aEditorBase, StyleSheet& aStyleSheet)
-  {
-    RefPtr<AddStyleSheetTransaction> transaction =
-      new AddStyleSheetTransaction(aEditorBase, aStyleSheet);
-    return transaction.forget();
-  }
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AddStyleSheetTransaction,
-                                           EditTransactionBase)
-  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-
-  NS_DECL_EDITTRANSACTIONBASE
-
-protected:
-  // The editor that created this transaction.
-  RefPtr<EditorBase> mEditorBase;
-  // The style sheet to add.
-  RefPtr<mozilla::StyleSheet> mSheet;
-};
-
-
-class RemoveStyleSheetTransaction final : public EditTransactionBase
-{
-protected:
-  RemoveStyleSheetTransaction(EditorBase& aEditor, StyleSheet& aStyleSheet);
-
-public:
-  /**
-   * Creates a remove style sheet transaction.  This never returns nullptr.
-   *
-   * @param aEditor     The object providing core editing operations.
-   * @param aSheet      The stylesheet to remove.
-   */
-  static already_AddRefed<RemoveStyleSheetTransaction>
-  Create(EditorBase& aEditorBase, StyleSheet& aStyleSheet)
-  {
-    RefPtr<RemoveStyleSheetTransaction> transaction =
-      new RemoveStyleSheetTransaction(aEditorBase, aStyleSheet);
-    return transaction.forget();
-  }
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(RemoveStyleSheetTransaction,
-                                           EditTransactionBase)
-  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
-
-  NS_DECL_EDITTRANSACTIONBASE
-
-protected:
-  // The editor that created this transaction.
-  RefPtr<EditorBase> mEditorBase;
-  // The style sheet to remove.
-  RefPtr<StyleSheet> mSheet;
-};
-
-} // namespace mozilla
-
-#endif // #ifndef StylesheetTransactions_h
--- a/editor/libeditor/moz.build
+++ b/editor/libeditor/moz.build
@@ -64,17 +64,16 @@ UNIFIED_SOURCES += [
     'HTMLURIRefObject.cpp',
     'InsertNodeTransaction.cpp',
     'InsertTextTransaction.cpp',
     'InternetCiter.cpp',
     'JoinNodeTransaction.cpp',
     'PlaceholderTransaction.cpp',
     'SelectionState.cpp',
     'SplitNodeTransaction.cpp',
-    'StyleSheetTransactions.cpp',
     'TextEditor.cpp',
     'TextEditorDataTransfer.cpp',
     'TextEditorTest.cpp',
     'TextEditRules.cpp',
     'TextEditRulesBidi.cpp',
     'TextEditUtils.cpp',
     'TypeInState.cpp',
     'WSRunObject.cpp',
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -51,17 +51,16 @@ skip-if = android_version == '18' # bug 
 [test_bug432225.html]
 skip-if = toolkit == 'android'
 [test_bug439808.html]
 [test_bug442186.html]
 [test_bug449243.html]
 [test_bug455992.html]
 [test_bug456244.html]
 [test_bug460740.html]
-[test_bug468353.html]
 [test_bug471319.html]
 [test_bug471722.html]
 [test_bug478725.html]
 subsuite = clipboard
 skip-if = toolkit == 'android'
 [test_bug480647.html]
 [test_bug480972.html]
 subsuite = clipboard
deleted file mode 100644
--- a/editor/libeditor/tests/test_bug468353.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=468353
--->
-<head>
-  <title>Test for Bug 468353</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=468353">Mozilla Bug 468353</a>
-<p id="display"></p>
-<div id="content">
-  <iframe></iframe>
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-var styleSheets = null;
-
-function checkStylesheets() {
-  // Evidently RemoveStyleSheet is the only method in nsIEditorStyleSheets
-  // that would throw. RemoveOverrideStyleSheet returns NS_OK even if the
-  // sheet is not there
-  var removed = 0;
-  try
-  {
-    styleSheets.removeStyleSheet("resource://gre/res/designmode.css");
-    removed++;
-  }
-  catch (ex) { }
-
-  try {
-    styleSheets.removeStyleSheet("resource://gre/res/contenteditable.css");
-    removed++;
-  }
-  catch (ex) { }
-
-  is(removed, 0, "Should have thrown if stylesheet was not there");
-}
-
-function runTest() {
-  const Ci = SpecialPowers.Ci;
-
-  /** Found while fixing bug 440614 **/
-  var editframe = window.frames[0];
-  var editdoc = editframe.document;
-  var editor = null;
-  editdoc.write('');
-  editdoc.close();
-
-  editdoc.designMode='on';
-
-  // Hold the reference to the editor
-  editor = SpecialPowers.wrap(editframe)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIWebNavigation)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIEditingSession)
-                        .getEditorForWindow(editframe);
-
-  styleSheets = editor.QueryInterface(Ci.nsIEditorStyleSheets);
-
-  editdoc.designMode='off';
-  
-  checkStylesheets();
-  
-  // Let go
-  editor = null;
-  styleSheets = null;
-  
-  editdoc.body.contentEditable = true;
-  
-  // Hold the reference to the editor
-  editor = SpecialPowers.wrap(editframe)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIWebNavigation)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIEditingSession)
-                        .getEditorForWindow(editframe);
-
-  styleSheets = editor.QueryInterface(Ci.nsIEditorStyleSheets);
-  
-  editdoc.body.contentEditable = false;
-  
-  checkStylesheets();
-
-  editdoc.designMode = "on";
-  editdoc.body.contentEditable = true;
-  editdoc.designMode = "off";
-
-  // Hold the reference to the editor
-  editor = SpecialPowers.wrap(editframe)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIWebNavigation)
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIEditingSession)
-                        .getEditorForWindow(editframe);
-
-  styleSheets = editor.QueryInterface(Ci.nsIEditorStyleSheets);
-
-  editdoc.body.contentEditable = false;
-
-  checkStylesheets();
-  
-  SimpleTest.finish();
-}
-
-//XXX I don't know if this is necessary, but we're dealing with iframes...
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(runTest);
-
-</script>
-</pre>
-</body>
-</html>
--- a/editor/nsIEditorStyleSheets.idl
+++ b/editor/nsIEditorStyleSheets.idl
@@ -4,32 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 [scriptable, builtinclass, uuid(4805e682-49b9-11d3-9ce4-ed60bd6cb5bc)]
 
 interface nsIEditorStyleSheets : nsISupports
 {
-  /** Load and apply the style sheet, specified by aURL, to the
-    * editor's document, replacing the last style sheet added (if any).
-    * This is always asynchronous, and may cause network I/O.
-    *
-    * @param aURL The style sheet to be loaded and applied.
-    */
-  void replaceStyleSheet(in AString aURL);
-
-  /** Add the given style sheet to the editor's document,
-    * on top of any that are already there.
-    * This is always asynchronous, and may cause network I/O.
-    *
-    * @param aURL The style sheet to be loaded and applied.
-    */
-  void addStyleSheet(in AString aURL);
-
   /** Load and apply the override style sheet, specified by aURL, to the
     * editor's document, replacing the last override style sheet added (if any).
     * This is always synchronous, so aURL should be a local file with only
     * local @imports. This action is not undoable. It is not intended for
     * "user" style sheets, only for editor developers to add sheets to change
     * display behavior for editing (like showing special cursors) that will
     * not be affected by loading "document" style sheets with addStyleSheet or
     * especially replaceStyleSheet.
@@ -42,23 +26,16 @@ interface nsIEditorStyleSheets : nsISupp
     * the editor's document, on top of any that are already there.
     * This is always synchronous, so the same caveats about local files and no
     * non-local @import as replaceOverrideStyleSheet apply here, too.
     *
     * @param aURL The style sheet to be loaded and applied.
     */
   void addOverrideStyleSheet(in AString aURL);
 
-  /** Remove the given style sheet from the editor's document
-    * This is always synchronous
-    *
-    * @param aURL The style sheet to be removed
-    */
-  void removeStyleSheet(in AString aURL);
-
   /** Remove the given override style sheet from the editor's document
     * This is always synchronous
     *
     * @param aURL The style sheet to be removed.
     */
   void removeOverrideStyleSheet(in AString aURL);
 
   /** Enable or disable the given style sheet from the editor's document
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -644,17 +644,17 @@ GCRuntime::pickChunk(AutoLockGCBgAlloc& 
 
 BackgroundAllocTask::BackgroundAllocTask(JSRuntime* rt, ChunkPool& pool)
   : GCParallelTaskHelper(rt),
     chunkPool_(pool),
     enabled_(CanUseExtraThreads() && GetCPUCount() >= 2)
 {
 }
 
-/* virtual */ void
+void
 BackgroundAllocTask::run()
 {
     TraceLoggerThread* logger = TraceLoggerForCurrentThread();
     AutoTraceLog logAllocation(logger, TraceLogger_GCAllocation);
 
     AutoLockGC lock(runtime());
     while (!cancel_ && runtime()->gc.wantBackgroundAllocation(lock)) {
         Chunk* chunk;
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -932,19 +932,17 @@ Chunk::updateChunkListAfterFree(JSRuntim
         rt->gc.recycleChunk(this, lock);
     }
 }
 
 void
 GCRuntime::releaseArena(Arena* arena, const AutoLockGC& lock)
 {
     arena->zone->usage.removeGCArena();
-    if (isBackgroundSweeping())
-        arena->zone->threshold.updateForRemovedArena(tunables);
-    return arena->chunk()->releaseArena(rt, arena, lock);
+    arena->chunk()->releaseArena(rt, arena, lock);
 }
 
 GCRuntime::GCRuntime(JSRuntime* rt) :
     rt(rt),
     systemZone(nullptr),
     atomsZone(nullptr),
     stats_(rt),
     marker(rt),
@@ -999,18 +997,18 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
     fullCompartmentChecks(false),
     gcCallbackDepth(0),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     arenasEmptyAtShutdown(true),
 #endif
     lock(mutexid::GCLock),
     allocTask(rt, emptyChunks_.ref()),
+    sweepTask(rt),
     decommitTask(rt),
-    helperState(rt),
     nursery_(rt),
     storeBuffer_(rt, nursery()),
     blocksToFreeAfterMinorGC((size_t) JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE)
 {
     setGCMode(JSGC_MODE_GLOBAL);
 }
 
 #ifdef JS_GC_ZEAL
@@ -1320,17 +1318,17 @@ GCRuntime::finish()
         nursery().disable();
     }
 
     /*
      * Wait until the background finalization and allocation stops and the
      * helper thread shuts down before we forcefully release any remaining GC
      * memory.
      */
-    helperState.finish();
+    sweepTask.join();
     allocTask.cancelAndWait();
     decommitTask.cancelAndWait();
 
 #ifdef JS_GC_ZEAL
     /* Free memory associated with GC verification. */
     finishVerifier();
 #endif
 
@@ -2742,17 +2740,17 @@ UpdatePointersTask::getArenasToUpdate()
 void
 UpdatePointersTask::updateArenas()
 {
     MovingTracer trc(runtime());
     for (Arena* arena = arenas_.begin; arena != arenas_.end; arena = arena->next)
         UpdateArenaPointers(&trc, arena);
 }
 
-/* virtual */ void
+void
 UpdatePointersTask::run()
 {
     // These checks assert when run in parallel.
     AutoDisableProxyCheck noProxyCheck;
 
     while (getArenasToUpdate())
         updateArenas();
 }
@@ -2995,17 +2993,20 @@ GCRuntime::updateRuntimePointersToReloca
 
     // Sweep everything to fix up weak pointers.
     Debugger::sweepAll(rt->defaultFreeOp());
     jit::JitRuntime::SweepJitcodeGlobalTable(rt);
     for (JS::detail::WeakCacheBase* cache : rt->weakCaches())
         cache->sweep();
 
     // Type inference may put more blocks here to free.
-    blocksToFreeAfterSweeping.ref().freeAll();
+    {
+        AutoLockHelperThreadState lock;
+        blocksToFreeAfterSweeping.ref().freeAll();
+    }
 
     // Call callbacks to get the rest of the system to fixup other untraced pointers.
     callWeakPointerZonesCallbacks();
 }
 
 void
 GCRuntime::protectAndHoldArenas(Arena* arenaList)
 {
@@ -3514,17 +3515,17 @@ void
 js::gc::BackgroundDecommitTask::setChunksToScan(ChunkVector &chunks)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
     MOZ_ASSERT(!isRunning());
     MOZ_ASSERT(toDecommit.ref().empty());
     Swap(toDecommit.ref(), chunks);
 }
 
-/* virtual */ void
+void
 js::gc::BackgroundDecommitTask::run()
 {
     AutoLockGC lock(runtime());
 
     for (Chunk* chunk : toDecommit.ref()) {
 
         // The arena list is not doubly-linked, so we have to work in the free
         // list order and not in the natural order.
@@ -3579,207 +3580,167 @@ GCRuntime::sweepBackgroundThings(ZoneLis
         // Release any arenas that are now empty, dropping and reaquiring the GC
         // lock every so often to avoid blocking the main thread from
         // allocating chunks.
         static const size_t LockReleasePeriod = 32;
         size_t releaseCount = 0;
         Arena* next;
         for (Arena* arena = emptyArenas; arena; arena = next) {
             next = arena->next;
+
+            // We already calculated the zone's GC trigger after foreground
+            // sweeping finished. Now we must update this value.
+            arena->zone->threshold.updateForRemovedArena(tunables);
+
             rt->gc.releaseArena(arena, lock);
             releaseCount++;
             if (releaseCount % LockReleasePeriod == 0) {
                 lock.unlock();
                 lock.lock();
             }
         }
     }
 }
 
 void
 GCRuntime::assertBackgroundSweepingFinished()
 {
 #ifdef DEBUG
-    MOZ_ASSERT(backgroundSweepZones.ref().isEmpty());
+    {
+        AutoLockHelperThreadState lock;
+        MOZ_ASSERT(backgroundSweepZones.ref().isEmpty());
+        MOZ_ASSERT(blocksToFreeAfterSweeping.ref().computedSizeOfExcludingThis() == 0);
+    }
+
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         for (auto i : AllAllocKinds()) {
             MOZ_ASSERT(!zone->arenas.arenaListsToSweep(i));
             MOZ_ASSERT(zone->arenas.doneBackgroundFinalize(i));
         }
     }
-    MOZ_ASSERT(blocksToFreeAfterSweeping.ref().computedSizeOfExcludingThis() == 0);
 #endif
 }
 
 void
-GCHelperState::finish()
-{
-    // Wait for any lingering background sweeping to finish.
-    waitBackgroundSweepEnd();
-}
-
-GCHelperState::State
-GCHelperState::state(const AutoLockGC&)
-{
-    return state_;
-}
-
-void
-GCHelperState::setState(State state, const AutoLockGC&)
-{
-    state_ = state;
-}
-
-void
-GCHelperState::startBackgroundThread(State newState, const AutoLockGC& lock,
-                                     const AutoLockHelperThreadState& helperLock)
-{
-    MOZ_ASSERT(!hasThread && state(lock) == IDLE && newState != IDLE);
-    setState(newState, lock);
-
-    {
-        AutoEnterOOMUnsafeRegion noOOM;
-        if (!HelperThreadState().gcHelperWorklist(helperLock).append(this))
-            noOOM.crash("Could not add to pending GC helpers list");
-    }
-
-    HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, helperLock);
-}
-
-void
-GCHelperState::waitForBackgroundThread(js::AutoLockGC& lock)
-{
-    while (isBackgroundSweeping())
-        done.wait(lock.guard());
-}
-
-void
-GCHelperState::work()
-{
-    MOZ_ASSERT(CanUseExtraThreads());
-
-    AutoLockGC lock(rt);
-
-    MOZ_ASSERT(!hasThread);
-    hasThread = true;
-
-#ifdef DEBUG
-    MOZ_ASSERT(!TlsContext.get()->gcHelperStateThread);
-    TlsContext.get()->gcHelperStateThread = true;
-#endif
-
-    TraceLoggerThread* logger = TraceLoggerForCurrentThread();
-
-    switch (state(lock)) {
-
-      case IDLE:
-        MOZ_CRASH("GC helper triggered on idle state");
-        break;
-
-      case SWEEPING: {
-        AutoTraceLog logSweeping(logger, TraceLogger_GCSweeping);
-        doSweep(lock);
-        MOZ_ASSERT(state(lock) == SWEEPING);
-        break;
-      }
-
-    }
-
-    setState(IDLE, lock);
-    hasThread = false;
-
-#ifdef DEBUG
-    TlsContext.get()->gcHelperStateThread = false;
-#endif
-
-    done.notify_all();
-}
-
-void
 GCRuntime::queueZonesForBackgroundSweep(ZoneList& zones)
 {
-    AutoLockHelperThreadState helperLock;
-    AutoLockGC lock(rt);
+    AutoLockHelperThreadState lock;
     backgroundSweepZones.ref().transferFrom(zones);
-    helperState.maybeStartBackgroundSweep(lock, helperLock);
+    if (sweepOnBackgroundThread)
+        sweepTask.startIfIdle(lock);
 }
 
 void
 GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo)
 {
     MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-    AutoLockGC lock(rt);
+    AutoLockHelperThreadState lock;
     blocksToFreeAfterSweeping.ref().transferUnusedFrom(lifo);
 }
 
 void
 GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo)
 {
     MOZ_ASSERT(JS::RuntimeHeapIsBusy());
-    AutoLockGC lock(rt);
+    AutoLockHelperThreadState lock;
     blocksToFreeAfterSweeping.ref().transferFrom(lifo);
 }
 
 void
 GCRuntime::freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo)
 {
     blocksToFreeAfterMinorGC.ref().transferFrom(lifo);
 }
 
-void
-GCHelperState::maybeStartBackgroundSweep(const AutoLockGC& lock,
-                                         const AutoLockHelperThreadState& helperLock)
+BackgroundSweepTask::BackgroundSweepTask(JSRuntime* rt)
+  : GCParallelTaskHelper(rt),
+    done(false)
+{}
+
+inline bool
+BackgroundSweepTask::isRunning() const
+{
+    AutoLockHelperThreadState lock;
+    return isRunningWithLockHeld(lock);
+}
+
+inline bool
+BackgroundSweepTask::isRunningWithLockHeld(const AutoLockHelperThreadState& lock) const
+{
+    return Base::isRunningWithLockHeld(lock) && !done;
+}
+
+void
+BackgroundSweepTask::startIfIdle(AutoLockHelperThreadState& lock)
 {
     MOZ_ASSERT(CanUseExtraThreads());
 
-    if (state(lock) == IDLE)
-        startBackgroundThread(SWEEPING, lock, helperLock);
-}
-
-void
-GCHelperState::waitBackgroundSweepEnd()
-{
-    AutoLockGC lock(rt);
-    while (state(lock) == SWEEPING)
-        waitForBackgroundThread(lock);
+    if (isRunningWithLockHeld(lock))
+        return;
+
+    // Join the previous invocation of the task. This will return immediately
+    // if the thread has never been started.
+    joinWithLockHeld(lock);
+
+    done = false;
+    startWithLockHeld(lock);
+}
+
+void
+BackgroundSweepTask::runFromMainThread(JSRuntime* rt)
+{
+    {
+        AutoLockHelperThreadState lock;
+        MOZ_ASSERT(!isRunningWithLockHeld(lock));
+        joinWithLockHeld(lock);
+        done = false;
+    }
+
+    Base::runFromMainThread(rt);
+}
+
+void
+BackgroundSweepTask::run()
+{
+    AutoTraceLog logSweeping(TraceLoggerForCurrentThread(), TraceLogger_GCSweeping);
+
+    AutoLockHelperThreadState lock;
+    AutoSetThreadIsSweeping threadIsSweeping;
+
+    MOZ_ASSERT(!done);
+
+    JSRuntime* rt = runtime();
+
+    // The main thread may call queueZonesForBackgroundSweep() while this is
+    // running so we must check there is no more work after releasing the lock.
+    do {
+        ZoneList zones;
+        zones.transferFrom(rt->gc.backgroundSweepZones.ref());
+        LifoAlloc freeLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
+        freeLifoAlloc.transferFrom(&rt->gc.blocksToFreeAfterSweeping.ref());
+
+        AutoUnlockHelperThreadState unlock(lock);
+        rt->gc.sweepBackgroundThings(zones, freeLifoAlloc);
+    } while (!rt->gc.backgroundSweepZones.ref().isEmpty());
+
+    // Signal to the main thread that we're finished, because we release the
+    // lock again before GCParallelTask's state is changed to finished.
+    done = true;
+}
+
+void
+GCRuntime::waitBackgroundSweepEnd()
+{
+    sweepTask.join();
+
+    // TODO: Improve assertion to work in incremental GC?
     if (!rt->gc.isIncrementalGCInProgress())
         rt->gc.assertBackgroundSweepingFinished();
 }
 
-void
-GCHelperState::doSweep(AutoLockGC& lock)
-{
-    // The main thread may call queueZonesForBackgroundSweep() while this is
-    // running so we must check there is no more work to do before exiting.
-
-    do {
-        while (!rt->gc.backgroundSweepZones.ref().isEmpty()) {
-            AutoSetThreadIsSweeping threadIsSweeping;
-
-            ZoneList zones;
-            zones.transferFrom(rt->gc.backgroundSweepZones.ref());
-            LifoAlloc freeLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
-            freeLifoAlloc.transferFrom(&rt->gc.blocksToFreeAfterSweeping.ref());
-
-            AutoUnlockGC unlock(lock);
-            rt->gc.sweepBackgroundThings(zones, freeLifoAlloc);
-        }
-    } while (!rt->gc.backgroundSweepZones.ref().isEmpty());
-}
-
-#ifdef DEBUG
-
-bool
-GCHelperState::onBackgroundThread()
-{
-    return TlsContext.get()->gcHelperStateThread;
-}
-
-#endif // DEBUG
-
 bool
 GCRuntime::shouldReleaseObservedTypes()
 {
     bool releaseTypes = false;
 
 #ifdef JS_GC_ZEAL
     if (zealModeBits != 0)
         releaseTypes = true;
@@ -5867,20 +5828,20 @@ GCRuntime::endSweepingSweepGroup(FreeOp*
         if (zone->isAtomsZone())
             sweepAtomsZone = true;
         else
             zones.append(zone);
     }
     if (sweepAtomsZone)
         zones.append(atomsZone);
 
-    if (sweepOnBackgroundThread)
-        queueZonesForBackgroundSweep(zones);
-    else
-        sweepBackgroundThings(zones, blocksToFreeAfterSweeping.ref());
+    queueZonesForBackgroundSweep(zones);
+
+    if (!sweepOnBackgroundThread)
+        sweepTask.runFromMainThread(rt);
 
     return Finished;
 }
 
 void
 GCRuntime::beginSweepPhase(JS::gcreason::Reason reason, AutoGCSession& session)
 {
     /*
@@ -6916,17 +6877,20 @@ GCRuntime::resetIncrementalGC(gc::AbortR
             ResetGrayList(c);
 
         for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
             zone->setNeedsIncrementalBarrier(false);
             zone->changeGCState(Zone::Mark, Zone::NoGC);
             zone->arenas.unmarkPreMarkedFreeCells();
         }
 
-        blocksToFreeAfterSweeping.ref().freeAll();
+        {
+            AutoLockHelperThreadState lock;
+            blocksToFreeAfterSweeping.ref().freeAll();
+        }
 
         incrementalState = State::NotActive;
 
         MOZ_ASSERT(!marker.shouldCheckCompartments());
 
         break;
       }
 
@@ -7210,17 +7174,16 @@ GCRuntime::incrementalCollectSlice(Slice
 
       case State::Finalize:
         {
             gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::WAIT_BACKGROUND_THREAD);
 
             // Yield until background finalization is done.
             if (!budget.isUnlimited()) {
                 // Poll for end of background sweeping
-                AutoLockGC lock(rt);
                 if (isBackgroundSweeping())
                     break;
             } else {
                 waitBackgroundSweepEnd();
             }
         }
 
         {
deleted file mode 100644
--- a/js/src/gc/GCHelperState.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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/. */
-
-#ifndef gc_GCHelperState_h
-#define gc_GCHelperState_h
-
-#include "js/TypeDecls.h"
-#include "threading/ConditionVariable.h"
-#include "threading/ProtectedData.h"
-
-namespace js {
-class AutoLockHelperThreadState;
-
-namespace gc {
-class ArenaLists;
-} /* namespace gc */
-
-/*
- * Helper state for use when JS helper threads sweep and allocate GC thing kinds
- * that can be swept and allocated off thread.
- *
- * In non-threadsafe builds, all actual sweeping and allocation is performed
- * on the main thread, but GCHelperState encapsulates this from clients as
- * much as possible.
- */
-class GCHelperState
-{
-    enum State {
-        IDLE,
-        SWEEPING
-    };
-
-    // Associated runtime.
-    JSRuntime* const rt;
-
-    // Condvar for notifying the main thread when work has finished. This is
-    // associated with the runtime's GC lock --- the worker thread state
-    // condvars can't be used here due to lock ordering issues.
-    ConditionVariable done;
-
-    // Activity for the helper to do, protected by the GC lock.
-    MainThreadOrGCTaskData<State> state_;
-
-    // Whether work is being performed on some thread.
-    GCLockData<bool> hasThread;
-
-    void startBackgroundThread(State newState, const AutoLockGC& lock,
-                               const AutoLockHelperThreadState& helperLock);
-    void waitForBackgroundThread(js::AutoLockGC& lock);
-
-    State state(const AutoLockGC&);
-    void setState(State state, const AutoLockGC&);
-
-    friend class js::gc::ArenaLists;
-
-    static void freeElementsAndArray(void** array, void** end) {
-        MOZ_ASSERT(array <= end);
-        for (void** p = array; p != end; ++p)
-            js_free(*p);
-        js_free(array);
-    }
-
-    void doSweep(AutoLockGC& lock);
-
-  public:
-    explicit GCHelperState(JSRuntime* rt)
-      : rt(rt),
-        done(),
-        state_(IDLE)
-    { }
-
-    JSRuntime* runtime() { return rt; }
-
-    void finish();
-
-    void work();
-
-    void maybeStartBackgroundSweep(const AutoLockGC& lock,
-                                   const AutoLockHelperThreadState& helperLock);
-    void startBackgroundShrink(const AutoLockGC& lock);
-
-    /* Must be called without the GC lock taken. */
-    void waitBackgroundSweepEnd();
-
-#ifdef DEBUG
-    bool onBackgroundThread();
-#endif
-
-    /*
-     * Outside the GC lock may give true answer when in fact the sweeping has
-     * been done.
-     */
-    bool isBackgroundSweeping() const {
-        return state_ == SWEEPING;
-    }
-};
-
-} /* namespace js */
-
-#endif /* gc_GCHelperState_h */
--- a/js/src/gc/GCParallelTask.h
+++ b/js/src/gc/GCParallelTask.h
@@ -9,16 +9,18 @@
 
 #include "mozilla/Move.h"
 
 #include "js/TypeDecls.h"
 #include "threading/ProtectedData.h"
 
 namespace js {
 
+class AutoLockHelperThreadState;
+
 // A generic task used to dispatch work to the helper thread system.
 // Users supply a function pointer to call.
 //
 // Note that we don't use virtual functions here because destructors can write
 // the vtable pointer on entry, which can causes races if synchronization
 // happens there.
 class GCParallelTask
 {
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -8,17 +8,16 @@
 #define gc_GCRuntime_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/Maybe.h"
 
 #include "gc/ArenaList.h"
 #include "gc/AtomMarking.h"
-#include "gc/GCHelperState.h"
 #include "gc/GCMarker.h"
 #include "gc/GCParallelTask.h"
 #include "gc/Nursery.h"
 #include "gc/Scheduling.h"
 #include "gc/Statistics.h"
 #include "gc/StoreBuffer.h"
 #include "js/GCAnnotations.h"
 #include "js/UniquePtr.h"
@@ -101,16 +100,34 @@ class ChunkPool
         Chunk* get() const { return current_; }
         operator Chunk*() const { return get(); }
         Chunk* operator->() const { return get(); }
       private:
         Chunk* current_;
     };
 };
 
+class BackgroundSweepTask : public GCParallelTaskHelper<BackgroundSweepTask>
+{
+    using Base = GCParallelTaskHelper<BackgroundSweepTask>;
+
+    HelperThreadLockData<bool> done;
+
+  public:
+    explicit BackgroundSweepTask(JSRuntime* rt);
+
+    bool isRunning() const;
+    bool isRunningWithLockHeld(const AutoLockHelperThreadState& lock) const;
+
+    void startIfIdle(AutoLockHelperThreadState& lock);
+    void runFromMainThread(JSRuntime* rt);
+
+    void run();
+};
+
 // Performs extra allocation off thread so that when memory is required on the
 // main thread it will already be available and waiting.
 class BackgroundAllocTask : public GCParallelTaskHelper<BackgroundAllocTask>
 {
     // Guarded by the GC lock.
     GCLockData<ChunkPool&> chunkPool_;
 
     const bool enabled_;
@@ -309,27 +326,25 @@ class GCRuntime
     }
 #endif
 
   public:
     // Internal public interface
     State state() const { return incrementalState; }
     bool isHeapCompacting() const { return state() == State::Compact; }
     bool isForegroundSweeping() const { return state() == State::Sweep; }
-    bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
-    void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
+    bool isBackgroundSweeping() {
+        return sweepTask.isRunning();
+    }
+    void waitBackgroundSweepEnd();
     void waitBackgroundSweepOrAllocEnd() {
-        helperState.waitBackgroundSweepEnd();
+        waitBackgroundSweepEnd();
         allocTask.cancelAndWait();
     }
 
-#ifdef DEBUG
-    bool onBackgroundThread() { return helperState.onBackgroundThread(); }
-#endif // DEBUG
-
     void lockGC() {
         lock.lock();
     }
 
     void unlockGC() {
         lock.unlock();
     }
 
@@ -608,16 +623,17 @@ class GCRuntime
                                           AllocKind kind);
     IncrementalProgress sweepShapeTree(FreeOp* fop, SliceBudget& budget, Zone* zone);
     void endSweepPhase(bool lastGC);
     bool allCCVisibleZonesWereCollected() const;
     void sweepZones(FreeOp* fop, bool destroyingRuntime);
     void decommitAllWithoutUnlocking(const AutoLockGC& lock);
     void startDecommit();
     void queueZonesForBackgroundSweep(ZoneList& zones);
+    void maybeStartBackgroundSweep(AutoLockHelperThreadState& lock);
     void sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks);
     void assertBackgroundSweepingFinished();
     bool shouldCompact();
     void beginCompactPhase();
     IncrementalProgress compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
                                      AutoGCSession& session);
     void endCompactPhase();
     void sweepTypesAfterCompacting(Zone* zone);
@@ -813,25 +829,24 @@ class GCRuntime
 
     /* Whether any sweeping will take place in the separate GC helper thread. */
     MainThreadData<bool> sweepOnBackgroundThread;
 
     /* Whether observed type information is being released in the current GC. */
     MainThreadData<bool> releaseObservedTypes;
 
     /* Singly linked list of zones to be swept in the background. */
-    MainThreadOrGCTaskData<ZoneList> backgroundSweepZones;
+    HelperThreadLockData<ZoneList> backgroundSweepZones;
 
     /*
      * Free LIFO blocks are transferred to this allocator before being freed on
      * the background GC thread after sweeping.
      */
-    MainThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
+    HelperThreadLockData<LifoAlloc> blocksToFreeAfterSweeping;
 
-  private:
     /* Index of current sweep group (for stats). */
     MainThreadData<unsigned> sweepGroupIndex;
 
     /*
      * Incremental sweep state.
      */
 
     MainThreadData<JS::Zone*> sweepGroups;
@@ -946,21 +961,22 @@ class GCRuntime
     MainThreadData<bool> arenasEmptyAtShutdown;
 #endif
 
     /* Synchronize GC heap access among GC helper threads and the main thread. */
     friend class js::AutoLockGC;
     friend class js::AutoLockGCBgAlloc;
     js::Mutex lock;
 
+    friend class BackgroundSweepTask;
+
     BackgroundAllocTask allocTask;
+    BackgroundSweepTask sweepTask;
     BackgroundDecommitTask decommitTask;
 
-    js::GCHelperState helperState;
-
     /*
      * During incremental sweeping, this field temporarily holds the arenas of
      * the current AllocKind being swept in order of increasing free space.
      */
     MainThreadData<SortedArenaList> incrementalSweepList;
 
   private:
     MainThreadData<Nursery> nursery_;
@@ -985,17 +1001,16 @@ class GCRuntime
 
     void minorGC(JS::gcreason::Reason reason,
                  gcstats::PhaseKind phase = gcstats::PhaseKind::MINOR_GC) JS_HAZ_GC_CALL;
     void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
         minorGC(reason, gcstats::PhaseKind::EVICT_NURSERY);
     }
     void freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo);
 
-    friend class js::GCHelperState;
     friend class MarkingValidator;
     friend class AutoEnterIteration;
 };
 
 /* Prevent compartments and zones from being collected during iteration. */
 class MOZ_RAII AutoEnterIteration {
     GCRuntime* gc;
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -264,18 +264,17 @@ js::CheckTracedThing(JSTracer* trc, T* t
      * either free or uninitialized in which case we check the free list.
      *
      * Further complications are that background sweeping may be running and
      * concurrently modifiying the free list and that tracing is done off
      * thread during compacting GC and reading the contents of the thing by
      * IsThingPoisoned would be racy in this case.
      */
     MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy() &&
-                  !zone->isGCCompacting() &&
-                  !rt->gc.isBackgroundSweeping(),
+                  !zone->isGCSweeping() && !zone->isGCFinished() && !zone->isGCCompacting(),
                   !IsThingPoisoned(thing) || !InFreeList(thing->asTenured().arena(), thing));
 #endif
 }
 
 template <typename S>
 struct CheckTracedFunctor : public VoidDefaultAdaptor<S> {
     template <typename T> void operator()(T* t, JSTracer* trc) { CheckTracedThing(trc, t); }
 };
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -5,24 +5,25 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Directory metadata
 component_engine = ('Core', 'JavaScript Engine')
 component_gc     = ('Core', 'JavaScript: GC')
 component_intl   = ('Core', 'JavaScript: Internationalization API')
 component_jit    = ('Core', 'JavaScript Engine: JIT')
 component_stl    = ('Core', 'JavaScript: Standard Library')
+component_wasm   = ('Core', 'Javascript: Web Assembly')
 
 FILES_PER_UNIFIED_FILE = 6
 
 with Files('*'):
     BUG_COMPONENT = component_engine
 
 with Files('wasm/**'):
-    BUG_COMPONENT = component_jit
+    BUG_COMPONENT = component_wasm
 with Files('builtin/**'):
     BUG_COMPONENT = component_stl
 with Files('ctypes/**'):
     BUG_COMPONENT = ('Core', 'js-ctypes')
 with Files('gc/**'):
     BUG_COMPONENT = component_gc
 with Files('jit/**'):
     BUG_COMPONENT = component_jit
--- a/js/src/threading/ProtectedData.cpp
+++ b/js/src/threading/ProtectedData.cpp
@@ -21,17 +21,17 @@ static inline bool
 OnHelperThread()
 {
     if (Helper == AllowedHelperThread::IonCompile || Helper == AllowedHelperThread::GCTaskOrIonCompile) {
         if (CurrentThreadIsIonCompiling())
             return true;
     }
 
     if (Helper == AllowedHelperThread::GCTask || Helper == AllowedHelperThread::GCTaskOrIonCompile) {
-        if (TlsContext.get()->performingGC || TlsContext.get()->runtime()->gc.onBackgroundThread())
+        if (TlsContext.get()->performingGC)
             return true;
     }
 
     return false;
 }
 
 void
 CheckThreadLocal::check() const
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -1208,17 +1208,16 @@ GlobalHelperThreadState::addSizeOfInclud
         wasmTier2GeneratorWorklist_.sizeOfExcludingThis(mallocSizeOf) +
         promiseHelperTasks_.sizeOfExcludingThis(mallocSizeOf) +
         parseWorklist_.sizeOfExcludingThis(mallocSizeOf) +
         parseFinishedList_.sizeOfExcludingThis(mallocSizeOf) +
         parseWaitingOnGC_.sizeOfExcludingThis(mallocSizeOf) +
         compressionPendingList_.sizeOfExcludingThis(mallocSizeOf) +
         compressionWorklist_.sizeOfExcludingThis(mallocSizeOf) +
         compressionFinishedList_.sizeOfExcludingThis(mallocSizeOf) +
-        gcHelperWorklist_.sizeOfExcludingThis(mallocSizeOf) +
         gcParallelWorklist_.sizeOfExcludingThis(mallocSizeOf);
 
     // Report ParseTasks on wait lists
     for (auto task : parseWorklist_)
         htStats.parseTask += task->sizeOfIncludingThis(mallocSizeOf);
     for (auto task : parseFinishedList_)
         htStats.parseTask += task->sizeOfIncludingThis(mallocSizeOf);
     for (auto task : parseWaitingOnGC_)
@@ -1295,24 +1294,16 @@ GlobalHelperThreadState::maxCompressionT
         return 1;
 
     // Compression is triggered on major GCs to compress ScriptSources. It is
     // considered low priority work.
     return 1;
 }
 
 size_t
-GlobalHelperThreadState::maxGCHelperThreads() const
-{
-    if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_GCHELPER))
-        return 1;
-    return threadCount;
-}
-
-size_t
 GlobalHelperThreadState::maxGCParallelThreads() const
 {
     if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_GCPARALLEL))
         return 1;
     return threadCount;
 }
 
 bool
@@ -1484,23 +1475,16 @@ GlobalHelperThreadState::scheduleCompres
             // and deleted.
             Unused << worklist.append(std::move(pending[i]));
             remove(pending, &i);
         }
     }
 }
 
 bool
-GlobalHelperThreadState::canStartGCHelperTask(const AutoLockHelperThreadState& lock)
-{
-    return !gcHelperWorklist(lock).empty() &&
-           checkTaskThreadLimit<GCHelperState*>(maxGCHelperThreads());
-}
-
-bool
 GlobalHelperThreadState::canStartGCParallelTask(const AutoLockHelperThreadState& lock)
 {
     return !gcParallelWorklist(lock).empty() &&
            checkTaskThreadLimit<GCParallelTask*>(maxGCParallelThreads());
 }
 
 js::GCParallelTask::~GCParallelTask()
 {
@@ -2303,36 +2287,16 @@ GlobalHelperThreadState::trace(JSTracer*
         parseTask->trace(trc);
     for (auto parseTask : parseFinishedList_)
         parseTask->trace(trc);
     for (auto parseTask : parseWaitingOnGC_)
         parseTask->trace(trc);
 }
 
 void
-HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
-{
-    MOZ_ASSERT(HelperThreadState().canStartGCHelperTask(locked));
-    MOZ_ASSERT(idle());
-
-    currentTask.emplace(HelperThreadState().gcHelperWorklist(locked).popCopy());
-    GCHelperState* task = gcHelperTask();
-
-    AutoSetContextRuntime ascr(task->runtime());
-
-    {
-        AutoUnlockHelperThreadState unlock(locked);
-        task->work();
-    }
-
-    currentTask.reset();
-    HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
-}
-
-void
 JSContext::setHelperThread(HelperThread* thread)
 {
     if (helperThread_)
         nurserySuppressions_--;
 
     helperThread_ = thread;
 
     if (helperThread_)
@@ -2344,21 +2308,16 @@ JSContext::setHelperThread(HelperThread*
 // Priority is determined by the order they're listed here.
 const HelperThread::TaskSpec HelperThread::taskSpecs[] = {
     {
         THREAD_TYPE_GCPARALLEL,
         &GlobalHelperThreadState::canStartGCParallelTask,
         &HelperThread::handleGCParallelWorkload
     },
     {
-        THREAD_TYPE_GCHELPER,
-        &GlobalHelperThreadState::canStartGCHelperTask,
-        &HelperThread::handleGCHelperWorkload
-    },
-    {
         THREAD_TYPE_ION,
         &GlobalHelperThreadState::canStartIonCompile,
         &HelperThread::handleIonWorkload
     },
     {
         THREAD_TYPE_WASM,
         &GlobalHelperThreadState::canStartWasmTier1Compile,
         &HelperThread::handleWasmTier1Workload
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -91,17 +91,16 @@ class GlobalHelperThreadState
 
     // Number of threads to create. May be accessed without locking.
     size_t threadCount;
 
     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
     typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
     typedef mozilla::LinkedList<ParseTask> ParseTaskList;
     typedef Vector<UniquePtr<SourceCompressionTask>, 0, SystemAllocPolicy> SourceCompressionTaskVector;
-    typedef Vector<GCHelperState*, 0, SystemAllocPolicy> GCHelperStateVector;
     typedef Vector<GCParallelTask*, 0, SystemAllocPolicy> GCParallelTaskVector;
     typedef Vector<PromiseHelperTask*, 0, SystemAllocPolicy> PromiseHelperTaskVector;
 
     // List of available threads, or null if the thread state has not been initialized.
     using HelperThreadVector = Vector<HelperThread, 0, SystemAllocPolicy>;
     UniquePtr<HelperThreadVector> threads;
 
     WriteOnceData<JS::RegisterThreadCallback> registerThread;
@@ -136,36 +135,32 @@ class GlobalHelperThreadState
     SourceCompressionTaskVector compressionPendingList_;
 
     // Source compression worklist of tasks that can start.
     SourceCompressionTaskVector compressionWorklist_;
 
     // Finished source compression tasks.
     SourceCompressionTaskVector compressionFinishedList_;
 
-    // Runtimes which have sweeping / allocating work to do.
-    GCHelperStateVector gcHelperWorklist_;
-
     // GC tasks needing to be done in parallel.
     GCParallelTaskVector gcParallelWorklist_;
 
     ParseTask* removeFinishedParseTask(ParseTaskKind kind, JS::OffThreadToken* token);
 
   public:
 
     void addSizeOfIncludingThis(JS::GlobalStats* stats,
                                 AutoLockHelperThreadState& lock) const;
 
     size_t maxIonCompilationThreads() const;
     size_t maxWasmCompilationThreads() const;
     size_t maxWasmTier2GeneratorThreads() const;
     size_t maxPromiseHelperThreads() const;
     size_t maxParseThreads() const;
     size_t maxCompressionThreads() const;
-    size_t maxGCHelperThreads() const;
     size_t maxGCParallelThreads() const;
 
     GlobalHelperThreadState();
 
     bool ensureInitialized();
     void finish();
     void finishThreads();
 
@@ -258,35 +253,30 @@ class GlobalHelperThreadState
     SourceCompressionTaskVector& compressionWorklist(const AutoLockHelperThreadState&) {
         return compressionWorklist_;
     }
 
     SourceCompressionTaskVector& compressionFinishedList(const AutoLockHelperThreadState&) {
         return compressionFinishedList_;
     }
 
-    GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
-        return gcHelperWorklist_;
-    }
-
     GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
         return gcParallelWorklist_;
     }
 
     bool canStartWasmCompile(const AutoLockHelperThreadState& lock, wasm::CompileMode mode);
 
     bool canStartWasmTier1Compile(const AutoLockHelperThreadState& lock);
     bool canStartWasmTier2Compile(const AutoLockHelperThreadState& lock);
     bool canStartWasmTier2Generator(const AutoLockHelperThreadState& lock);
     bool canStartPromiseHelperTask(const AutoLockHelperThreadState& lock);
     bool canStartIonCompile(const AutoLockHelperThreadState& lock);
     bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
     bool canStartParseTask(const AutoLockHelperThreadState& lock);
     bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
-    bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
     bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
 
     // Used by a major GC to signal processing enqueued compression tasks.
     void startHandlingCompressionTasks(const AutoLockHelperThreadState&);
 
   private:
     void scheduleCompressionTasks(const AutoLockHelperThreadState&);
 
@@ -359,17 +349,16 @@ HelperThreadState()
 }
 
 typedef mozilla::Variant<jit::IonBuilder*,
                          wasm::CompileTask*,
                          wasm::Tier2GeneratorTask*,
                          PromiseHelperTask*,
                          ParseTask*,
                          SourceCompressionTask*,
-                         GCHelperState*,
                          GCParallelTask*> HelperTaskUnion;
 
 /* Individual helper thread, one allocated per core. */
 struct HelperThread
 {
     mozilla::Maybe<Thread> thread;
 
     /*
@@ -410,21 +399,16 @@ struct HelperThread
         return maybeCurrentTaskAs<ParseTask*>();
     }
 
     /* Any source being compressed on this thread. */
     SourceCompressionTask* compressionTask() {
         return maybeCurrentTaskAs<SourceCompressionTask*>();
     }
 
-    /* Any GC state for background sweeping or allocating being performed. */
-    GCHelperState* gcHelperTask() {
-        return maybeCurrentTaskAs<GCHelperState*>();
-    }
-
     /* State required to perform a GC parallel task. */
     GCParallelTask* gcParallelTask() {
         return maybeCurrentTaskAs<GCParallelTask*>();
     }
 
     void destroy();
 
     static void ThreadMain(void* arg);
@@ -461,17 +445,16 @@ struct HelperThread
     void handleWasmTier1Workload(AutoLockHelperThreadState& locked);
     void handleWasmTier2Workload(AutoLockHelperThreadState& locked);
     void handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked);
     void handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked);
     void handleIonWorkload(AutoLockHelperThreadState& locked);
     void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
     void handleParseWorkload(AutoLockHelperThreadState& locked);
     void handleCompressionWorkload(AutoLockHelperThreadState& locked);
-    void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
     void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
 };
 
 /* Methods for interacting with helper threads. */
 
 // Create data structures used by helper threads.
 bool
 CreateHelperThreadsState();
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -1269,34 +1269,34 @@ struct MOZ_RAII AutoSetThreadIsPerformin
 
   private:
     JSContext* cx;
 #else
     AutoSetThreadIsPerformingGC() {}
 #endif
 };
 
-// In debug builds, set/unset the GC sweeping flag for the current thread.
+// In debug builds, set/reset the GC sweeping flag for the current thread.
 struct MOZ_RAII AutoSetThreadIsSweeping
 {
 #ifdef DEBUG
     AutoSetThreadIsSweeping()
-      : cx(TlsContext.get())
+      : cx(TlsContext.get()),
+        prevState(cx->gcSweeping)
     {
-        MOZ_ASSERT(!cx->gcSweeping);
         cx->gcSweeping = true;
     }
 
     ~AutoSetThreadIsSweeping() {
-        MOZ_ASSERT(cx->gcSweeping);
-        cx->gcSweeping = false;
+        cx->gcSweeping = prevState;
     }
 
   private:
     JSContext* cx;
+    bool prevState;
 #else
     AutoSetThreadIsSweeping() {}
 #endif
 };
 
 } // namespace gc
 
 } /* namespace js */
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -104,18 +104,18 @@ HasAvailableCompilerTier(JSContext* cx)
 bool
 wasm::HasSupport(JSContext* cx)
 {
     return cx->options().wasm() &&
            HasCompilerSupport(cx) &&
            HasAvailableCompilerTier(cx);
 }
 
-bool
-wasm::ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, Val* val)
+static bool
+ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, Val* val)
 {
     switch (targetType.code()) {
       case ValType::I32: {
         int32_t i32;
         if (!ToInt32(cx, v, &i32))
             return false;
         *val = Val(uint32_t(i32));
         return true;
@@ -135,18 +135,18 @@ wasm::ToWebAssemblyValue(JSContext* cx, 
         return true;
       }
       default: {
         MOZ_CRASH("unexpected import value type, caller must guard");
       }
     }
 }
 
-Value
-wasm::ToJSValue(const Val& val)
+static Value
+ToJSValue(const Val& val)
 {
     switch (val.type().code()) {
       case ValType::I32:
         return Int32Value(val.i32());
       case ValType::F32:
         return DoubleValue(JS::CanonicalizeNaN(double(val.f32())));
       case ValType::F64:
         return DoubleValue(JS::CanonicalizeNaN(val.f64()));
--- a/js/src/wasm/WasmJS.h
+++ b/js/src/wasm/WasmJS.h
@@ -39,25 +39,16 @@ namespace wasm {
 bool
 HasCompilerSupport(JSContext* cx);
 
 // Return whether WebAssembly is enabled on this platform.
 
 bool
 HasSupport(JSContext* cx);
 
-// ToWebAssemblyValue and ToJSValue are conversion functions defined in
-// the Wasm JS API spec.
-
-bool
-ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v, Val* val);
-
-Value
-ToJSValue(const Val& val);
-
 // Compiles the given binary wasm module given the ArrayBufferObject
 // and links the module's imports with the given import object.
 
 MOZ_MUST_USE bool
 Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj,
      MutableHandleWasmInstanceObject instanceObj);
 
 // These accessors can be used to probe JS values for being an exported wasm
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1115,34 +1115,21 @@ GetFunctionExport(JSContext* cx,
     if (!instanceObj->getExportedFunction(cx, instanceObj, exp.funcIndex(), &fun))
         return false;
 
     val.setObject(*fun);
     return true;
 }
 
 static bool
-GetGlobalExport(JSContext* cx,
-                const GlobalDescVector& globals,
-                uint32_t globalIndex,
-                const ValVector& globalImportValues,
-                const WasmGlobalObjectVector& globalObjs,
-                MutableHandleValue jsval)
-{
-    jsval.setObject(*globalObjs[globalIndex]);
-    return true;
-}
-
-static bool
 CreateExportObject(JSContext* cx,
                    HandleWasmInstanceObject instanceObj,
                    Handle<FunctionVector> funcImports,
                    HandleWasmTableObject tableObj,
                    HandleWasmMemoryObject memoryObj,
-                   const ValVector& globalImportValues,
                    const WasmGlobalObjectVector& globalObjs,
                    const ExportVector& exports)
 {
     const Instance& instance = instanceObj->instance();
     const Metadata& metadata = instance.metadata();
 
     if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
         RootedValue val(cx);
@@ -1174,21 +1161,17 @@ CreateExportObject(JSContext* cx,
             break;
           case DefinitionKind::Table:
             val = ObjectValue(*tableObj);
             break;
           case DefinitionKind::Memory:
             val = ObjectValue(*memoryObj);
             break;
           case DefinitionKind::Global:
-            if (!GetGlobalExport(cx, metadata.globals, exp.globalIndex(), globalImportValues,
-                                 globalObjs, &val))
-            {
-                return false;
-            }
+            val.setObject(*globalObjs[exp.globalIndex()]);
             break;
         }
 
         if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
             return false;
     }
 
     if (!metadata.isAsmJS()) {
@@ -1301,21 +1284,18 @@ Module::instantiate(JSContext* cx,
                                             funcImports,
                                             metadata().globals,
                                             globalImportValues,
                                             globalObjs,
                                             instanceProto));
     if (!instance)
         return false;
 
-    if (!CreateExportObject(cx, instance, funcImports, table, memory, globalImportValues,
-                            globalObjs, exports_))
-    {
+    if (!CreateExportObject(cx, instance, funcImports, table, memory, globalObjs, exports_))
         return false;
-    }
 
     // Register the instance with the Realm so that it can find out about global
     // events like profiling being enabled in the realm. Registration does not
     // require a fully-initialized instance and must precede initSegments as the
     // final pre-requisite for a live instance.
 
     if (!cx->realm()->wasm.registerInstance(cx, instance))
         return false;
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -3468,17 +3468,17 @@ RestyleManager::DoReparentComputedStyleF
   }
 
   if (!providerFrame) {
     // No providerFrame means we inherited from a display:contents thing.  Our
     // layout parent style is the style of our nearest ancestor frame.  But we have
     // to be careful to do that with our placeholder, not with us, if we're out of
     // flow.
     if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
-      aFrame->GetPlaceholderFrame()->GetLayoutParentStyleForOutOfFlow(&providerFrame);
+      aFrame->FirstContinuation()->GetPlaceholderFrame()->GetLayoutParentStyleForOutOfFlow(&providerFrame);
     } else {
       providerFrame = nsFrame::CorrectStyleParentFrame(aFrame->GetParent(),
                                                        oldStyle->GetPseudo());
     }
   }
   ComputedStyle* layoutParent = providerFrame->Style();
 
   RefPtr<ComputedStyle> newStyle =
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1469354.html
@@ -0,0 +1,16 @@
+<style>
+:root { columns: 0px }
+hr::first-line {}
+li { display: contents }
+</style>
+<script>
+function go() {
+  a.appendChild(c);
+  c.appendChild(b);
+  b.style.setProperty("float", "left");
+}
+</script>
+<svg onload="go()">
+<hr id="a">
+<dd id="b">
+<li id="c">%
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -538,8 +538,9 @@ load 1453342.html
 load 1453702.html
 pref(dom.webcomponents.shadowdom.enabled,true) load 1461749.html
 load 1461812.html
 load 1462412.html
 load 1463940.html
 pref(dom.webcomponents.shadowdom.enabled,true) HTTP load 1464641.html
 load 1464737.html
 load 1467964.html
+load 1469354.html
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2507,19 +2507,22 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
   // We don't add quirk.css here; nsPresContext::CompatibilityModeChanged will
   // append it if needed.
 
   sheet = cache->HTMLSheet();
   if (sheet) {
     styleSet->PrependStyleSheet(SheetType::Agent, sheet);
   }
 
-  sheet = cache->SVGSheet();
-  if (sheet) {
-    styleSet->PrependStyleSheet(SheetType::Agent, sheet);
+  if (MOZ_LIKELY(mDocument->NodeInfoManager()->SVGEnabled())) {
+    styleSet->PrependStyleSheet(SheetType::Agent, cache->SVGSheet());
+  }
+
+  if (MOZ_LIKELY(mDocument->NodeInfoManager()->MathMLEnabled())) {
+    styleSet->PrependStyleSheet(SheetType::Agent, cache->MathMLSheet());
   }
 
   styleSet->PrependStyleSheet(SheetType::Agent, cache->UASheet());
 
   if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
     for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
       styleSet->AppendStyleSheet(SheetType::Agent, sheet);
     }
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/file_disabled_iframe.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<script>
+window.is = window.parent.is;
+window.SimpleTest = window.parent.SimpleTest;
+</script>
+<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<pre id="test">
+<script>
+  let t = document.getElementById('testnodes');
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math:math"));
+  t.firstChild.textContent = "<foo>";
+  is(t.innerHTML, "<math:math>&lt;foo&gt;</math:math>");
+
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
+  is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+  t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script"));
+  is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+  t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+  is(t.innerHTML, '<math><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></math>');
+
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
+  is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+  t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "style"));
+  is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
+  t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+  is(t.innerHTML, '<math><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></math>');
+
+  SimpleTest.finish();
+</script>
+</pre>
--- a/layout/mathml/tests/mochitest.ini
+++ b/layout/mathml/tests/mochitest.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
+support-files =
+  file_disabled_iframe.html
 
 [test_bug330964.html]
 [test_bug553917.html]
 [test_bug706406.html]
 [test_bug827713-2.html]
 [test_bug827713.html]
 [test_bug975681.html]
 [test_disabled.html]
--- a/layout/mathml/tests/test_disabled.html
+++ b/layout/mathml/tests/test_disabled.html
@@ -1,47 +1,23 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-Copied from
-https://bugzilla.mozilla.org/show_bug.cgi?id=744830
+Copied from https://bugzilla.mozilla.org/show_bug.cgi?id=744830
 -->
 <head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
-<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<iframe></iframe>
 <pre id="test">
 <script type="application/javascript">
   SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({"set": [["mathml.disabled", true]]}, doTest);
-  function doTest() {
-    let t = document.getElementById('testnodes');
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math:math"));
-    t.firstChild.textContent = "<foo>";
-    is(t.innerHTML, "<math:math>&lt;foo&gt;</math:math>");
-
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
-    is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
-    t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script"));
-    is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
-    t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
-    is(t.innerHTML, '<math><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></math>');
-
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
-    is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
-    t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "style"));
-    is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
-    t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
-    is(t.innerHTML, '<math><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></math>');
-
-    SimpleTest.finish();
-  }
+  SpecialPowers.pushPrefEnv({"set": [["mathml.disabled", true]]}, function() {
+    document.querySelector('iframe').src = "file_disabled_iframe.html";
+  });
 </script>
 </pre>
 </body>
 </html>
 
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -1,14 +1,14 @@
 == default-size.html default-size-ref.html
 fuzzy-if(Android,8,1000) == size-1.html size-1-ref.html
 
 == empty-transaction-1.html empty-transaction-1-ref.html
 
-fails-if(webrender&&!gtkWidget) == image-rendering-test.html image-rendering-ref.html
+fails-if(webrender&&winWidget) == image-rendering-test.html image-rendering-ref.html
 == image-shadow.html image-shadow-ref.html
 
 asserts-if(cocoaWidget,0-2) == size-change-1.html size-change-1-ref.html
 
 random-if(cocoaWidget) == subpixel-1.html about:blank # see bug 1192616, re-enable once we're off the pandaboards
 
 != text-ltr-left.html text-blank.html
 != text-ltr-right.html text-blank.html
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -1,10 +1,10 @@
 fuzzy-if(!contentSameGfxBackendAsCanvas,4,88500) fuzzy-if(azureSkiaGL||skiaContent,4,89700) == linear-1a.html linear-1-ref.html
-fuzzy-if(!contentSameGfxBackendAsCanvas,2,88500) fuzzy-if(azureSkiaGL,2,89997) fuzzy-if(skiaContent,1,16000) fuzzy-if(webrender,1,23905) == linear-keywords-1a.html linear-keywords-1-ref.html
+fuzzy-if(!contentSameGfxBackendAsCanvas,2,88500) fuzzy-if(azureSkiaGL,2,89997) fuzzy-if(skiaContent,1,16000) fuzzy-if(webrender,1,23918) == linear-keywords-1a.html linear-keywords-1-ref.html
 == linear-diagonal-1a.html linear-diagonal-1-ref.html
 == linear-diagonal-2a.html linear-diagonal-2-ref.html
 == linear-diagonal-3a.html linear-diagonal-3-ref.html
 == linear-diagonal-4a.html linear-diagonal-4-ref.html
 == linear-premul.html linear-premul-ref.html
 
 fuzzy(1,800000) == linear-flipped-1.html linear-flipped-1-ref.html
 == linear-position-1a.html linear-position-1-ref.html
deleted file mode 100644
--- a/layout/style/GenericSpecifiedValues.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/*
- * Generic representation of a container of specified CSS values, which
- * could potentially be Servo- or Gecko- format. Used to make attribute mapping
- * code generic over style backends.
- */
-
-#ifndef mozilla_GenericSpecifiedValues_h
-#define mozilla_GenericSpecifiedValues_h
-
-#include "mozilla/ServoUtils.h"
-#include "mozilla/FontPropertyTypes.h"
-#include "nsCSSPropertyID.h"
-#include "nsCSSValue.h"
-#include "nsColor.h"
-
-class nsAttrValue;
-
-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.
-class GenericSpecifiedValues
-{
-protected:
-  explicit GenericSpecifiedValues(nsIDocument* aDoc)
-    : mDocument(aDoc)
-  {}
-
-public:
-  MOZ_DECL_STYLO_METHODS(nsRuleData, ServoSpecifiedValues)
-
-  nsIDocument* Document()
-  {
-    return mDocument;
-  }
-
-  // Check if we already contain a certain longhand
-  inline bool PropertyIsSet(nsCSSPropertyID aId);
-
-  // 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);
-
-  // Set a property to a keyword (usually NS_STYLE_* or StyleFoo::*)
-  inline void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue);
-  inline void SetKeywordValueIfUnset(nsCSSPropertyID aId, int32_t aValue);
-
-  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 an integer value
-  inline void SetIntValue(nsCSSPropertyID aId, int32_t aValue);
-  // Set a property to a pixel value
-  inline void SetPixelValue(nsCSSPropertyID aId, float aValue);
-  inline void SetPixelValueIfUnset(nsCSSPropertyID aId, float aValue);
-
-  inline void SetLengthValue(nsCSSPropertyID aId, nsCSSValue aValue);
-
-  // Set a property to a number value
-  inline void SetNumberValue(nsCSSPropertyID aId, float aValue);
-
-  // Set a property to a percent value
-  inline void SetPercentValue(nsCSSPropertyID aId, float aValue);
-  inline void SetPercentValueIfUnset(nsCSSPropertyID aId, float aValue);
-
-  // Set a property to `auto`
-  inline void SetAutoValue(nsCSSPropertyID aId);
-  inline void SetAutoValueIfUnset(nsCSSPropertyID aId);
-
-  // Set a property to `currentcolor`
-  inline void SetCurrentColor(nsCSSPropertyID aId);
-  inline void SetCurrentColorIfUnset(nsCSSPropertyID aId);
-
-  // Set a property to an RGBA nscolor value
-  inline void SetColorValue(nsCSSPropertyID aId, nscolor aValue);
-  inline void SetColorValueIfUnset(nsCSSPropertyID aId, nscolor aValue);
-
-  // 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);
-
-  nsIDocument* const mDocument;
-};
-
-} // namespace mozilla
-
-#endif // mozilla_GenericSpecifiedValues_h
deleted file mode 100644
--- a/layout/style/GenericSpecifiedValuesInlines.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/*
- * Inlined methods for GenericSpecifiedValues. Will just redirect to
- * nsRuleData methods when compiled without stylo, but will do
- * virtual dispatch (by checking which kind of container it is)
- * in stylo mode.
- */
-
-#ifndef mozilla_GenericSpecifiedValuesInlines_h
-#define mozilla_GenericSpecifiedValuesInlines_h
-
-#include "mozilla/GenericSpecifiedValues.h"
-#include "mozilla/ServoSpecifiedValues.h"
-
-namespace mozilla {
-
-MOZ_DEFINE_STYLO_METHODS(GenericSpecifiedValues,
-                         nsRuleData,
-                         ServoSpecifiedValues)
-
-bool
-GenericSpecifiedValues::PropertyIsSet(nsCSSPropertyID aId)
-{
-  MOZ_STYLO_FORWARD(PropertyIsSet, (aId))
-}
-
-void
-GenericSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
-                                            const nsString& aValue)
-{
-  MOZ_STYLO_FORWARD(SetIdentStringValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetIdentStringValueIfUnset(nsCSSPropertyID aId,
-                                                   const nsString& aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetIdentStringValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue)
-{
-  MOZ_STYLO_FORWARD(SetIdentAtomValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetIdentAtomValueIfUnset(nsCSSPropertyID aId,
-                                                 nsAtom* aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetIdentAtomValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
-{
-
-  return AsServo()->SetKeywordValue(aId, aValue);
-}
-
-void
-GenericSpecifiedValues::SetKeywordValueIfUnset(nsCSSPropertyID aId,
-                                               int32_t aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetKeywordValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetIntValue(nsCSSPropertyID aId, int32_t aValue)
-{
-  MOZ_STYLO_FORWARD(SetIntValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetPixelValue(nsCSSPropertyID aId, float aValue)
-{
-  MOZ_STYLO_FORWARD(SetPixelValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetPixelValueIfUnset(nsCSSPropertyID aId, float aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetPixelValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetLengthValue(nsCSSPropertyID aId, nsCSSValue aValue)
-{
-  MOZ_STYLO_FORWARD(SetLengthValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetNumberValue(nsCSSPropertyID aId, float aValue)
-{
-  MOZ_STYLO_FORWARD(SetNumberValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetPercentValue(nsCSSPropertyID aId, float aValue)
-{
-  MOZ_STYLO_FORWARD(SetPercentValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetPercentValueIfUnset(nsCSSPropertyID aId,
-                                               float aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetPercentValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetAutoValue(nsCSSPropertyID aId)
-{
-  MOZ_STYLO_FORWARD(SetAutoValue, (aId))
-}
-
-void
-GenericSpecifiedValues::SetAutoValueIfUnset(nsCSSPropertyID aId)
-{
-  if (!PropertyIsSet(aId)) {
-    SetAutoValue(aId);
-  }
-}
-
-void
-GenericSpecifiedValues::SetCurrentColor(nsCSSPropertyID aId)
-{
-  MOZ_STYLO_FORWARD(SetCurrentColor, (aId))
-}
-
-void
-GenericSpecifiedValues::SetCurrentColorIfUnset(nsCSSPropertyID aId)
-{
-  if (!PropertyIsSet(aId)) {
-    SetCurrentColor(aId);
-  }
-}
-
-void
-GenericSpecifiedValues::SetColorValue(nsCSSPropertyID aId, nscolor aValue)
-{
-  MOZ_STYLO_FORWARD(SetColorValue, (aId, aValue))
-}
-
-void
-GenericSpecifiedValues::SetColorValueIfUnset(nsCSSPropertyID aId,
-                                             nscolor aValue)
-{
-  if (!PropertyIsSet(aId)) {
-    SetColorValue(aId, aValue);
-  }
-}
-
-void
-GenericSpecifiedValues::SetFontFamily(const nsString& aValue)
-{
-  MOZ_STYLO_FORWARD(SetFontFamily, (aValue))
-}
-
-void
-GenericSpecifiedValues::SetTextDecorationColorOverride()
-{
-  MOZ_STYLO_FORWARD(SetTextDecorationColorOverride, ())
-}
-
-void
-GenericSpecifiedValues::SetBackgroundImage(nsAttrValue& aValue)
-{
-  MOZ_STYLO_FORWARD(SetBackgroundImage, (aValue))
-}
-
-} // namespace mozilla
-
-#endif // mozilla_GenericSpecifiedValuesInlines_h
new file mode 100644
--- /dev/null
+++ b/layout/style/MappedDeclarations.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/MappedDeclarations.h"
+
+namespace mozilla {
+
+void
+MappedDeclarations::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.
+    //
+    // 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 (nsPresContext* pc = mDocument->GetPresContext()) {
+      pc->ForceCacheLang(aValue);
+    }
+  }
+}
+
+void
+MappedDeclarations::SetBackgroundImage(const nsAttrValue& aValue)
+{
+  if (aValue.Type() != nsAttrValue::eURL) {
+    return;
+  }
+  // FIXME(emilio): Going through URL parsing again seems slightly wasteful.
+  nsAutoString str;
+  aValue.ToString(str);
+  Servo_DeclarationBlock_SetBackgroundImage(
+    mDecl, str, mDocument->DefaultStyleAttrURLData());
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/MappedDeclarations.h
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* Representation of a declaration block used for attribute mapping */
+
+#ifndef mozilla_MappedDeclarations_h
+#define mozilla_MappedDeclarations_h
+
+#include "mozilla/FontPropertyTypes.h"
+#include "mozilla/ServoBindingTypes.h"
+#include "mozilla/ServoBindings.h"
+#include "nsCSSPropertyID.h"
+#include "nsCSSValue.h"
+#include "nsColor.h"
+
+class nsAttrValue;
+
+namespace mozilla {
+
+// This provides a convenient interface for attribute mappers
+// (MapAttributesIntoRule) to modify the presentation attribute declaration
+// block for a given element.
+class MappedDeclarations final
+{
+public:
+  explicit MappedDeclarations(nsIDocument* aDoc,
+                              already_AddRefed<RawServoDeclarationBlock> aDecls)
+    : mDocument(aDoc)
+    , mDecl(aDecls)
+  {
+    MOZ_ASSERT(mDecl);
+  }
+
+  ~MappedDeclarations()
+  {
+    MOZ_ASSERT(!mDecl, "Forgot to take the block?");
+  }
+
+  nsIDocument* Document()
+  {
+    return mDocument;
+  }
+
+  already_AddRefed<RawServoDeclarationBlock> TakeDeclarationBlock()
+  {
+    MOZ_ASSERT(mDecl);
+    return mDecl.forget();
+  }
+
+  // Check if we already contain a certain longhand
+  bool PropertyIsSet(nsCSSPropertyID aId) const
+  {
+    return Servo_DeclarationBlock_PropertyIsSet(mDecl, aId);
+  }
+
+  // Set a property to an identifier (string)
+  void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue)
+  {
+    RefPtr<nsAtom> atom = NS_AtomizeMainThread(aValue);
+    SetIdentAtomValue(aId, atom);
+  }
+
+  void SetIdentStringValueIfUnset(nsCSSPropertyID aId, const nsString& aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetIdentStringValue(aId, aValue);
+    }
+  }
+
+  void SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue);
+
+  void SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsAtom* aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetIdentAtomValue(aId, aValue);
+    }
+  }
+
+  // Set a property to a keyword (usually NS_STYLE_* or StyleFoo::*)
+  void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
+  {
+    Servo_DeclarationBlock_SetKeywordValue(mDecl, aId, aValue);
+  }
+
+  void SetKeywordValueIfUnset(nsCSSPropertyID aId, int32_t aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetKeywordValue(aId, aValue);
+    }
+  }
+
+  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 an integer value
+  void SetIntValue(nsCSSPropertyID aId, int32_t aValue)
+  {
+    Servo_DeclarationBlock_SetIntValue(mDecl, aId, aValue);
+  }
+
+  // Set a property to a pixel value
+  void SetPixelValue(nsCSSPropertyID aId, float aValue)
+  {
+    Servo_DeclarationBlock_SetPixelValue(mDecl, aId, aValue);
+  }
+
+  void SetPixelValueIfUnset(nsCSSPropertyID aId, float aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetPixelValue(aId, aValue);
+    }
+  }
+
+  void SetLengthValue(nsCSSPropertyID aId, const nsCSSValue& aValue)
+  {
+    MOZ_ASSERT(aValue.IsLengthUnit());
+    Servo_DeclarationBlock_SetLengthValue(
+      mDecl, aId, aValue.GetFloatValue(), aValue.GetUnit());
+  }
+
+  // Set a property to a number value
+  void SetNumberValue(nsCSSPropertyID aId, float aValue)
+  {
+    Servo_DeclarationBlock_SetNumberValue(mDecl, aId, aValue);
+  }
+
+  // Set a property to a percent value
+  void SetPercentValue(nsCSSPropertyID aId, float aValue)
+  {
+    Servo_DeclarationBlock_SetPercentValue(mDecl, aId, aValue);
+  }
+
+  void SetPercentValueIfUnset(nsCSSPropertyID aId, float aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetPercentValue(aId, aValue);
+    }
+  }
+
+  // Set a property to `auto`
+  void SetAutoValue(nsCSSPropertyID aId)
+  {
+    Servo_DeclarationBlock_SetAutoValue(mDecl, aId);
+  }
+
+  void SetAutoValueIfUnset(nsCSSPropertyID aId)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetAutoValue(aId);
+    }
+  }
+
+  // Set a property to `currentcolor`
+  void SetCurrentColor(nsCSSPropertyID aId)
+  {
+    Servo_DeclarationBlock_SetCurrentColor(mDecl, aId);
+  }
+
+  void SetCurrentColorIfUnset(nsCSSPropertyID aId)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetCurrentColor(aId);
+    }
+  }
+
+  // Set a property to an RGBA nscolor value
+  void SetColorValue(nsCSSPropertyID aId, nscolor aValue)
+  {
+    Servo_DeclarationBlock_SetColorValue(mDecl, aId, aValue);
+  }
+
+  void SetColorValueIfUnset(nsCSSPropertyID aId, nscolor aValue)
+  {
+    if (!PropertyIsSet(aId)) {
+      SetColorValue(aId, aValue);
+    }
+  }
+
+  // Set font-family to a string
+  void SetFontFamily(const nsString& aValue)
+  {
+    Servo_DeclarationBlock_SetFontFamily(mDecl, aValue);
+  }
+
+  // Add a quirks-mode override to the decoration color of elements nested in <a>
+  void SetTextDecorationColorOverride()
+  {
+    Servo_DeclarationBlock_SetTextDecorationColorOverride(mDecl);
+  }
+
+  void SetBackgroundImage(const nsAttrValue& value);
+
+private:
+  nsIDocument* const mDocument;
+  RefPtr<RawServoDeclarationBlock> mDecl;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_MappedDeclarations_h
deleted file mode 100644
--- a/layout/style/ServoSpecifiedValues.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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"
-
-using namespace mozilla;
-
-bool
-ServoSpecifiedValues::PropertyIsSet(nsCSSPropertyID aId)
-{
-  return Servo_DeclarationBlock_PropertyIsSet(mDecl, aId);
-}
-
-void
-ServoSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
-                                          const nsString& aValue)
-{
-  RefPtr<nsAtom> atom = NS_Atomize(aValue);
-  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.
-    //
-    // 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 (nsPresContext* pc = mDocument->GetPresContext()) {
-      pc->ForceCacheLang(aValue);
-    }
-  }
-}
-
-void
-ServoSpecifiedValues::SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
-{
-  Servo_DeclarationBlock_SetKeywordValue(mDecl, aId, aValue);
-}
-
-void
-ServoSpecifiedValues::SetIntValue(nsCSSPropertyID aId, int32_t aValue)
-{
-  Servo_DeclarationBlock_SetIntValue(mDecl, aId, aValue);
-}
-
-void
-ServoSpecifiedValues::SetPixelValue(nsCSSPropertyID aId, float aValue)
-{
-  Servo_DeclarationBlock_SetPixelValue(mDecl, aId, aValue);
-}
-
-void
-ServoSpecifiedValues::SetLengthValue(nsCSSPropertyID aId, nsCSSValue aValue)
-{
-  MOZ_ASSERT(aValue.IsLengthUnit());
-  Servo_DeclarationBlock_SetLengthValue(
-    mDecl, aId, aValue.GetFloatValue(), aValue.GetUnit());
-}
-
-void
-ServoSpecifiedValues::SetNumberValue(nsCSSPropertyID aId, float aValue)
-{
-  Servo_DeclarationBlock_SetNumberValue(mDecl, aId, aValue);
-}
-
-void
-ServoSpecifiedValues::SetPercentValue(nsCSSPropertyID aId, float aValue)
-{
-  Servo_DeclarationBlock_SetPercentValue(mDecl, aId, aValue);
-}
-
-void
-ServoSpecifiedValues::SetAutoValue(nsCSSPropertyID aId)
-{
-  Servo_DeclarationBlock_SetAutoValue(mDecl, aId);
-}
-
-void
-ServoSpecifiedValues::SetCurrentColor(nsCSSPropertyID aId)
-{
-  Servo_DeclarationBlock_SetCurrentColor(mDecl, aId);
-}
-
-void
-ServoSpecifiedValues::SetColorValue(nsCSSPropertyID aId, nscolor aColor)
-{
-  Servo_DeclarationBlock_SetColorValue(mDecl, aId, aColor);
-}
-
-void
-ServoSpecifiedValues::SetFontFamily(const nsString& aValue)
-{
-  Servo_DeclarationBlock_SetFontFamily(mDecl, aValue);
-}
-
-void
-ServoSpecifiedValues::SetTextDecorationColorOverride()
-{
-  Servo_DeclarationBlock_SetTextDecorationColorOverride(mDecl);
-}
-
-void
-ServoSpecifiedValues::SetBackgroundImage(nsAttrValue& aValue)
-{
-  if (aValue.Type() != nsAttrValue::eURL) {
-    return;
-  }
-  nsAutoString str;
-  aValue.ToString(str);
-  Servo_DeclarationBlock_SetBackgroundImage(
-    mDecl, str, mDocument->DefaultStyleAttrURLData());
-}
deleted file mode 100644
--- a/layout/style/ServoSpecifiedValues.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/*
- * Servo-backed specified value store, to be used when mapping presentation
- * attributes
- */
-
-#ifndef mozilla_ServoSpecifiedValues_h
-#define mozilla_ServoSpecifiedValues_h
-
-#include "mozilla/GenericSpecifiedValues.h"
-#include "mozilla/ServoBindingTypes.h"
-
-namespace mozilla {
-
-class ServoSpecifiedValues final : public GenericSpecifiedValues
-{
-public:
-  ServoSpecifiedValues(nsIDocument* aDocument, RawServoDeclarationBlock* aDecl)
-    : GenericSpecifiedValues(aDocument)
-    , mDecl(aDecl)
-  {}
-
-  // GenericSpecifiedValues overrides
-  bool PropertyIsSet(nsCSSPropertyID aId);
-
-  void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue);
-
-  void SetIdentAtomValue(nsCSSPropertyID aId, nsAtom* aValue);
-
-  void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue);
-
-  void SetIntValue(nsCSSPropertyID aId, int32_t aValue);
-
-  void SetPixelValue(nsCSSPropertyID aId, float aValue);
-
-  void SetLengthValue(nsCSSPropertyID aId, nsCSSValue aValue);
-
-  void SetNumberValue(nsCSSPropertyID aId, float aValue);
-
-  void SetPercentValue(nsCSSPropertyID aId, float aValue);
-
-  void SetAutoValue(nsCSSPropertyID aId);
-
-  void SetCurrentColor(nsCSSPropertyID aId);
-
-  void SetColorValue(nsCSSPropertyID aId, nscolor aValue);
-
-  void SetFontFamily(const nsString& aValue);
-  void SetTextDecorationColorOverride();
-  void SetBackgroundImage(nsAttrValue& aValue);
-
-private:
-  RefPtr<RawServoDeclarationBlock> mDecl;
-};
-
-} // namespace mozilla
-
-#endif // mozilla_ServoSpecifiedValues_h
--- a/layout/style/ServoUtils.h
+++ b/layout/style/ServoUtils.h
@@ -30,62 +30,9 @@ inline bool IsInServoTraversal()
   // are generally unprepared to deal with non-Servo-but-also-non-main-thread
   // callers, and are likely to take the main-thread codepath if this function
   // returns false. So we assert against other non-main-thread callers here.
   MOZ_ASSERT(sInServoTraversal || NS_IsMainThread());
   return sInServoTraversal;
 }
 } // namespace mozilla
 
-#define MOZ_DECL_STYLO_CONVERT_METHODS_SERVO(servotype_) \
-  inline servotype_* AsServo();                         \
-  inline const servotype_* AsServo() const;             \
-  inline servotype_* GetAsServo();                      \
-  inline const servotype_* GetAsServo() const;
-
-#define MOZ_DECL_STYLO_CONVERT_METHODS(geckotype_, servotype_) \
-  MOZ_DECL_STYLO_CONVERT_METHODS_SERVO(servotype_)
-
-/**
- * Macro used in a base class of |geckotype_| and |servotype_|.
- * The class should define |StyleBackendType mType;| itself.
- */
-#define MOZ_DECL_STYLO_METHODS(geckotype_, servotype_)  \
-  MOZ_DECL_STYLO_CONVERT_METHODS(geckotype_, servotype_)
-
-#define MOZ_DEFINE_STYLO_METHODS_SERVO(type_, servotype_) \
-  servotype_* type_::AsServo() {                                \
-    return static_cast<servotype_*>(this);                      \
-  }                                                             \
-  const servotype_* type_::AsServo() const {                    \
-    return static_cast<const servotype_*>(this);                \
-  }                                                             \
-  servotype_* type_::GetAsServo() {                             \
-    return AsServo();                                           \
-  }                                                             \
-  const servotype_* type_::GetAsServo() const {                 \
-    return AsServo();                                           \
-  }
-
-
-/**
- * Macro used in inline header of class |type_| with its Gecko and Servo
- * subclasses named |geckotype_| and |servotype_| correspondingly for
- * implementing the inline methods defined by MOZ_DECL_STYLO_METHODS.
- */
-#define MOZ_DEFINE_STYLO_METHODS(type_, geckotype_, servotype_) \
-  MOZ_DEFINE_STYLO_METHODS_SERVO(type_, servotype_)
-
-#define MOZ_STYLO_THIS_TYPE  mozilla::RemovePointer<decltype(this)>::Type
-#define MOZ_STYLO_SERVO_TYPE mozilla::RemovePointer<decltype(AsServo())>::Type
-
-/**
- * Macro used to forward a method call to the concrete method defined by
- * the Servo or Gecko implementation. The class of the method using it
- * should use MOZ_DECL_STYLO_METHODS to define basic stylo methods.
- */
-#define MOZ_STYLO_FORWARD_CONCRETE(method_, geckoargs_, servoargs_)         \
-  return AsServo()->method_ servoargs_;
-
-#define MOZ_STYLO_FORWARD(method_, args_) \
-  MOZ_STYLO_FORWARD_CONCRETE(method_, args_, args_)
-
 #endif // mozilla_ServoUtils_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -64,33 +64,31 @@ EXPORTS.mozilla += [
     'BindingStyleRule.h',
     'CachedInheritingStyles.h',
     'ComputedStyle.h',
     'ComputedStyleInlines.h',
     'CSSEnabledState.h',
     'CSSPropFlags.h',
     'DeclarationBlock.h',
     'DocumentStyleRootIterator.h',
-    'GenericSpecifiedValues.h',
-    'GenericSpecifiedValuesInlines.h',
     'LayerAnimationInfo.h',
+    'MappedDeclarations.h',
     'MediaFeatureChange.h',
     'PostTraversalTask.h',
     'PreloadedStyleSheet.h',
     'ServoArcTypeList.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
     'ServoComputedData.h',
     'ServoComputedDataInlines.h',
     'ServoCSSParser.h',
     'ServoCSSRuleList.h',
     'ServoElementSnapshot.h',
     'ServoElementSnapshotTable.h',
-    'ServoSpecifiedValues.h',
     'ServoStyleSet.h',
     'ServoStyleSetInlines.h',
     'ServoTraversalStatistics.h',
     'ServoTypes.h',
     'ServoUtils.h',
     'SheetType.h',
     'StyleAnimationValue.h',
     'StyleComplexColor.h',
@@ -160,16 +158,17 @@ UNIFIED_SOURCES += [
     'ErrorReporter.cpp',
     'FontFace.cpp',
     'FontFaceSet.cpp',
     'FontFaceSetIterator.cpp',
     'GroupRule.cpp',
     'ImageLoader.cpp',
     'LayerAnimationInfo.cpp',
     'Loader.cpp',
+    'MappedDeclarations.cpp',
     'MediaList.cpp',
     'MediaQueryList.cpp',
     'nsAnimationManager.cpp',
     'nsComputedDOMStyle.cpp',
     'nsCSSKeywords.cpp',
     'nsCSSProps.cpp',
     'nsCSSValue.cpp',
     'nsDOMCSSAttrDeclaration.cpp',
@@ -191,17 +190,16 @@ UNIFIED_SOURCES += [
     'nsTransitionManager.cpp',
     'PostTraversalTask.cpp',
     'PreloadedStyleSheet.cpp',
     'Rule.cpp',
     'ServoBindings.cpp',
     'ServoCSSParser.cpp',
     'ServoCSSRuleList.cpp',
     'ServoElementSnapshot.cpp',
-    'ServoSpecifiedValues.cpp',
     'ServoStyleSet.cpp',
     'StreamLoader.cpp',
     'StyleAnimationValue.cpp',
     'StyleComplexColor.cpp',
     'StyleSheet.cpp',
     'URLExtraData.cpp',
 ]
 
new file mode 100644
--- /dev/null
+++ b/layout/svg/tests/file_disabled_iframe.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<script>
+  window.is = window.parent.is;
+  window.SimpleTest = window.parent.SimpleTest;
+</script>
+<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
+<script>
+  let t = document.getElementById('testnodes');
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
+  t.firstChild.textContent = "<foo>";
+  is(t.innerHTML, "<svg:svg>&lt;foo&gt;</svg:svg>");
+
+  // This test crashes if the style tags are not handled correctly
+  t.innerHTML = `<svg version="1.1">
+    <style>
+        circle {
+            fill: currentColor;
+        }
+    </style>
+    <g><circle cx="25.8" cy="9.3" r="1.5"/></g>
+  </svg>
+  `;
+  is(t.firstChild.tagName.toLowerCase(), 'svg');
+
+  // This test crashes if the script tags are not handled correctly
+  t.innerHTML = `<svg version="1.1">
+    <scri` + `pt>
+      throw "badment, should never fire.";
+    </scri` + `pt>
+    <g><circle cx="25.8" cy="9.3" r="1.5"/></g>
+  </svg>`;
+  is(t.firstChild.tagName.toLowerCase(), 'svg');
+
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+  is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+  t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
+  is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+  t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+  is(t.innerHTML, '<svg><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></svg>');
+
+  t.innerHTML = null;
+  t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
+  is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+  t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
+  is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
+  t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
+  is(t.innerHTML, '<svg><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></svg>');
+
+  SimpleTest.finish();
+</script>
--- a/layout/svg/tests/mochitest.ini
+++ b/layout/svg/tests/mochitest.ini
@@ -1,3 +1,5 @@
 [DEFAULT]
+support-files =
+  file_disabled_iframe.html
 
 [test_disabled.html]
--- a/layout/svg/tests/test_disabled.html
+++ b/layout/svg/tests/test_disabled.html
@@ -1,68 +1,14 @@
 <!DOCTYPE HTML>
-<html>
 <!--
-Copied from
-https://bugzilla.mozilla.org/show_bug.cgi?id=744830
+Copied from https://bugzilla.mozilla.org/show_bug.cgi?id=744830
 -->
-<head>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
-<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
-<pre id="test">
+<iframe></iframe>
 <script type="application/javascript">
   SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({"set": [["svg.disabled", true]]}, doTest);
-  function doTest() {
-    let t = document.getElementById('testnodes');
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
-    t.firstChild.textContent = "<foo>";
-    is(t.innerHTML, "<svg:svg>&lt;foo&gt;</svg:svg>");
-
-    // This test crashes if the style tags are not handled correctly
-    t.innerHTML = `<svg version="1.1">
-      <style>
-          circle {
-              fill: currentColor;
-          }
-      </style>
-      <g><circle cx="25.8" cy="9.3" r="1.5"/></g>
-    </svg>
-    `;
-    is(t.firstChild.tagName.toLowerCase(), 'svg');
-
-    // This test crashes if the script tags are not handled correctly
-    t.innerHTML = `<svg version="1.1">
-      <scri` + `pt>
-        throw "badment, should never fire.";
-      </scri` + `pt>
-      <g><circle cx="25.8" cy="9.3" r="1.5"/></g>
-    </svg>`;
-    is(t.firstChild.tagName.toLowerCase(), 'svg');
-
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
-    is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
-    t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
-    is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
-    t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
-    is(t.innerHTML, '<svg><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></svg>');
-
-    t.innerHTML = null;
-    t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
-    is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
-    t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
-    is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
-    t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
-    is(t.innerHTML, '<svg><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></svg>');
-
-    SimpleTest.finish();
-  }
+  SpecialPowers.pushPrefEnv({"set": [["svg.disabled", true]]}, function() {
+    document.querySelector('iframe').src = "file_disabled_iframe.html";
+  });
 </script>
-</pre>
-</body>
-</html>
-
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -699,19 +699,19 @@ pref("browser.contentHandlers.types.3.ur
 pref("browser.contentHandlers.types.3.type", "application/vnd.mozilla.maybe.feed");
 
 // Shortnumber matching needed for e.g. Brazil:
 // 01187654321 can be found with 87654321
 pref("dom.phonenumber.substringmatching.BR", 8);
 pref("dom.phonenumber.substringmatching.CO", 10);
 pref("dom.phonenumber.substringmatching.VE", 7);
 
-// Enable hardware-accelerated Skia canvas
+// Support, but deprecate, hardware-accelerated Skia canvas
 pref("gfx.canvas.azure.backends", "skia");
-pref("gfx.canvas.azure.accelerated", true);
+pref("gfx.canvas.azure.accelerated", false);
 pref("gfx.canvas.azure.accelerated.limit", 64);
 
 // See ua-update.json.in for the packaged UA override list
 pref("general.useragent.updates.enabled", true);
 pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%");
 pref("general.useragent.updates.interval", 604800); // 1 week
 pref("general.useragent.updates.retry", 86400); // 1 day
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -809,18 +809,16 @@ pref("gfx.font_rendering.directwrite.use
 // comma separated list of backends to use in order of preference
 // e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo");
 pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo");
 pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo");
 #else
 #ifdef XP_MACOSX
 pref("gfx.content.azure.backends", "skia");
 pref("gfx.canvas.azure.backends", "skia");
-// Accelerated cg canvas where available (10.7+)
-pref("gfx.canvas.azure.accelerated", true);
 #else
 pref("gfx.canvas.azure.backends", "skia");
 pref("gfx.content.azure.backends", "skia");
 #endif
 #endif
 
 pref("gfx.canvas.skiagl.dynamic-cache", true);
 
--- a/servo/components/style/selector_map.rs
+++ b/servo/components/style/selector_map.rs
@@ -1,16 +1,16 @@
 /* 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/. */
 
 //! A data structure to efficiently index structs containing selectors by local
 //! name, ids and hash.
 
-use {Atom, LocalName, WeakAtom};
+use {Atom, LocalName, Namespace, WeakAtom};
 use applicable_declarations::ApplicableDeclarationList;
 use context::QuirksMode;
 use dom::TElement;
 use fallible::FallibleVec;
 use hash::{HashMap, HashSet};
 use hash::map as hash_map;
 use hashglobe::FailedAllocationError;
 use precomputed_hash::PrecomputedHash;
@@ -97,16 +97,18 @@ pub trait SelectorMapEntry: Sized + Clon
 #[derive(Debug, MallocSizeOf)]
 pub struct SelectorMap<T: 'static> {
     /// A hash from an ID to rules which contain that ID selector.
     pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
     /// A hash from a class name to rules which contain that class selector.
     pub class_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
     /// A hash from local name to rules which contain that local name selector.
     pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
+    /// A hash from namespace to rules which contain that namespace selector.
+    pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
     /// Rules that don't have ID, class, or element selectors.
     pub other: SmallVec<[T; 1]>,
     /// The number of entries in this map.
     pub count: usize,
 }
 
 impl<T: 'static> Default for SelectorMap<T> {
     #[inline]
@@ -120,26 +122,28 @@ impl<T: 'static> Default for SelectorMap
 // or when stdlib gets fallible collections
 impl<T: 'static> SelectorMap<T> {
     /// Trivially constructs an empty `SelectorMap`.
     pub fn new() -> Self {
         SelectorMap {
             id_hash: MaybeCaseInsensitiveHashMap::new(),
             class_hash: MaybeCaseInsensitiveHashMap::new(),
             local_name_hash: HashMap::default(),
+            namespace_hash: HashMap::default(),
             other: SmallVec::new(),
             count: 0,
         }
     }
 
     /// Clears the hashmap retaining storage.
     pub fn clear(&mut self) {
         self.id_hash.clear();
         self.class_hash.clear();
         self.local_name_hash.clear();
+        self.namespace_hash.clear();
         self.other.clear();
         self.count = 0;
     }
 
     /// Returns whether there are any entries in the map.
     pub fn is_empty(&self) -> bool {
         self.count == 0
     }
@@ -212,16 +216,28 @@ impl SelectorMap<Rule> {
                 matching_rules_list,
                 context,
                 flags_setter,
                 cascade_level,
                 shadow_cascade_order,
             )
         }
 
+        if let Some(rules) = self.namespace_hash.get(rule_hash_target.namespace()) {
+            SelectorMap::get_matching_rules(
+                element,
+                rules,
+                matching_rules_list,
+                context,
+                flags_setter,
+                cascade_level,
+                shadow_cascade_order,
+            )
+        }
+
         SelectorMap::get_matching_rules(
             element,
             &self.other,
             matching_rules_list,
             context,
             flags_setter,
             cascade_level,
             shadow_cascade_order,
@@ -256,17 +272,18 @@ impl SelectorMap<Rule> {
             ) {
                 matching_rules.push(rule.to_applicable_declaration_block(cascade_level, shadow_cascade_order));
             }
         }
     }
 }
 
 impl<T: SelectorMapEntry> SelectorMap<T> {
-    /// Inserts into the correct hash, trying id, class, and localname.
+    /// Inserts into the correct hash, trying id, class, localname and
+    /// namespace.
     pub fn insert(
         &mut self,
         entry: T,
         quirks_mode: QuirksMode,
     ) -> Result<(), FailedAllocationError> {
         self.count += 1;
 
         let vector = match find_bucket(entry.selector()) {
@@ -293,49 +310,51 @@ impl<T: SelectorMapEntry> SelectorMap<T>
                         .try_entry(lower_name.clone())?
                         .or_insert_with(SmallVec::new)
                         .try_push(entry.clone())?;
                 }
                 self.local_name_hash
                     .try_entry(name.clone())?
                     .or_insert_with(SmallVec::new)
             },
+            Bucket::Namespace(url) => self.namespace_hash
+                .try_entry(url.clone())?
+                .or_insert_with(SmallVec::new),
             Bucket::Universal => &mut self.other,
         };
 
         vector.try_push(entry)
     }
 
-    /// Looks up entries by id, class, local name, and other (in order).
+    /// Looks up entries by id, class, local name, namespace, and other (in
+    /// order).
     ///
     /// Each entry is passed to the callback, which returns true to continue
     /// iterating entries, or false to terminate the lookup.
     ///
     /// Returns false if the callback ever returns false.
     ///
     /// FIXME(bholley) This overlaps with SelectorMap<Rule>::get_all_matching_rules,
     /// but that function is extremely hot and I'd rather not rearrange it.
     #[inline]
     pub fn lookup<'a, E, F>(&'a self, element: E, quirks_mode: QuirksMode, mut f: F) -> bool
     where
         E: TElement,
         F: FnMut(&'a T) -> bool,
     {
-        // Id.
         if let Some(id) = element.id() {
             if let Some(v) = self.id_hash.get(id, quirks_mode) {
                 for entry in v.iter() {
                     if !f(&entry) {
                         return false;
                     }
                 }
             }
         }
 
-        // Class.
         let mut done = false;
         element.each_class(|class| {
             if !done {
                 if let Some(v) = self.class_hash.get(class, quirks_mode) {
                     for entry in v.iter() {
                         if !f(&entry) {
                             done = true;
                             return;
@@ -343,26 +362,32 @@ impl<T: SelectorMapEntry> SelectorMap<T>
                     }
                 }
             }
         });
         if done {
             return false;
         }
 
-        // Local name.
         if let Some(v) = self.local_name_hash.get(element.local_name()) {
             for entry in v.iter() {
                 if !f(&entry) {
                     return false;
                 }
             }
         }
 
-        // Other.
+        if let Some(v) = self.namespace_hash.get(element.namespace()) {
+            for entry in v.iter() {
+                if !f(&entry) {
+                    return false;
+                }
+            }
+        }
+
         for entry in self.other.iter() {
             if !f(&entry) {
                 return false;
             }
         }
 
         true
     }
@@ -420,27 +445,30 @@ impl<T: SelectorMapEntry> SelectorMap<T>
 
 enum Bucket<'a> {
     ID(&'a Atom),
     Class(&'a Atom),
     LocalName {
         name: &'a LocalName,
         lower_name: &'a LocalName,
     },
+    Namespace(&'a Namespace),
     Universal,
 }
 
 fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
     match *component {
         Component::ID(ref id) => Bucket::ID(id),
         Component::Class(ref class) => Bucket::Class(class),
         Component::LocalName(ref selector) => Bucket::LocalName {
             name: &selector.name,
             lower_name: &selector.lower_name,
         },
+        Component::Namespace(_, ref url) |
+        Component::DefaultNamespace(ref url) => Bucket::Namespace(url),
         // ::slotted(..) isn't a normal pseudo-element, so we can insert it on
         // the rule hash normally without much problem. For example, in a
         // selector like:
         //
         //   div::slotted(span)::before
         //
         // It looks like:
         //
@@ -465,30 +493,35 @@ fn specific_bucket_for<'a>(component: &'
 #[inline(always)]
 fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
     let mut current_bucket = Bucket::Universal;
 
     loop {
         // We basically want to find the most specific bucket,
         // where:
         //
-        //   id > class > local name > universal.
+        //   id > class > local name > namespace > universal.
         //
         for ss in &mut iter {
             let new_bucket = specific_bucket_for(ss);
             match new_bucket {
                 Bucket::ID(..) => return new_bucket,
                 Bucket::Class(..) => {
                     current_bucket = new_bucket;
                 },
                 Bucket::LocalName { .. } => {
+                    if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {
+                        current_bucket = new_bucket;
+                    }
+                },
+                Bucket::Namespace(..) => {
                     if matches!(current_bucket, Bucket::Universal) {
                         current_bucket = new_bucket;
                     }
-                },
+                }
                 Bucket::Universal => {},
             }
         }
 
         // Effectively, pseudo-elements are ignored, given only state
         // pseudo-classes may appear before them.
         if iter.next_sequence() != Some(Combinator::PseudoElement) {
             break;
--- a/testing/mochitest/runjunit.py
+++ b/testing/mochitest/runjunit.py
@@ -244,17 +244,20 @@ class JUnitTestRunner(MochitestDesktop):
                     self.current_full_name = full_name
 
         # Ideally all test names should be reported to suite_start, but these test
         # names are not known in advance.
         self.log.suite_start(["geckoview-junit"])
         try:
             cmd = self.build_command_line(test_filters)
             self.log.info("launching %s" % cmd)
-            self.device.shell(cmd, timeout=self.options.max_time, stdout_callback=callback)
+            p = self.device.shell(cmd, timeout=self.options.max_time, stdout_callback=callback)
+            if p.timedout:
+                self.log.error("TEST-UNEXPECTED-TIMEOUT | runjunit.py | "
+                               "Timed out after %d seconds" % self.options.max_time)
             self.log.info("Passed: %d" % self.pass_count)
             self.log.info("Failed: %d" % self.fail_count)
             self.log.info("Todo: %d" % self.todo_count)
         finally:
             self.log.suite_end()
 
         if self.check_for_crashes():
             self.fail_count = 1
@@ -321,17 +324,17 @@ class JunitArgumentParser(argparse.Argum
                                "(eg. /mnt/sdcard/tests or /data/local/tests).")
         self.add_argument("--disable-e10s",
                           action="store_false",
                           dest="e10s",
                           default=True,
                           help="Disable multiprocess mode in test app.")
         self.add_argument("--max-time",
                           action="store",
-                          type=str,
+                          type=int,
                           dest="max_time",
                           default="2400",
                           help="Max time in seconds to wait for tests (default 2400s).")
         self.add_argument("--runner",
                           action="store",
                           type=str,
                           dest="runner",
                           default="android.support.test.runner.AndroidJUnitRunner",
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -240,17 +240,17 @@ class ADBCommand(object):
 
         adb_process = ADBProcess(args)
 
         if timeout is None:
             timeout = self._timeout
 
         start_time = time.time()
         adb_process.exitcode = adb_process.proc.poll()
-        while ((time.time() - start_time) <= timeout and
+        while ((time.time() - start_time) <= float(timeout) and
                adb_process.exitcode is None):
             time.sleep(self._polling_interval)
             adb_process.exitcode = adb_process.proc.poll()
         if adb_process.exitcode is None:
             adb_process.proc.kill()
             adb_process.timedout = True
             adb_process.exitcode = adb_process.proc.poll()
 
@@ -1055,17 +1055,17 @@ class ADBDevice(ADBCommand):
             """
             if not hasattr(signal, 'SIGALRM'):
                 return filehandle.readline()
             if timeout is None:
                 timeout = 5
             line = ''
             default_alarm_handler = signal.getsignal(signal.SIGALRM)
             signal.signal(signal.SIGALRM, _timed_read_line_handler)
-            signal.alarm(timeout)
+            signal.alarm(int(timeout))
             try:
                 line = filehandle.readline()
             finally:
                 signal.alarm(0)
                 signal.signal(signal.SIGALRM, default_alarm_handler)
             return line
 
         if root and not self._have_root_shell:
@@ -1100,22 +1100,22 @@ class ADBDevice(ADBCommand):
         adb_process = ADBProcess(args)
 
         if timeout is None:
             timeout = self._timeout
 
         start_time = time.time()
         exitcode = adb_process.proc.poll()
         if not stdout_callback:
-            while ((time.time() - start_time) <= timeout) and exitcode is None:
+            while ((time.time() - start_time) <= float(timeout)) and exitcode is None:
                 time.sleep(self._polling_interval)
                 exitcode = adb_process.proc.poll()
         else:
             stdout2 = open(adb_process.stdout_file.name, 'rb')
-            while ((time.time() - start_time) <= timeout) and exitcode is None:
+            while ((time.time() - start_time) <= float(timeout)) and exitcode is None:
                 try:
                     line = _timed_read_line(stdout2)
                     if line and len(line) > 0:
                         stdout_callback(line.rstrip())
                     else:
                         # no new output, so sleep and poll
                         time.sleep(self._polling_interval)
                 except IOError:
--- a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/too_many_cues.html.ini
+++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/too_many_cues.html.ini
@@ -1,4 +1,3 @@
 [too_many_cues.html]
   expected:
-    if (os == "mac") and (processor == "x86_64") and (bits == 64): PASS
     FAIL
--- a/toolkit/components/find/nsFind.cpp
+++ b/toolkit/components/find/nsFind.cpp
@@ -591,21 +591,19 @@ nsFind::InitIterator(nsINode* aStartNode
   }
 
   NS_ENSURE_ARG_POINTER(aStartNode);
   NS_ENSURE_ARG_POINTER(aEndNode);
 
 #ifdef DEBUG_FIND
   DEBUG_FIND_PRINTF("InitIterator search range:\n");
   DEBUG_FIND_PRINTF(" -- start %d, ", aStartOffset);
-  nsCOMPtr<nsINode> start = do_QueryInterface(aStartNode);
-  DumpNode(start);
+  DumpNode(aStartNode);
   DEBUG_FIND_PRINTF(" -- end %d, ", aEndOffset);
-  nsCOMPtr<nsINode> end = do_QueryInterface(aEndNode);
-  DumpNode(end);
+  DumpNode(aEndNode);
 #endif
 
   nsresult rv = mIterator->Init(aStartNode, aStartOffset, aEndNode, aEndOffset);
   NS_ENSURE_SUCCESS(rv, rv);
   if (mFindBackward) {
     mIterator->Last();
   } else {
     mIterator->First();